function downloadHttp($url, &$ui, $save_dir = '.', $callback = null, $lastmodified = null, $accept = false, $channel = false)
{
static $redirect = 0;
// always reset , so we are clean case of error
$wasredirect = $redirect;
$redirect = 0;
if ($callback) {
call_user_func($callback, 'setup', array(&$ui));
}
$info = parse_url($url);
if (!isset($info['scheme']) || !in_array($info['scheme'], array('http', 'https'))) {
return PEAR::raiseError('Cannot download non-http URL "' . $url . '"');
}
if (!isset($info['host'])) {
return PEAR::raiseError('Cannot download from non-URL "' . $url . '"');
}
$host = isset($info['host']) ? $info['host'] : null;
$port = isset($info['port']) ? $info['port'] : null;
$path = isset($info['path']) ? $info['path'] : null;
if (isset($this)) {
$config =& $this->config;
} else {
$config =& PEAR_Config::singleton();
}
$proxy_host = $proxy_port = $proxy_user = $proxy_pass = '';
if ($config->get('http_proxy') && ($proxy = parse_url($config->get('http_proxy')))) {
$proxy_host = isset($proxy['host']) ? $proxy['host'] : null;
if (isset($proxy['scheme']) && $proxy['scheme'] == 'https') {
$proxy_host = 'ssl://' . $proxy_host;
}
$proxy_port = isset($proxy['port']) ? $proxy['port'] : 8080;
$proxy_user = isset($proxy['user']) ? urldecode($proxy['user']) : null;
$proxy_pass = isset($proxy['pass']) ? urldecode($proxy['pass']) : null;
if ($callback) {
call_user_func($callback, 'message', "Using HTTP proxy {$host}:{$port}");
}
}
if (empty($port)) {
$port = isset($info['scheme']) && $info['scheme'] == 'https' ? 443 : 80;
}
$scheme = isset($info['scheme']) && $info['scheme'] == 'https' ? 'https' : 'http';
if ($proxy_host != '') {
$fp = @fsockopen($proxy_host, $proxy_port, $errno, $errstr);
if (!$fp) {
if ($callback) {
call_user_func($callback, 'connfailed', array($proxy_host, $proxy_port, $errno, $errstr));
}
return PEAR::raiseError("Connection to `{$proxy_host}:{$proxy_port}' failed: {$errstr}", $errno);
}
if ($lastmodified === false || $lastmodified) {
$request = "GET {$url} HTTP/1.1\r\n";
$request .= "Host: {$host}\r\n";
} else {
$request = "GET {$url} HTTP/1.0\r\n";
$request .= "Host: {$host}\r\n";
}
} else {
$network_host = $host;
if (isset($info['scheme']) && $info['scheme'] == 'https') {
$network_host = 'ssl://' . $host;
}
$fp = @fsockopen($network_host, $port, $errno, $errstr);
if (!$fp) {
if ($callback) {
call_user_func($callback, 'connfailed', array($host, $port, $errno, $errstr));
}
return PEAR::raiseError("Connection to `{$host}:{$port}' failed: {$errstr}", $errno);
}
if ($lastmodified === false || $lastmodified) {
$request = "GET {$path} HTTP/1.1\r\n";
$request .= "Host: {$host}\r\n";
} else {
$request = "GET {$path} HTTP/1.0\r\n";
$request .= "Host: {$host}\r\n";
}
}
$ifmodifiedsince = '';
if (is_array($lastmodified)) {
if (isset($lastmodified['Last-Modified'])) {
$ifmodifiedsince = 'If-Modified-Since: ' . $lastmodified['Last-Modified'] . "\r\n";
}
if (isset($lastmodified['ETag'])) {
$ifmodifiedsince .= "If-None-Match: {$lastmodified['ETag']}\r\n";
}
} else {
$ifmodifiedsince = $lastmodified ? "If-Modified-Since: {$lastmodified}\r\n" : '';
}
$request .= $ifmodifiedsince . "User-Agent: PEAR/1.9.1/PHP/" . PHP_VERSION . "\r\n";
if (isset($this)) {
// only pass in authentication for non-static calls
$username = $config->get('username', null, $channel);
$password = $config->get('password', null, $channel);
if ($username && $password) {
$tmp = base64_encode("{$username}:{$password}");
$request .= "Authorization: Basic {$tmp}\r\n";
}
}
if ($proxy_host != '' && $proxy_user != '') {
$request .= 'Proxy-Authorization: Basic ' . base64_encode($proxy_user . ':' . $proxy_pass) . "\r\n";
}
if ($accept) {
$request .= 'Accept: ' . implode(', ', $accept) . "\r\n";
}
$request .= "Connection: close\r\n";
$request .= "\r\n";
fwrite($fp, $request);
$headers = array();
$reply = 0;
while (trim($line = fgets($fp, 1024))) {
if (preg_match('/^([^:]+):\\s+(.*)\\s*\\z/', $line, $matches)) {
$headers[strtolower($matches[1])] = trim($matches[2]);
} elseif (preg_match('|^HTTP/1.[01] ([0-9]{3}) |', $line, $matches)) {
$reply = (int) $matches[1];
if ($reply == 304 && ($lastmodified || $lastmodified === false)) {
return false;
}
if (!in_array($reply, array(200, 301, 302, 303, 305, 307))) {
return PEAR::raiseError("File {$scheme}://{$host}:{$port}{$path} not valid (received: {$line})");
}
}
}
if ($reply != 200) {
if (!isset($headers['location'])) {
return PEAR::raiseError("File {$scheme}://{$host}:{$port}{$path} not valid (redirected but no location)");
}
if ($wasredirect > 4) {
return PEAR::raiseError("File {$scheme}://{$host}:{$port}{$path} not valid (redirection looped more than 5 times)");
}
$redirect = $wasredirect + 1;
return $this->downloadHttp($headers['location'], $ui, $save_dir, $callback, $lastmodified, $accept);
}
if (isset($headers['content-disposition']) && preg_match('/\\sfilename=\\"([^;]*\\S)\\"\\s*(;|\\z)/', $headers['content-disposition'], $matches)) {
$save_as = basename($matches[1]);
} else {
$save_as = basename($url);
}
if ($callback) {
$tmp = call_user_func($callback, 'saveas', $save_as);
if ($tmp) {
$save_as = $tmp;
}
}
$dest_file = $save_dir . DIRECTORY_SEPARATOR . $save_as;
if (is_link($dest_file)) {
return PEAR::raiseError('SECURITY ERROR: Will not write to ' . $dest_file . ' as it is symlinked to ' . readlink($dest_file) . ' - Possible symlink attack');
}
if (!($wp = @fopen($dest_file, 'wb'))) {
fclose($fp);
if ($callback) {
call_user_func($callback, 'writefailed', array($dest_file, $php_errormsg));
}
return PEAR::raiseError("could not open {$dest_file} for writing");
}
$length = isset($headers['content-length']) ? $headers['content-length'] : -1;
$bytes = 0;
if ($callback) {
call_user_func($callback, 'start', array(basename($dest_file), $length));
}
while ($data = fread($fp, 1024)) {
$bytes += strlen($data);
if ($callback) {
call_user_func($callback, 'bytesread', $bytes);
}
if (!@fwrite($wp, $data)) {
fclose($fp);
if ($callback) {
call_user_func($callback, 'writefailed', array($dest_file, $php_errormsg));
}
return PEAR::raiseError("{$dest_file}: write failed ({$php_errormsg})");
}
}
fclose($fp);
fclose($wp);
if ($callback) {
call_user_func($callback, 'done', $bytes);
}
if ($lastmodified === false || $lastmodified) {
if (isset($headers['etag'])) {
$lastmodified = array('ETag' => $headers['etag']);
}
if (isset($headers['last-modified'])) {
if (is_array($lastmodified)) {
$lastmodified['Last-Modified'] = $headers['last-modified'];
} else {
$lastmodified = $headers['last-modified'];
}
}
return array($dest_file, $lastmodified, $headers);
}
return $dest_file;
}