PageRenderTime 102ms CodeModel.GetById 4ms app.highlight 86ms RepoModel.GetById 1ms app.codeStats 1ms

/lib/httpclient/http.php

https://github.com/abiggerhammer/pat-twitter
PHP | 2122 lines | 2069 code | 44 blank | 9 comment | 438 complexity | 888dd8efb744393aebcd2f075a18390f MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1<?php
   2/*
   3 * http.php
   4 *
   5 * @(#) $Header: /opt2/ena/metal/http/http.php,v 1.91 2013/07/14 13:21:38 mlemos Exp $
   6 *
   7 */
   8
   9define('HTTP_CLIENT_ERROR_UNSPECIFIED_ERROR',       -1);
  10define('HTTP_CLIENT_ERROR_NO_ERROR',                 0);
  11define('HTTP_CLIENT_ERROR_INVALID_SERVER_ADDRESS',   1);
  12define('HTTP_CLIENT_ERROR_CANNOT_CONNECT',           2);
  13define('HTTP_CLIENT_ERROR_COMMUNICATION_FAILURE',    3);
  14define('HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE', 4);
  15define('HTTP_CLIENT_ERROR_PROTOCOL_FAILURE',         5);
  16define('HTTP_CLIENT_ERROR_INVALID_PARAMETERS',       6);
  17
  18class http_class
  19{
  20	var $host_name="";
  21	var $host_port=0;
  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';
  27
  28	var $protocol="http";
  29	var $request_method="GET";
  30	var $user_agent='httpclient (http://www.phpclasses.org/httpclient $Revision: 1.91 $)';
  31	var $accept='';
  32	var $authentication_mechanism="";
  33	var $user;
  34	var $password;
  35	var $realm;
  36	var $workstation;
  37	var $proxy_authentication_mechanism="";
  38	var $proxy_user;
  39	var $proxy_password;
  40	var $proxy_realm;
  41	var $proxy_workstation;
  42	var $request_uri="";
  43	var $request="";
  44	var $request_headers=array();
  45	var $request_user;
  46	var $request_password;
  47	var $request_realm;
  48	var $request_workstation;
  49	var $proxy_request_user;
  50	var $proxy_request_password;
  51	var $proxy_request_realm;
  52	var $proxy_request_workstation;
  53	var $request_body="";
  54	var $request_arguments=array();
  55	var $protocol_version="1.1";
  56	var $timeout=0;
  57	var $data_timeout=0;
  58	var $debug=0;
  59	var $log_debug=0;
  60	var $debug_response_body=1;
  61	var $html_debug=0;
  62	var $support_cookies=1;
  63	var $cookies=array();
  64	var $error="";
  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;
  73	var $prefer_curl = 0;
  74	var $keep_alive = 1;
  75	var $sasl_authenticate = 1;
  76
  77	/* private variables - DO NOT ACCESS */
  78
  79	var $state="Disconnected";
  80	var $use_curl=0;
  81	var $connection=0;
  82	var $content_length=0;
  83	var $response="";
  84	var $read_response=0;
  85	var $read_length=0;
  86	var $request_host="";
  87	var $next_token="";
  88	var $redirection_level=0;
  89	var $chunked=0;
  90	var $remaining_chunk=0;
  91	var $last_chunk_read=0;
  92	var $months=array(
  93		"Jan"=>"01",
  94		"Feb"=>"02",
  95		"Mar"=>"03",
  96		"Apr"=>"04",
  97		"May"=>"05",
  98		"Jun"=>"06",
  99		"Jul"=>"07",
 100		"Aug"=>"08",
 101		"Sep"=>"09",
 102		"Oct"=>"10",
 103		"Nov"=>"11",
 104		"Dec"=>"12");
 105	var $session='';
 106	var $connection_close=0;
 107	var $force_close = 0;
 108	var $connected_host = '';
 109	var $connected_port = -1;
 110	var $connected_ssl = 0;
 111
 112	/* Private methods - DO NOT CALL */
 113
 114	Function Tokenize($string,$separator="")
 115	{
 116		if(!strcmp($separator,""))
 117		{
 118			$separator=$string;
 119			$string=$this->next_token;
 120		}
 121		for($character=0;$character<strlen($separator);$character++)
 122		{
 123			if(GetType($position=strpos($string,$separator[$character]))=="integer")
 124				$found=(IsSet($found) ? min($found,$position) : $position);
 125		}
 126		if(IsSet($found))
 127		{
 128			$this->next_token=substr($string,$found+1);
 129			return(substr($string,0,$found));
 130		}
 131		else
 132		{
 133			$this->next_token="";
 134			return($string);
 135		}
 136	}
 137
 138	Function CookieEncode($value, $name)
 139	{
 140		return($name ? str_replace("=", "%25", $value) : str_replace(";", "%3B", $value));
 141	}
 142
 143	Function SetError($error, $error_code = HTTP_CLIENT_ERROR_UNSPECIFIED_ERROR)
 144	{
 145		$this->error_code = $error_code;
 146		return($this->error=$error);
 147	}
 148
 149	Function SetPHPError($error, &$php_error_message, $error_code = HTTP_CLIENT_ERROR_UNSPECIFIED_ERROR)
 150	{
 151		if(IsSet($php_error_message)
 152		&& strlen($php_error_message))
 153			$error.=": ".$php_error_message;
 154		return($this->SetError($error, $error_code));
 155	}
 156
 157	Function SetDataAccessError($error,$check_connection=0)
 158	{
 159		$this->error=$error;
 160		$this->error_code = HTTP_CLIENT_ERROR_COMMUNICATION_FAILURE;
 161		if(!$this->use_curl
 162		&& function_exists("socket_get_status"))
 163		{
 164			$status=socket_get_status($this->connection);
 165			if($status["timed_out"])
 166				$this->error.=": data access time out";
 167			elseif($status["eof"])
 168			{
 169				if($check_connection)
 170					$this->error="";
 171				else
 172					$this->error.=": the server disconnected";
 173			}
 174		}
 175	}
 176
 177	Function OutputDebug($message)
 178	{
 179		if($this->log_debug)
 180			error_log($message);
 181		else
 182		{
 183			$message.="\n";
 184			if($this->html_debug)
 185				$message=str_replace("\n","<br />\n",HtmlEntities($message));
 186			echo $message;
 187			flush();
 188		}
 189	}
 190
 191	Function GetLine()
 192	{
 193		for($line="";;)
 194		{
 195			if($this->use_curl)
 196			{
 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);
 200			}
 201			else
 202			{
 203				if(feof($this->connection))
 204				{
 205					$this->SetDataAccessError("reached the end of data while reading from the HTTP server connection");
 206					return(0);
 207				}
 208				$data=fgets($this->connection,100);
 209			}
 210			if(GetType($data)!="string"
 211			|| strlen($data)==0)
 212			{
 213				$this->SetDataAccessError("it was not possible to read line from the HTTP server");
 214				return(0);
 215			}
 216			$line.=$data;
 217			$length=strlen($line);
 218			if($length
 219			&& !strcmp(substr($line,$length-1,1),"\n"))
 220			{
 221				$length-=(($length>=2 && !strcmp(substr($line,$length-2,1),"\r")) ? 2 : 1);
 222				$line=substr($line,0,$length);
 223				if($this->debug)
 224					$this->OutputDebug("S $line");
 225				return($line);
 226			}
 227		}
 228	}
 229
 230	Function PutLine($line)
 231	{
 232		if($this->debug)
 233			$this->OutputDebug("C $line");
 234		if(!fputs($this->connection,$line."\r\n"))
 235		{
 236			$this->SetDataAccessError("it was not possible to send a line to the HTTP server");
 237			return(0);
 238		}
 239		return(1);
 240	}
 241
 242	Function PutData($data)
 243	{
 244		if(strlen($data))
 245		{
 246			if($this->debug)
 247				$this->OutputDebug('C '.$data);
 248			if(!fputs($this->connection,$data))
 249			{
 250				$this->SetDataAccessError("it was not possible to send data to the HTTP server");
 251				return(0);
 252			}
 253		}
 254		return(1);
 255	}
 256
 257	Function FlushData()
 258	{
 259		if(!fflush($this->connection))
 260		{
 261			$this->SetDataAccessError("it was not possible to send data to the HTTP server");
 262			return(0);
 263		}
 264		return(1);
 265	}
 266
 267	Function ReadChunkSize()
 268	{
 269		if($this->remaining_chunk==0)
 270		{
 271			$debug=$this->debug;
 272			if(!$this->debug_response_body)
 273				$this->debug=0;
 274			$line=$this->GetLine();
 275			$this->debug=$debug;
 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)
 280			{
 281				if(!$this->debug_response_body)
 282					$this->debug=0;
 283				$line=$this->GetLine();
 284				$this->debug=$debug;
 285				if(GetType($line)!="string")
 286					return($this->SetError("could not read chunk end: ".$this->error, $this->error_code));
 287			}
 288		}
 289		return("");
 290	}
 291
 292	Function ReadBytes($length)
 293	{
 294		if($this->use_curl)
 295		{
 296			$bytes=substr($this->response,$this->read_response,min($length,strlen($this->response)-$this->read_response));
 297			$this->read_response+=strlen($bytes);
 298			if($this->debug
 299			&& $this->debug_response_body
 300			&& strlen($bytes))
 301				$this->OutputDebug("S ".$bytes);
 302		}
 303		else
 304		{
 305			if($this->chunked)
 306			{
 307				for($bytes="",$remaining=$length;$remaining;)
 308				{
 309					if(strlen($this->ReadChunkSize()))
 310						return("");
 311					if($this->remaining_chunk==0)
 312					{
 313						$this->last_chunk_read=1;
 314						break;
 315					}
 316					$ask=min($this->remaining_chunk,$remaining);
 317					$chunk=@fread($this->connection,$ask);
 318					$read=strlen($chunk);
 319					if($read==0)
 320					{
 321						$this->SetDataAccessError("it was not possible to read data chunk from the HTTP server");
 322						return("");
 323					}
 324					if($this->debug
 325					&& $this->debug_response_body)
 326						$this->OutputDebug("S ".$chunk);
 327					$bytes.=$chunk;
 328					$this->remaining_chunk-=$read;
 329					$remaining-=$read;
 330					if($this->remaining_chunk==0)
 331					{
 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"))
 336						{
 337							$this->SetDataAccessError("it was not possible to read end of data chunk from the HTTP server");
 338							return("");
 339						}
 340					}
 341				}
 342			}
 343			else
 344			{
 345				$bytes=@fread($this->connection,$length);
 346				if(strlen($bytes))
 347				{
 348					if($this->debug
 349					&& $this->debug_response_body)
 350						$this->OutputDebug("S ".$bytes);
 351				}
 352				else
 353					$this->SetDataAccessError("it was not possible to read data from the HTTP server", $this->connection_close);
 354			}
 355		}
 356		return($bytes);
 357	}
 358
 359	Function EndOfInput()
 360	{
 361		if($this->use_curl)
 362			return($this->read_response>=strlen($this->response));
 363		if($this->chunked)
 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));
 368	}
 369
 370	Function Resolve($domain, &$ip, $server_type)
 371	{
 372		if(preg_match('/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/',$domain))
 373			$ip=$domain;
 374		else
 375		{
 376			if($this->debug)
 377				$this->OutputDebug('Resolving '.$server_type.' server domain "'.$domain.'"...');
 378			if(!strcmp($ip=@gethostbyname($domain),$domain))
 379				$ip="";
 380		}
 381		if(strlen($ip)==0
 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));
 385		return('');
 386	}
 387
 388	Function Connect($host_name, $host_port, $ssl, $server_type = 'HTTP')
 389	{
 390		$domain=$host_name;
 391		$port = $host_port;
 392		if(strlen($error = $this->Resolve($domain, $ip, $server_type)))
 393			return($error);
 394		if(strlen($this->socks_host_name))
 395		{
 396			switch($this->socks_version)
 397			{
 398				case '4':
 399					$version = 4;
 400					break;
 401				case '5':
 402					$version = 5;
 403					break;
 404				default:
 405					return('it was not specified a supported SOCKS protocol version');
 406					break;
 407			}
 408			$host_ip = $ip;
 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)))
 413				return($error);
 414		}
 415		if($this->debug)
 416			$this->OutputDebug('Connecting to '.$server_type.' server IP '.$ip.' port '.$port.'...');
 417		if($ssl)
 418			$ip="ssl://".$host_name;
 419		if(($this->connection=($this->timeout ? @fsockopen($ip, $port, $errno, $error, $this->timeout) : @fsockopen($ip, $port, $errno)))==0)
 420		{
 421			$error_code = HTTP_CLIENT_ERROR_CANNOT_CONNECT;
 422			switch($errno)
 423			{
 424				case -3:
 425					return($this->SetError("socket could not be created", $error_code));
 426				case -4:
 427					return($this->SetError("dns lookup on hostname \"".$host_name."\" failed", $error_code));
 428				case -5:
 429					return($this->SetError("connection refused or timed out", $error_code));
 430				case -6:
 431					return($this->SetError("fdopen() call failed", $error_code));
 432				case -7:
 433					return($this->SetError("setvbuf() call failed", $error_code));
 434				default:
 435					return($this->SetPHPError($errno." could not connect to the host \"".$host_name."\"",$php_errormsg, $error_code));
 436			}
 437		}
 438		else
 439		{
 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))
 444			{
 445				if($this->debug)
 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';
 449				switch($version)
 450				{
 451					case 4:
 452						$command = 1;
 453						$user = '';
 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);
 456						else
 457						{
 458							$response = fgets($this->connection, 9);
 459							if(strlen($response) != 8)
 460								$error = $this->SetDataAccessError($receive_error);
 461							else
 462							{
 463								$socks_errors = array(
 464									"\x5a"=>'',
 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',
 468								);
 469								$error_code = $response[1];
 470								$error = (IsSet($socks_errors[$error_code]) ? $socks_errors[$error_code] : 'unknown');
 471								if(strlen($error))
 472									$error = 'SOCKS error: '.$error;
 473							}
 474						}
 475						break;
 476					case 5:
 477						if($this->debug)
 478							$this->OutputDebug('Negotiating the authentication method ...');
 479						$methods = 1;
 480						$method = 0;
 481						if(!fputs($this->connection, chr($version).chr($methods).chr($method)))
 482							$error = $this->SetDataAccessError($send_error);
 483						else
 484						{
 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';
 490							else
 491							{
 492								if($this->debug)
 493									$this->OutputDebug('Connecting to '.$host_server_type.' server IP '.$host_ip.' port '.$host_port.'...');
 494								$command = 1;
 495								$address_type = 1;
 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);
 498								else
 499								{
 500									$response = fgets($this->connection, 11);
 501									if(strlen($response) != 10)
 502										$error = $this->SetDataAccessError($receive_error);
 503									else
 504									{
 505										$socks_errors = array(
 506											"\x00"=>'',
 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'
 515										);
 516										$error_code = $response[1];
 517										$error = (IsSet($socks_errors[$error_code]) ? $socks_errors[$error_code] : 'unknown');
 518										if(strlen($error))
 519											$error = 'SOCKS error: '.$error;
 520									}
 521								}
 522							}
 523						}
 524						break;
 525					default:
 526						$error = 'support for SOCKS protocol version '.$this->socks_version.' is not yet implemented';
 527						break;
 528				}
 529				if(strlen($error))
 530				{
 531					fclose($this->connection);
 532					return($error);
 533				}
 534			}
 535			if($this->debug)
 536				$this->OutputDebug("Connected to $host_name");
 537			if(strlen($this->proxy_host_name)
 538			&& !strcmp(strtolower($this->protocol), 'https'))
 539			{
 540				if(function_exists('stream_socket_enable_crypto')
 541				&& in_array('ssl', stream_get_transports()))
 542					$this->state = "ConnectedToProxy";
 543				else
 544				{
 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";
 547				}
 548			}
 549			else
 550				$this->state="Connected";
 551			return("");
 552		}
 553	}
 554
 555	Function Disconnect()
 556	{
 557		if($this->debug)
 558			$this->OutputDebug("Disconnected from ".$this->connected_host);
 559		if($this->use_curl)
 560		{
 561			curl_close($this->connection);
 562			$this->response="";
 563		}
 564		else
 565			fclose($this->connection);
 566		$this->state="Disconnected";
 567		return("");
 568	}
 569
 570	/* Public methods */
 571
 572	Function GetRequestArguments($url, &$arguments)
 573	{
 574		$this->error = '';
 575		$this->error_code = HTTP_CLIENT_ERROR_NO_ERROR;
 576		$arguments=array();
 577		$url = str_replace(' ', '%20', $url);
 578		$parameters=@parse_url($url);
 579		if(!$parameters)
 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"]))
 584		{
 585			case "http":
 586			case "https":
 587				$arguments["Protocol"]=$parameters["scheme"];
 588				break;
 589			default:
 590				return($parameters["scheme"]." connection scheme is not yet supported");
 591		}
 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"]))
 597		{
 598			$arguments["AuthUser"]=UrlDecode($parameters["user"]);
 599			if(!IsSet($parameters["pass"]))
 600				$arguments["AuthPassword"]="";
 601		}
 602		if(IsSet($parameters["pass"]))
 603		{
 604			if(!IsSet($parameters["user"]))
 605				$arguments["AuthUser"]="";
 606			$arguments["AuthPassword"]=UrlDecode($parameters["pass"]);
 607		}
 608		if(IsSet($parameters["port"]))
 609		{
 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"]);
 613		}
 614		else
 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;
 621		return("");
 622	}
 623
 624	Function Open($arguments)
 625	{
 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))
 646		{
 647			case "http":
 648				$default_port=80;
 649				break;
 650			case "https":
 651				$default_port=443;
 652				break;
 653			default:
 654				return($this->SetError("it was not specified a valid connection protocol", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
 655		}
 656		if(strlen($this->proxy_host_name)==0)
 657		{
 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';
 663		}
 664		else
 665		{
 666			$host_name=$this->proxy_host_name;
 667			$host_port=$this->proxy_host_port;
 668			$server_type = 'HTTP proxy';
 669		}
 670		$ssl=(strtolower($this->protocol)=="https" && strlen($this->proxy_host_name)==0);
 671		if($ssl
 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"));
 675		switch($this->state)
 676		{
 677			case 'Connected':
 678				if(!strcmp($host_name, $this->connected_host)
 679				&& intval($host_port) == $this->connected_port
 680				&& intval($ssl) == $this->connected_ssl)
 681				{
 682					if($this->debug)
 683						$this->OutputDebug("Reusing connection to ".$this->connected_host);
 684					return('');
 685				}
 686				if(strlen($error = $this->Disconnect()))
 687					return($error);
 688			case "Disconnected":
 689				break;
 690			default:
 691				return("1 already connected");
 692		}
 693		if($this->debug)
 694			$this->OutputDebug("Connecting to ".$this->host_name);
 695		if($this->use_curl)
 696		{
 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)
 699			{
 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"]);
 708			}
 709			$this->state="Connected";
 710		}
 711		else
 712		{
 713			$error="";
 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";
 718			else
 719			{
 720				if($ssl)
 721				{
 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";
 726					else
 727					{
 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";
 735					}
 736				}
 737				if(strlen($error)==0)
 738				{
 739					$error=$this->Connect($host_name, $host_port, $ssl, $server_type);
 740					$error_code = $this->error_code;
 741				}
 742			}
 743		}
 744		if(strlen($error))
 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);
 750		return("");
 751	}
 752
 753	Function Close($force = 0)
 754	{
 755		if($this->state=="Disconnected")
 756			return("1 already disconnected");
 757		if(!$this->force_close
 758		&& $this->keep_alive
 759		&& !$force
 760		&& $this->state == 'ResponseReceived')
 761		{
 762			if($this->debug)
 763				$this->OutputDebug('Keeping the connection alive to '.$this->connected_host);
 764			$this->state = 'Connected';
 765			return('');
 766		}
 767		return($this->Disconnect());
 768	}
 769
 770	Function PickCookies(&$cookies,$secure)
 771	{
 772		if(IsSet($this->cookies[$secure]))
 773		{
 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++)
 776			{
 777				$domain_pattern=Key($this->cookies[$secure]);
 778				$match=strlen($this->request_host)-strlen($domain_pattern);
 779				if($match>=0
 780				&& !strcmp($domain_pattern,substr($this->request_host,$match))
 781				&& ($match==0
 782				|| $domain_pattern[0]=="."
 783				|| $this->request_host[$match-1]=="."))
 784				{
 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++)
 786					{
 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)
 790						{
 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++)
 792							{
 793								$cookie_name=Key($this->cookies[$secure][$domain_pattern][$path]);
 794								$expires=$this->cookies[$secure][$domain_pattern][$path][$cookie_name]["expires"];
 795								if($expires==""
 796								|| strcmp($now,$expires)<0)
 797									$cookies[$cookie_name]=$this->cookies[$secure][$domain_pattern][$path][$cookie_name];
 798							}
 799						}
 800					}
 801				}
 802			}
 803		}
 804	}
 805
 806	Function GetFileDefinition($file, &$definition)
 807	{
 808		$name="";
 809		if(IsSet($file["FileName"]))
 810			$name=basename($file["FileName"]);
 811		if(IsSet($file["Name"]))
 812			$name=$file["Name"];
 813		if(strlen($name)==0)
 814			return("it was not specified the file part name");
 815		if(IsSet($file["Content-Type"]))
 816		{
 817			$content_type=$file["Content-Type"];
 818			$type=$this->Tokenize(strtolower($content_type),"/");
 819			$sub_type=$this->Tokenize("");
 820			switch($type)
 821			{
 822				case "text":
 823				case "image":
 824				case "audio":
 825				case "video":
 826				case "application":
 827				case "message":
 828					break;
 829				case "automatic":
 830					switch($sub_type)
 831					{
 832						case "name":
 833							switch(GetType($dot=strrpos($name,"."))=="integer" ? strtolower(substr($name,$dot)) : "")
 834							{
 835								case ".xls":
 836									$content_type="application/excel";
 837									break;
 838								case ".hqx":
 839									$content_type="application/macbinhex40";
 840									break;
 841								case ".doc":
 842								case ".dot":
 843								case ".wrd":
 844									$content_type="application/msword";
 845									break;
 846								case ".pdf":
 847									$content_type="application/pdf";
 848									break;
 849								case ".pgp":
 850									$content_type="application/pgp";
 851									break;
 852								case ".ps":
 853								case ".eps":
 854								case ".ai":
 855									$content_type="application/postscript";
 856									break;
 857								case ".ppt":
 858									$content_type="application/powerpoint";
 859									break;
 860								case ".rtf":
 861									$content_type="application/rtf";
 862									break;
 863								case ".tgz":
 864								case ".gtar":
 865									$content_type="application/x-gtar";
 866									break;
 867								case ".gz":
 868									$content_type="application/x-gzip";
 869									break;
 870								case ".php":
 871								case ".php3":
 872									$content_type="application/x-httpd-php";
 873									break;
 874								case ".js":
 875									$content_type="application/x-javascript";
 876									break;
 877								case ".ppd":
 878								case ".psd":
 879									$content_type="application/x-photoshop";
 880									break;
 881								case ".swf":
 882								case ".swc":
 883								case ".rf":
 884									$content_type="application/x-shockwave-flash";
 885									break;
 886								case ".tar":
 887									$content_type="application/x-tar";
 888									break;
 889								case ".zip":
 890									$content_type="application/zip";
 891									break;
 892								case ".mid":
 893								case ".midi":
 894								case ".kar":
 895									$content_type="audio/midi";
 896									break;
 897								case ".mp2":
 898								case ".mp3":
 899								case ".mpga":
 900									$content_type="audio/mpeg";
 901									break;
 902								case ".ra":
 903									$content_type="audio/x-realaudio";
 904									break;
 905								case ".wav":
 906									$content_type="audio/wav";
 907									break;
 908								case ".bmp":
 909									$content_type="image/bitmap";
 910									break;
 911								case ".gif":
 912									$content_type="image/gif";
 913									break;
 914								case ".iff":
 915									$content_type="image/iff";
 916									break;
 917								case ".jb2":
 918									$content_type="image/jb2";
 919									break;
 920								case ".jpg":
 921								case ".jpe":
 922								case ".jpeg":
 923									$content_type="image/jpeg";
 924									break;
 925								case ".jpx":
 926									$content_type="image/jpx";
 927									break;
 928								case ".png":
 929									$content_type="image/png";
 930									break;
 931								case ".tif":
 932								case ".tiff":
 933									$content_type="image/tiff";
 934									break;
 935								case ".wbmp":
 936									$content_type="image/vnd.wap.wbmp";
 937									break;
 938								case ".xbm":
 939									$content_type="image/xbm";
 940									break;
 941								case ".css":
 942									$content_type="text/css";
 943									break;
 944								case ".txt":
 945									$content_type="text/plain";
 946									break;
 947								case ".htm":
 948								case ".html":
 949									$content_type="text/html";
 950									break;
 951								case ".xml":
 952									$content_type="text/xml";
 953									break;
 954								case ".mpg":
 955								case ".mpe":
 956								case ".mpeg":
 957									$content_type="video/mpeg";
 958									break;
 959								case ".qt":
 960								case ".mov":
 961									$content_type="video/quicktime";
 962									break;
 963								case ".avi":
 964									$content_type="video/x-ms-video";
 965									break;
 966								case ".eml":
 967									$content_type="message/rfc822";
 968									break;
 969								default:
 970									$content_type="application/octet-stream";
 971									break;
 972							}
 973							break;
 974						default:
 975							return($content_type." is not a supported automatic content type detection method");
 976					}
 977					break;
 978				default:
 979					return($content_type." is not a supported file content type");
 980			}
 981		}
 982		else
 983			$content_type="application/octet-stream";
 984		$definition=array(
 985			"Content-Type"=>$content_type,
 986			"NAME"=>$name
 987		);
 988		if(IsSet($file["FileName"]))
 989		{
 990			if(GetType($length=@filesize($file["FileName"]))!="integer")
 991			{
 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"];
 998				return($error);
 999			}
1000			$definition["FILENAME"]=$file["FileName"];
1001			$definition["Content-Length"]=$length;
1002		}
1003		elseif(IsSet($file["Data"]))
1004			$definition["Content-Length"]=strlen($definition["DATA"]=$file["Data"]);
1005		else
1006			return("it was not specified a valid file name");
1007		return("");
1008	}
1009
1010	Function ConnectFromProxy($arguments, &$headers)
1011	{
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(''))
1020		{
1021			$this->Disconnect();
1022			return($this->error);
1023		}
1024		$this->state = "ConnectSent";
1025		if(strlen($error=$this->ReadReplyHeadersResponse($headers)))
1026			return($error);
1027		$proxy_authorization="";
1028		while(!strcmp($this->response_status, "100"))
1029		{
1030			$this->state="ConnectSent";
1031			if(strlen($error=$this->ReadReplyHeadersResponse($headers)))
1032				return($error);
1033		}
1034		switch($this->response_status)
1035		{
1036			case "200":
1037				if(!@stream_socket_enable_crypto($this->connection, 1, STREAM_CRYPTO_METHOD_SSLv23_CLIENT))
1038				{
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);
1042				}
1043				$this->state = "Connected";
1044				break;
1045			case "407":
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)))
1047					return($error);
1048				break;
1049			default:
1050				return($this->SetError("unable to send request via proxy", HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
1051		}
1052		return("");
1053	}
1054
1055	Function SendRequest($arguments)
1056	{
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)
1076		{
1077			case "Disconnected":
1078				return($this->SetError("connection was not yet established", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
1079			case "Connected":
1080				$connect = 0;
1081				break;
1082			case "ConnectedToProxy":
1083				if(strlen($error = $this->ConnectFromProxy($arguments, $headers)))
1084					return($error);
1085				$connect = 1;
1086				break;
1087			default:
1088				return($this->SetError("can not send request in the current connection state", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
1089		}
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());
1116		$body_length=0;
1117		$this->request_body="";
1118		$get_body=1;
1119		if($this->request_method=="POST"
1120		|| $this->request_method=="PUT")
1121		{
1122			if(IsSet($arguments['StreamRequest']))
1123			{
1124				$get_body = 0;
1125				$this->request_headers["Transfer-Encoding"]="chunked";
1126			}
1127			elseif(IsSet($arguments["PostFiles"])
1128			|| ($this->force_multipart_form_post
1129			&& IsSet($arguments["PostValues"])))
1130			{
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"]))
1135				{
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++)
1140					{
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");
1146					}
1147				}
1148				$body_length+=strlen("--".$boundary."--\r\n");
1149				$files=(IsSet($arguments["PostFiles"]) ? $arguments["PostFiles"] : array());
1150				Reset($files);
1151				$end=(GetType($input=Key($files))!="string");
1152				for(;!$end;)
1153				{
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"]))
1160					{
1161						$post_parts[$part]["FILENAME"]=$definition["FILENAME"];
1162						$data="";
1163					}
1164					else
1165						$data=$definition["DATA"];
1166					$post_parts[$part]["DATA"]=$data;
1167					$body_length+=strlen($headers)+$definition["Content-Length"]+strlen("\r\n");
1168					Next($files);
1169					$end=(GetType($input=Key($files))!="string");
1170				}
1171				$get_body=0;
1172			}
1173			elseif(IsSet($arguments["PostValues"]))
1174			{
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++)
1179				{
1180					$k=Key($values);
1181					if(GetType($values[$k])=="array")
1182					{
1183						for($v = 0; $v < count($values[$k]); $v++)
1184						{
1185							if($value+$v>0)
1186								$this->request_body.="&";
1187							$this->request_body.=UrlEncode($k)."=".UrlEncode($values[$k][$v]);
1188						}
1189					}
1190					else
1191					{
1192						if($value>0)
1193							$this->request_body.="&";
1194						$this->request_body.=UrlEncode($k)."=".UrlEncode($values[$k]);
1195					}
1196				}
1197				$this->request_headers["Content-Type"]="application/x-www-form-urlencoded".(IsSet($arguments["CharSet"]) ? "; charset=".$arguments["CharSet"] : "");
1198				$get_body=0;
1199			}
1200		}
1201		if($get_body
1202		&& (IsSet($arguments["Body"])
1203		|| IsSet($arguments["BodyStream"])))
1204		{
1205			if(IsSet($arguments["Body"]))
1206				$this->request_body=$arguments["Body"];
1207			else
1208			{
1209				$stream=$arguments["BodyStream"];
1210				$this->request_body="";
1211				for($part=0; $part<count($stream); $part++)
1212				{
1213					if(IsSet($stream[$part]["Data"]))
1214						$this->request_body.=$stream[$part]["Data"];
1215					elseif(IsSet($stream[$part]["File"]))
1216					{
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));
1219						while(!feof($file))
1220						{
1221							if(GetType($block=@fread($file,$this->file_buffer_length))!="string")
1222							{
1223								$error=$this->SetPHPError("could not read body stream file ".$stream[$part]["File"], $php_errormsg, HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
1224								fclose($file);
1225								return($error);
1226							}
1227							$this->request_body.=$block;
1228						}
1229						fclose($file);
1230					}
1231					else
1232						return("5 it was not specified a valid file or data body stream element at position ".$part);
1233				}
1234			}
1235			if(!IsSet($this->request_headers["Content-Type"]))
1236				$this->request_headers["Content-Type"]="application/octet-stream".(IsSet($arguments["CharSet"]) ? "; charset=".$arguments["CharSet"] : "");
1237		}
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
1255		|| $connect)
1256			$request_uri=$this->request_uri;
1257		else
1258		{
1259			switch(strtolower($this->protocol))
1260			{
1261				case "http":
1262					$default_port=80;
1263					break;
1264				case "https":
1265					$default_port=443;
1266					break;
1267			}
1268			$request_uri=strtolower($this->protocol)."://".$this->host_name.(($this->host_port==0 || $this->host_port==$default_port) ? "" : ":".$this->host_port).$this->request_uri;
1269		}
1270		if($this->use_curl)
1271		{
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);
1275		}
1276		else
1277			$protocol_version=$this->protocol_version;
1278		$this->request=$this->request_method." ".$request_uri." HTTP/".$protocol_version;
1279		if($body_length
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++)
1284		{
1285			$header_name=Key($this->request_headers);
1286			$header_value=$this->request_headers[$header_name];
1287			if(GetType($header_value)=="array")
1288			{
1289				for(Reset($header_value),$value=0;$value<count($header_value);Next($header_value),$value++)
1290					$headers[]=$header_name.": ".$header_value[Key($header_value)];
1291			}
1292			else
1293				$headers[]=$header_name.": ".$header_value;
1294			if(strtolower(Key($this->request_headers))=="host")
1295			{
1296				$this->request_host=strtolower($header_value);
1297				$host_set=1;
1298			}
1299		}
1300		if(!$host_set)
1301		{
1302			$headers[]="Host: ".$this->host_name;
1303			$this->request_host=strtolower($this->host_name);
1304		}
1305		if(count($this->cookies))
1306		{
1307			$cookies=array();
1308			$this->PickCookies($cookies,0);
1309			if(strtolower($this->protocol)=="https")
1310				$this->PickCookies($cookies,1);
1311			if(count($cookies))
1312			{
1313				$h=count($headers);
1314				$headers[$h]="Cookie:";
1315				for(Reset($cookies),$cookie=0;$cookie<count($cookies);Next($cookies),$cookie++)
1316				{
1317					$cookie_name=Key($cookies);
1318					$headers[$h].=" ".$cookie_name."=".$cookies[$cookie_name]["value"].";";
1319				}
1320			}
1321		}
1322		$next_state = "RequestSent";
1323		if($this->use_curl)
1324		{
1325			if(IsSet($arguments['StreamRequest']))
1326				return($this->SetError("Streaming request data is not supported when using Curl", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
1327			if($body_length
1328			&& strlen($this->request_body)==0)
1329			{
1330				for($request_body="",$success=1,$part=0;$part<count($post_parts);$part++)
1331				{
1332					$request_body.=$post_parts[$part]["HEADERS"].$post_parts[$part]["DATA"];
1333					if(IsSet($post_parts[$part]["FILENAME"]))
1334					{
1335						if(!($file=@fopen($post_parts[$part]["FILENAME"],"rb")))
1336						{
1337							$this->SetPHPError("could not open upload file ".$post_parts[$part]["FILENAME"], $php_errormsg, HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
1338							$success=0;
1339							break;
1340						}
1341						while(!feof($file))
1342						{
1343							if(GetType($block=@fread($file,$this->file_buffer_length))!="string")
1344							{
1345								$this->SetPHPError("could not read upload file", $php_errormsg, HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
1346								$success=0;
1347								break;
1348							}
1349							$request_body.=$block;
1350						}
1351						fclose($file);
1352						if(!$success)
1353							break;
1354					}
1355					$request_body.="\r\n";
1356				}
1357				$request_body.="--".$boundary."--\r\n";
1358			}
1359			else
1360				$request_body=$this->request_body;
1361			curl_setopt($this->connection,CURLOPT_HEADER,1);
1362			curl_setopt($this->connection,CURLOPT_RETURNTRANSFER,1);
1363			if($this->timeout)
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);
1369			if($this->debug)
1370				$this->OutputDebug("C ".$request);
1371			if(!($success=(strlen($this->response=curl_exec($this->connection))!=0)))
1372			{
1373				$error=curl_error($this->connection);
1374				$this->SetError("Could not execute the request".(strlen($error) ? ": ".$error : ""), HTTP_CLIENT_ERROR_PROTOCOL_FAILURE);
1375			}
1376		}
1377		else
1378		{
1379			if(($success=$this->PutLine($this->request)))
1380			{
1381				for($header=0;$header<count($headers);$header++)
1382				{
1383					if(!$success=$this->PutLine($headers[$header]))
1384						break;
1385				}
1386				if($success
1387				&& ($success=$this->PutLine("")))
1388				{
1389					if(IsSet($arguments['StreamRequest']))
1390						$next_state = "SendingRequestBody";
1391					elseif($body_length)
1392					{
1393						if(strlen($this->request_body))
1394							$success=$this->PutData($this->request_body);
1395						else
1396						{
1397							for($part=0;$part<count($post_parts);$part++)
1398							{
1399								if(!($success=$this->PutData($post_parts[$part]["HEADERS"]))
1400								|| !($success=$this->PutData($post_parts[$part]["DATA"])))
1401									break;
1402								if(IsSet($post_parts[$part]["FILENAME"]))
1403								{
1404									if(!($file=@fopen($post_parts[$part]["FILENAME"],"rb")))
1405									{
1406										$this->SetPHPError("could not open upload file ".$post_parts[$part]["FILENAME"], $php_errormsg, HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
1407										$success=0;
1408										break;
1409									}
1410									while(!feof($file))
1411									{
1412										if(GetType($block=@fread($file,$this->file_buffer_length))!="string")
1413										{
1414											$this->SetPHPError("could not read upload file", $php_errormsg, HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
1415											$success=0;
1416											break;
1417										}
1418										if(!($success=$this->PutData($block)))
1419											break;
1420									}
1421									fclose($file);
1422									if(!$success)
1423										break;
1424								}
1425								if(!($success=$this->PutLine("")))
1426									break;
1427							}
1428							if($success)
1429								$success=$this->PutLine("--".$boundary."--");
1430						}
1431						if($success)
1432							$sucess=$this->FlushData();
1433					}
1434				}
1435			}
1436		}
1437		if(!$success)
1438			return($this->SetError("could not send the HTTP request: ".$this->error, $this->error_code));
1439		$this->state=$next_state;
1440		return("");
1441	}
1442
1443	Function SetCookie($name, $value, $expires="" , $path="/" , $domain="" , $secure=0, $verbatim=0)
1444	{
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));
1449		if(strlen($path)==0
1450		|| strcmp($path[0],"/"))
1451			return($this->SetError($path." is not a valid path for setting cookie ".$name, HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
1452		if($domain==""
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);
1458		if(!$verbatim)
1459		{
1460			$name=$this->CookieEncode($name,1);
1461			$value=$this->CookieEncode($value,0);
1462		}
1463		$secure=intval($secure);
1464		$this->cookies[$secure][$domain][$path][$name]=array(
1465			"name"=>$name,
1466			"value"=>$value,
1467			"domain"=>$domain,
1468			"path"=>$path,
1469			"expires"=>$expires,
1470			"secure"=>$secure
1471		);
1472		return("");
1473	}
1474
1475	Function SendRequestBody($data, $end_of_data)
1476	{
1477		if(strlen($this->error))
1478			return($this->error);
1479		switch($this->state)
1480		{
1481			case "Disconnected":
1482				return($this->SetError("connection was not yet established", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
1483			case "Connected":
1484			case "ConnectedToProxy":
1485				return($this->SetError("request was not sent", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
1486			case "SendingRequestBody":
1487				break;
1488			case "RequestSent":
1489				return($this->SetError("request body was already sent", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
1490			default:
1491				return($this->SetError("can not send the request body in the current connection state", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
1492		}
1493		$length = strlen($data);
1494		if($length)
1495		{
1496			$size = dechex($length)."\r\n";
1497			if(!$this->PutData($size)
1498			|| !$this->PutData($data))
1499				return($this->error);
1500		}
1501		if($end_of_data)
1502		{
1503			$size = "0\r\n";
1504			if(!$this->PutData($size))
1505				return($this->error);
1506			$this->state = "RequestSent";
1507		}
1508		return("");
1509	}
1510
1511	Function ReadReplyHeadersResponse(&$headers)
1512	{
1513		$headers=array();
1514		if(strlen($this->error))
1515			return($this->error);
1516		switch($this->state)
1517		{
1518			case "Disconnected":
1519				return($this->SetError("connection was not yet established", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
1520			case "Connected":
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));
1526			case "ConnectSent":
1527				$connect = 1;
1528				break;
1529			case "RequestSent":
1530				$connect = 0;
1531				break;
1532			default:
1533				return($this->SetError("can not get request headers in the current connection state", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
1534		}
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="";;)
1539		{
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)
1544			{
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];
1549			}
1550			if($line=="")
1551			{
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");
1555				break;
1556			}
1557			$header_name=strtolower($this->Tokenize($line,":"));
1558			$header_value=Trim(Chop($this->Tokenize("\r\n")));
1559			if(IsSet($headers[$header_name]))
1560			{
1561				if(GetType($headers[$header_name])=="string")
1562					$headers[$header_name]=array($headers[$header_name]);
1563		

Large files files are truncated, but you can click here to view the full file