/public/external/pydio/core/classes/http_class/http_class.php
PHP | 1883 lines | 1832 code | 42 blank | 9 comment | 484 complexity | a4cff61c9334d287a97a6faeb4236763 MD5 | raw file
Possible License(s): BSD-2-Clause, Apache-2.0, LGPL-3.0, LGPL-2.1, MPL-2.0-no-copyleft-exception, BSD-3-Clause, LGPL-2.0, AGPL-3.0
- <?php
- /*
- * http.php
- *
- * @(#) $Header: /opt2/ena/metal/http/http.php,v 1.88 2011/10/24 08:26:56 mlemos Exp $
- *
- */
- define('HTTP_CLIENT_ERROR_UNSPECIFIED_ERROR', -1);
- define('HTTP_CLIENT_ERROR_NO_ERROR', 0);
- define('HTTP_CLIENT_ERROR_INVALID_SERVER_ADDRESS', 1);
- define('HTTP_CLIENT_ERROR_CANNOT_CONNECT', 2);
- define('HTTP_CLIENT_ERROR_COMMUNICATION_FAILURE', 3);
- define('HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE', 4);
- define('HTTP_CLIENT_ERROR_PROTOCOL_FAILURE', 5);
- define('HTTP_CLIENT_ERROR_INVALID_PARAMETERS', 6);
- class http_class
- {
- public $host_name="";
- public $host_port=0;
- public $proxy_host_name="";
- public $proxy_host_port=80;
- public $socks_host_name = '';
- public $socks_host_port = 1080;
- public $socks_version = '5';
- public $protocol="http";
- public $request_method="GET";
- public $user_agent='httpclient (http://www.phpclasses.org/httpclient $Revision: 1.88 $)';
- public $accept='';
- public $authentication_mechanism="";
- public $user;
- public $password;
- public $realm;
- public $workstation;
- public $proxy_authentication_mechanism="";
- public $proxy_user;
- public $proxy_password;
- public $proxy_realm;
- public $proxy_workstation;
- public $request_uri="";
- public $request="";
- public $request_headers=array();
- public $request_user;
- public $request_password;
- public $request_realm;
- public $request_workstation;
- public $proxy_request_user;
- public $proxy_request_password;
- public $proxy_request_realm;
- public $proxy_request_workstation;
- public $request_body="";
- public $request_arguments=array();
- public $protocol_version="1.1";
- public $timeout=0;
- public $data_timeout=0;
- public $debug=0;
- public $log_debug=0;
- public $debug_response_body=1;
- public $html_debug=0;
- public $support_cookies=1;
- public $cookies=array();
- public $error="";
- public $error_code = HTTP_CLIENT_ERROR_NO_ERROR;
- public $exclude_address="";
- public $follow_redirect=0;
- public $redirection_limit=5;
- public $response_status="";
- public $response_message="";
- public $file_buffer_length=8000;
- public $force_multipart_form_post=0;
- public $prefer_curl = 0;
- public $keep_alive = 1;
- /* private variables - DO NOT ACCESS */
- public $state="Disconnected";
- public $use_curl=0;
- public $connection=0;
- public $content_length=0;
- public $response="";
- public $read_response=0;
- public $read_length=0;
- public $request_host="";
- public $next_token="";
- public $redirection_level=0;
- public $chunked=0;
- public $remaining_chunk=0;
- public $last_chunk_read=0;
- public $months=array(
- "Jan"=>"01",
- "Feb"=>"02",
- "Mar"=>"03",
- "Apr"=>"04",
- "May"=>"05",
- "Jun"=>"06",
- "Jul"=>"07",
- "Aug"=>"08",
- "Sep"=>"09",
- "Oct"=>"10",
- "Nov"=>"11",
- "Dec"=>"12");
- public $session='';
- public $connection_close=0;
- public $force_close = 0;
- public $connected_host = '';
- public $connected_port = -1;
- public $connected_ssl = 0;
- /* Private methods - DO NOT CALL */
- public Function Tokenize($string,$separator="")
- {
- if (!strcmp($separator,"")) {
- $separator=$string;
- $string=$this->next_token;
- }
- for ($character=0;$character<strlen($separator);$character++) {
- if(GetType($position=strpos($string,$separator[$character]))=="integer")
- $found=(IsSet($found) ? min($found,$position) : $position);
- }
- if (IsSet($found)) {
- $this->next_token=substr($string,$found+1);
- return(substr($string,0,$found));
- } else {
- $this->next_token="";
- return($string);
- }
- }
- public Function CookieEncode($value, $name)
- {
- return($name ? str_replace("=", "%25", $value) : str_replace(";", "%3B", $value));
- }
- public Function SetError($error, $error_code = HTTP_CLIENT_ERROR_UNSPECIFIED_ERROR)
- {
- $this->error_code = $error_code;
- return($this->error=$error);
- }
- public Function SetPHPError($error, &$php_error_message, $error_code = HTTP_CLIENT_ERROR_UNSPECIFIED_ERROR)
- {
- if(IsSet($php_error_message)
- && strlen($php_error_message))
- $error.=": ".$php_error_message;
- return($this->SetError($error, $error_code));
- }
- public Function SetDataAccessError($error,$check_connection=0)
- {
- $this->error=$error;
- $this->error_code = HTTP_CLIENT_ERROR_COMMUNICATION_FAILURE;
- if(!$this->use_curl
- && function_exists("socket_get_status"))
- {
- $status=socket_get_status($this->connection);
- if($status["timed_out"])
- $this->error.=": data access time out";
- elseif ($status["eof"]) {
- if($check_connection)
- $this->error="";
- else
- $this->error.=": the server disconnected";
- }
- }
- }
- public Function OutputDebug($message)
- {
- if($this->log_debug)
- error_log($message);
- else {
- $message.="\n";
- if($this->html_debug)
- $message=str_replace("\n","<br />\n",HtmlEntities($message));
- echo $message;
- flush();
- }
- }
- public Function GetLine()
- {
- for ($line="";;) {
- if ($this->use_curl) {
- $eol=strpos($this->response,"\n",$this->read_response);
- $data=($eol ? substr($this->response,$this->read_response,$eol+1-$this->read_response) : "");
- $this->read_response+=strlen($data);
- } else {
- if (feof($this->connection)) {
- $this->SetDataAccessError("reached the end of data while reading from the HTTP server connection");
- return(0);
- }
- $data=fgets($this->connection,100);
- }
- if(GetType($data)!="string"
- || strlen($data)==0)
- {
- $this->SetDataAccessError("it was not possible to read line from the HTTP server");
- return(0);
- }
- $line.=$data;
- $length=strlen($line);
- if($length
- && !strcmp(substr($line,$length-1,1),"\n"))
- {
- $length-=(($length>=2 && !strcmp(substr($line,$length-2,1),"\r")) ? 2 : 1);
- $line=substr($line,0,$length);
- if($this->debug)
- $this->OutputDebug("S $line");
- return($line);
- }
- }
- }
- public Function PutLine($line)
- {
- if($this->debug)
- $this->OutputDebug("C $line");
- if (!fputs($this->connection,$line."\r\n")) {
- $this->SetDataAccessError("it was not possible to send a line to the HTTP server");
- return(0);
- }
- return(1);
- }
- public Function PutData($data)
- {
- if (strlen($data)) {
- if($this->debug)
- $this->OutputDebug('C '.$data);
- if (!fputs($this->connection,$data)) {
- $this->SetDataAccessError("it was not possible to send data to the HTTP server");
- return(0);
- }
- }
- return(1);
- }
- public Function FlushData()
- {
- if (!fflush($this->connection)) {
- $this->SetDataAccessError("it was not possible to send data to the HTTP server");
- return(0);
- }
- return(1);
- }
- public Function ReadChunkSize()
- {
- if ($this->remaining_chunk==0) {
- $debug=$this->debug;
- if(!$this->debug_response_body)
- $this->debug=0;
- $line=$this->GetLine();
- $this->debug=$debug;
- if(GetType($line)!="string")
- return($this->SetError("could not read chunk start: ".$this->error, $this->error_code));
- $this->remaining_chunk=hexdec($line);
- if ($this->remaining_chunk == 0) {
- if(!$this->debug_response_body)
- $this->debug=0;
- $line=$this->GetLine();
- $this->debug=$debug;
- if(GetType($line)!="string")
- return($this->SetError("could not read chunk end: ".$this->error, $this->error_code));
- }
- }
- return("");
- }
- public Function ReadBytes($length)
- {
- if ($this->use_curl) {
- $bytes=substr($this->response,$this->read_response,min($length,strlen($this->response)-$this->read_response));
- $this->read_response+=strlen($bytes);
- if($this->debug
- && $this->debug_response_body
- && strlen($bytes))
- $this->OutputDebug("S ".$bytes);
- } else {
- if ($this->chunked) {
- for ($bytes="",$remaining=$length;$remaining;) {
- if(strlen($this->ReadChunkSize()))
- return("");
- if ($this->remaining_chunk==0) {
- $this->last_chunk_read=1;
- break;
- }
- $ask=min($this->remaining_chunk,$remaining);
- $chunk=@fread($this->connection,$ask);
- $read=strlen($chunk);
- if ($read==0) {
- $this->SetDataAccessError("it was not possible to read data chunk from the HTTP server");
- return("");
- }
- if($this->debug
- && $this->debug_response_body)
- $this->OutputDebug("S ".$chunk);
- $bytes.=$chunk;
- $this->remaining_chunk-=$read;
- $remaining-=$read;
- if ($this->remaining_chunk==0) {
- if(feof($this->connection))
- return($this->SetError("reached the end of data while reading the end of data chunk mark from the HTTP server", HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
- $data=@fread($this->connection,2);
- if (strcmp($data,"\r\n")) {
- $this->SetDataAccessError("it was not possible to read end of data chunk from the HTTP server");
- return("");
- }
- }
- }
- } else {
- $bytes=@fread($this->connection,$length);
- if (strlen($bytes)) {
- if($this->debug
- && $this->debug_response_body)
- $this->OutputDebug("S ".$bytes);
- } else
- $this->SetDataAccessError("it was not possible to read data from the HTTP server", $this->connection_close);
- }
- }
- return($bytes);
- }
- public Function EndOfInput()
- {
- if($this->use_curl)
- return($this->read_response>=strlen($this->response));
- if($this->chunked)
- return($this->last_chunk_read);
- if($this->content_length_set)
- return($this->content_length <= $this->read_length);
- return(feof($this->connection));
- }
- public Function Resolve($domain, &$ip, $server_type)
- {
- if(preg_match('/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/',$domain))
- $ip=$domain;
- else {
- if($this->debug)
- $this->OutputDebug('Resolving '.$server_type.' server domain "'.$domain.'"...');
- if(!strcmp($ip=@gethostbyname($domain),$domain))
- $ip="";
- }
- if(strlen($ip)==0
- || (strlen($this->exclude_address)
- && !strcmp(@gethostbyname($this->exclude_address),$ip)))
- return($this->SetError("could not resolve the host domain \"".$domain."\"", HTTP_CLIENT_ERROR_INVALID_SERVER_ADDRESS));
- return('');
- }
- public Function Connect($host_name, $host_port, $ssl, $server_type = 'HTTP')
- {
- $domain=$host_name;
- $port = $host_port;
- if(strlen($error = $this->Resolve($domain, $ip, $server_type)))
- return($error);
- if (strlen($this->socks_host_name)) {
- switch ($this->socks_version) {
- case '4':
- $version = 4;
- break;
- case '5':
- $version = 5;
- break;
- default:
- return('it was not specified a supported SOCKS protocol version');
- break;
- }
- $host_ip = $ip;
- $port = $this->socks_host_port;
- $host_server_type = $server_type;
- $server_type = 'SOCKS';
- if(strlen($error = $this->Resolve($this->socks_host_name, $ip, $server_type)))
- return($error);
- }
- if($this->debug)
- $this->OutputDebug('Connecting to '.$server_type.' server IP '.$ip.' port '.$port.'...');
- if($ssl)
- $ip="ssl://".$host_name;
- if (($this->connection=($this->timeout ? @fsockopen($ip, $port, $errno, $error, $this->timeout) : @fsockopen($ip, $port, $errno)))==0) {
- $error_code = HTTP_CLIENT_ERROR_CANNOT_CONNECT;
- switch ($errno) {
- case -3:
- return($this->SetError("socket could not be created", $error_code));
- case -4:
- return($this->SetError("dns lookup on hostname \"".$host_name."\" failed", $error_code));
- case -5:
- return($this->SetError("connection refused or timed out", $error_code));
- case -6:
- return($this->SetError("fdopen() call failed", $error_code));
- case -7:
- return($this->SetError("setvbuf() call failed", $error_code));
- default:
- return($this->SetPHPError($errno." could not connect to the host \"".$host_name."\"",$php_errormsg, $error_code));
- }
- } else {
- if($this->data_timeout
- && function_exists("socket_set_timeout"))
- socket_set_timeout($this->connection,$this->data_timeout,0);
- if (strlen($this->socks_host_name)) {
- if($this->debug)
- $this->OutputDebug('Connected to the SOCKS server '.$this->socks_host_name);
- $send_error = 'it was not possible to send data to the SOCKS server';
- $receive_error = 'it was not possible to receive data from the SOCKS server';
- switch ($version) {
- case 4:
- $command = 1;
- $user = '';
- if(!fputs($this->connection, chr($version).chr($command).pack('nN', $host_port, ip2long($host_ip)).$user.Chr(0)))
- $error = $this->SetDataAccessError($send_error);
- else {
- $response = fgets($this->connection, 9);
- if(strlen($response) != 8)
- $error = $this->SetDataAccessError($receive_error);
- else {
- $socks_errors = array(
- "\x5a"=>'',
- "\x5b"=>'request rejected',
- "\x5c"=>'request failed because client is not running identd (or not reachable from the server)',
- "\x5d"=>'request failed because client\'s identd could not confirm the user ID string in the request',
- );
- $error_code = $response[1];
- $error = (IsSet($socks_errors[$error_code]) ? $socks_errors[$error_code] : 'unknown');
- if(strlen($error))
- $error = 'SOCKS error: '.$error;
- }
- }
- break;
- case 5:
- if($this->debug)
- $this->OutputDebug('Negotiating the authentication method ...');
- $methods = 1;
- $method = 0;
- if(!fputs($this->connection, chr($version).chr($methods).chr($method)))
- $error = $this->SetDataAccessError($send_error);
- else {
- $response = fgets($this->connection, 3);
- if(strlen($response) != 2)
- $error = $this->SetDataAccessError($receive_error);
- elseif(Ord($response[1]) != $method)
- $error = 'the SOCKS server requires an authentication method that is not yet supported';
- else {
- if($this->debug)
- $this->OutputDebug('Connecting to '.$host_server_type.' server IP '.$host_ip.' port '.$host_port.'...');
- $command = 1;
- $address_type = 1;
- if(!fputs($this->connection, chr($version).chr($command)."\x00".chr($address_type).pack('Nn', ip2long($host_ip), $host_port)))
- $error = $this->SetDataAccessError($send_error);
- else {
- $response = fgets($this->connection, 11);
- if(strlen($response) != 10)
- $error = $this->SetDataAccessError($receive_error);
- else {
- $socks_errors = array(
- "\x00"=>'',
- "\x01"=>'general SOCKS server failure',
- "\x02"=>'connection not allowed by ruleset',
- "\x03"=>'Network unreachable',
- "\x04"=>'Host unreachable',
- "\x05"=>'Connection refused',
- "\x06"=>'TTL expired',
- "\x07"=>'Command not supported',
- "\x08"=>'Address type not supported'
- );
- $error_code = $response[1];
- $error = (IsSet($socks_errors[$error_code]) ? $socks_errors[$error_code] : 'unknown');
- if(strlen($error))
- $error = 'SOCKS error: '.$error;
- }
- }
- }
- }
- break;
- default:
- $error = 'support for SOCKS protocol version '.$this->socks_version.' is not yet implemented';
- break;
- }
- if (strlen($error)) {
- fclose($this->connection);
- return($error);
- }
- }
- if($this->debug)
- $this->OutputDebug("Connected to $host_name");
- if(strlen($this->proxy_host_name)
- && !strcmp(strtolower($this->protocol), 'https'))
- {
- if(function_exists('stream_socket_enable_crypto')
- && in_array('ssl', stream_get_transports()))
- $this->state = "ConnectedToProxy";
- else {
- $this->OutputDebug("It is not possible to start SSL after connecting to the proxy server. If the proxy refuses to forward the SSL request, you may need to upgrade to PHP 5.1 or later with OpenSSL support enabled.");
- $this->state="Connected";
- }
- } else
- $this->state="Connected";
- return("");
- }
- }
- public Function Disconnect()
- {
- if($this->debug)
- $this->OutputDebug("Disconnected from ".$this->connected_host);
- if ($this->use_curl) {
- curl_close($this->connection);
- $this->response="";
- } else
- fclose($this->connection);
- $this->state="Disconnected";
- return("");
- }
- /* Public methods */
- public Function GetRequestArguments($url, &$arguments)
- {
- $this->error = '';
- $this->error_code = HTTP_CLIENT_ERROR_NO_ERROR;
- $arguments=array();
- $url = str_replace(' ', '%20', $url);
- $parameters=@parse_url($url);
- if(!$parameters)
- return($this->SetError("it was not specified a valid URL", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
- if(!IsSet($parameters["scheme"]))
- return($this->SetError("it was not specified the protocol type argument", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
- switch (strtolower($parameters["scheme"])) {
- case "http":
- case "https":
- $arguments["Protocol"]=$parameters["scheme"];
- break;
- default:
- return($parameters["scheme"]." connection scheme is not yet supported");
- }
- if(!IsSet($parameters["host"]))
- return($this->SetError("it was not specified the connection host argument", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
- $arguments["HostName"]=$parameters["host"];
- $arguments["Headers"]=array("Host"=>$parameters["host"].(IsSet($parameters["port"]) ? ":".$parameters["port"] : ""));
- if (IsSet($parameters["user"])) {
- $arguments["AuthUser"]=UrlDecode($parameters["user"]);
- if(!IsSet($parameters["pass"]))
- $arguments["AuthPassword"]="";
- }
- if (IsSet($parameters["pass"])) {
- if(!IsSet($parameters["user"]))
- $arguments["AuthUser"]="";
- $arguments["AuthPassword"]=UrlDecode($parameters["pass"]);
- }
- if (IsSet($parameters["port"])) {
- if(strcmp($parameters["port"],strval(intval($parameters["port"]))))
- return($this->SetError("it was not specified a valid connection host argument", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
- $arguments["HostPort"]=intval($parameters["port"]);
- } else
- $arguments["HostPort"]=0;
- $arguments["RequestURI"]=(IsSet($parameters["path"]) ? $parameters["path"] : "/").(IsSet($parameters["query"]) ? "?".$parameters["query"] : "");
- if(strlen($this->user_agent))
- $arguments["Headers"]["User-Agent"]=$this->user_agent;
- if(strlen($this->accept))
- $arguments["Headers"]["Accept"]=$this->accept;
- return("");
- }
- public Function Open($arguments)
- {
- if(strlen($this->error))
- return($this->error);
- $error_code = HTTP_CLIENT_ERROR_UNSPECIFIED_ERROR;
- if(IsSet($arguments["HostName"]))
- $this->host_name=$arguments["HostName"];
- if(IsSet($arguments["HostPort"]))
- $this->host_port=$arguments["HostPort"];
- if(IsSet($arguments["ProxyHostName"]))
- $this->proxy_host_name=$arguments["ProxyHostName"];
- if(IsSet($arguments["ProxyHostPort"]))
- $this->proxy_host_port=$arguments["ProxyHostPort"];
- if(IsSet($arguments["SOCKSHostName"]))
- $this->socks_host_name=$arguments["SOCKSHostName"];
- if(IsSet($arguments["SOCKSHostPort"]))
- $this->socks_host_port=$arguments["SOCKSHostPort"];
- if(IsSet($arguments["SOCKSVersion"]))
- $this->socks_version=$arguments["SOCKSVersion"];
- if(IsSet($arguments["Protocol"]))
- $this->protocol=$arguments["Protocol"];
- switch (strtolower($this->protocol)) {
- case "http":
- $default_port=80;
- break;
- case "https":
- $default_port=443;
- break;
- default:
- return($this->SetError("it was not specified a valid connection protocol", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
- }
- if (strlen($this->proxy_host_name)==0) {
- if(strlen($this->host_name)==0)
- return($this->SetError("it was not specified a valid hostname", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
- $host_name=$this->host_name;
- $host_port=($this->host_port ? $this->host_port : $default_port);
- $server_type = 'HTTP';
- } else {
- $host_name=$this->proxy_host_name;
- $host_port=$this->proxy_host_port;
- $server_type = 'HTTP proxy';
- }
- $ssl=(strtolower($this->protocol)=="https" && strlen($this->proxy_host_name)==0);
- if($ssl
- && strlen($this->socks_host_name))
- return($this->SetError('establishing SSL connections via a SOCKS server is not yet supported', HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
- $this->use_curl=($ssl && $this->prefer_curl && function_exists("curl_init"));
- switch ($this->state) {
- case 'Connected':
- if(!strcmp($host_name, $this->connected_host)
- && intval($host_port) == $this->connected_port
- && intval($ssl) == $this->connected_ssl)
- {
- if($this->debug)
- $this->OutputDebug("Reusing connection to ".$this->connected_host);
- return('');
- }
- if(strlen($error = $this->Disconnect()))
- return($error);
- case "Disconnected":
- break;
- default:
- return("1 already connected");
- }
- if($this->debug)
- $this->OutputDebug("Connecting to ".$this->host_name);
- if ($this->use_curl) {
- $error=(($this->connection=curl_init($this->protocol."://".$this->host_name.($host_port==$default_port ? "" : ":".strval($host_port))."/")) ? "" : "Could not initialize a CURL session");
- if (strlen($error)==0) {
- if(IsSet($arguments["SSLCertificateFile"]))
- curl_setopt($this->connection,CURLOPT_SSLCERT,$arguments["SSLCertificateFile"]);
- if(IsSet($arguments["SSLCertificatePassword"]))
- curl_setopt($this->connection,CURLOPT_SSLCERTPASSWD,$arguments["SSLCertificatePassword"]);
- if(IsSet($arguments["SSLKeyFile"]))
- curl_setopt($this->connection,CURLOPT_SSLKEY,$arguments["SSLKeyFile"]);
- if(IsSet($arguments["SSLKeyPassword"]))
- curl_setopt($this->connection,CURLOPT_SSLKEYPASSWD,$arguments["SSLKeyPassword"]);
- }
- $this->state="Connected";
- } else {
- $error="";
- if(strlen($this->proxy_host_name)
- && (IsSet($arguments["SSLCertificateFile"])
- || IsSet($arguments["SSLCertificateFile"])))
- $error="establishing SSL connections using certificates or private keys via non-SSL proxies is not supported";
- else {
- if ($ssl) {
- if(IsSet($arguments["SSLCertificateFile"]))
- $error="establishing SSL connections using certificates is only supported when the cURL extension is enabled";
- elseif(IsSet($arguments["SSLKeyFile"]))
- $error="establishing SSL connections using a private key is only supported when the cURL extension is enabled";
- else {
- $version=explode(".",function_exists("phpversion") ? phpversion() : "3.0.7");
- $php_version=intval($version[0])*1000000+intval($version[1])*1000+intval($version[2]);
- if($php_version<4003000)
- $error="establishing SSL connections requires at least PHP version 4.3.0 or having the cURL extension enabled";
- elseif(!function_exists("extension_loaded")
- || !extension_loaded("openssl"))
- $error="establishing SSL connections requires the OpenSSL extension enabled";
- }
- }
- if (strlen($error)==0) {
- $error=$this->Connect($host_name, $host_port, $ssl, $server_type);
- $error_code = $this->error_code;
- }
- }
- }
- if(strlen($error))
- return($this->SetError($error, $error_code));
- $this->session=md5(uniqid(""));
- $this->connected_host = $host_name;
- $this->connected_port = intval($host_port);
- $this->connected_ssl = intval($ssl);
- return("");
- }
- public Function Close($force = 0)
- {
- if($this->state=="Disconnected")
- return("1 already disconnected");
- if(!$this->force_close
- && $this->keep_alive
- && !$force
- && $this->state == 'ResponseReceived')
- {
- if($this->debug)
- $this->OutputDebug('Keeping the connection alive to '.$this->connected_host);
- $this->state = 'Connected';
- return('');
- }
- return($this->Disconnect());
- }
- public Function PickCookies(&$cookies,$secure)
- {
- if (IsSet($this->cookies[$secure])) {
- $now=gmdate("Y-m-d H-i-s");
- for ($domain=0,Reset($this->cookies[$secure]);$domain<count($this->cookies[$secure]);Next($this->cookies[$secure]),$domain++) {
- $domain_pattern=Key($this->cookies[$secure]);
- $match=strlen($this->request_host)-strlen($domain_pattern);
- if($match>=0
- && !strcmp($domain_pattern,substr($this->request_host,$match))
- && ($match==0
- || $domain_pattern[0]=="."
- || $this->request_host[$match-1]=="."))
- {
- for (Reset($this->cookies[$secure][$domain_pattern]),$path_part=0;$path_part<count($this->cookies[$secure][$domain_pattern]);Next($this->cookies[$secure][$domain_pattern]),$path_part++) {
- $path=Key($this->cookies[$secure][$domain_pattern]);
- if(strlen($this->request_uri)>=strlen($path)
- && substr($this->request_uri,0,strlen($path))==$path)
- {
- for (Reset($this->cookies[$secure][$domain_pattern][$path]),$cookie=0;$cookie<count($this->cookies[$secure][$domain_pattern][$path]);Next($this->cookies[$secure][$domain_pattern][$path]),$cookie++) {
- $cookie_name=Key($this->cookies[$secure][$domain_pattern][$path]);
- $expires=$this->cookies[$secure][$domain_pattern][$path][$cookie_name]["expires"];
- if($expires==""
- || strcmp($now,$expires)<0)
- $cookies[$cookie_name]=$this->cookies[$secure][$domain_pattern][$path][$cookie_name];
- }
- }
- }
- }
- }
- }
- }
- public Function GetFileDefinition($file, &$definition)
- {
- $name="";
- if(IsSet($file["FileName"]))
- $name=basename($file["FileName"]);
- if(IsSet($file["Name"]))
- $name=$file["Name"];
- if(strlen($name)==0)
- return("it was not specified the file part name");
- if (IsSet($file["Content-Type"])) {
- $content_type=$file["Content-Type"];
- $type=$this->Tokenize(strtolower($content_type),"/");
- $sub_type=$this->Tokenize("");
- switch ($type) {
- case "text":
- case "image":
- case "audio":
- case "video":
- case "application":
- case "message":
- break;
- case "automatic":
- switch ($sub_type) {
- case "name":
- switch (GetType($dot=strrpos($name,"."))=="integer" ? strtolower(substr($name,$dot)) : "") {
- case ".xls":
- $content_type="application/excel";
- break;
- case ".hqx":
- $content_type="application/macbinhex40";
- break;
- case ".doc":
- case ".dot":
- case ".wrd":
- $content_type="application/msword";
- break;
- case ".pdf":
- $content_type="application/pdf";
- break;
- case ".pgp":
- $content_type="application/pgp";
- break;
- case ".ps":
- case ".eps":
- case ".ai":
- $content_type="application/postscript";
- break;
- case ".ppt":
- $content_type="application/powerpoint";
- break;
- case ".rtf":
- $content_type="application/rtf";
- break;
- case ".tgz":
- case ".gtar":
- $content_type="application/x-gtar";
- break;
- case ".gz":
- $content_type="application/x-gzip";
- break;
- case ".php":
- case ".php3":
- $content_type="application/x-httpd-php";
- break;
- case ".js":
- $content_type="application/x-javascript";
- break;
- case ".ppd":
- case ".psd":
- $content_type="application/x-photoshop";
- break;
- case ".swf":
- case ".swc":
- case ".rf":
- $content_type="application/x-shockwave-flash";
- break;
- case ".tar":
- $content_type="application/x-tar";
- break;
- case ".zip":
- $content_type="application/zip";
- break;
- case ".mid":
- case ".midi":
- case ".kar":
- $content_type="audio/midi";
- break;
- case ".mp2":
- case ".mp3":
- case ".mpga":
- $content_type="audio/mpeg";
- break;
- case ".ra":
- $content_type="audio/x-realaudio";
- break;
- case ".wav":
- $content_type="audio/wav";
- break;
- case ".bmp":
- $content_type="image/bitmap";
- break;
- case ".gif":
- $content_type="image/gif";
- break;
- case ".iff":
- $content_type="image/iff";
- break;
- case ".jb2":
- $content_type="image/jb2";
- break;
- case ".jpg":
- case ".jpe":
- case ".jpeg":
- $content_type="image/jpeg";
- break;
- case ".jpx":
- $content_type="image/jpx";
- break;
- case ".png":
- $content_type="image/png";
- break;
- case ".tif":
- case ".tiff":
- $content_type="image/tiff";
- break;
- case ".wbmp":
- $content_type="image/vnd.wap.wbmp";
- break;
- case ".xbm":
- $content_type="image/xbm";
- break;
- case ".css":
- $content_type="text/css";
- break;
- case ".txt":
- $content_type="text/plain";
- break;
- case ".htm":
- case ".html":
- $content_type="text/html";
- break;
- case ".xml":
- $content_type="text/xml";
- break;
- case ".mpg":
- case ".mpe":
- case ".mpeg":
- $content_type="video/mpeg";
- break;
- case ".qt":
- case ".mov":
- $content_type="video/quicktime";
- break;
- case ".avi":
- $content_type="video/x-ms-video";
- break;
- case ".eml":
- $content_type="message/rfc822";
- break;
- default:
- $content_type="application/octet-stream";
- break;
- }
- break;
- default:
- return($content_type." is not a supported automatic content type detection method");
- }
- break;
- default:
- return($content_type." is not a supported file content type");
- }
- } else
- $content_type="application/octet-stream";
- $definition=array(
- "Content-Type"=>$content_type,
- "NAME"=>$name
- );
- if (IsSet($file["FileName"])) {
- if (GetType($length=@filesize($file["FileName"]))!="integer") {
- $error="it was not possible to determine the length of the file ".$file["FileName"];
- if(IsSet($php_errormsg)
- && strlen($php_errormsg))
- $error.=": ".$php_errormsg;
- if(!file_exists($file["FileName"]))
- $error="it was not possible to access the file ".$file["FileName"];
- return($error);
- }
- $definition["FILENAME"]=$file["FileName"];
- $definition["Content-Length"]=$length;
- } elseif(IsSet($file["Data"]))
- $definition["Content-Length"]=strlen($definition["DATA"]=$file["Data"]);
- else
- return("it was not specified a valid file name");
- return("");
- }
- public Function ConnectFromProxy($arguments, &$headers)
- {
- if(!$this->PutLine('CONNECT '.$this->host_name.':'.($this->host_port ? $this->host_port : 443).' HTTP/1.0')
- || (strlen($this->user_agent)
- && !$this->PutLine('User-Agent: '.$this->user_agent))
- || (strlen($this->accept)
- && !$this->PutLine('Accept: '.$this->accept))
- || (IsSet($arguments['Headers']['Proxy-Authorization'])
- && !$this->PutLine('Proxy-Authorization: '.$arguments['Headers']['Proxy-Authorization']))
- || !$this->PutLine(''))
- {
- $this->Disconnect();
- return($this->error);
- }
- $this->state = "ConnectSent";
- if(strlen($error=$this->ReadReplyHeadersResponse($headers)))
- return($error);
- $proxy_authorization="";
- while (!strcmp($this->response_status, "100")) {
- $this->state="ConnectSent";
- if(strlen($error=$this->ReadReplyHeadersResponse($headers)))
- return($error);
- }
- switch ($this->response_status) {
- case "200":
- if (!@stream_socket_enable_crypto($this->connection, 1, STREAM_CRYPTO_METHOD_SSLv23_CLIENT)) {
- $this->SetPHPError('it was not possible to start a SSL encrypted connection via this proxy', $php_errormsg, HTTP_CLIENT_ERROR_COMMUNICATION_FAILURE);
- $this->Disconnect();
- return($this->error);
- }
- $this->state = "Connected";
- break;
- case "407":
- if(strlen($error=$this->Authenticate($headers, -1, $proxy_authorization, $this->proxy_request_user, $this->proxy_request_password, $this->proxy_request_realm, $this->proxy_request_workstation)))
- return($error);
- break;
- default:
- return($this->SetError("unable to send request via proxy", HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
- }
- return("");
- }
- public Function SendRequest($arguments)
- {
- if(strlen($this->error))
- return($this->error);
- if(IsSet($arguments["ProxyUser"]))
- $this->proxy_request_user=$arguments["ProxyUser"];
- elseif(IsSet($this->proxy_user))
- $this->proxy_request_user=$this->proxy_user;
- if(IsSet($arguments["ProxyPassword"]))
- $this->proxy_request_password=$arguments["ProxyPassword"];
- elseif(IsSet($this->proxy_password))
- $this->proxy_request_password=$this->proxy_password;
- if(IsSet($arguments["ProxyRealm"]))
- $this->proxy_request_realm=$arguments["ProxyRealm"];
- elseif(IsSet($this->proxy_realm))
- $this->proxy_request_realm=$this->proxy_realm;
- if(IsSet($arguments["ProxyWorkstation"]))
- $this->proxy_request_workstation=$arguments["ProxyWorkstation"];
- elseif(IsSet($this->proxy_workstation))
- $this->proxy_request_workstation=$this->proxy_workstation;
- switch ($this->state) {
- case "Disconnected":
- return($this->SetError("connection was not yet established", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
- case "Connected":
- $connect = 0;
- break;
- case "ConnectedToProxy":
- if(strlen($error = $this->ConnectFromProxy($arguments, $headers)))
- return($error);
- $connect = 1;
- break;
- default:
- return($this->SetError("can not send request in the current connection state", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
- }
- if(IsSet($arguments["RequestMethod"]))
- $this->request_method=$arguments["RequestMethod"];
- if(IsSet($arguments["User-Agent"]))
- $this->user_agent=$arguments["User-Agent"];
- if(!IsSet($arguments["Headers"]["User-Agent"])
- && strlen($this->user_agent))
- $arguments["Headers"]["User-Agent"]=$this->user_agent;
- if(IsSet($arguments["KeepAlive"]))
- $this->keep_alive=intval($arguments["KeepAlive"]);
- if(!IsSet($arguments["Headers"]["Connection"])
- && $this->keep_alive)
- $arguments["Headers"]["Connection"]='Keep-Alive';
- if(IsSet($arguments["Accept"]))
- $this->user_agent=$arguments["Accept"];
- if(!IsSet($arguments["Headers"]["Accept"])
- && strlen($this->accept))
- $arguments["Headers"]["Accept"]=$this->accept;
- if(strlen($this->request_method)==0)
- return($this->SetError("it was not specified a valid request method", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
- if(IsSet($arguments["RequestURI"]))
- $this->request_uri=$arguments["RequestURI"];
- if(strlen($this->request_uri)==0
- || substr($this->request_uri,0,1)!="/")
- return($this->SetError("it was not specified a valid request URI", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
- $this->request_arguments=$arguments;
- $this->request_headers=(IsSet($arguments["Headers"]) ? $arguments["Headers"] : array());
- $body_length=0;
- $this->request_body="";
- $get_body=1;
- if($this->request_method=="POST"
- || $this->request_method=="PUT")
- {
- if (IsSet($arguments['StreamRequest'])) {
- $get_body = 0;
- $this->request_headers["Transfer-Encoding"]="chunked";
- } elseif(IsSet($arguments["PostFiles"])
- || ($this->force_multipart_form_post
- && IsSet($arguments["PostValues"])))
- {
- $boundary="--".md5(uniqid(time()));
- $this->request_headers["Content-Type"]="multipart/form-data; boundary=".$boundary.(IsSet($arguments["CharSet"]) ? "; charset=".$arguments["CharSet"] : "");
- $post_parts=array();
- if (IsSet($arguments["PostValues"])) {
- $values=$arguments["PostValues"];
- if(GetType($values)!="array")
- return($this->SetError("it was not specified a valid POST method values array", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
- for (Reset($values),$value=0;$value<count($values);Next($values),$value++) {
- $input=Key($values);
- $headers="--".$boundary."\r\nContent-Disposition: form-data; name=\"".$input."\"\r\n\r\n";
- $data=$values[$input];
- $post_parts[]=array("HEADERS"=>$headers,"DATA"=>$data);
- $body_length+=strlen($headers)+strlen($data)+strlen("\r\n");
- }
- }
- $body_length+=strlen("--".$boundary."--\r\n");
- $files=(IsSet($arguments["PostFiles"]) ? $arguments["PostFiles"] : array());
- Reset($files);
- $end=(GetType($input=Key($files))!="string");
- for (;!$end;) {
- if(strlen($error=$this->GetFileDefinition($files[$input],$definition)))
- return("3 ".$error);
- $headers="--".$boundary."\r\nContent-Disposition: form-data; name=\"".$input."\"; filename=\"".$definition["NAME"]."\"\r\nContent-Type: ".$definition["Content-Type"]."\r\n\r\n";
- $part=count($post_parts);
- $post_parts[$part]=array("HEADERS"=>$headers);
- if (IsSet($definition["FILENAME"])) {
- $post_parts[$part]["FILENAME"]=$definition["FILENAME"];
- $data="";
- } else
- $data=$definition["DATA"];
- $post_parts[$part]["DATA"]=$data;
- $body_length+=strlen($headers)+$definition["Content-Length"]+strlen("\r\n");
- Next($files);
- $end=(GetType($input=Key($files))!="string");
- }
- $get_body=0;
- } elseif (IsSet($arguments["PostValues"])) {
- $values=$arguments["PostValues"];
- if(GetType($values)!="array")
- return($this->SetError("it was not specified a valid POST method values array", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
- for (Reset($values),$value=0;$value<count($values);Next($values),$value++) {
- $k=Key($values);
- if (GetType($values[$k])=="array") {
- for ($v = 0; $v < count($values[$k]); $v++) {
- if($value+$v>0)
- $this->request_body.="&";
- $this->request_body.=UrlEncode($k)."=".UrlEncode($values[$k][$v]);
- }
- } else {
- if($value>0)
- $this->request_body.="&";
- $this->request_body.=UrlEncode($k)."=".UrlEncode($values[$k]);
- }
- }
- $this->request_headers["Content-Type"]="application/x-www-form-urlencoded".(IsSet($arguments["CharSet"]) ? "; charset=".$arguments["CharSet"] : "");
- $get_body=0;
- }
- }
- if($get_body
- && (IsSet($arguments["Body"])
- || IsSet($arguments["BodyStream"])))
- {
- if(IsSet($arguments["Body"]))
- $this->request_body=$arguments["Body"];
- else {
- $stream=$arguments["BodyStream"];
- $this->request_body="";
- for ($part=0; $part<count($stream); $part++) {
- if(IsSet($stream[$part]["Data"]))
- $this->request_body.=$stream[$part]["Data"];
- elseif (IsSet($stream[$part]["File"])) {
- if(!($file=@fopen($stream[$part]["File"],"rb")))
- return($this->SetPHPError("could not open upload file ".$stream[$part]["File"], $php_errormsg, HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE));
- while (!feof($file)) {
- if (GetType($block=@fread($file,$this->file_buffer_length))!="string") {
- $error=$this->SetPHPError("could not read body stream file ".$stream[$part]["File"], $php_errormsg, HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
- fclose($file);
- return($error);
- }
- $this->request_body.=$block;
- }
- fclose($file);
- } else
- return("5 it was not specified a valid file or data body stream element at position ".$part);
- }
- }
- if(!IsSet($this->request_headers["Content-Type"]))
- $this->request_headers["Content-Type"]="application/octet-stream".(IsSet($arguments["CharSet"]) ? "; charset=".$arguments["CharSet"] : "");
- }
- if(IsSet($arguments["AuthUser"]))
- $this->request_user=$arguments["AuthUser"];
- elseif(IsSet($this->user))
- $this->request_user=$this->user;
- if(IsSet($arguments["AuthPassword"]))
- $this->request_password=$arguments["AuthPassword"];
- elseif(IsSet($this->password))
- $this->request_password=$this->password;
- if(IsSet($arguments["AuthRealm"]))
- $this->request_realm=$arguments["AuthRealm"];
- elseif(IsSet($this->realm))
- $this->request_realm=$this->realm;
- if(IsSet($arguments["AuthWorkstation"]))
- $this->request_workstation=$arguments["AuthWorkstation"];
- elseif(IsSet($this->workstation))
- $this->request_workstation=$this->workstation;
- if(strlen($this->proxy_host_name)==0
- || $connect)
- $request_uri=$this->request_uri;
- else {
- switch (strtolower($this->protocol)) {
- case "http":
- $default_port=80;
- break;
- case "https":
- $default_port=443;
- break;
- }
- $request_uri=strtolower($this->protocol)."://".$this->host_name.(($this->host_port==0 || $this->host_port==$default_port) ? "" : ":".$this->host_port).$this->request_uri;
- }
- if ($this->use_curl) {
- $version=(GetType($v=curl_version())=="array" ? (IsSet($v["version"]) ? $v["version"] : "0.0.0") : (preg_match("/^libcurl\\/([0-9]+\\.[0-9]+\\.[0-9]+)/",$v,$m) ? $m[1] : "0.0.0"));
- $curl_version=100000*intval($this->Tokenize($version,"."))+1000*intval($this->Tokenize("."))+intval($this->Tokenize(""));
- $protocol_version=($curl_version<713002 ? "1.0" : $this->protocol_version);
- } else
- $protocol_version=$this->protocol_version;
- $this->request=$this->request_method." ".$request_uri." HTTP/".$protocol_version;
- if($body_length
- || ($body_length=strlen($this->request_body)))
- $this->request_headers["Content-Length"]=$body_length;
- for ($headers=array(),$host_set=0,Reset($this->request_headers),$header=0;$header<count($this->request_headers);Next($this->request_headers),$header++) {
- $header_name=Key($this->request_headers);
- $header_value=$this->request_headers[$header_name];
- if (GetType($header_value)=="array") {
- for(Reset($header_value),$value=0;$value<count($header_value);Next($header_value),$value++)
- $headers[]=$header_name.": ".$header_value[Key($header_value)];
- } else
- $headers[]=$header_name.": ".$header_value;
- if (strtolower(Key($this->request_headers))=="host") {
- $this->request_host=strtolower($header_value);
- $host_set=1;
- }
- }
- if (!$host_set) {
- $headers[]="Host: ".$this->host_name;
- $this->request_host=strtolower($this->host_name);
- }
- if (count($this->cookies)) {
- $cookies=array();
- $this->PickCookies($cookies,0);
- if(strtolower($this->protocol)=="https")
- $this->PickCookies($cookies,1);
- if (count($cookies)) {
- $h=count($headers);
- $headers[$h]="Cookie:";
- for (Reset($cookies),$cookie=0;$cookie<count($cookies);Next($cookies),$cookie++) {
- $cookie_name=Key($cookies);
- $headers[$h].=" ".$cookie_name."=".$cookies[$cookie_name]["value"].";";
- }
- }
- }
- $next_state = "RequestSent";
- if ($this->use_curl) {
- if(IsSet($arguments['StreamRequest']))
- return($this->SetError("Streaming request data is not supported when using Curl", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
- if($body_length
- && strlen($this->request_body)==0)
- {
- for ($request_body="",$success=1,$part=0;$part<count($post_parts);$part++) {
- $request_body.=$post_parts[$part]["HEADERS"].$post_parts[$part]["DATA"];
- if (IsSet($post_parts[$part]["FILENAME"])) {
- if (!($file=@fopen($post_parts[$part]["FILENAME"],"rb"))) {
- $this->SetPHPError("could not open upload file ".$post_parts[$part]["FILENAME"], $php_errormsg, HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
- $success=0;
- break;
- }
- while (!feof($file)) {
- if (GetType($block=@fread($file,$this->file_buffer_length))!="string") {
- $this->SetPHPError("could not read upload file", $php_errormsg, HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
- $success=0;
- break;
- }
- $request_body.=$block;
- }
- fclose($file);
- if(!$success)
- break;
- }
- $request_body.="\r\n";
- }
- $request_body.="--".$boundary."--\r\n";
- } else
- $request_body=$this->request_body;
- curl_setopt($this->connection,CURLOPT_HEADER,1);
- curl_setopt($this->connection,CURLOPT_RETURNTRANSFER,1);
- if($this->timeout)
- curl_setopt($this->connection,CURLOPT_TIMEOUT,$this->timeout);
- curl_setopt($this->connection,CURLOPT_SSL_VERIFYPEER,0);
- curl_setopt($this->connection,CURLOPT_SSL_VERIFYHOST,0);
- $request=$this->request."\r\n".implode("\r\n",$headers)."\r\n\r\n".$request_body;
- curl_setopt($this->connection,CURLOPT_CUSTOMREQUEST,$request);
- if($this->debug)
- $this->OutputDebug("C ".$request);
- if (!($success=(strlen($this->response=curl_exec($this->connection))!=0))) {
- $error=curl_error($this->connection);
- $this->SetError("Could not execute the request".(strlen($error) ? ": ".$error : ""), HTTP_CLIENT_ERROR_PROTOCOL_FAILURE);
- }
- } else {
- if (($success=$this->PutLine($this->request))) {
- for ($header=0;$header<count($headers);$header++) {
- if(!$success=$this->PutLine($headers[$header]))
- break;
- }
- if($success
- && ($success=$this->PutLine("")))
- {
- if(IsSet($arguments['StreamRequest']))
- $next_state = "SendingRequestBody";
- elseif ($body_length) {
- if(strlen($this->request_body))
- $success=$this->PutData($this->request_body);
- else {
- for ($part=0;$part<count($post_parts);$part++) {
- if(!($success=$this->PutData($post_parts[$part]["HEADERS"]))
- || !($success=$this->PutData($post_parts[$part]["DATA"])))
- break;
- if (IsSet($post_parts[$part]["FILENAME"])) {
- if (!($file=@fopen($post_parts[$part]["FILENAME"],"rb"))) {
- $this->SetPHPError("could not open upload file ".$post_parts[$part]["FILENAME"], $php_errormsg, HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
- $success=0;
- break;
- }
- while (!feof($file)) {
- if (GetType($block=@fread($file,$this->file_buffer_length))!="string") {
- $this->SetPHPError("could not read upload file", $php_errormsg, HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
- $success=0;
- break;
- }
- if(!($success=$this->PutData($block)))
- break;
- }
- fclose($file);
- if(!$success)
- break;
- }
- if(!($success=$this->PutLine("")))
- break;
- }
- if($success)
- $success=$this->PutLine("--".$boundary."--");
- }
- if($success)
- $sucess=$this->FlushData();
- }
- }
- }
- }
- if(!$success)
- return($this->SetError("could not send the HTTP request: ".$this->error, $this->error_code));
- $this->state=$next_state;
- return("");
- }
- public Function SetCookie($name, $value, $expires="" , $path="/" , $domain="" , $secure=0, $verbatim=0)
- {
- if(strlen($this->error))
- return($this->error);
- if(strlen($name)==0)
- return($this->SetError("it was not specified a valid cookie name", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
- if(strlen($path)==0
- || strcmp($path[0],"/"))
- return($this->SetError($path." is not a valid path for setting cookie ".$name, HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
- if($domain==""
- || !strpos($domain,".",$domain[0]=="." ? 1 : 0))
- return($this->SetError($domain." is not a valid domain for setting cookie ".$name, HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
- $domain=strtolower($domain);
- if(!strcmp($domain[0],"."))
- $domain=substr($domain,1);
- if (!$verbatim) {
- $name=$this->CookieEncode($name,1);
- $value=$this->CookieEncode($value,0);
- }
- $secure=intval($secure);
- $this->cookies[$secure][$domain][$path][$name]=array(
- "name"=>$name,
- "value"=>$value,
- "domain"=>$domain,
- "path"=>$path,
- "expires"=>$expires,
- "secure"=>$secure
- );
- return("");
- }
- public Function SendRequestBody($data, $end_of_data)
- {
- if(strlen($this->error))
- return($this->error);
- switch ($this->state) {
- case "Disconnected":
- return($this->SetError("connection was not yet established", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
- case "Connected":
- case "ConnectedToProxy":
- return($this->SetError("request was not sent", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
- case "SendingRequestBody":
- break;
- case "RequestSent":
- return($this->SetError("request body was already sent", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
- default:
- return($this->SetError("can not send the request body in the current connection state", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
- }
- $length = strlen($data);
- if ($length) {
- $size = dechex($length)."\r\n";
- if(!$this->PutData($size)
- || !$this->PutData($data))
- return($this->error);
- }
- if ($end_of_data) {
- $size = "0\r\n";
- if(!$this->PutData($size))
- return($this->error);
- $this->state = "RequestSent";
- }
- return("");
- }
- public Function ReadReplyHeadersResponse(&$headers)
- {
- $headers=array();
- if(strlen($this->error))
- return($this->error);
- switch ($this->state) {
- case "Disconnected":
- return($this->SetError("connection was not yet established", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
- case "Connected":
- return($this->SetError("request was not sent", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
- case "ConnectedToProxy":
- return($this->SetError("connection from the remote server from the proxy was not yet established", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
- case "SendingRequestBody":
- return($this->SetError("request body data was not completely sent", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
- case "ConnectSent":
- $connect = 1;
- break;
- case "RequestSent":
- $connect = 0;
- break;
- default:
- return($this->SetError("can not get request headers in the current connection state", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
- }
- $this->content_length=$this->read_length=$this->read_response=$this->remaining_chunk=0;
- $this->content_length_set=$this->chunked=$this->last_chunk_read=$chunked=0;
- $this->force_close = $this->connection_close=0;
- for ($this->response_status="";;) {
- $line=$this->GetLine();
- if(GetType($line)!="string")
- return($this->SetError("could not read request reply: ".$this->error, $this->error_code));
- if (strlen($this->response_status)==0) {
- if(!preg_match($match="/^http\\/[0-9]+\\.[0-9]+[ \t]+([0-9]+)[ \t]*(.*)\$/i",$line,$matches))
- return($this->SetError("it was received an unexpected HTTP response status", HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
- $this->response_status=$matches[1];
- $this->response_message=$matches[2];
- }
- if ($line=="") {
- if(strlen($this->response_status)==0)
- return($this->SetError("it was not received HTTP response status", HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
- $this->state=($connect ? "GotConnectHeaders" : "GotReplyHeaders");
- break;
- }
- $header_name=strtolower($this->Tokenize($line,":"));
- $header_value=Trim(Chop($this->Tokenize("\r\n")));
- if (IsSet($headers[$header_name])) {
- if(GetType($headers[$header_name])=="string")
- $headers[$header_name]=array($headers[$header_name]);
- $headers[$header_name][]=$header_value;
- } else
- $headers[$header_name]=$header_value;
- if (!$connect) {
- switch ($header_name) {
- case "content-length":
- $this->content_length=intval($headers[$header_name]);
- $this->content_length_set=1;
- break;
- case "transfer-encoding":
- $encoding=$this->Tokenize($header_value,"; \t");
- if(!$this->use_curl
- && !strcmp($encoding,"chunked"))
- $chunked=1;
- break;
- case "set-cookie":
- if ($this->support_cookies) {
- if(GetType($headers[$header_name])=="array")
- $cookie_headers=$headers[$header_name];
- else
- $cookie_headers=array($headers[$header_name]);
- for ($cookie=0;$cookie<count($cookie_headers);$cookie++) {
- $cookie_name=trim($this->Tokenize($cookie_headers[$cookie],"="));
- $cookie_value=$this->Tokenize(";");
- $domain=$this->request_host;
- $path="/";
- $expires="";
- $secure=0;
- while (($name = strtolower(trim(UrlDecode($this->Tokenize("=")))))!="") {
- $value=UrlDecode($this->Tokenize(";"));
- switch ($name) {
- case "domain":
- $domain=$value;
- break;
- case "path":
- $path=$value;
- break;
- case "expires":
- if (preg_match("/^((Mon|Monday|Tue|Tuesday|Wed|Wednesday|Thu|Thursday|Fri|Friday|Sat|Saturday|Sun|Sunday), )?([0-9]{2})\\-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\\-([0-9]{2,4}) ([0-9]{2})\\:([0-9]{2})\\:([0-9]{2}) GMT\$/",$value,$matches)) {
- $year=intval($matches[5]);
- if($year<1900)
- $year+=($year<70 ? 2000 : 1900);
- $expires="$year-".$this->months[$matches[4]]."-".$matches[3]." ".$matches[6].":".$matches[7].":".$matches[8];
- }
- break;
- case "secure":
- $secure=1;
- break;
- }
- }
- if(strlen($this->SetCookie($cookie_name, $cookie_value, $expires, $path , $domain, $secure, 1)))
- $this->error="";
- }
- }
- break;
- case "connection":
- $this->force_close = $this->connection_close=!strcmp(strtolower($header_value),"close");
- break;
- }
- }
- }
- $this->chunked=$chunked;
- if($this->content_length_set)
- $this->connection_close=0;
- return("");
- }
- public Function Redirect(&$headers)
- {
- if ($this->follow_redirect) {
- if(!IsSet($headers["location"])
- || (GetType($headers["location"])!="array"
- && strlen($location=$headers["location"])==0)
- || (GetType($headers["location"])=="array"
- && strlen($location=$headers["location"][0])==0))
- return($this->SetError("it was received a redirect without location URL", HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
- if (strcmp($location[0],"/")) {
- if(!($location_arguments=@parse_url($location)))
- return($this->SetError("the server did not return a valid redirection location URL", HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
- if(!IsSet($location_arguments["scheme"]))
- $location=((GetType($end=strrpos($this->request_uri,"/"))=="integer" && $end>1) ? substr($this->request_uri,0,$end) : "")."/".$location;
- }
- if(!strcmp($location[0],"/"))
- $location=$this->protocol."://".$this->host_name.($this->host_port ? ":".$this->host_port : "").$location;
- $error=$this->GetRequestArguments($location,$arguments);
- if(strlen($error))
- return($this->SetError("could not process redirect url: ".$error, HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
- $arguments["RequestMethod"]="GET";
- if(strlen($error=$this->Close())==0
- && strlen($error=$this->Open($arguments))==0
- && strlen($error=$this->SendRequest($arguments))==0)
- {
- $this->redirection_level++;
- if ($this->redirection_level>$this->redirection_limit) {
- $error="it was exceeded the limit of request redirections";
- $this->error_code = HTTP_CLIENT_ERROR_PROTOCOL_FAILURE;
- } else
- $error=$this->ReadReplyHeaders($headers);
- $this->redirection_level--;
- }
- if(strlen($error))
- return($this->SetError($error, $this->error_code));
- }
- return("");
- }
- public Function Authenticate(&$headers, $proxy, &$proxy_authorization, &$user, &$password, &$realm, &$workstation)
- {
- if ($proxy) {
- $authenticate_header="proxy-authenticate";
- $authorization_header="Proxy-Authorization";
- $authenticate_status="407";
- $authentication_mechanism=$this->proxy_authentication_mechanism;
- } else {
- $authenticate_header="www-authenticate";
- $authorization_header="Authorization";
- $authenticate_status="401";
- $authentication_mechanism=$this->authentication_mechanism;
- }
- if (IsSet($headers[$authenticate_header])) {
- if(function_exists("class_exists")
- && !class_exists("sasl_client_class"))
- return($this->SetError("the SASL client class needs to be loaded to be able to authenticate".($proxy ? " with the proxy server" : "")." and access this site", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
- if(GetType($headers[$authenticate_header])=="array")
- $authenticate=$headers[$authenticate_header];
- else
- $authenticate=array($headers[$authenticate_header]);
- for ($response="", $mechanisms=array(),$m=0;$m<count($authenticate);$m++) {
- $mechanism=$this->Tokenize($authenticate[$m]," ");
- $response=$this->Tokenize("");
- if (strlen($authentication_mechanism)) {
- if (!strcmp($authentication_mechanism,$mechanism)) {
- $mechanisms[]=$mechanism;
- break;
- }
- } else
- $mechanisms[]=$mechanism;
- }
- $sasl=new sasl_client_class;
- if(IsSet($user))
- $sasl->SetCredential("user",$user);
- if(IsSet($password))
- $sasl->SetCredential("password",$password);
- if(IsSet($realm))
- $sasl->SetCredential("realm",$realm);
- if(IsSet($workstation))
- $sasl->SetCredential("workstation",$workstation);
- $sasl->SetCredential("uri",$this->request_uri);
- $sasl->SetCredential("method",$this->request_method);
- $sasl->SetCredential("session",$this->session);
- do {
- $status=$sasl->Start($mechanisms,$message,$interactions);
- } while ($status==SASL_INTERACT);
- switch ($status) {
- case SASL_CONTINUE:
- break;
- case SASL_NOMECH:
- return($this->SetError(($proxy ? "proxy " : "")."authentication error: ".(strlen($authentication_mechanism) ? "authentication mechanism ".$authentication_mechanism." may not be used: " : "").$sasl->error, HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
- default:
- return($this->SetError("Could not start the SASL ".($proxy ? "proxy " : "")."authentication client: ".$sasl->error, HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
- }
- if ($proxy >= 0) {
- for (;;) {
- if(strlen($error=$this->ReadReplyBody($body,$this->file_buffer_length)))
- return($error);
- if(strlen($body)==0)
- break;
- }
- }
- $authorization_value=$sasl->mechanism.(IsSet($message) ? " ".($sasl->encode_response ? base64_encode($message) : $message) : "");
- $request_arguments=$this->request_arguments;
- $arguments=$request_arguments;
- $arguments["Headers"][$authorization_header]=$authorization_value;
- if(!$proxy
- && strlen($proxy_authorization))
- $arguments["Headers"]["Proxy-Authorization"]=$proxy_authorization;
- if(strlen($error=$this->Close())
- || strlen($error=$this->Open($arguments)))
- return($this->SetError($error, $this->error_code));
- $authenticated=0;
- if (IsSet($message)) {
- if ($proxy < 0) {
- if(strlen($error=$this->ConnectFromProxy($arguments, $headers)))
- return($this->SetError($error, $this->error_code));
- } else {
- if(strlen($error=$this->SendRequest($arguments))
- || strlen($error=$this->ReadReplyHeadersResponse($headers)))
- return($this->SetError($error, $this->error_code));
- }
- if(!IsSet($headers[$authenticate_header]))
- $authenticate=array();
- elseif(GetType($headers[$authenticate_header])=="array")
- $authenticate=$headers[$authenticate_header];
- else
- $authenticate=array($headers[$authenticate_header]);
- for ($mechanism=0;$mechanism<count($authenticate);$mechanism++) {
- if (!strcmp($this->Tokenize($authenticate[$mechanism]," "),$sasl->mechanism)) {
- $response=$this->Tokenize("");
- break;
- }
- }
- switch ($this->response_status) {
- case $authenticate_status:
- break;
- case "301":
- case "302":
- case "303":
- case "307":
- if($proxy >= 0)
- return($this->Redirect($headers));
- default:
- if (intval($this->response_status/100)==2) {
- if($proxy)
- $proxy_authorization=$authorization_value;
- $authenticated=1;
- break;
- }
- if($proxy
- && !strcmp($this->response_status,"401"))
- {
- $proxy_authorization=$authorization_value;
- $authenticated=1;
- break;
- }
- return($this->SetError(($proxy ? "proxy " : "")."authentication error: ".$this->response_status." ".$this->response_message, HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
- }
- }
- for (;!$authenticated;) {
- do {
- $status=$sasl->Step($response,$message,$interactions);
- } while ($status==SASL_INTERACT);
- switch ($status) {
- case SASL_CONTINUE:
- $authorization_value=$sasl->mechanism.(IsSet($message) ? " ".($sasl->encode_response ? base64_encode($message) : $message) : "");
- $arguments=$request_arguments;
- $arguments["Headers"][$authorization_header]=$authorization_value;
- if(!$proxy
- && strlen($proxy_authorization))
- $arguments["Headers"]["Proxy-Authorization"]=$proxy_authorization;
- if ($proxy < 0) {
- if(strlen($error=$this->ConnectFromProxy($arguments, $headers)))
- return($this->SetError($error, $this->error_code));
- } else {
- if(strlen($error=$this->SendRequest($arguments))
- || strlen($error=$this->ReadReplyHeadersResponse($headers)))
- return($this->SetError($error, $this->error_code));
- }
- switch ($this->response_status) {
- case $authenticate_status:
- if(GetType($headers[$authenticate_header])=="array")
- $authenticate=$headers[$authenticate_header];
- else
- $authenticate=array($headers[$authenticate_header]);
- for ($response="",$mechanism=0;$mechanism<count($authenticate);$mechanism++) {
- if (!strcmp($this->Tokenize($authenticate[$mechanism]," "),$sasl->mechanism)) {
- $response=$this->Tokenize("");
- break;
- }
- }
- if ($proxy >= 0) {
- for (;;) {
- if(strlen($error=$this->ReadReplyBody($body,$this->file_buffer_length)))
- return($error);
- if(strlen($body)==0)
- break;
- }
- }
- $this->state="Connected";
- break;
- case "301":
- case "302":
- case "303":
- case "307":
- if($proxy >= 0)
- return($this->Redirect($headers));
- default:
- if (intval($this->response_status/100)==2) {
- if($proxy)
- $proxy_authorization=$authorization_value;
- $authenticated=1;
- break;
- }
- if($proxy
- && !strcmp($this->response_status,"401"))
- {
- $proxy_authorization=$authorization_value;
- $authenticated=1;
- break;
- }
- return($this->SetError(($proxy ? "proxy " : "")."authentication error: ".$this->response_status." ".$this->response_message));
- }
- break;
- default:
- return($this->SetError("Could not process the SASL ".($proxy ? "proxy " : "")."authentication step: ".$sasl->error, HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
- }
- }
- }
- return("");
- }
- public Function ReadReplyHeaders(&$headers)
- {
- if(strlen($error=$this->ReadReplyHeadersResponse($headers)))
- return($error);
- $proxy_authorization="";
- while (!strcmp($this->response_status, "100")) {
- $this->state="RequestSent";
- if(strlen($error=$this->ReadReplyHeadersResponse($headers)))
- return($error);
- }
- switch ($this->response_status) {
- case "301":
- case "302":
- case "303":
- case "307":
- if(strlen($error=$this->Redirect($headers)))
- return($error);
- break;
- case "407":
- if(strlen($error=$this->Authenticate($headers, 1, $proxy_authorization, $this->proxy_request_user, $this->proxy_request_password, $this->proxy_request_realm, $this->proxy_request_workstation)))
- return($error);
- if(strcmp($this->response_status,"401"))
- return("");
- case "401":
- return($this->Authenticate($headers, 0, $proxy_authorization, $this->request_user, $this->request_password, $this->request_realm, $this->request_workstation));
- }
- return("");
- }
- public Function ReadReplyBody(&$body,$length)
- {
- $body="";
- if(strlen($this->error))
- return($this->error);
- switch ($this->state) {
- case "Disconnected":
- return($this->SetError("connection was not yet established", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
- case "Connected":
- case "ConnectedToProxy":
- return($this->SetError("request was not sent", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
- case "RequestSent":
- if(($error=$this->ReadReplyHeaders($headers))!="")
- return($error);
- break;
- case "GotReplyHeaders":
- break;
- case 'ResponseReceived':
- $body = '';
- return('');
- default:
- return($this->SetError("can not get request headers in the current connection state", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
- }
- if($this->content_length_set)
- $length=min($this->content_length-$this->read_length,$length);
- $body = '';
- if ($length>0) {
- if(!$this->EndOfInput()
- && ($body=$this->ReadBytes($length))=="")
- {
- if(strlen($this->error))
- return($this->SetError("could not get the request reply body: ".$this->error, $this->error_code));
- }
- $this->read_length+=strlen($body);
- if($this->EndOfInput())
- $this->state = 'ResponseReceived';
- }
- return("");
- }
- public Function ReadWholeReplyBody(&$body)
- {
- $body = '';
- for (;;) {
- if(strlen($error = $this->ReadReplyBody($block, $this->file_buffer_length)))
- return($error);
- if(strlen($block) == 0)
- return('');
- $body .= $block;
- }
- }
- public Function SaveCookies(&$cookies, $domain='', $secure_only=0, $persistent_only=0)
- {
- $now=gmdate("Y-m-d H-i-s");
- $cookies=array();
- for ($secure_cookies=0,Reset($this->cookies);$secure_cookies<count($this->cookies);Next($this->cookies),$secure_cookies++) {
- $secure=Key($this->cookies);
- if(!$secure_only
- || $secure)
- {
- for ($cookie_domain=0,Reset($this->cookies[$secure]);$cookie_domain<count($this->cookies[$secure]);Next($this->cookies[$secure]),$cookie_domain++) {
- $domain_pattern=Key($this->cookies[$secure]);
- $match=strlen($domain)-strlen($domain_pattern);
- if(strlen($domain)==0
- || ($match>=0
- && !strcmp($domain_pattern,substr($domain,$match))
- && ($match==0
- || $domain_pattern[0]=="."
- || $domain[$match-1]==".")))
- {
- for (Reset($this->cookies[$secure][$domain_pattern]),$path_part=0;$path_part<count($this->cookies[$secure][$domain_pattern]);Next($this->cookies[$secure][$domain_pattern]),$path_part++) {
- $path=Key($this->cookies[$secure][$domain_pattern]);
- for (Reset($this->cookies[$secure][$domain_pattern][$path]),$cookie=0;$cookie<count($this->cookies[$secure][$domain_pattern][$path]);Next($this->cookies[$secure][$domain_pattern][$path]),$cookie++) {
- $cookie_name=Key($this->cookies[$secure][$domain_pattern][$path]);
- $expires=$this->cookies[$secure][$domain_pattern][$path][$cookie_name]["expires"];
- if((!$persistent_only
- && strlen($expires)==0)
- || (strlen($expires)
- && strcmp($now,$expires)<0))
- $cookies[$secure][$domain_pattern][$path][$cookie_name]=$this->cookies[$secure][$domain_pattern][$path][$cookie_name];
- }
- }
- }
- }
- }
- }
- }
- public Function SavePersistentCookies(&$cookies, $domain='', $secure_only=0)
- {
- $this->SaveCookies($cookies, $domain, $secure_only, 1);
- }
- public Function GetPersistentCookies(&$cookies, $domain='', $secure_only=0)
- {
- $this->SavePersistentCookies($cookies, $domain, $secure_only);
- }
- public Function RestoreCookies($cookies, $clear=1)
- {
- $new_cookies=($clear ? array() : $this->cookies);
- for ($secure_cookies=0, Reset($cookies); $secure_cookies<count($cookies); Next($cookies), $secure_cookies++) {
- $secure=Key($cookies);
- if(GetType($secure)!="integer")
- return($this->SetError("invalid cookie secure value type (".serialize($secure).")", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
- for ($cookie_domain=0,Reset($cookies[$secure]);$cookie_domain<count($cookies[$secure]);Next($cookies[$secure]),$cookie_domain++) {
- $domain_pattern=Key($cookies[$secure]);
- if(GetType($domain_pattern)!="string")
- return($this->SetError("invalid cookie domain value type (".serialize($domain_pattern).")", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
- for (Reset($cookies[$secure][$domain_pattern]),$path_part=0;$path_part<count($cookies[$secure][$domain_pattern]);Next($cookies[$secure][$domain_pattern]),$path_part++) {
- $path=Key($cookies[$secure][$domain_pattern]);
- if(GetType($path)!="string"
- || strcmp(substr($path, 0, 1), "/"))
- return($this->SetError("invalid cookie path value type (".serialize($path).")", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
- for (Reset($cookies[$secure][$domain_pattern][$path]),$cookie=0;$cookie<count($cookies[$secure][$domain_pattern][$path]);Next($cookies[$secure][$domain_pattern][$path]),$cookie++) {
- $cookie_name=Key($cookies[$secure][$domain_pattern][$path]);
- $expires=$cookies[$secure][$domain_pattern][$path][$cookie_name]["expires"];
- $value=$cookies[$secure][$domain_pattern][$path][$cookie_name]["value"];
- if(GetType($expires)!="string"
- || (strlen($expires)
- && !preg_match("/^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}\$/", $expires)))
- return($this->SetError("invalid cookie expiry value type (".serialize($expires).")", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
- $new_cookies[$secure][$domain_pattern][$path][$cookie_name]=array(
- "name"=>$cookie_name,
- "value"=>$value,
- "domain"=>$domain_pattern,
- "path"=>$path,
- "expires"=>$expires,
- "secure"=>$secure
- );
- }
- }
- }
- }
- $this->cookies=$new_cookies;
- return("");
- }
- };