<?php
/* HTTP Retriever
 * Version v1.1.10
 * Copyright 2004-2007, Steve Blinch
 * http://code.blitzaffe.com
 * ============================================================================ 
 * LICENSE
 *
 * This script is free software; you can redistribute it and/or modify it under the
 * terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option) any later
 * version.
 *
 * This script is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 * details.
 *	
 * You should have received a copy of the GNU General Public License along
 * with this script; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
define("UA_EXPLORER", 0);
define("UA_MOZILLA", 1);
define("UA_FIREFOX", 2);
define("UA_OPERA", 3);define('HRP_DEBUG', 0);
define('HRP_INFO', 1);
define('HRP_ERROR', 2);if (!defined("CURL_PATH"))
	define("CURL_PATH", "/usr/bin/curl");
if (!extension_loaded("curl") && !defined('HTTPR_NO_REDECLARE_CURL'))
{
	foreach (array(dirname(__FILE__) . "/", dirname(__FILE__) . "/libcurlemu/") as $k =>
		$libcurlemupath)
	{
		$libcurlemuinc = $libcurlemupath . 'libcurlemu.inc.php';
		if (is_readable($libcurlemuinc))
			require_once ($libcurlemuinc);
	}
}class HTTPRetriever
{	function HTTPRetriever()
	{		$this->headers = array("Referer" => "", "User-Agent" => "Joomla! 1.5 Installer",
			"Connection" => "close");		$this->version = "1.1";
		$this->force_curl = false;		$this->disable_curl = false;
		$this->insecure_ssl = false;		$this->connect_timeout = 15;		$this->max_time = 0;		$this->stream_timeout = 0;		$this->ignore_ssl_hostname = false;
		$this->result_close = false;
		$this->caching = false;
		$this->caching_intelligent = false;
		$this->caching_highvolume = false;
		$this->cache_path = '/tmp/';		$this->auth_username = '';
		$this->auth_password = '';
		$this->page_preprocessor = null;
		$this->progress_callback = null;		$this->transfer_callback = null;
		$this->follow_redirects = false;
	}
	function get($url, $ipaddress = false, $cookies = false)
	{
		$this->method = "GET";
		$this->post_data = "";
		$this->connect_ip = $ipaddress;
		return $this->_execute_request($url, $cookies);
	}
	function post($url, $data = "", $ipaddress = false, $cookies = false)
	{
		$this->method = "POST";
		$this->post_data = $data;
		$this->connect_ip = $ipaddress;
		return $this->_execute_request($url, $cookies);
	}	function head($url, $ipaddress = false, $cookies = false)
	{
		$this->method = "HEAD";
		$this->post_data = "";
		$this->connect_ip = $ipaddress;
		return $this->_execute_request($url, $cookies);
	}	function custom($method, $url, $data = "", $ipaddress = false, $cookies = false)
	{
		$this->method = $method;
		$this->post_data = $data;
		$this->connect_ip = $ipaddress;
		return $this->_execute_request($url, $cookies);
	}	function array_to_query($arrayname, $arraycontents)
	{
		$output = "";
		foreach ($arraycontents as $key => $value)
		{
			if (is_array($value))
			{
				$output .= $this->array_to_query(sprintf('%s[%s]', $arrayname, urlencode($key)),
					$value);
			} else
			{
				$output .= sprintf('%s[%s]=%s&', $arrayname, urlencode($key), urlencode($value));
			}
		}
		return $output;
	}
	function make_query_string($data)
	{
		$output = "";
		if (is_array($data))
		{
			foreach ($data as $name => $value)
			{
				if (is_array($value))
				{
					$output .= $this->array_to_query(urlencode($name), $value);
				} elseif (is_scalar($value))
				{
					$output .= urlencode($name) . "=" . urlencode($value) . "&";
				} else
				{
					$output .= urlencode($name) . "=" . urlencode(serialize($value)) . '&';
				}
			}
		}
		return substr($output, 0, strlen($output) - 1);
	}	function set_user_agent($agenttype, $agentversion, $windowsversion)
	{
		$useragents = array("Mozilla/4.0 (compatible; MSIE %agent%; Windows NT %os%)",
			"Mozilla/5.0 (Windows; U; Windows NT %os%; en-US; rv:%agent%) Gecko/20040514",
			"Mozilla/5.0 (Windows; U; Windows NT %os%; en-US; rv:1.7) Gecko/20040803 Firefox/%agent%",
			"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT %os%) Opera %agent%  [en]",
			);
		$agent = $useragents[$agenttype];
		$this->headers["User-Agent"] = str_replace(array("%agent%", "%os%"), array($agentversion,
			$windowsversion), $agent);
	}	function remove_chunkiness()
	{
		$remaining = $this->response;
		$this->response = "";		while ($remaining)
		{
			$hexlen = strpos($remaining, "\r");
			$chunksize = substr($remaining, 0, $hexlen);
			$argstart = strpos($chunksize, ';');
			if ($argstart !== false)
				$chunksize = substr($chunksize, 0, $argstart);
			$chunksize = (int)@hexdec($chunksize);			$this->response .= substr($remaining, $hexlen + 2, $chunksize);
			$remaining = substr($remaining, $hexlen + 2 + $chunksize + 2);			if (!$chunksize)
			{				$this->response .= $remaining;
				return;
			}
		}
	}	function _cache_store($token, $url)
	{		if ($this->caching_intelligent)
		{
			$urlinfo = parse_url($url);
			if ($this->method == 'POST')
			{
				$this->progress(HRP_DEBUG, "POST request; not caching");
				return;
			} else
				if (strlen($urlinfo['query']))
				{
					$this->progress(HRP_DEBUG, "Request used query string; not caching");
					return;
				} else
				{
					$this->progress(HRP_DEBUG, "Request appears to be static and cacheable");
				}
		}		$values = array("stats" => $this->stats, "result_code" => $this->result_code,
			"result_text" => $this->result_text, "version" => $this->version, "response" =>
			$this->response, "response_headers" => $this->response_headers,
			"response_cookies" => $this->response_cookies, "raw_response" => $this->
			raw_response, );
		$values = serialize($values);		$cache_dir = $this->cache_path;
		if (substr($cache_dir, -1) != '/')
			$cache_dir .= '/';		if ($this->caching_highvolume)
		{
			$cache_dir .= substr($token, 0, 2) . '/';
			if (!is_dir($cache_dir))
				@mkdir($cache_dir);
		}		$filename = $cache_dir . $token . '.tmp';		$fp = @fopen($filename, "w");
		if (!$fp)
		{
			$this->progress(HRP_DEBUG, "Unable to create cache file");
			return false;
		}
		fwrite($fp, $values);
		fclose($fp);		$this->progress(HRP_DEBUG, "HTTP response stored to cache");
	}	function _cache_fetch($token)
	{
		$this->cache_hit = false;
		$this->progress(HRP_DEBUG, "Checking for cached page value");		$cache_dir = $this->cache_path;
		if (substr($cache_dir, -1) != '/')
			$cache_dir .= '/';		if ($this->caching_highvolume)
			$cache_dir .= substr($token, 0, 2) . '/';		$filename = $cache_dir . $token . '.tmp';
		if (!file_exists($filename))
		{
			$this->progress(HRP_DEBUG, "Page not available in cache");
			return false;
		}		if (time() - filemtime($filename) > $this->caching)
		{
			$this->progress(HRP_DEBUG, "Page in cache is expired");
			@unlink($filename);
			return false;
		}		if ($values = file_get_contents($filename))
		{
			$values = unserialize($values);
			if (!$values)
			{
				$this->progress(HRP_DEBUG, "Invalid cache contents");
				return false;
			}			$this->stats = $values["stats"];
			$this->result_code = $values["result_code"];
			$this->result_text = $values["result_text"];
			$this->version = $values["version"];
			$this->response = $values["response"];
			$this->response_headers = $values["response_headers"];
			$this->response_cookies = $values["response_cookies"];
			$this->raw_response = $values["raw_response"];			$this->progress(HRP_DEBUG, "Page loaded from cache");
			$this->cache_hit = true;
			return true;
		} else
		{
			$this->progress(HRP_DEBUG, "Error reading cache file");
			return false;
		}
	}	function parent_path($path)
	{
		if (substr($path, 0, 1) == '/')
			$path = substr($path, 1);
		if (substr($path, -1) == '/')
			$path = substr($path, 0, strlen($path) - 1);
		$path = explode('/', $path);
		array_pop($path);
		return count($path) ? ('/' . implode('/', $path)) : '';
	}
	function response_to_request_cookies($cookies, $urlinfo)
	{		$cookiekeys = array_keys($cookies);
		if (!count($cookiekeys))
			return;		$testkey = array_pop($cookiekeys);
		if (!is_array($cookies[$testkey]))
		{
			foreach ($cookies as $k => $v)
				$this->request_cookies[$k] = $v;
			return;
		}		foreach ($cookies as $name => $paths)
		{
			foreach ($paths as $path => $values)
			{				if (isset($values['expires']) && ($values['expires'] < time()))
					continue;				$cookiehost = $values['domain'];
				$requesthost = $urlinfo['host'];				$domain_match = (($requesthost == $cookiehost) || (substr($requesthost, -(strlen
					($cookiehost) + 1)) == '.' . $cookiehost));				$cookiepath = $path;
				if (substr($cookiepath, -1) != '/')
					$cookiepath .= '/';
				$requestpath = $urlinfo['path'];
				if (substr($requestpath, -1) != '/')
					$requestpath .= '/';
				if (substr($requestpath, 0, strlen($cookiepath)) != $cookiepath)
					continue;				$this->request_cookies[$name] = $values['value'];
			}
		}
	}
	function _execute_request($url, $cookies = false)
	{		$redirect_codes = array(301, 302, 303, 307);		$redirect_methods = array('GET', 'HEAD');		$request_result = false;		$this->followed_redirect = false;
		$this->response_cookies = array();
		$this->cookie_headers = '';		$previous_redirects = array();
		do
		{			$request_result = $this->_send_request($url, $cookies);
			$lasturl = $url;
			$url = false;			if ($this->follow_redirects && in_array($this->result_code, $redirect_codes))
			{				if (($this->result_code == 303) || in_array($this->method, $redirect_methods))
				{
					$oldurlinfo = parse_url($lasturl);					$url = $this->response_headers['Location'];
					$urlinfo = parse_url($url);
					foreach ($oldurlinfo as $k => $v)
					{
						if (!$urlinfo[$k])
							$urlinfo[$k] = $v;
					}					if (substr($urlinfo['path'], 0, 1) != '/')
					{
						$baseurl = $oldurlinfo['path'];
						if (substr($baseurl, -1) != '/')
							$baseurl = $this->parent_path($url) . '/';
						$urlinfo['path'] = $baseurl . $urlinfo['path'];
					}					$url = $this->rebuild_url($urlinfo);					$this->method = "GET";
					$this->post_data = "";					$this->progress(HRP_INFO, 'Redirected to ' . $url);
				}
			}			if ($url && strlen($url))
			{				if (isset($previous_redirects[$url]))
				{
					$this->error = "Infinite redirection loop";
					$request_result = false;
					break;
				}
				if (is_numeric($this->follow_redirects) && (count($previous_redirects) > $this->
					follow_redirects))
				{
					$this->error = "Exceeded redirection limit";
					$request_result = false;
					break;
				}				$previous_redirects[$url] = true;
			}		} while ($url && strlen($url));		$per_request_headers = array('Host', 'Content-Length');
		foreach ($per_request_headers as $k => $v)
			unset($this->headers[$v]);		if (count($previous_redirects) > 1)
			$this->followed_redirect = array_keys($previous_redirects);		return $request_result;
	}	function _send_request($url, $cookies = false)
	{
		$this->progress(HRP_INFO, "Initiating {$this->method} request for $url");
		if ($this->caching)
		{
			$cachetoken = md5($url . '|' . $this->post_data);
			if ($this->_cache_fetch($cachetoken))
				return true;
		}		$time_request_start = $this->getmicrotime();		$urldata = parse_url($url);
		$this->urldata = &$urldata;
		$http_host = $urldata['host'] . (isset($urldata['port']) ? ':' . $urldata['port'] :
			'');		if (!isset($urldata["port"]) || !$urldata["port"])
			$urldata["port"] = ($urldata["scheme"] == "https") ? 443 : 80;
		if (!isset($urldata["path"]) || !$urldata["path"])
			$urldata["path"] = '/';		if (!empty($urldata['user']))
			$this->auth_username = $urldata['user'];
		if (!empty($urldata['pass']))
			$this->auth_password = $urldata['pass'];
		if ($this->version > "1.0")
			$this->headers["Host"] = $http_host;
		if ($this->method == "POST")
		{
			$this->headers["Content-Length"] = strlen($this->post_data);
			if (!isset($this->headers["Content-Type"]))
				$this->headers["Content-Type"] = "application/x-www-form-urlencoded";
		}		if (!empty($this->auth_username) || !empty($this->auth_password))
		{
			$this->headers['Authorization'] = 'Basic ' . base64_encode($this->auth_username .
				':' . $this->auth_password);
		} else
		{
			unset($this->headers['Authorization']);
		}		if (is_array($cookies))
		{
			$this->response_to_request_cookies($cookies, $urldata);
		}		if (!empty($urldata["query"]))
			$urldata["path"] .= "?" . $urldata["query"];
		$request = $this->method . " " . $urldata["path"] . " HTTP/" . $this->version .
			"\r\n";
		$request .= $this->build_headers();
		$request .= $this->post_data;		$this->response = "";
		$per_request_headers = array('Host', 'Content-Length');
		foreach ($per_request_headers as $k => $v)
			unset($this->headers[$v]);		$php_ssl_support = extension_loaded("openssl") && version_compare(phpversion(),
			"4.3.0") >= 0;
		if ((($urldata["scheme"] == "http") || ($php_ssl_support && ($urldata["scheme"] ==
			"https"))) && (!$this->force_curl))
		{
			$curl_mode = false;			$hostname = $this->connect_ip ? $this->connect_ip : $urldata['host'];
			if ($urldata["scheme"] == "https")
				$hostname = 'ssl://' . $hostname;			$time_connect_start = $this->getmicrotime();			$this->progress(HRP_INFO, 'Opening socket connection to ' . $hostname . ' port ' .
				$urldata['port']);			$this->expected_bytes = -1;
			$this->received_bytes = 0;			$fp = @fsockopen($hostname, $urldata["port"], $errno, $errstr, $this->
				connect_timeout);
			$time_connected = $this->getmicrotime();
			$connect_time = $time_connected - $time_connect_start;
			if ($fp)
			{
				if ($this->stream_timeout)
					stream_set_timeout($fp, $this->stream_timeout);
				$this->progress(HRP_INFO, "Connected; sending request");				$this->progress(HRP_DEBUG, $request);
				fputs($fp, $request);
				$this->raw_request = $request;				if ($this->stream_timeout)
				{
					$meta = socket_get_status($fp);
					if ($meta['timed_out'])
					{
						$this->error = "Exceeded socket write timeout of " . $this->stream_timeout .
							" seconds";
						$this->progress(HRP_ERROR, $this->error);
						return false;
					}
				}				$this->progress(HRP_INFO, "Request sent; awaiting reply");				$headers_received = false;
				$data_length = false;
				$chunked = false;
				$iterations = 0;
				while (!feof($fp))
				{
					if ($data_length > 0)
					{
						$line = fread($fp, $data_length);
						$this->progress(HRP_DEBUG, "[DL] Got a line: [{$line}] " . gettype($line));						if ($line !== false)
							$data_length -= strlen($line);
					} else
					{
						$line = @fgets($fp, 10240);
						$this->progress(HRP_DEBUG, "[NDL] Got a line: [{$line}] " . gettype($line));						if (($chunked) && ($line !== false))
						{
							$line = trim($line);
							if (!strlen($line))
								continue;							list($data_length, ) = explode(';', $line, 2);
							$data_length = (int)hexdec(trim($data_length));							if ($data_length == 0)
							{
								$this->progress(HRP_DEBUG, "Done");								break;
							}
							$this->progress(HRP_DEBUG, "Chunk length $data_length (0x$line)");
							continue;
						}
					}					if ($line === false)
					{
						$meta = socket_get_status($fp);
						if ($meta['timed_out'])
						{
							if ($this->stream_timeout)
							{
								$this->error = "Exceeded socket read timeout of " . $this->stream_timeout .
									" seconds";
							} else
							{
								$this->error = "Exceeded default socket read timeout";
							}
							$this->progress(HRP_ERROR, $this->error);
							return false;
						} else
						{
							$this->progress(HRP_ERROR, 'No data but not timed out');
						}
						continue;
					}					if ($this->max_time > 0)
					{
						if ($this->getmicrotime() - $time_request_start > $this->max_time)
						{
							$this->error = "Exceeded maximum transfer time of " . $this->max_time .
								" seconds";
							$this->progress(HRP_ERROR, $this->error);
							return false;
							break;
						}
					}					$this->response .= $line;					$iterations++;
					if ($headers_received)
					{
						if ($time_connected > 0)
						{
							$time_firstdata = $this->getmicrotime();
							$process_time = $time_firstdata - $time_connected;
							$time_connected = 0;
						}
						$this->received_bytes += strlen($line);
						if ($iterations % 20 == 0)
						{
							$this->update_transfer_counters();
						}
					}
					if ((!$headers_received) && (trim($line) == ""))
					{
						$headers_received = true;
						$this->progress(HRP_DEBUG, "Got headers: {$this->response}");						if (preg_match('/^Content-Length: ([0-9]+)/im', $this->response, $matches))
						{
							$data_length = (int)$matches[1];
							$this->progress(HRP_DEBUG, "Content length is $data_length");
							$this->expected_bytes = $data_length;
							$this->update_transfer_counters();
						} else
						{
							$this->progress(HRP_DEBUG, "No data length specified");
						}
						if (preg_match("/^Transfer-Encoding: chunked/im", $this->response, $matches))
						{
							$chunked = true;
							$this->progress(HRP_DEBUG, "Chunked transfer encoding requested");
						} else
						{
							$this->progress(HRP_DEBUG, "CTE not requested");
						}						if (preg_match_all("/^Set-Cookie: ((.*?)\=(.*?)(?:;\s*(.*))?)$/im", $this->
							response, $cookielist, PREG_SET_ORDER))
						{
							foreach ($cookielist as $k => $cookie)
								$this->cookie_headers .= $cookie[0] . "\n";							$cookiepath = preg_replace('/\/{2,}/', '', $urldata['path']);
							if (substr($cookiepath, -1) != '/')
							{
								$cookiepath = explode('/', $cookiepath);
								array_pop($cookiepath);
								$cookiepath = implode('/', $cookiepath) . '/';
							}							foreach ($cookielist as $k => $cookiedata)
							{
								list(, $rawcookie, $name, $value, $attributedata) = $cookiedata;
								$attributedata = explode(';', trim($attributedata));
								$attributes = array();								$cookie = array('value' => $value, 'raw' => trim($rawcookie), );
								foreach ($attributedata as $k => $attribute)
								{
									list($attrname, $attrvalue) = explode('=', trim($attribute));
									$cookie[$attrname] = $attrvalue;
								}								if (!isset($cookie['domain']) || !$cookie['domain'])
									$cookie['domain'] = $urldata['host'];
								if (!isset($cookie['path']) || !$cookie['path'])
									$cookie['path'] = $cookiepath;
								if (isset($cookie['expires']) && $cookie['expires'])
									$cookie['expires'] = strtotime($cookie['expires']);								if (!$this->validate_response_cookie($cookie, $urldata['host']))
									continue;								if (isset($cookie['expires']) && ($cookie['expires'] < time()))
								{
									unset($this->response_cookies[$name][$cookie['path']]);
									continue;
								}								$this->response_cookies[$name][$cookie['path']] = $cookie;
							}
						}
					}					if ($this->result_close)
					{
						if (preg_match_all("/HTTP\/([0-9\.]+) ([0-9]+) (.*?)[\r\n]/", $this->response, $matches))
						{
							$resultcodes = $matches[2];
							foreach ($resultcodes as $k => $code)
							{
								if ($code != 100)
								{
									$this->progress(HRP_INFO, 'HTTP result code received; closing connection');									$this->result_code = $code;
									$this->result_text = $matches[3][$k];
									fclose($fp);									return ($this->result_code == 200);
								}
							}
						}
					}
				}
				if (feof($fp))
					$this->progress(HRP_DEBUG, 'EOF on socket');
				@fclose($fp);				$this->update_transfer_counters();				if (is_array($this->response_cookies))
				{
					foreach ($this->response_cookies as $name => $paths)
					{
						ksort($this->response_cookies[$name]);
					}
				}
				$this->progress(HRP_INFO, 'Request complete');
			} else
			{
				$this->error = strtoupper($urldata["scheme"]) . " connection to " . $hostname .
					" port " . $urldata["port"] . " failed";
				$this->progress(HRP_ERROR, $this->error);
				return false;
			}		} elseif (!$this->disable_curl && (($urldata["scheme"] == "https") || ($this->
		force_curl)))
		{
			$this->progress(HRP_INFO, 'Passing HTTP request for $url to CURL');
			$curl_mode = true;
			if (!$this->_curl_request($url))
				return false;		} else
		{
			$this->error = "Unsupported protocol: " . $urldata["scheme"];
			$this->progress(HRP_ERROR, $this->error);
			return false;
		}		$this->raw_response = $this->response;		$totallength = strlen($this->response);		do
		{
			$headerlength = strpos($this->response, "\r\n\r\n");			$response_headers = explode("\r\n", substr($this->response, 0, $headerlength));
			$http_status = trim(array_shift($response_headers));
			foreach ($response_headers as $line)
			{
				list($k, $v) = explode(":", $line, 2);
				$this->response_headers[trim($k)] = trim($v);
			}
			$this->response = substr($this->response, $headerlength + 4);
			if (!preg_match("/^HTTP\/([0-9\.]+) ([0-9]+) (.*?)$/", $http_status, $matches))
			{
				$matches = array("", $this->version, 0, "HTTP request error");
			}
			list(, $response_version, $this->result_code, $this->result_text) = $matches;		} while (($this->result_code == 100) && ($headerlength));		if (!$curl_mode)
		{
			$total_time = $this->getmicrotime() - $time_request_start;
			$transfer_time = $total_time - $connect_time;
			$this->stats = array("total_time" => $total_time, "connect_time" => $connect_time,
				"process_time" => $process_time,
				"url" => $url, "content_type" => $this->response_headers["Content-Type"],
				"http_code" => $this->result_code, "header_size" => $headerlength,
				"request_size" => $totallength, "filetime" => strtotime($this->response_headers["Date"]),
				"pretransfer_time" => $connect_time, "size_download" => $totallength,
				"speed_download" => $transfer_time > 0 ? round($totallength / $transfer_time) :
				0, "download_content_length" => $totallength, "upload_content_length" => 0,
				"starttransfer_time" => $connect_time, );
		}
		$ok = ($this->result_code == 200);
		if ($ok)
		{			if (is_callable($this->page_preprocessor))
				$this->response = call_user_func($this->page_preprocessor, $this, $this->
					response);			if ($this->caching)
				$this->_cache_store($cachetoken, $url);
		}		return $ok;
	}	function validate_response_cookie($cookie, $actual_hostname)
	{		$cookiehost = $cookie['domain'];
		$p = strrpos($cookiehost, '.');
		if ($p === false)
			return false;		$tld = strtolower(substr($cookiehost, $p + 1));
		$special_domains = array("com", "edu", "net", "org", "gov", "mil", "int");
		$periods_required = in_array($tld, $special_domains) ? 1 : 2;		$periods = substr_count($cookiehost, '.');
		if ($periods < $periods_required)
			return false;		if (substr($actual_hostname, 0, 1) != '.')
			$actual_hostname = '.' . $actual_hostname;
		if (substr($cookiehost, 0, 1) != '.')
			$cookiehost = '.' . $cookiehost;
		$domain_match = (($actual_hostname == $cookiehost) || (substr($actual_hostname,
			-strlen($cookiehost)) == $cookiehost));		return $domain_match;	}	function build_headers()
	{
		$headers = "";
		foreach ($this->headers as $name => $value)
		{
			$value = trim($value);
			if (empty($value))
				continue;
			$headers .= "{$name}: {$value}\r\n";
		}		if (isset($this->request_cookies) && is_array($this->request_cookies))
		{
			$cookielist = array();
			foreach ($this->request_cookies as $name => $value)
			{
				$cookielist[] = "{$name}={$value}";
			}
			if (count($cookielist))
				$headers .= "Cookie: " . implode('; ', $cookielist) . "\r\n";
		}
		$headers .= "\r\n";		return $headers;
	}	function rebuild_url($urlinfo)
	{
		$url = $urlinfo['scheme'] . '://';		if ($urlinfo['user'] || $urlinfo['pass'])
		{
			$url .= $urlinfo['user'];
			if ($urlinfo['pass'])
			{
				if ($urlinfo['user'])
					$url .= ':';
				$url .= $urlinfo['pass'];
			}
			$url .= '@';
		}		$url .= $urlinfo['host'];
		if ($urlinfo['port'])
			$url .= ':' . $urlinfo['port'];		$url .= $urlinfo['path'];		if ($urlinfo['query'])
			$url .= '?' . $urlinfo['query'];
		if ($urlinfo['fragment'])
			$url .= '#' . $urlinfo['fragment'];		return $url;
	}	function _replace_hostname(&$url, $new_hostname)
	{
		$parts = parse_url($url);
		$old_hostname = $parts['host'];		$parts['host'] = $new_hostname;		$url = $this->rebuild_url($parts);		return $old_hostname;
	}	function _curl_request($url)
	{
		$this->error = false;		if ($this->connect_ip)
		{
			$old_hostname = $this->_replace_hostname($url, $this->connect_ip);
			$this->headers["Host"] = $old_hostname;
		}
		unset($this->headers["Content-Length"]);
		$headers = explode("\n", $this->build_headers());		$ch = curl_init();
		curl_setopt($ch, CURLOPT_URL, $url);
		curl_setopt($ch, CURLOPT_USERAGENT, $this->headers["User-Agent"]);
		curl_setopt($ch, CURLOPT_HEADER, 1);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);		curl_setopt($ch, CURLOPT_TIMEOUT, 10);
		if ($this->curl_proxy)
		{
			curl_setopt($ch, CURLOPT_PROXY, $this->curl_proxy);
		}
		curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);		if ($this->method == "POST")
		{
			curl_setopt($ch, CURLOPT_POST, 1);
			curl_setopt($ch, CURLOPT_POSTFIELDS, $this->post_data);
		}
		if ($this->insecure_ssl)
		{
			curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
		}
		if ($this->ignore_ssl_hostname)
		{
			curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1);
		}		$this->response = curl_exec($ch);
		if (curl_errno($ch) != 0)
		{
			$this->error = "CURL error #" . curl_errno($ch) . ": " . curl_error($ch);
		}		$this->stats = curl_getinfo($ch);
		curl_close($ch);		return ($this->error === false);
	}	function progress($level, $msg)
	{
		if (is_callable($this->progress_callback))
			call_user_func($this->progress_callback, $level, $msg);
	}
	function get_error()
	{
		return $this->error ? $this->error : 'HTTP ' . $this->result_code . ': ' . $this->
			result_text;
	}	function get_content_type()
	{
		if (!$ctype = $this->response_headers['Content-Type'])
		{
			$ctype = $this->response_headers['Content-type'];
		}
		list($ctype, ) = explode(';', $ctype);		return strtolower($ctype);
	}	function update_transfer_counters()
	{
		if (is_callable($this->transfer_callback))
			call_user_func($this->transfer_callback, $this->received_bytes, $this->
				expected_bytes);
	}	function set_transfer_display($enabled = true)
	{
		if ($enabled)
		{
			$this->transfer_callback = array(&$this, 'default_transfer_callback');
		} else
		{
			unset($this->transfer_callback);
		}
	}	function set_progress_display($enabled = true)
	{
		if ($enabled)
		{
			$this->progress_callback = array(&$this, 'default_progress_callback');
		} else
		{
			unset($this->progress_callback);
		}
	}	function default_progress_callback($severity, $message)
	{
		$severities = array(HRP_DEBUG => 'debug', HRP_INFO => 'info', HRP_ERROR =>
			'error', );		echo date('Y-m-d H:i:sa') . ' [' . $severities[$severity] . '] ' . $message . "\n";
		flush();
	}	function default_transfer_callback($transferred, $expected)
	{
		$msg = "Transferred " . round($transferred / 1024, 1);
		if ($expected >= 0)
			$msg .= "/" . round($expected / 1024, 1);
		$msg .= "KB";
		if ($expected > 0)
			$msg .= " (" . round($transferred * 100 / $expected, 1) . "%)";
		echo date('Y-m-d H:i:sa') . " $msg\n";
		flush();
	}	function getmicrotime()
	{
		list($usec, $sec) = explode(" ", microtime());
		return ((float)$usec + (float)$sec);
	}
}?>