5 * @(#) $Header: /opt2/ena/metal/http/http.php,v 1.90 2013/02/20 11:45:28 mlemos Exp $
9 define('HTTP_CLIENT_ERROR_UNSPECIFIED_ERROR', -1);
10 define('HTTP_CLIENT_ERROR_NO_ERROR', 0);
11 define('HTTP_CLIENT_ERROR_INVALID_SERVER_ADDRESS', 1);
12 define('HTTP_CLIENT_ERROR_CANNOT_CONNECT', 2);
13 define('HTTP_CLIENT_ERROR_COMMUNICATION_FAILURE', 3);
14 define('HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE', 4);
15 define('HTTP_CLIENT_ERROR_PROTOCOL_FAILURE', 5);
16 define('HTTP_CLIENT_ERROR_INVALID_PARAMETERS', 6);
22 var $proxy_host_name="";
23 var $proxy_host_port=80;
24 var $socks_host_name = '';
25 var $socks_host_port = 1080;
26 var $socks_version = '5';
29 var $request_method="GET";
30 var $user_agent='httpclient (http://www.phpclasses.org/httpclient $Revision: 1.90 $)';
32 var $authentication_mechanism="";
37 var $proxy_authentication_mechanism="";
41 var $proxy_workstation;
44 var $request_headers=array();
46 var $request_password;
48 var $request_workstation;
49 var $proxy_request_user;
50 var $proxy_request_password;
51 var $proxy_request_realm;
52 var $proxy_request_workstation;
54 var $request_arguments=array();
55 var $protocol_version="1.1";
60 var $debug_response_body=1;
62 var $support_cookies=1;
65 var $error_code = HTTP_CLIENT_ERROR_NO_ERROR;
66 var $exclude_address="";
67 var $follow_redirect=0;
68 var $redirection_limit=5;
69 var $response_status="";
70 var $response_message="";
71 var $file_buffer_length=8000;
72 var $force_multipart_form_post=0;
75 var $sasl_authenticate = 1;
77 /* private variables - DO NOT ACCESS */
79 var $state="Disconnected";
82 var $content_length=0;
88 var $redirection_level=0;
90 var $remaining_chunk=0;
91 var $last_chunk_read=0;
106 var $connection_close=0;
107 var $force_close = 0;
108 var $connected_host = '';
109 var $connected_port = -1;
110 var $connected_ssl = 0;
112 /* Private methods - DO NOT CALL */
114 Function Tokenize($string,$separator="")
116 if(!strcmp($separator,""))
119 $string=$this->next_token;
121 for($character=0;$character<strlen($separator);$character++)
123 if(GetType($position=strpos($string,$separator[$character]))=="integer")
124 $found=(IsSet($found) ? min($found,$position) : $position);
128 $this->next_token=substr($string,$found+1);
129 return(substr($string,0,$found));
133 $this->next_token="";
138 Function CookieEncode($value, $name)
140 return($name ? str_replace("=", "%25", $value) : str_replace(";", "%3B", $value));
143 Function SetError($error, $error_code = HTTP_CLIENT_ERROR_UNSPECIFIED_ERROR)
145 $this->error_code = $error_code;
146 return($this->error=$error);
149 Function SetPHPError($error, &$php_error_message, $error_code = HTTP_CLIENT_ERROR_UNSPECIFIED_ERROR)
151 if(IsSet($php_error_message)
152 && strlen($php_error_message))
153 $error.=": ".$php_error_message;
154 return($this->SetError($error, $error_code));
157 Function SetDataAccessError($error,$check_connection=0)
160 $this->error_code = HTTP_CLIENT_ERROR_COMMUNICATION_FAILURE;
162 && function_exists("socket_get_status"))
164 $status=socket_get_status($this->connection);
165 if($status["timed_out"])
166 $this->error.=": data access time out";
167 elseif($status["eof"])
169 if($check_connection)
172 $this->error.=": the server disconnected";
177 Function OutputDebug($message)
184 if($this->html_debug)
185 $message=str_replace("\n","<br />\n",HtmlEntities($message));
197 $eol=strpos($this->response,"\n",$this->read_response);
198 $data=($eol ? substr($this->response,$this->read_response,$eol+1-$this->read_response) : "");
199 $this->read_response+=strlen($data);
203 if(feof($this->connection))
205 $this->SetDataAccessError("reached the end of data while reading from the HTTP server connection");
208 $data=fgets($this->connection,100);
210 if(GetType($data)!="string"
213 $this->SetDataAccessError("it was not possible to read line from the HTTP server");
217 $length=strlen($line);
219 && !strcmp(substr($line,$length-1,1),"\n"))
221 $length-=(($length>=2 && !strcmp(substr($line,$length-2,1),"\r")) ? 2 : 1);
222 $line=substr($line,0,$length);
224 $this->OutputDebug("S $line");
230 Function PutLine($line)
233 $this->OutputDebug("C $line");
234 if(!fputs($this->connection,$line."\r\n"))
236 $this->SetDataAccessError("it was not possible to send a line to the HTTP server");
242 Function PutData($data)
247 $this->OutputDebug('C '.$data);
248 if(!fputs($this->connection,$data))
250 $this->SetDataAccessError("it was not possible to send data to the HTTP server");
259 if(!fflush($this->connection))
261 $this->SetDataAccessError("it was not possible to send data to the HTTP server");
267 Function ReadChunkSize()
269 if($this->remaining_chunk==0)
272 if(!$this->debug_response_body)
274 $line=$this->GetLine();
276 if(GetType($line)!="string")
277 return($this->SetError("could not read chunk start: ".$this->error, $this->error_code));
278 $this->remaining_chunk=hexdec($line);
279 if($this->remaining_chunk == 0)
281 if(!$this->debug_response_body)
283 $line=$this->GetLine();
285 if(GetType($line)!="string")
286 return($this->SetError("could not read chunk end: ".$this->error, $this->error_code));
292 Function ReadBytes($length)
296 $bytes=substr($this->response,$this->read_response,min($length,strlen($this->response)-$this->read_response));
297 $this->read_response+=strlen($bytes);
299 && $this->debug_response_body
301 $this->OutputDebug("S ".$bytes);
307 for($bytes="",$remaining=$length;$remaining;)
309 if(strlen($this->ReadChunkSize()))
311 if($this->remaining_chunk==0)
313 $this->last_chunk_read=1;
316 $ask=min($this->remaining_chunk,$remaining);
317 $chunk=@fread($this->connection,$ask);
318 $read=strlen($chunk);
321 $this->SetDataAccessError("it was not possible to read data chunk from the HTTP server");
325 && $this->debug_response_body)
326 $this->OutputDebug("S ".$chunk);
328 $this->remaining_chunk-=$read;
330 if($this->remaining_chunk==0)
332 if(feof($this->connection))
333 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));
334 $data=@fread($this->connection,2);
335 if(strcmp($data,"\r\n"))
337 $this->SetDataAccessError("it was not possible to read end of data chunk from the HTTP server");
345 $bytes=@fread($this->connection,$length);
349 && $this->debug_response_body)
350 $this->OutputDebug("S ".$bytes);
353 $this->SetDataAccessError("it was not possible to read data from the HTTP server", $this->connection_close);
359 Function EndOfInput()
362 return($this->read_response>=strlen($this->response));
364 return($this->last_chunk_read);
365 if($this->content_length_set)
366 return($this->content_length <= $this->read_length);
367 return(feof($this->connection));
370 Function Resolve($domain, &$ip, $server_type)
372 if(preg_match('/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/',$domain))
377 $this->OutputDebug('Resolving '.$server_type.' server domain "'.$domain.'"...');
378 if(!strcmp($ip=@gethostbyname($domain),$domain))
382 || (strlen($this->exclude_address)
383 && !strcmp(@gethostbyname($this->exclude_address),$ip)))
384 return($this->SetError("could not resolve the host domain \"".$domain."\"", HTTP_CLIENT_ERROR_INVALID_SERVER_ADDRESS));
388 Function Connect($host_name, $host_port, $ssl, $server_type = 'HTTP')
392 if(strlen($error = $this->Resolve($domain, $ip, $server_type)))
394 if(strlen($this->socks_host_name))
396 switch($this->socks_version)
405 return('it was not specified a supported SOCKS protocol version');
409 $port = $this->socks_host_port;
410 $host_server_type = $server_type;
411 $server_type = 'SOCKS';
412 if(strlen($error = $this->Resolve($this->socks_host_name, $ip, $server_type)))
416 $this->OutputDebug('Connecting to '.$server_type.' server IP '.$ip.' port '.$port.'...');
418 $ip="ssl://".$host_name;
419 if(($this->connection=($this->timeout ? @fsockopen($ip, $port, $errno, $error, $this->timeout) : @fsockopen($ip, $port, $errno)))==0)
421 $error_code = HTTP_CLIENT_ERROR_CANNOT_CONNECT;
425 return($this->SetError("socket could not be created", $error_code));
427 return($this->SetError("dns lookup on hostname \"".$host_name."\" failed", $error_code));
429 return($this->SetError("connection refused or timed out", $error_code));
431 return($this->SetError("fdopen() call failed", $error_code));
433 return($this->SetError("setvbuf() call failed", $error_code));
435 return($this->SetPHPError($errno." could not connect to the host \"".$host_name."\"",$php_errormsg, $error_code));
440 if($this->data_timeout
441 && function_exists("socket_set_timeout"))
442 socket_set_timeout($this->connection,$this->data_timeout,0);
443 if(strlen($this->socks_host_name))
446 $this->OutputDebug('Connected to the SOCKS server '.$this->socks_host_name);
447 $send_error = 'it was not possible to send data to the SOCKS server';
448 $receive_error = 'it was not possible to receive data from the SOCKS server';
454 if(!fputs($this->connection, chr($version).chr($command).pack('nN', $host_port, ip2long($host_ip)).$user.Chr(0)))
455 $error = $this->SetDataAccessError($send_error);
458 $response = fgets($this->connection, 9);
459 if(strlen($response) != 8)
460 $error = $this->SetDataAccessError($receive_error);
463 $socks_errors = array(
465 "\x5b"=>'request rejected',
466 "\x5c"=>'request failed because client is not running identd (or not reachable from the server)',
467 "\x5d"=>'request failed because client\'s identd could not confirm the user ID string in the request',
469 $error_code = $response[1];
470 $error = (IsSet($socks_errors[$error_code]) ? $socks_errors[$error_code] : 'unknown');
472 $error = 'SOCKS error: '.$error;
478 $this->OutputDebug('Negotiating the authentication method ...');
481 if(!fputs($this->connection, chr($version).chr($methods).chr($method)))
482 $error = $this->SetDataAccessError($send_error);
485 $response = fgets($this->connection, 3);
486 if(strlen($response) != 2)
487 $error = $this->SetDataAccessError($receive_error);
488 elseif(Ord($response[1]) != $method)
489 $error = 'the SOCKS server requires an authentication method that is not yet supported';
493 $this->OutputDebug('Connecting to '.$host_server_type.' server IP '.$host_ip.' port '.$host_port.'...');
496 if(!fputs($this->connection, chr($version).chr($command)."\x00".chr($address_type).pack('Nn', ip2long($host_ip), $host_port)))
497 $error = $this->SetDataAccessError($send_error);
500 $response = fgets($this->connection, 11);
501 if(strlen($response) != 10)
502 $error = $this->SetDataAccessError($receive_error);
505 $socks_errors = array(
507 "\x01"=>'general SOCKS server failure',
508 "\x02"=>'connection not allowed by ruleset',
509 "\x03"=>'Network unreachable',
510 "\x04"=>'Host unreachable',
511 "\x05"=>'Connection refused',
512 "\x06"=>'TTL expired',
513 "\x07"=>'Command not supported',
514 "\x08"=>'Address type not supported'
516 $error_code = $response[1];
517 $error = (IsSet($socks_errors[$error_code]) ? $socks_errors[$error_code] : 'unknown');
519 $error = 'SOCKS error: '.$error;
526 $error = 'support for SOCKS protocol version '.$this->socks_version.' is not yet implemented';
531 fclose($this->connection);
536 $this->OutputDebug("Connected to $host_name");
537 if(strlen($this->proxy_host_name)
538 && !strcmp(strtolower($this->protocol), 'https'))
540 if(function_exists('stream_socket_enable_crypto')
541 && in_array('ssl', stream_get_transports()))
542 $this->state = "ConnectedToProxy";
545 $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.");
546 $this->state="Connected";
550 $this->state="Connected";
555 Function Disconnect()
558 $this->OutputDebug("Disconnected from ".$this->connected_host);
561 curl_close($this->connection);
565 fclose($this->connection);
566 $this->state="Disconnected";
572 Function GetRequestArguments($url, &$arguments)
575 $this->error_code = HTTP_CLIENT_ERROR_NO_ERROR;
577 $url = str_replace(' ', '%20', $url);
578 $parameters=@parse_url($url);
580 return($this->SetError("it was not specified a valid URL", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
581 if(!IsSet($parameters["scheme"]))
582 return($this->SetError("it was not specified the protocol type argument", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
583 switch(strtolower($parameters["scheme"]))
587 $arguments["Protocol"]=$parameters["scheme"];
590 return($parameters["scheme"]." connection scheme is not yet supported");
592 if(!IsSet($parameters["host"]))
593 return($this->SetError("it was not specified the connection host argument", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
594 $arguments["HostName"]=$parameters["host"];
595 $arguments["Headers"]=array("Host"=>$parameters["host"].(IsSet($parameters["port"]) ? ":".$parameters["port"] : ""));
596 if(IsSet($parameters["user"]))
598 $arguments["AuthUser"]=UrlDecode($parameters["user"]);
599 if(!IsSet($parameters["pass"]))
600 $arguments["AuthPassword"]="";
602 if(IsSet($parameters["pass"]))
604 if(!IsSet($parameters["user"]))
605 $arguments["AuthUser"]="";
606 $arguments["AuthPassword"]=UrlDecode($parameters["pass"]);
608 if(IsSet($parameters["port"]))
610 if(strcmp($parameters["port"],strval(intval($parameters["port"]))))
611 return($this->SetError("it was not specified a valid connection host argument", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
612 $arguments["HostPort"]=intval($parameters["port"]);
615 $arguments["HostPort"]=0;
616 $arguments["RequestURI"]=(IsSet($parameters["path"]) ? $parameters["path"] : "/").(IsSet($parameters["query"]) ? "?".$parameters["query"] : "");
617 if(strlen($this->user_agent))
618 $arguments["Headers"]["User-Agent"]=$this->user_agent;
619 if(strlen($this->accept))
620 $arguments["Headers"]["Accept"]=$this->accept;
624 Function Open($arguments)
626 if(strlen($this->error))
627 return($this->error);
628 $error_code = HTTP_CLIENT_ERROR_UNSPECIFIED_ERROR;
629 if(IsSet($arguments["HostName"]))
630 $this->host_name=$arguments["HostName"];
631 if(IsSet($arguments["HostPort"]))
632 $this->host_port=$arguments["HostPort"];
633 if(IsSet($arguments["ProxyHostName"]))
634 $this->proxy_host_name=$arguments["ProxyHostName"];
635 if(IsSet($arguments["ProxyHostPort"]))
636 $this->proxy_host_port=$arguments["ProxyHostPort"];
637 if(IsSet($arguments["SOCKSHostName"]))
638 $this->socks_host_name=$arguments["SOCKSHostName"];
639 if(IsSet($arguments["SOCKSHostPort"]))
640 $this->socks_host_port=$arguments["SOCKSHostPort"];
641 if(IsSet($arguments["SOCKSVersion"]))
642 $this->socks_version=$arguments["SOCKSVersion"];
643 if(IsSet($arguments["Protocol"]))
644 $this->protocol=$arguments["Protocol"];
645 switch(strtolower($this->protocol))
654 return($this->SetError("it was not specified a valid connection protocol", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
656 if(strlen($this->proxy_host_name)==0)
658 if(strlen($this->host_name)==0)
659 return($this->SetError("it was not specified a valid hostname", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
660 $host_name=$this->host_name;
661 $host_port=($this->host_port ? $this->host_port : $default_port);
662 $server_type = 'HTTP';
666 $host_name=$this->proxy_host_name;
667 $host_port=$this->proxy_host_port;
668 $server_type = 'HTTP proxy';
670 $ssl=(strtolower($this->protocol)=="https" && strlen($this->proxy_host_name)==0);
672 && strlen($this->socks_host_name))
673 return($this->SetError('establishing SSL connections via a SOCKS server is not yet supported', HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
674 $this->use_curl=($ssl && $this->prefer_curl && function_exists("curl_init"));
678 if(!strcmp($host_name, $this->connected_host)
679 && intval($host_port) == $this->connected_port
680 && intval($ssl) == $this->connected_ssl)
683 $this->OutputDebug("Reusing connection to ".$this->connected_host);
686 if(strlen($error = $this->Disconnect()))
691 return("1 already connected");
694 $this->OutputDebug("Connecting to ".$this->host_name);
697 $error=(($this->connection=curl_init($this->protocol."://".$this->host_name.($host_port==$default_port ? "" : ":".strval($host_port))."/")) ? "" : "Could not initialize a CURL session");
698 if(strlen($error)==0)
700 if(IsSet($arguments["SSLCertificateFile"]))
701 curl_setopt($this->connection,CURLOPT_SSLCERT,$arguments["SSLCertificateFile"]);
702 if(IsSet($arguments["SSLCertificatePassword"]))
703 curl_setopt($this->connection,CURLOPT_SSLCERTPASSWD,$arguments["SSLCertificatePassword"]);
704 if(IsSet($arguments["SSLKeyFile"]))
705 curl_setopt($this->connection,CURLOPT_SSLKEY,$arguments["SSLKeyFile"]);
706 if(IsSet($arguments["SSLKeyPassword"]))
707 curl_setopt($this->connection,CURLOPT_SSLKEYPASSWD,$arguments["SSLKeyPassword"]);
709 $this->state="Connected";
714 if(strlen($this->proxy_host_name)
715 && (IsSet($arguments["SSLCertificateFile"])
716 || IsSet($arguments["SSLCertificateFile"])))
717 $error="establishing SSL connections using certificates or private keys via non-SSL proxies is not supported";
722 if(IsSet($arguments["SSLCertificateFile"]))
723 $error="establishing SSL connections using certificates is only supported when the cURL extension is enabled";
724 elseif(IsSet($arguments["SSLKeyFile"]))
725 $error="establishing SSL connections using a private key is only supported when the cURL extension is enabled";
728 $version=explode(".",function_exists("phpversion") ? phpversion() : "3.0.7");
729 $php_version=intval($version[0])*1000000+intval($version[1])*1000+intval($version[2]);
730 if($php_version<4003000)
731 $error="establishing SSL connections requires at least PHP version 4.3.0 or having the cURL extension enabled";
732 elseif(!function_exists("extension_loaded")
733 || !extension_loaded("openssl"))
734 $error="establishing SSL connections requires the OpenSSL extension enabled";
737 if(strlen($error)==0)
739 $error=$this->Connect($host_name, $host_port, $ssl, $server_type);
740 $error_code = $this->error_code;
745 return($this->SetError($error, $error_code));
746 $this->session=md5(uniqid(""));
747 $this->connected_host = $host_name;
748 $this->connected_port = intval($host_port);
749 $this->connected_ssl = intval($ssl);
753 Function Close($force = 0)
755 if($this->state=="Disconnected")
756 return("1 already disconnected");
757 if(!$this->force_close
760 && $this->state == 'ResponseReceived')
763 $this->OutputDebug('Keeping the connection alive to '.$this->connected_host);
764 $this->state = 'Connected';
767 return($this->Disconnect());
770 Function PickCookies(&$cookies,$secure)
772 if(IsSet($this->cookies[$secure]))
774 $now=gmdate("Y-m-d H-i-s");
775 for($domain=0,Reset($this->cookies[$secure]);$domain<count($this->cookies[$secure]);Next($this->cookies[$secure]),$domain++)
777 $domain_pattern=Key($this->cookies[$secure]);
778 $match=strlen($this->request_host)-strlen($domain_pattern);
780 && !strcmp($domain_pattern,substr($this->request_host,$match))
782 || $domain_pattern[0]=="."
783 || $this->request_host[$match-1]=="."))
785 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++)
787 $path=Key($this->cookies[$secure][$domain_pattern]);
788 if(strlen($this->request_uri)>=strlen($path)
789 && substr($this->request_uri,0,strlen($path))==$path)
791 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++)
793 $cookie_name=Key($this->cookies[$secure][$domain_pattern][$path]);
794 $expires=$this->cookies[$secure][$domain_pattern][$path][$cookie_name]["expires"];
796 || strcmp($now,$expires)<0)
797 $cookies[$cookie_name]=$this->cookies[$secure][$domain_pattern][$path][$cookie_name];
806 Function GetFileDefinition($file, &$definition)
809 if(IsSet($file["FileName"]))
810 $name=basename($file["FileName"]);
811 if(IsSet($file["Name"]))
814 return("it was not specified the file part name");
815 if(IsSet($file["Content-Type"]))
817 $content_type=$file["Content-Type"];
818 $type=$this->Tokenize(strtolower($content_type),"/");
819 $sub_type=$this->Tokenize("");
833 switch(GetType($dot=strrpos($name,"."))=="integer" ? strtolower(substr($name,$dot)) : "")
836 $content_type="application/excel";
839 $content_type="application/macbinhex40";
844 $content_type="application/msword";
847 $content_type="application/pdf";
850 $content_type="application/pgp";
855 $content_type="application/postscript";
858 $content_type="application/powerpoint";
861 $content_type="application/rtf";
865 $content_type="application/x-gtar";
868 $content_type="application/x-gzip";
872 $content_type="application/x-httpd-php";
875 $content_type="application/x-javascript";
879 $content_type="application/x-photoshop";
884 $content_type="application/x-shockwave-flash";
887 $content_type="application/x-tar";
890 $content_type="application/zip";
895 $content_type="audio/midi";
900 $content_type="audio/mpeg";
903 $content_type="audio/x-realaudio";
906 $content_type="audio/wav";
909 $content_type="image/bitmap";
912 $content_type="image/gif";
915 $content_type="image/iff";
918 $content_type="image/jb2";
923 $content_type="image/jpeg";
926 $content_type="image/jpx";
929 $content_type="image/png";
933 $content_type="image/tiff";
936 $content_type="image/vnd.wap.wbmp";
939 $content_type="image/xbm";
942 $content_type="text/css";
945 $content_type="text/plain";
949 $content_type="text/html";
952 $content_type="text/xml";
957 $content_type="video/mpeg";
961 $content_type="video/quicktime";
964 $content_type="video/x-ms-video";
967 $content_type="message/rfc822";
970 $content_type="application/octet-stream";
975 return($content_type." is not a supported automatic content type detection method");
979 return($content_type." is not a supported file content type");
983 $content_type="application/octet-stream";
985 "Content-Type"=>$content_type,
988 if(IsSet($file["FileName"]))
990 if(GetType($length=@filesize($file["FileName"]))!="integer")
992 $error="it was not possible to determine the length of the file ".$file["FileName"];
993 if(IsSet($php_errormsg)
994 && strlen($php_errormsg))
995 $error.=": ".$php_errormsg;
996 if(!file_exists($file["FileName"]))
997 $error="it was not possible to access the file ".$file["FileName"];
1000 $definition["FILENAME"]=$file["FileName"];
1001 $definition["Content-Length"]=$length;
1003 elseif(IsSet($file["Data"]))
1004 $definition["Content-Length"]=strlen($definition["DATA"]=$file["Data"]);
1006 return("it was not specified a valid file name");
1010 Function ConnectFromProxy($arguments, &$headers)
1012 if(!$this->PutLine('CONNECT '.$this->host_name.':'.($this->host_port ? $this->host_port : 443).' HTTP/1.0')
1013 || (strlen($this->user_agent)
1014 && !$this->PutLine('User-Agent: '.$this->user_agent))
1015 || (strlen($this->accept)
1016 && !$this->PutLine('Accept: '.$this->accept))
1017 || (IsSet($arguments['Headers']['Proxy-Authorization'])
1018 && !$this->PutLine('Proxy-Authorization: '.$arguments['Headers']['Proxy-Authorization']))
1019 || !$this->PutLine(''))
1021 $this->Disconnect();
1022 return($this->error);
1024 $this->state = "ConnectSent";
1025 if(strlen($error=$this->ReadReplyHeadersResponse($headers)))
1027 $proxy_authorization="";
1028 while(!strcmp($this->response_status, "100"))
1030 $this->state="ConnectSent";
1031 if(strlen($error=$this->ReadReplyHeadersResponse($headers)))
1034 switch($this->response_status)
1037 if(!@stream_socket_enable_crypto($this->connection, 1, STREAM_CRYPTO_METHOD_SSLv23_CLIENT))
1039 $this->SetPHPError('it was not possible to start a SSL encrypted connection via this proxy', $php_errormsg, HTTP_CLIENT_ERROR_COMMUNICATION_FAILURE);
1040 $this->Disconnect();
1041 return($this->error);
1043 $this->state = "Connected";
1046 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)))
1050 return($this->SetError("unable to send request via proxy", HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
1055 Function SendRequest($arguments)
1057 if(strlen($this->error))
1058 return($this->error);
1059 if(IsSet($arguments["ProxyUser"]))
1060 $this->proxy_request_user=$arguments["ProxyUser"];
1061 elseif(IsSet($this->proxy_user))
1062 $this->proxy_request_user=$this->proxy_user;
1063 if(IsSet($arguments["ProxyPassword"]))
1064 $this->proxy_request_password=$arguments["ProxyPassword"];
1065 elseif(IsSet($this->proxy_password))
1066 $this->proxy_request_password=$this->proxy_password;
1067 if(IsSet($arguments["ProxyRealm"]))
1068 $this->proxy_request_realm=$arguments["ProxyRealm"];
1069 elseif(IsSet($this->proxy_realm))
1070 $this->proxy_request_realm=$this->proxy_realm;
1071 if(IsSet($arguments["ProxyWorkstation"]))
1072 $this->proxy_request_workstation=$arguments["ProxyWorkstation"];
1073 elseif(IsSet($this->proxy_workstation))
1074 $this->proxy_request_workstation=$this->proxy_workstation;
1075 switch($this->state)
1077 case "Disconnected":
1078 return($this->SetError("connection was not yet established", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
1082 case "ConnectedToProxy":
1083 if(strlen($error = $this->ConnectFromProxy($arguments, $headers)))
1088 return($this->SetError("can not send request in the current connection state", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
1090 if(IsSet($arguments["RequestMethod"]))
1091 $this->request_method=$arguments["RequestMethod"];
1092 if(IsSet($arguments["User-Agent"]))
1093 $this->user_agent=$arguments["User-Agent"];
1094 if(!IsSet($arguments["Headers"]["User-Agent"])
1095 && strlen($this->user_agent))
1096 $arguments["Headers"]["User-Agent"]=$this->user_agent;
1097 if(IsSet($arguments["KeepAlive"]))
1098 $this->keep_alive=intval($arguments["KeepAlive"]);
1099 if(!IsSet($arguments["Headers"]["Connection"])
1100 && $this->keep_alive)
1101 $arguments["Headers"]["Connection"]='Keep-Alive';
1102 if(IsSet($arguments["Accept"]))
1103 $this->user_agent=$arguments["Accept"];
1104 if(!IsSet($arguments["Headers"]["Accept"])
1105 && strlen($this->accept))
1106 $arguments["Headers"]["Accept"]=$this->accept;
1107 if(strlen($this->request_method)==0)
1108 return($this->SetError("it was not specified a valid request method", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
1109 if(IsSet($arguments["RequestURI"]))
1110 $this->request_uri=$arguments["RequestURI"];
1111 if(strlen($this->request_uri)==0
1112 || substr($this->request_uri,0,1)!="/")
1113 return($this->SetError("it was not specified a valid request URI", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
1114 $this->request_arguments=$arguments;
1115 $this->request_headers=(IsSet($arguments["Headers"]) ? $arguments["Headers"] : array());
1117 $this->request_body="";
1119 if($this->request_method=="POST"
1120 || $this->request_method=="PUT")
1122 if(IsSet($arguments['StreamRequest']))
1125 $this->request_headers["Transfer-Encoding"]="chunked";
1127 elseif(IsSet($arguments["PostFiles"])
1128 || ($this->force_multipart_form_post
1129 && IsSet($arguments["PostValues"])))
1131 $boundary="--".md5(uniqid(time()));
1132 $this->request_headers["Content-Type"]="multipart/form-data; boundary=".$boundary.(IsSet($arguments["CharSet"]) ? "; charset=".$arguments["CharSet"] : "");
1133 $post_parts=array();
1134 if(IsSet($arguments["PostValues"]))
1136 $values=$arguments["PostValues"];
1137 if(GetType($values)!="array")
1138 return($this->SetError("it was not specified a valid POST method values array", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
1139 for(Reset($values),$value=0;$value<count($values);Next($values),$value++)
1141 $input=Key($values);
1142 $headers="--".$boundary."\r\nContent-Disposition: form-data; name=\"".$input."\"\r\n\r\n";
1143 $data=$values[$input];
1144 $post_parts[]=array("HEADERS"=>$headers,"DATA"=>$data);
1145 $body_length+=strlen($headers)+strlen($data)+strlen("\r\n");
1148 $body_length+=strlen("--".$boundary."--\r\n");
1149 $files=(IsSet($arguments["PostFiles"]) ? $arguments["PostFiles"] : array());
1151 $end=(GetType($input=Key($files))!="string");
1154 if(strlen($error=$this->GetFileDefinition($files[$input],$definition)))
1155 return("3 ".$error);
1156 $headers="--".$boundary."\r\nContent-Disposition: form-data; name=\"".$input."\"; filename=\"".$definition["NAME"]."\"\r\nContent-Type: ".$definition["Content-Type"]."\r\n\r\n";
1157 $part=count($post_parts);
1158 $post_parts[$part]=array("HEADERS"=>$headers);
1159 if(IsSet($definition["FILENAME"]))
1161 $post_parts[$part]["FILENAME"]=$definition["FILENAME"];
1165 $data=$definition["DATA"];
1166 $post_parts[$part]["DATA"]=$data;
1167 $body_length+=strlen($headers)+$definition["Content-Length"]+strlen("\r\n");
1169 $end=(GetType($input=Key($files))!="string");
1173 elseif(IsSet($arguments["PostValues"]))
1175 $values=$arguments["PostValues"];
1176 if(GetType($values)!="array")
1177 return($this->SetError("it was not specified a valid POST method values array", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
1178 for(Reset($values),$value=0;$value<count($values);Next($values),$value++)
1181 if(GetType($values[$k])=="array")
1183 for($v = 0; $v < count($values[$k]); $v++)
1186 $this->request_body.="&";
1187 $this->request_body.=UrlEncode($k)."=".UrlEncode($values[$k][$v]);
1193 $this->request_body.="&";
1194 $this->request_body.=UrlEncode($k)."=".UrlEncode($values[$k]);
1197 $this->request_headers["Content-Type"]="application/x-www-form-urlencoded".(IsSet($arguments["CharSet"]) ? "; charset=".$arguments["CharSet"] : "");
1202 && (IsSet($arguments["Body"])
1203 || IsSet($arguments["BodyStream"])))
1205 if(IsSet($arguments["Body"]))
1206 $this->request_body=$arguments["Body"];
1209 $stream=$arguments["BodyStream"];
1210 $this->request_body="";
1211 for($part=0; $part<count($stream); $part++)
1213 if(IsSet($stream[$part]["Data"]))
1214 $this->request_body.=$stream[$part]["Data"];
1215 elseif(IsSet($stream[$part]["File"]))
1217 if(!($file=@fopen($stream[$part]["File"],"rb")))
1218 return($this->SetPHPError("could not open upload file ".$stream[$part]["File"], $php_errormsg, HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE));
1221 if(GetType($block=@fread($file,$this->file_buffer_length))!="string")
1223 $error=$this->SetPHPError("could not read body stream file ".$stream[$part]["File"], $php_errormsg, HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
1227 $this->request_body.=$block;
1232 return("5 it was not specified a valid file or data body stream element at position ".$part);
1235 if(!IsSet($this->request_headers["Content-Type"]))
1236 $this->request_headers["Content-Type"]="application/octet-stream".(IsSet($arguments["CharSet"]) ? "; charset=".$arguments["CharSet"] : "");
1238 if(IsSet($arguments["AuthUser"]))
1239 $this->request_user=$arguments["AuthUser"];
1240 elseif(IsSet($this->user))
1241 $this->request_user=$this->user;
1242 if(IsSet($arguments["AuthPassword"]))
1243 $this->request_password=$arguments["AuthPassword"];
1244 elseif(IsSet($this->password))
1245 $this->request_password=$this->password;
1246 if(IsSet($arguments["AuthRealm"]))
1247 $this->request_realm=$arguments["AuthRealm"];
1248 elseif(IsSet($this->realm))
1249 $this->request_realm=$this->realm;
1250 if(IsSet($arguments["AuthWorkstation"]))
1251 $this->request_workstation=$arguments["AuthWorkstation"];
1252 elseif(IsSet($this->workstation))
1253 $this->request_workstation=$this->workstation;
1254 if(strlen($this->proxy_host_name)==0
1256 $request_uri=$this->request_uri;
1259 switch(strtolower($this->protocol))
1268 $request_uri=strtolower($this->protocol)."://".$this->host_name.(($this->host_port==0 || $this->host_port==$default_port) ? "" : ":".$this->host_port).$this->request_uri;
1272 $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"));
1273 $curl_version=100000*intval($this->Tokenize($version,"."))+1000*intval($this->Tokenize("."))+intval($this->Tokenize(""));
1274 $protocol_version=($curl_version<713002 ? "1.0" : $this->protocol_version);
1277 $protocol_version=$this->protocol_version;
1278 $this->request=$this->request_method." ".$request_uri." HTTP/".$protocol_version;
1280 || ($body_length=strlen($this->request_body))
1281 || !strcmp($this->request_method, 'POST'))
1282 $this->request_headers["Content-Length"]=$body_length;
1283 for($headers=array(),$host_set=0,Reset($this->request_headers),$header=0;$header<count($this->request_headers);Next($this->request_headers),$header++)
1285 $header_name=Key($this->request_headers);
1286 $header_value=$this->request_headers[$header_name];
1287 if(GetType($header_value)=="array")
1289 for(Reset($header_value),$value=0;$value<count($header_value);Next($header_value),$value++)
1290 $headers[]=$header_name.": ".$header_value[Key($header_value)];
1293 $headers[]=$header_name.": ".$header_value;
1294 if(strtolower(Key($this->request_headers))=="host")
1296 $this->request_host=strtolower($header_value);
1302 $headers[]="Host: ".$this->host_name;
1303 $this->request_host=strtolower($this->host_name);
1305 if(count($this->cookies))
1308 $this->PickCookies($cookies,0);
1309 if(strtolower($this->protocol)=="https")
1310 $this->PickCookies($cookies,1);
1314 $headers[$h]="Cookie:";
1315 for(Reset($cookies),$cookie=0;$cookie<count($cookies);Next($cookies),$cookie++)
1317 $cookie_name=Key($cookies);
1318 $headers[$h].=" ".$cookie_name."=".$cookies[$cookie_name]["value"].";";
1322 $next_state = "RequestSent";
1325 if(IsSet($arguments['StreamRequest']))
1326 return($this->SetError("Streaming request data is not supported when using Curl", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
1328 && strlen($this->request_body)==0)
1330 for($request_body="",$success=1,$part=0;$part<count($post_parts);$part++)
1332 $request_body.=$post_parts[$part]["HEADERS"].$post_parts[$part]["DATA"];
1333 if(IsSet($post_parts[$part]["FILENAME"]))
1335 if(!($file=@fopen($post_parts[$part]["FILENAME"],"rb")))
1337 $this->SetPHPError("could not open upload file ".$post_parts[$part]["FILENAME"], $php_errormsg, HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
1343 if(GetType($block=@fread($file,$this->file_buffer_length))!="string")
1345 $this->SetPHPError("could not read upload file", $php_errormsg, HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
1349 $request_body.=$block;
1355 $request_body.="\r\n";
1357 $request_body.="--".$boundary."--\r\n";
1360 $request_body=$this->request_body;
1361 curl_setopt($this->connection,CURLOPT_HEADER,1);
1362 curl_setopt($this->connection,CURLOPT_RETURNTRANSFER,1);
1364 curl_setopt($this->connection,CURLOPT_TIMEOUT,$this->timeout);
1365 curl_setopt($this->connection,CURLOPT_SSL_VERIFYPEER,0);
1366 curl_setopt($this->connection,CURLOPT_SSL_VERIFYHOST,0);
1367 $request=$this->request."\r\n".implode("\r\n",$headers)."\r\n\r\n".$request_body;
1368 curl_setopt($this->connection,CURLOPT_CUSTOMREQUEST,$request);
1370 $this->OutputDebug("C ".$request);
1371 if(!($success=(strlen($this->response=curl_exec($this->connection))!=0)))
1373 $error=curl_error($this->connection);
1374 $this->SetError("Could not execute the request".(strlen($error) ? ": ".$error : ""), HTTP_CLIENT_ERROR_PROTOCOL_FAILURE);
1379 if(($success=$this->PutLine($this->request)))
1381 for($header=0;$header<count($headers);$header++)
1383 if(!$success=$this->PutLine($headers[$header]))
1387 && ($success=$this->PutLine("")))
1389 if(IsSet($arguments['StreamRequest']))
1390 $next_state = "SendingRequestBody";
1391 elseif($body_length)
1393 if(strlen($this->request_body))
1394 $success=$this->PutData($this->request_body);
1397 for($part=0;$part<count($post_parts);$part++)
1399 if(!($success=$this->PutData($post_parts[$part]["HEADERS"]))
1400 || !($success=$this->PutData($post_parts[$part]["DATA"])))
1402 if(IsSet($post_parts[$part]["FILENAME"]))
1404 if(!($file=@fopen($post_parts[$part]["FILENAME"],"rb")))
1406 $this->SetPHPError("could not open upload file ".$post_parts[$part]["FILENAME"], $php_errormsg, HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
1412 if(GetType($block=@fread($file,$this->file_buffer_length))!="string")
1414 $this->SetPHPError("could not read upload file", $php_errormsg, HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
1418 if(!($success=$this->PutData($block)))
1425 if(!($success=$this->PutLine("")))
1429 $success=$this->PutLine("--".$boundary."--");
1432 $sucess=$this->FlushData();
1438 return($this->SetError("could not send the HTTP request: ".$this->error, $this->error_code));
1439 $this->state=$next_state;
1443 Function SetCookie($name, $value, $expires="" , $path="/" , $domain="" , $secure=0, $verbatim=0)
1445 if(strlen($this->error))
1446 return($this->error);
1447 if(strlen($name)==0)
1448 return($this->SetError("it was not specified a valid cookie name", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
1450 || strcmp($path[0],"/"))
1451 return($this->SetError($path." is not a valid path for setting cookie ".$name, HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
1453 || !strpos($domain,".",$domain[0]=="." ? 1 : 0))
1454 return($this->SetError($domain." is not a valid domain for setting cookie ".$name, HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
1455 $domain=strtolower($domain);
1456 if(!strcmp($domain[0],"."))
1457 $domain=substr($domain,1);
1460 $name=$this->CookieEncode($name,1);
1461 $value=$this->CookieEncode($value,0);
1463 $secure=intval($secure);
1464 $this->cookies[$secure][$domain][$path][$name]=array(
1469 "expires"=>$expires,
1475 Function SendRequestBody($data, $end_of_data)
1477 if(strlen($this->error))
1478 return($this->error);
1479 switch($this->state)
1481 case "Disconnected":
1482 return($this->SetError("connection was not yet established", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
1484 case "ConnectedToProxy":
1485 return($this->SetError("request was not sent", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
1486 case "SendingRequestBody":
1489 return($this->SetError("request body was already sent", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
1491 return($this->SetError("can not send the request body in the current connection state", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
1493 $length = strlen($data);
1496 $size = dechex($length)."\r\n";
1497 if(!$this->PutData($size)
1498 || !$this->PutData($data))
1499 return($this->error);
1504 if(!$this->PutData($size))
1505 return($this->error);
1506 $this->state = "RequestSent";
1511 Function ReadReplyHeadersResponse(&$headers)
1514 if(strlen($this->error))
1515 return($this->error);
1516 switch($this->state)
1518 case "Disconnected":
1519 return($this->SetError("connection was not yet established", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
1521 return($this->SetError("request was not sent", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
1522 case "ConnectedToProxy":
1523 return($this->SetError("connection from the remote server from the proxy was not yet established", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
1524 case "SendingRequestBody":
1525 return($this->SetError("request body data was not completely sent", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
1533 return($this->SetError("can not get request headers in the current connection state", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
1535 $this->content_length=$this->read_length=$this->read_response=$this->remaining_chunk=0;
1536 $this->content_length_set=$this->chunked=$this->last_chunk_read=$chunked=0;
1537 $this->force_close = $this->connection_close=0;
1538 for($this->response_status="";;)
1540 $line=$this->GetLine();
1541 if(GetType($line)!="string")
1542 return($this->SetError("could not read request reply: ".$this->error, $this->error_code));
1543 if(strlen($this->response_status)==0)
1545 if(!preg_match($match="/^http\\/[0-9]+\\.[0-9]+[ \t]+([0-9]+)[ \t]*(.*)\$/i",$line,$matches))
1546 return($this->SetError("it was received an unexpected HTTP response status", HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
1547 $this->response_status=$matches[1];
1548 $this->response_message=$matches[2];
1552 if(strlen($this->response_status)==0)
1553 return($this->SetError("it was not received HTTP response status", HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
1554 $this->state=($connect ? "GotConnectHeaders" : "GotReplyHeaders");
1557 $header_name=strtolower($this->Tokenize($line,":"));
1558 $header_value=Trim(Chop($this->Tokenize("\r\n")));
1559 if(IsSet($headers[$header_name]))
1561 if(GetType($headers[$header_name])=="string")
1562 $headers[$header_name]=array($headers[$header_name]);
1563 $headers[$header_name][]=$header_value;
1566 $headers[$header_name]=$header_value;
1569 switch($header_name)
1571 case "content-length":
1572 $this->content_length=intval($headers[$header_name]);
1573 $this->content_length_set=1;
1575 case "transfer-encoding":
1576 $encoding=$this->Tokenize($header_value,"; \t");
1578 && !strcmp($encoding,"chunked"))
1582 if($this->support_cookies)
1584 if(GetType($headers[$header_name])=="array")
1585 $cookie_headers=$headers[$header_name];
1587 $cookie_headers=array($headers[$header_name]);
1588 for($cookie=0;$cookie<count($cookie_headers);$cookie++)
1590 $cookie_name=trim($this->Tokenize($cookie_headers[$cookie],"="));
1591 $cookie_value=$this->Tokenize(";");
1592 $domain=$this->request_host;
1596 while(($name = strtolower(trim(UrlDecode($this->Tokenize("=")))))!="")
1598 $value=UrlDecode($this->Tokenize(";"));
1608 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))
1610 $year=intval($matches[5]);
1612 $year+=($year<70 ? 2000 : 1900);
1613 $expires="$year-".$this->months[$matches[4]]."-".$matches[3]." ".$matches[6].":".$matches[7].":".$matches[8];
1621 if(strlen($this->SetCookie($cookie_name, $cookie_value, $expires, $path , $domain, $secure, 1)))
1627 $this->force_close = $this->connection_close=!strcmp(strtolower($header_value),"close");
1632 $this->chunked=$chunked;
1633 if($this->content_length_set)
1634 $this->connection_close=0;
1638 Function Redirect(&$headers)
1640 if($this->follow_redirect)
1642 if(!IsSet($headers["location"])
1643 || (GetType($headers["location"])!="array"
1644 && strlen($location=$headers["location"])==0)
1645 || (GetType($headers["location"])=="array"
1646 && strlen($location=$headers["location"][0])==0))
1647 return($this->SetError("it was received a redirect without location URL", HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
1648 if(strcmp($location[0],"/"))
1650 if(!($location_arguments=@parse_url($location)))
1651 return($this->SetError("the server did not return a valid redirection location URL", HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
1652 if(!IsSet($location_arguments["scheme"]))
1653 $location=((GetType($end=strrpos($this->request_uri,"/"))=="integer" && $end>1) ? substr($this->request_uri,0,$end) : "")."/".$location;
1655 if(!strcmp($location[0],"/"))
1656 $location=$this->protocol."://".$this->host_name.($this->host_port ? ":".$this->host_port : "").$location;
1657 $error=$this->GetRequestArguments($location,$arguments);
1659 return($this->SetError("could not process redirect url: ".$error, HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
1660 $arguments["RequestMethod"]="GET";
1661 if(strlen($error=$this->Close())==0
1662 && strlen($error=$this->Open($arguments))==0
1663 && strlen($error=$this->SendRequest($arguments))==0)
1665 $this->redirection_level++;
1666 if($this->redirection_level>$this->redirection_limit)
1668 $error="it was exceeded the limit of request redirections";
1669 $this->error_code = HTTP_CLIENT_ERROR_PROTOCOL_FAILURE;
1672 $error=$this->ReadReplyHeaders($headers);
1673 $this->redirection_level--;
1676 return($this->SetError($error, $this->error_code));
1681 Function Authenticate(&$headers, $proxy, &$proxy_authorization, &$user, &$password, &$realm, &$workstation)
1685 $authenticate_header="proxy-authenticate";
1686 $authorization_header="Proxy-Authorization";
1687 $authenticate_status="407";
1688 $authentication_mechanism=$this->proxy_authentication_mechanism;
1692 $authenticate_header="www-authenticate";
1693 $authorization_header="Authorization";
1694 $authenticate_status="401";
1695 $authentication_mechanism=$this->authentication_mechanism;
1697 if(IsSet($headers[$authenticate_header])
1698 && $this->sasl_authenticate)
1700 if(function_exists("class_exists")
1701 && !class_exists("sasl_client_class"))
1702 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));
1703 if(GetType($headers[$authenticate_header])=="array")
1704 $authenticate=$headers[$authenticate_header];
1706 $authenticate=array($headers[$authenticate_header]);
1707 for($response="", $mechanisms=array(),$m=0;$m<count($authenticate);$m++)
1709 $mechanism=$this->Tokenize($authenticate[$m]," ");
1710 $response=$this->Tokenize("");
1711 if(strlen($authentication_mechanism))
1713 if(!strcmp($authentication_mechanism,$mechanism))
1715 $mechanisms[]=$mechanism;
1720 $mechanisms[]=$mechanism;
1722 $sasl=new sasl_client_class;
1724 $sasl->SetCredential("user",$user);
1725 if(IsSet($password))
1726 $sasl->SetCredential("password",$password);
1728 $sasl->SetCredential("realm",$realm);
1729 if(IsSet($workstation))
1730 $sasl->SetCredential("workstation",$workstation);
1731 $sasl->SetCredential("uri",$this->request_uri);
1732 $sasl->SetCredential("method",$this->request_method);
1733 $sasl->SetCredential("session",$this->session);
1736 $status=$sasl->Start($mechanisms,$message,$interactions);
1738 while($status==SASL_INTERACT);
1744 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));
1746 return($this->SetError("Could not start the SASL ".($proxy ? "proxy " : "")."authentication client: ".$sasl->error, HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
1752 if(strlen($error=$this->ReadReplyBody($body,$this->file_buffer_length)))
1754 if(strlen($body)==0)
1758 $authorization_value=$sasl->mechanism.(IsSet($message) ? " ".($sasl->encode_response ? base64_encode($message) : $message) : "");
1759 $request_arguments=$this->request_arguments;
1760 $arguments=$request_arguments;
1761 $arguments["Headers"][$authorization_header]=$authorization_value;
1763 && strlen($proxy_authorization))
1764 $arguments["Headers"]["Proxy-Authorization"]=$proxy_authorization;
1765 if(strlen($error=$this->Close())
1766 || strlen($error=$this->Open($arguments)))
1767 return($this->SetError($error, $this->error_code));
1773 if(strlen($error=$this->ConnectFromProxy($arguments, $headers)))
1774 return($this->SetError($error, $this->error_code));
1778 if(strlen($error=$this->SendRequest($arguments))
1779 || strlen($error=$this->ReadReplyHeadersResponse($headers)))
1780 return($this->SetError($error, $this->error_code));
1782 if(!IsSet($headers[$authenticate_header]))
1783 $authenticate=array();
1784 elseif(GetType($headers[$authenticate_header])=="array")
1785 $authenticate=$headers[$authenticate_header];
1787 $authenticate=array($headers[$authenticate_header]);
1788 for($mechanism=0;$mechanism<count($authenticate);$mechanism++)
1790 if(!strcmp($this->Tokenize($authenticate[$mechanism]," "),$sasl->mechanism))
1792 $response=$this->Tokenize("");
1796 switch($this->response_status)
1798 case $authenticate_status:
1805 return($this->Redirect($headers));
1807 if(intval($this->response_status/100)==2)
1810 $proxy_authorization=$authorization_value;
1815 && !strcmp($this->response_status,"401"))
1817 $proxy_authorization=$authorization_value;
1821 return($this->SetError(($proxy ? "proxy " : "")."authentication error: ".$this->response_status." ".$this->response_message, HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
1824 for(;!$authenticated;)
1828 $status=$sasl->Step($response,$message,$interactions);
1830 while($status==SASL_INTERACT);
1834 $authorization_value=$sasl->mechanism.(IsSet($message) ? " ".($sasl->encode_response ? base64_encode($message) : $message) : "");
1835 $arguments=$request_arguments;
1836 $arguments["Headers"][$authorization_header]=$authorization_value;
1838 && strlen($proxy_authorization))
1839 $arguments["Headers"]["Proxy-Authorization"]=$proxy_authorization;
1842 if(strlen($error=$this->ConnectFromProxy($arguments, $headers)))
1843 return($this->SetError($error, $this->error_code));
1847 if(strlen($error=$this->SendRequest($arguments))
1848 || strlen($error=$this->ReadReplyHeadersResponse($headers)))
1849 return($this->SetError($error, $this->error_code));
1851 switch($this->response_status)
1853 case $authenticate_status:
1854 if(GetType($headers[$authenticate_header])=="array")
1855 $authenticate=$headers[$authenticate_header];
1857 $authenticate=array($headers[$authenticate_header]);
1858 for($response="",$mechanism=0;$mechanism<count($authenticate);$mechanism++)
1860 if(!strcmp($this->Tokenize($authenticate[$mechanism]," "),$sasl->mechanism))
1862 $response=$this->Tokenize("");
1870 if(strlen($error=$this->ReadReplyBody($body,$this->file_buffer_length)))
1872 if(strlen($body)==0)
1876 $this->state="Connected";
1883 return($this->Redirect($headers));
1885 if(intval($this->response_status/100)==2)
1888 $proxy_authorization=$authorization_value;
1893 && !strcmp($this->response_status,"401"))
1895 $proxy_authorization=$authorization_value;
1899 return($this->SetError(($proxy ? "proxy " : "")."authentication error: ".$this->response_status." ".$this->response_message));
1903 return($this->SetError("Could not process the SASL ".($proxy ? "proxy " : "")."authentication step: ".$sasl->error, HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
1910 Function ReadReplyHeaders(&$headers)
1912 if(strlen($error=$this->ReadReplyHeadersResponse($headers)))
1914 $proxy_authorization="";
1915 while(!strcmp($this->response_status, "100"))
1917 $this->state="RequestSent";
1918 if(strlen($error=$this->ReadReplyHeadersResponse($headers)))
1921 switch($this->response_status)
1927 if(strlen($error=$this->Redirect($headers)))
1931 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)))
1933 if(strcmp($this->response_status,"401"))
1936 return($this->Authenticate($headers, 0, $proxy_authorization, $this->request_user, $this->request_password, $this->request_realm, $this->request_workstation));
1941 Function ReadReplyBody(&$body,$length)
1944 if(strlen($this->error))
1945 return($this->error);
1946 switch($this->state)
1948 case "Disconnected":
1949 return($this->SetError("connection was not yet established", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
1951 case "ConnectedToProxy":
1952 return($this->SetError("request was not sent", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
1954 if(($error=$this->ReadReplyHeaders($headers))!="")
1957 case "GotReplyHeaders":
1959 case 'ResponseReceived':
1963 return($this->SetError("can not get request headers in the current connection state", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
1965 if($this->content_length_set)
1966 $length=min($this->content_length-$this->read_length,$length);
1970 if(!$this->EndOfInput()
1971 && ($body=$this->ReadBytes($length))=="")
1973 if(strlen($this->error))
1974 return($this->SetError("could not get the request reply body: ".$this->error, $this->error_code));
1976 $this->read_length+=strlen($body);
1977 if($this->EndOfInput())
1978 $this->state = 'ResponseReceived';
1983 Function ReadWholeReplyBody(&$body)
1988 if(strlen($error = $this->ReadReplyBody($block, $this->file_buffer_length)))
1990 if(strlen($block) == 0)
1996 Function SaveCookies(&$cookies, $domain='', $secure_only=0, $persistent_only=0)
1998 $now=gmdate("Y-m-d H-i-s");
2000 for($secure_cookies=0,Reset($this->cookies);$secure_cookies<count($this->cookies);Next($this->cookies),$secure_cookies++)
2002 $secure=Key($this->cookies);
2006 for($cookie_domain=0,Reset($this->cookies[$secure]);$cookie_domain<count($this->cookies[$secure]);Next($this->cookies[$secure]),$cookie_domain++)
2008 $domain_pattern=Key($this->cookies[$secure]);
2009 $match=strlen($domain)-strlen($domain_pattern);
2010 if(strlen($domain)==0
2012 && !strcmp($domain_pattern,substr($domain,$match))
2014 || $domain_pattern[0]=="."
2015 || $domain[$match-1]==".")))
2017 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++)
2019 $path=Key($this->cookies[$secure][$domain_pattern]);
2020 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++)
2022 $cookie_name=Key($this->cookies[$secure][$domain_pattern][$path]);
2023 $expires=$this->cookies[$secure][$domain_pattern][$path][$cookie_name]["expires"];
2024 if((!$persistent_only
2025 && strlen($expires)==0)
2026 || (strlen($expires)
2027 && strcmp($now,$expires)<0))
2028 $cookies[$secure][$domain_pattern][$path][$cookie_name]=$this->cookies[$secure][$domain_pattern][$path][$cookie_name];
2037 Function SavePersistentCookies(&$cookies, $domain='', $secure_only=0)
2039 $this->SaveCookies($cookies, $domain, $secure_only, 1);
2042 Function GetPersistentCookies(&$cookies, $domain='', $secure_only=0)
2044 $this->SavePersistentCookies($cookies, $domain, $secure_only);
2047 Function RestoreCookies($cookies, $clear=1)
2049 $new_cookies=($clear ? array() : $this->cookies);
2050 for($secure_cookies=0, Reset($cookies); $secure_cookies<count($cookies); Next($cookies), $secure_cookies++)
2052 $secure=Key($cookies);
2053 if(GetType($secure)!="integer")
2054 return($this->SetError("invalid cookie secure value type (".serialize($secure).")", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
2055 for($cookie_domain=0,Reset($cookies[$secure]);$cookie_domain<count($cookies[$secure]);Next($cookies[$secure]),$cookie_domain++)
2057 $domain_pattern=Key($cookies[$secure]);
2058 if(GetType($domain_pattern)!="string")
2059 return($this->SetError("invalid cookie domain value type (".serialize($domain_pattern).")", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
2060 for(Reset($cookies[$secure][$domain_pattern]),$path_part=0;$path_part<count($cookies[$secure][$domain_pattern]);Next($cookies[$secure][$domain_pattern]),$path_part++)
2062 $path=Key($cookies[$secure][$domain_pattern]);
2063 if(GetType($path)!="string"
2064 || strcmp(substr($path, 0, 1), "/"))
2065 return($this->SetError("invalid cookie path value type (".serialize($path).")", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
2066 for(Reset($cookies[$secure][$domain_pattern][$path]),$cookie=0;$cookie<count($cookies[$secure][$domain_pattern][$path]);Next($cookies[$secure][$domain_pattern][$path]),$cookie++)
2068 $cookie_name=Key($cookies[$secure][$domain_pattern][$path]);
2069 $expires=$cookies[$secure][$domain_pattern][$path][$cookie_name]["expires"];
2070 $value=$cookies[$secure][$domain_pattern][$path][$cookie_name]["value"];
2071 if(GetType($expires)!="string"
2072 || (strlen($expires)
2073 && !preg_match("/^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}\$/", $expires)))
2074 return($this->SetError("invalid cookie expiry value type (".serialize($expires).")", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
2075 $new_cookies[$secure][$domain_pattern][$path][$cookie_name]=array(
2076 "name"=>$cookie_name,
2078 "domain"=>$domain_pattern,
2080 "expires"=>$expires,
2087 $this->cookies=$new_cookies;