PageRenderTime 66ms CodeModel.GetById 21ms RepoModel.GetById 0ms 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
Possible License(s): BSD-3-Clause
  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. define('HTTP_CLIENT_ERROR_UNSPECIFIED_ERROR', -1);
  9. define('HTTP_CLIENT_ERROR_NO_ERROR', 0);
  10. define('HTTP_CLIENT_ERROR_INVALID_SERVER_ADDRESS', 1);
  11. define('HTTP_CLIENT_ERROR_CANNOT_CONNECT', 2);
  12. define('HTTP_CLIENT_ERROR_COMMUNICATION_FAILURE', 3);
  13. define('HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE', 4);
  14. define('HTTP_CLIENT_ERROR_PROTOCOL_FAILURE', 5);
  15. define('HTTP_CLIENT_ERROR_INVALID_PARAMETERS', 6);
  16. class http_class
  17. {
  18. var $host_name="";
  19. var $host_port=0;
  20. var $proxy_host_name="";
  21. var $proxy_host_port=80;
  22. var $socks_host_name = '';
  23. var $socks_host_port = 1080;
  24. var $socks_version = '5';
  25. var $protocol="http";
  26. var $request_method="GET";
  27. var $user_agent='httpclient (http://www.phpclasses.org/httpclient $Revision: 1.91 $)';
  28. var $accept='';
  29. var $authentication_mechanism="";
  30. var $user;
  31. var $password;
  32. var $realm;
  33. var $workstation;
  34. var $proxy_authentication_mechanism="";
  35. var $proxy_user;
  36. var $proxy_password;
  37. var $proxy_realm;
  38. var $proxy_workstation;
  39. var $request_uri="";
  40. var $request="";
  41. var $request_headers=array();
  42. var $request_user;
  43. var $request_password;
  44. var $request_realm;
  45. var $request_workstation;
  46. var $proxy_request_user;
  47. var $proxy_request_password;
  48. var $proxy_request_realm;
  49. var $proxy_request_workstation;
  50. var $request_body="";
  51. var $request_arguments=array();
  52. var $protocol_version="1.1";
  53. var $timeout=0;
  54. var $data_timeout=0;
  55. var $debug=0;
  56. var $log_debug=0;
  57. var $debug_response_body=1;
  58. var $html_debug=0;
  59. var $support_cookies=1;
  60. var $cookies=array();
  61. var $error="";
  62. var $error_code = HTTP_CLIENT_ERROR_NO_ERROR;
  63. var $exclude_address="";
  64. var $follow_redirect=0;
  65. var $redirection_limit=5;
  66. var $response_status="";
  67. var $response_message="";
  68. var $file_buffer_length=8000;
  69. var $force_multipart_form_post=0;
  70. var $prefer_curl = 0;
  71. var $keep_alive = 1;
  72. var $sasl_authenticate = 1;
  73. /* private variables - DO NOT ACCESS */
  74. var $state="Disconnected";
  75. var $use_curl=0;
  76. var $connection=0;
  77. var $content_length=0;
  78. var $response="";
  79. var $read_response=0;
  80. var $read_length=0;
  81. var $request_host="";
  82. var $next_token="";
  83. var $redirection_level=0;
  84. var $chunked=0;
  85. var $remaining_chunk=0;
  86. var $last_chunk_read=0;
  87. var $months=array(
  88. "Jan"=>"01",
  89. "Feb"=>"02",
  90. "Mar"=>"03",
  91. "Apr"=>"04",
  92. "May"=>"05",
  93. "Jun"=>"06",
  94. "Jul"=>"07",
  95. "Aug"=>"08",
  96. "Sep"=>"09",
  97. "Oct"=>"10",
  98. "Nov"=>"11",
  99. "Dec"=>"12");
  100. var $session='';
  101. var $connection_close=0;
  102. var $force_close = 0;
  103. var $connected_host = '';
  104. var $connected_port = -1;
  105. var $connected_ssl = 0;
  106. /* Private methods - DO NOT CALL */
  107. Function Tokenize($string,$separator="")
  108. {
  109. if(!strcmp($separator,""))
  110. {
  111. $separator=$string;
  112. $string=$this->next_token;
  113. }
  114. for($character=0;$character<strlen($separator);$character++)
  115. {
  116. if(GetType($position=strpos($string,$separator[$character]))=="integer")
  117. $found=(IsSet($found) ? min($found,$position) : $position);
  118. }
  119. if(IsSet($found))
  120. {
  121. $this->next_token=substr($string,$found+1);
  122. return(substr($string,0,$found));
  123. }
  124. else
  125. {
  126. $this->next_token="";
  127. return($string);
  128. }
  129. }
  130. Function CookieEncode($value, $name)
  131. {
  132. return($name ? str_replace("=", "%25", $value) : str_replace(";", "%3B", $value));
  133. }
  134. Function SetError($error, $error_code = HTTP_CLIENT_ERROR_UNSPECIFIED_ERROR)
  135. {
  136. $this->error_code = $error_code;
  137. return($this->error=$error);
  138. }
  139. Function SetPHPError($error, &$php_error_message, $error_code = HTTP_CLIENT_ERROR_UNSPECIFIED_ERROR)
  140. {
  141. if(IsSet($php_error_message)
  142. && strlen($php_error_message))
  143. $error.=": ".$php_error_message;
  144. return($this->SetError($error, $error_code));
  145. }
  146. Function SetDataAccessError($error,$check_connection=0)
  147. {
  148. $this->error=$error;
  149. $this->error_code = HTTP_CLIENT_ERROR_COMMUNICATION_FAILURE;
  150. if(!$this->use_curl
  151. && function_exists("socket_get_status"))
  152. {
  153. $status=socket_get_status($this->connection);
  154. if($status["timed_out"])
  155. $this->error.=": data access time out";
  156. elseif($status["eof"])
  157. {
  158. if($check_connection)
  159. $this->error="";
  160. else
  161. $this->error.=": the server disconnected";
  162. }
  163. }
  164. }
  165. Function OutputDebug($message)
  166. {
  167. if($this->log_debug)
  168. error_log($message);
  169. else
  170. {
  171. $message.="\n";
  172. if($this->html_debug)
  173. $message=str_replace("\n","<br />\n",HtmlEntities($message));
  174. echo $message;
  175. flush();
  176. }
  177. }
  178. Function GetLine()
  179. {
  180. for($line="";;)
  181. {
  182. if($this->use_curl)
  183. {
  184. $eol=strpos($this->response,"\n",$this->read_response);
  185. $data=($eol ? substr($this->response,$this->read_response,$eol+1-$this->read_response) : "");
  186. $this->read_response+=strlen($data);
  187. }
  188. else
  189. {
  190. if(feof($this->connection))
  191. {
  192. $this->SetDataAccessError("reached the end of data while reading from the HTTP server connection");
  193. return(0);
  194. }
  195. $data=fgets($this->connection,100);
  196. }
  197. if(GetType($data)!="string"
  198. || strlen($data)==0)
  199. {
  200. $this->SetDataAccessError("it was not possible to read line from the HTTP server");
  201. return(0);
  202. }
  203. $line.=$data;
  204. $length=strlen($line);
  205. if($length
  206. && !strcmp(substr($line,$length-1,1),"\n"))
  207. {
  208. $length-=(($length>=2 && !strcmp(substr($line,$length-2,1),"\r")) ? 2 : 1);
  209. $line=substr($line,0,$length);
  210. if($this->debug)
  211. $this->OutputDebug("S $line");
  212. return($line);
  213. }
  214. }
  215. }
  216. Function PutLine($line)
  217. {
  218. if($this->debug)
  219. $this->OutputDebug("C $line");
  220. if(!fputs($this->connection,$line."\r\n"))
  221. {
  222. $this->SetDataAccessError("it was not possible to send a line to the HTTP server");
  223. return(0);
  224. }
  225. return(1);
  226. }
  227. Function PutData($data)
  228. {
  229. if(strlen($data))
  230. {
  231. if($this->debug)
  232. $this->OutputDebug('C '.$data);
  233. if(!fputs($this->connection,$data))
  234. {
  235. $this->SetDataAccessError("it was not possible to send data to the HTTP server");
  236. return(0);
  237. }
  238. }
  239. return(1);
  240. }
  241. Function FlushData()
  242. {
  243. if(!fflush($this->connection))
  244. {
  245. $this->SetDataAccessError("it was not possible to send data to the HTTP server");
  246. return(0);
  247. }
  248. return(1);
  249. }
  250. Function ReadChunkSize()
  251. {
  252. if($this->remaining_chunk==0)
  253. {
  254. $debug=$this->debug;
  255. if(!$this->debug_response_body)
  256. $this->debug=0;
  257. $line=$this->GetLine();
  258. $this->debug=$debug;
  259. if(GetType($line)!="string")
  260. return($this->SetError("could not read chunk start: ".$this->error, $this->error_code));
  261. $this->remaining_chunk=hexdec($line);
  262. if($this->remaining_chunk == 0)
  263. {
  264. if(!$this->debug_response_body)
  265. $this->debug=0;
  266. $line=$this->GetLine();
  267. $this->debug=$debug;
  268. if(GetType($line)!="string")
  269. return($this->SetError("could not read chunk end: ".$this->error, $this->error_code));
  270. }
  271. }
  272. return("");
  273. }
  274. Function ReadBytes($length)
  275. {
  276. if($this->use_curl)
  277. {
  278. $bytes=substr($this->response,$this->read_response,min($length,strlen($this->response)-$this->read_response));
  279. $this->read_response+=strlen($bytes);
  280. if($this->debug
  281. && $this->debug_response_body
  282. && strlen($bytes))
  283. $this->OutputDebug("S ".$bytes);
  284. }
  285. else
  286. {
  287. if($this->chunked)
  288. {
  289. for($bytes="",$remaining=$length;$remaining;)
  290. {
  291. if(strlen($this->ReadChunkSize()))
  292. return("");
  293. if($this->remaining_chunk==0)
  294. {
  295. $this->last_chunk_read=1;
  296. break;
  297. }
  298. $ask=min($this->remaining_chunk,$remaining);
  299. $chunk=@fread($this->connection,$ask);
  300. $read=strlen($chunk);
  301. if($read==0)
  302. {
  303. $this->SetDataAccessError("it was not possible to read data chunk from the HTTP server");
  304. return("");
  305. }
  306. if($this->debug
  307. && $this->debug_response_body)
  308. $this->OutputDebug("S ".$chunk);
  309. $bytes.=$chunk;
  310. $this->remaining_chunk-=$read;
  311. $remaining-=$read;
  312. if($this->remaining_chunk==0)
  313. {
  314. if(feof($this->connection))
  315. 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));
  316. $data=@fread($this->connection,2);
  317. if(strcmp($data,"\r\n"))
  318. {
  319. $this->SetDataAccessError("it was not possible to read end of data chunk from the HTTP server");
  320. return("");
  321. }
  322. }
  323. }
  324. }
  325. else
  326. {
  327. $bytes=@fread($this->connection,$length);
  328. if(strlen($bytes))
  329. {
  330. if($this->debug
  331. && $this->debug_response_body)
  332. $this->OutputDebug("S ".$bytes);
  333. }
  334. else
  335. $this->SetDataAccessError("it was not possible to read data from the HTTP server", $this->connection_close);
  336. }
  337. }
  338. return($bytes);
  339. }
  340. Function EndOfInput()
  341. {
  342. if($this->use_curl)
  343. return($this->read_response>=strlen($this->response));
  344. if($this->chunked)
  345. return($this->last_chunk_read);
  346. if($this->content_length_set)
  347. return($this->content_length <= $this->read_length);
  348. return(feof($this->connection));
  349. }
  350. Function Resolve($domain, &$ip, $server_type)
  351. {
  352. if(preg_match('/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/',$domain))
  353. $ip=$domain;
  354. else
  355. {
  356. if($this->debug)
  357. $this->OutputDebug('Resolving '.$server_type.' server domain "'.$domain.'"...');
  358. if(!strcmp($ip=@gethostbyname($domain),$domain))
  359. $ip="";
  360. }
  361. if(strlen($ip)==0
  362. || (strlen($this->exclude_address)
  363. && !strcmp(@gethostbyname($this->exclude_address),$ip)))
  364. return($this->SetError("could not resolve the host domain \"".$domain."\"", HTTP_CLIENT_ERROR_INVALID_SERVER_ADDRESS));
  365. return('');
  366. }
  367. Function Connect($host_name, $host_port, $ssl, $server_type = 'HTTP')
  368. {
  369. $domain=$host_name;
  370. $port = $host_port;
  371. if(strlen($error = $this->Resolve($domain, $ip, $server_type)))
  372. return($error);
  373. if(strlen($this->socks_host_name))
  374. {
  375. switch($this->socks_version)
  376. {
  377. case '4':
  378. $version = 4;
  379. break;
  380. case '5':
  381. $version = 5;
  382. break;
  383. default:
  384. return('it was not specified a supported SOCKS protocol version');
  385. break;
  386. }
  387. $host_ip = $ip;
  388. $port = $this->socks_host_port;
  389. $host_server_type = $server_type;
  390. $server_type = 'SOCKS';
  391. if(strlen($error = $this->Resolve($this->socks_host_name, $ip, $server_type)))
  392. return($error);
  393. }
  394. if($this->debug)
  395. $this->OutputDebug('Connecting to '.$server_type.' server IP '.$ip.' port '.$port.'...');
  396. if($ssl)
  397. $ip="ssl://".$host_name;
  398. if(($this->connection=($this->timeout ? @fsockopen($ip, $port, $errno, $error, $this->timeout) : @fsockopen($ip, $port, $errno)))==0)
  399. {
  400. $error_code = HTTP_CLIENT_ERROR_CANNOT_CONNECT;
  401. switch($errno)
  402. {
  403. case -3:
  404. return($this->SetError("socket could not be created", $error_code));
  405. case -4:
  406. return($this->SetError("dns lookup on hostname \"".$host_name."\" failed", $error_code));
  407. case -5:
  408. return($this->SetError("connection refused or timed out", $error_code));
  409. case -6:
  410. return($this->SetError("fdopen() call failed", $error_code));
  411. case -7:
  412. return($this->SetError("setvbuf() call failed", $error_code));
  413. default:
  414. return($this->SetPHPError($errno." could not connect to the host \"".$host_name."\"",$php_errormsg, $error_code));
  415. }
  416. }
  417. else
  418. {
  419. if($this->data_timeout
  420. && function_exists("socket_set_timeout"))
  421. socket_set_timeout($this->connection,$this->data_timeout,0);
  422. if(strlen($this->socks_host_name))
  423. {
  424. if($this->debug)
  425. $this->OutputDebug('Connected to the SOCKS server '.$this->socks_host_name);
  426. $send_error = 'it was not possible to send data to the SOCKS server';
  427. $receive_error = 'it was not possible to receive data from the SOCKS server';
  428. switch($version)
  429. {
  430. case 4:
  431. $command = 1;
  432. $user = '';
  433. if(!fputs($this->connection, chr($version).chr($command).pack('nN', $host_port, ip2long($host_ip)).$user.Chr(0)))
  434. $error = $this->SetDataAccessError($send_error);
  435. else
  436. {
  437. $response = fgets($this->connection, 9);
  438. if(strlen($response) != 8)
  439. $error = $this->SetDataAccessError($receive_error);
  440. else
  441. {
  442. $socks_errors = array(
  443. "\x5a"=>'',
  444. "\x5b"=>'request rejected',
  445. "\x5c"=>'request failed because client is not running identd (or not reachable from the server)',
  446. "\x5d"=>'request failed because client\'s identd could not confirm the user ID string in the request',
  447. );
  448. $error_code = $response[1];
  449. $error = (IsSet($socks_errors[$error_code]) ? $socks_errors[$error_code] : 'unknown');
  450. if(strlen($error))
  451. $error = 'SOCKS error: '.$error;
  452. }
  453. }
  454. break;
  455. case 5:
  456. if($this->debug)
  457. $this->OutputDebug('Negotiating the authentication method ...');
  458. $methods = 1;
  459. $method = 0;
  460. if(!fputs($this->connection, chr($version).chr($methods).chr($method)))
  461. $error = $this->SetDataAccessError($send_error);
  462. else
  463. {
  464. $response = fgets($this->connection, 3);
  465. if(strlen($response) != 2)
  466. $error = $this->SetDataAccessError($receive_error);
  467. elseif(Ord($response[1]) != $method)
  468. $error = 'the SOCKS server requires an authentication method that is not yet supported';
  469. else
  470. {
  471. if($this->debug)
  472. $this->OutputDebug('Connecting to '.$host_server_type.' server IP '.$host_ip.' port '.$host_port.'...');
  473. $command = 1;
  474. $address_type = 1;
  475. if(!fputs($this->connection, chr($version).chr($command)."\x00".chr($address_type).pack('Nn', ip2long($host_ip), $host_port)))
  476. $error = $this->SetDataAccessError($send_error);
  477. else
  478. {
  479. $response = fgets($this->connection, 11);
  480. if(strlen($response) != 10)
  481. $error = $this->SetDataAccessError($receive_error);
  482. else
  483. {
  484. $socks_errors = array(
  485. "\x00"=>'',
  486. "\x01"=>'general SOCKS server failure',
  487. "\x02"=>'connection not allowed by ruleset',
  488. "\x03"=>'Network unreachable',
  489. "\x04"=>'Host unreachable',
  490. "\x05"=>'Connection refused',
  491. "\x06"=>'TTL expired',
  492. "\x07"=>'Command not supported',
  493. "\x08"=>'Address type not supported'
  494. );
  495. $error_code = $response[1];
  496. $error = (IsSet($socks_errors[$error_code]) ? $socks_errors[$error_code] : 'unknown');
  497. if(strlen($error))
  498. $error = 'SOCKS error: '.$error;
  499. }
  500. }
  501. }
  502. }
  503. break;
  504. default:
  505. $error = 'support for SOCKS protocol version '.$this->socks_version.' is not yet implemented';
  506. break;
  507. }
  508. if(strlen($error))
  509. {
  510. fclose($this->connection);
  511. return($error);
  512. }
  513. }
  514. if($this->debug)
  515. $this->OutputDebug("Connected to $host_name");
  516. if(strlen($this->proxy_host_name)
  517. && !strcmp(strtolower($this->protocol), 'https'))
  518. {
  519. if(function_exists('stream_socket_enable_crypto')
  520. && in_array('ssl', stream_get_transports()))
  521. $this->state = "ConnectedToProxy";
  522. else
  523. {
  524. $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.");
  525. $this->state="Connected";
  526. }
  527. }
  528. else
  529. $this->state="Connected";
  530. return("");
  531. }
  532. }
  533. Function Disconnect()
  534. {
  535. if($this->debug)
  536. $this->OutputDebug("Disconnected from ".$this->connected_host);
  537. if($this->use_curl)
  538. {
  539. curl_close($this->connection);
  540. $this->response="";
  541. }
  542. else
  543. fclose($this->connection);
  544. $this->state="Disconnected";
  545. return("");
  546. }
  547. /* Public methods */
  548. Function GetRequestArguments($url, &$arguments)
  549. {
  550. $this->error = '';
  551. $this->error_code = HTTP_CLIENT_ERROR_NO_ERROR;
  552. $arguments=array();
  553. $url = str_replace(' ', '%20', $url);
  554. $parameters=@parse_url($url);
  555. if(!$parameters)
  556. return($this->SetError("it was not specified a valid URL", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
  557. if(!IsSet($parameters["scheme"]))
  558. return($this->SetError("it was not specified the protocol type argument", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
  559. switch(strtolower($parameters["scheme"]))
  560. {
  561. case "http":
  562. case "https":
  563. $arguments["Protocol"]=$parameters["scheme"];
  564. break;
  565. default:
  566. return($parameters["scheme"]." connection scheme is not yet supported");
  567. }
  568. if(!IsSet($parameters["host"]))
  569. return($this->SetError("it was not specified the connection host argument", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
  570. $arguments["HostName"]=$parameters["host"];
  571. $arguments["Headers"]=array("Host"=>$parameters["host"].(IsSet($parameters["port"]) ? ":".$parameters["port"] : ""));
  572. if(IsSet($parameters["user"]))
  573. {
  574. $arguments["AuthUser"]=UrlDecode($parameters["user"]);
  575. if(!IsSet($parameters["pass"]))
  576. $arguments["AuthPassword"]="";
  577. }
  578. if(IsSet($parameters["pass"]))
  579. {
  580. if(!IsSet($parameters["user"]))
  581. $arguments["AuthUser"]="";
  582. $arguments["AuthPassword"]=UrlDecode($parameters["pass"]);
  583. }
  584. if(IsSet($parameters["port"]))
  585. {
  586. if(strcmp($parameters["port"],strval(intval($parameters["port"]))))
  587. return($this->SetError("it was not specified a valid connection host argument", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
  588. $arguments["HostPort"]=intval($parameters["port"]);
  589. }
  590. else
  591. $arguments["HostPort"]=0;
  592. $arguments["RequestURI"]=(IsSet($parameters["path"]) ? $parameters["path"] : "/").(IsSet($parameters["query"]) ? "?".$parameters["query"] : "");
  593. if(strlen($this->user_agent))
  594. $arguments["Headers"]["User-Agent"]=$this->user_agent;
  595. if(strlen($this->accept))
  596. $arguments["Headers"]["Accept"]=$this->accept;
  597. return("");
  598. }
  599. Function Open($arguments)
  600. {
  601. if(strlen($this->error))
  602. return($this->error);
  603. $error_code = HTTP_CLIENT_ERROR_UNSPECIFIED_ERROR;
  604. if(IsSet($arguments["HostName"]))
  605. $this->host_name=$arguments["HostName"];
  606. if(IsSet($arguments["HostPort"]))
  607. $this->host_port=$arguments["HostPort"];
  608. if(IsSet($arguments["ProxyHostName"]))
  609. $this->proxy_host_name=$arguments["ProxyHostName"];
  610. if(IsSet($arguments["ProxyHostPort"]))
  611. $this->proxy_host_port=$arguments["ProxyHostPort"];
  612. if(IsSet($arguments["SOCKSHostName"]))
  613. $this->socks_host_name=$arguments["SOCKSHostName"];
  614. if(IsSet($arguments["SOCKSHostPort"]))
  615. $this->socks_host_port=$arguments["SOCKSHostPort"];
  616. if(IsSet($arguments["SOCKSVersion"]))
  617. $this->socks_version=$arguments["SOCKSVersion"];
  618. if(IsSet($arguments["Protocol"]))
  619. $this->protocol=$arguments["Protocol"];
  620. switch(strtolower($this->protocol))
  621. {
  622. case "http":
  623. $default_port=80;
  624. break;
  625. case "https":
  626. $default_port=443;
  627. break;
  628. default:
  629. return($this->SetError("it was not specified a valid connection protocol", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
  630. }
  631. if(strlen($this->proxy_host_name)==0)
  632. {
  633. if(strlen($this->host_name)==0)
  634. return($this->SetError("it was not specified a valid hostname", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
  635. $host_name=$this->host_name;
  636. $host_port=($this->host_port ? $this->host_port : $default_port);
  637. $server_type = 'HTTP';
  638. }
  639. else
  640. {
  641. $host_name=$this->proxy_host_name;
  642. $host_port=$this->proxy_host_port;
  643. $server_type = 'HTTP proxy';
  644. }
  645. $ssl=(strtolower($this->protocol)=="https" && strlen($this->proxy_host_name)==0);
  646. if($ssl
  647. && strlen($this->socks_host_name))
  648. return($this->SetError('establishing SSL connections via a SOCKS server is not yet supported', HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
  649. $this->use_curl=($ssl && $this->prefer_curl && function_exists("curl_init"));
  650. switch($this->state)
  651. {
  652. case 'Connected':
  653. if(!strcmp($host_name, $this->connected_host)
  654. && intval($host_port) == $this->connected_port
  655. && intval($ssl) == $this->connected_ssl)
  656. {
  657. if($this->debug)
  658. $this->OutputDebug("Reusing connection to ".$this->connected_host);
  659. return('');
  660. }
  661. if(strlen($error = $this->Disconnect()))
  662. return($error);
  663. case "Disconnected":
  664. break;
  665. default:
  666. return("1 already connected");
  667. }
  668. if($this->debug)
  669. $this->OutputDebug("Connecting to ".$this->host_name);
  670. if($this->use_curl)
  671. {
  672. $error=(($this->connection=curl_init($this->protocol."://".$this->host_name.($host_port==$default_port ? "" : ":".strval($host_port))."/")) ? "" : "Could not initialize a CURL session");
  673. if(strlen($error)==0)
  674. {
  675. if(IsSet($arguments["SSLCertificateFile"]))
  676. curl_setopt($this->connection,CURLOPT_SSLCERT,$arguments["SSLCertificateFile"]);
  677. if(IsSet($arguments["SSLCertificatePassword"]))
  678. curl_setopt($this->connection,CURLOPT_SSLCERTPASSWD,$arguments["SSLCertificatePassword"]);
  679. if(IsSet($arguments["SSLKeyFile"]))
  680. curl_setopt($this->connection,CURLOPT_SSLKEY,$arguments["SSLKeyFile"]);
  681. if(IsSet($arguments["SSLKeyPassword"]))
  682. curl_setopt($this->connection,CURLOPT_SSLKEYPASSWD,$arguments["SSLKeyPassword"]);
  683. }
  684. $this->state="Connected";
  685. }
  686. else
  687. {
  688. $error="";
  689. if(strlen($this->proxy_host_name)
  690. && (IsSet($arguments["SSLCertificateFile"])
  691. || IsSet($arguments["SSLCertificateFile"])))
  692. $error="establishing SSL connections using certificates or private keys via non-SSL proxies is not supported";
  693. else
  694. {
  695. if($ssl)
  696. {
  697. if(IsSet($arguments["SSLCertificateFile"]))
  698. $error="establishing SSL connections using certificates is only supported when the cURL extension is enabled";
  699. elseif(IsSet($arguments["SSLKeyFile"]))
  700. $error="establishing SSL connections using a private key is only supported when the cURL extension is enabled";
  701. else
  702. {
  703. $version=explode(".",function_exists("phpversion") ? phpversion() : "3.0.7");
  704. $php_version=intval($version[0])*1000000+intval($version[1])*1000+intval($version[2]);
  705. if($php_version<4003000)
  706. $error="establishing SSL connections requires at least PHP version 4.3.0 or having the cURL extension enabled";
  707. elseif(!function_exists("extension_loaded")
  708. || !extension_loaded("openssl"))
  709. $error="establishing SSL connections requires the OpenSSL extension enabled";
  710. }
  711. }
  712. if(strlen($error)==0)
  713. {
  714. $error=$this->Connect($host_name, $host_port, $ssl, $server_type);
  715. $error_code = $this->error_code;
  716. }
  717. }
  718. }
  719. if(strlen($error))
  720. return($this->SetError($error, $error_code));
  721. $this->session=md5(uniqid(""));
  722. $this->connected_host = $host_name;
  723. $this->connected_port = intval($host_port);
  724. $this->connected_ssl = intval($ssl);
  725. return("");
  726. }
  727. Function Close($force = 0)
  728. {
  729. if($this->state=="Disconnected")
  730. return("1 already disconnected");
  731. if(!$this->force_close
  732. && $this->keep_alive
  733. && !$force
  734. && $this->state == 'ResponseReceived')
  735. {
  736. if($this->debug)
  737. $this->OutputDebug('Keeping the connection alive to '.$this->connected_host);
  738. $this->state = 'Connected';
  739. return('');
  740. }
  741. return($this->Disconnect());
  742. }
  743. Function PickCookies(&$cookies,$secure)
  744. {
  745. if(IsSet($this->cookies[$secure]))
  746. {
  747. $now=gmdate("Y-m-d H-i-s");
  748. for($domain=0,Reset($this->cookies[$secure]);$domain<count($this->cookies[$secure]);Next($this->cookies[$secure]),$domain++)
  749. {
  750. $domain_pattern=Key($this->cookies[$secure]);
  751. $match=strlen($this->request_host)-strlen($domain_pattern);
  752. if($match>=0
  753. && !strcmp($domain_pattern,substr($this->request_host,$match))
  754. && ($match==0
  755. || $domain_pattern[0]=="."
  756. || $this->request_host[$match-1]=="."))
  757. {
  758. 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++)
  759. {
  760. $path=Key($this->cookies[$secure][$domain_pattern]);
  761. if(strlen($this->request_uri)>=strlen($path)
  762. && substr($this->request_uri,0,strlen($path))==$path)
  763. {
  764. 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++)
  765. {
  766. $cookie_name=Key($this->cookies[$secure][$domain_pattern][$path]);
  767. $expires=$this->cookies[$secure][$domain_pattern][$path][$cookie_name]["expires"];
  768. if($expires==""
  769. || strcmp($now,$expires)<0)
  770. $cookies[$cookie_name]=$this->cookies[$secure][$domain_pattern][$path][$cookie_name];
  771. }
  772. }
  773. }
  774. }
  775. }
  776. }
  777. }
  778. Function GetFileDefinition($file, &$definition)
  779. {
  780. $name="";
  781. if(IsSet($file["FileName"]))
  782. $name=basename($file["FileName"]);
  783. if(IsSet($file["Name"]))
  784. $name=$file["Name"];
  785. if(strlen($name)==0)
  786. return("it was not specified the file part name");
  787. if(IsSet($file["Content-Type"]))
  788. {
  789. $content_type=$file["Content-Type"];
  790. $type=$this->Tokenize(strtolower($content_type),"/");
  791. $sub_type=$this->Tokenize("");
  792. switch($type)
  793. {
  794. case "text":
  795. case "image":
  796. case "audio":
  797. case "video":
  798. case "application":
  799. case "message":
  800. break;
  801. case "automatic":
  802. switch($sub_type)
  803. {
  804. case "name":
  805. switch(GetType($dot=strrpos($name,"."))=="integer" ? strtolower(substr($name,$dot)) : "")
  806. {
  807. case ".xls":
  808. $content_type="application/excel";
  809. break;
  810. case ".hqx":
  811. $content_type="application/macbinhex40";
  812. break;
  813. case ".doc":
  814. case ".dot":
  815. case ".wrd":
  816. $content_type="application/msword";
  817. break;
  818. case ".pdf":
  819. $content_type="application/pdf";
  820. break;
  821. case ".pgp":
  822. $content_type="application/pgp";
  823. break;
  824. case ".ps":
  825. case ".eps":
  826. case ".ai":
  827. $content_type="application/postscript";
  828. break;
  829. case ".ppt":
  830. $content_type="application/powerpoint";
  831. break;
  832. case ".rtf":
  833. $content_type="application/rtf";
  834. break;
  835. case ".tgz":
  836. case ".gtar":
  837. $content_type="application/x-gtar";
  838. break;
  839. case ".gz":
  840. $content_type="application/x-gzip";
  841. break;
  842. case ".php":
  843. case ".php3":
  844. $content_type="application/x-httpd-php";
  845. break;
  846. case ".js":
  847. $content_type="application/x-javascript";
  848. break;
  849. case ".ppd":
  850. case ".psd":
  851. $content_type="application/x-photoshop";
  852. break;
  853. case ".swf":
  854. case ".swc":
  855. case ".rf":
  856. $content_type="application/x-shockwave-flash";
  857. break;
  858. case ".tar":
  859. $content_type="application/x-tar";
  860. break;
  861. case ".zip":
  862. $content_type="application/zip";
  863. break;
  864. case ".mid":
  865. case ".midi":
  866. case ".kar":
  867. $content_type="audio/midi";
  868. break;
  869. case ".mp2":
  870. case ".mp3":
  871. case ".mpga":
  872. $content_type="audio/mpeg";
  873. break;
  874. case ".ra":
  875. $content_type="audio/x-realaudio";
  876. break;
  877. case ".wav":
  878. $content_type="audio/wav";
  879. break;
  880. case ".bmp":
  881. $content_type="image/bitmap";
  882. break;
  883. case ".gif":
  884. $content_type="image/gif";
  885. break;
  886. case ".iff":
  887. $content_type="image/iff";
  888. break;
  889. case ".jb2":
  890. $content_type="image/jb2";
  891. break;
  892. case ".jpg":
  893. case ".jpe":
  894. case ".jpeg":
  895. $content_type="image/jpeg";
  896. break;
  897. case ".jpx":
  898. $content_type="image/jpx";
  899. break;
  900. case ".png":
  901. $content_type="image/png";
  902. break;
  903. case ".tif":
  904. case ".tiff":
  905. $content_type="image/tiff";
  906. break;
  907. case ".wbmp":
  908. $content_type="image/vnd.wap.wbmp";
  909. break;
  910. case ".xbm":
  911. $content_type="image/xbm";
  912. break;
  913. case ".css":
  914. $content_type="text/css";
  915. break;
  916. case ".txt":
  917. $content_type="text/plain";
  918. break;
  919. case ".htm":
  920. case ".html":
  921. $content_type="text/html";
  922. break;
  923. case ".xml":
  924. $content_type="text/xml";
  925. break;
  926. case ".mpg":
  927. case ".mpe":
  928. case ".mpeg":
  929. $content_type="video/mpeg";
  930. break;
  931. case ".qt":
  932. case ".mov":
  933. $content_type="video/quicktime";
  934. break;
  935. case ".avi":
  936. $content_type="video/x-ms-video";
  937. break;
  938. case ".eml":
  939. $content_type="message/rfc822";
  940. break;
  941. default:
  942. $content_type="application/octet-stream";
  943. break;
  944. }
  945. break;
  946. default:
  947. return($content_type." is not a supported automatic content type detection method");
  948. }
  949. break;
  950. default:
  951. return($content_type." is not a supported file content type");
  952. }
  953. }
  954. else
  955. $content_type="application/octet-stream";
  956. $definition=array(
  957. "Content-Type"=>$content_type,
  958. "NAME"=>$name
  959. );
  960. if(IsSet($file["FileName"]))
  961. {
  962. if(GetType($length=@filesize($file["FileName"]))!="integer")
  963. {
  964. $error="it was not possible to determine the length of the file ".$file["FileName"];
  965. if(IsSet($php_errormsg)
  966. && strlen($php_errormsg))
  967. $error.=": ".$php_errormsg;
  968. if(!file_exists($file["FileName"]))
  969. $error="it was not possible to access the file ".$file["FileName"];
  970. return($error);
  971. }
  972. $definition["FILENAME"]=$file["FileName"];
  973. $definition["Content-Length"]=$length;
  974. }
  975. elseif(IsSet($file["Data"]))
  976. $definition["Content-Length"]=strlen($definition["DATA"]=$file["Data"]);
  977. else
  978. return("it was not specified a valid file name");
  979. return("");
  980. }
  981. Function ConnectFromProxy($arguments, &$headers)
  982. {
  983. if(!$this->PutLine('CONNECT '.$this->host_name.':'.($this->host_port ? $this->host_port : 443).' HTTP/1.0')
  984. || (strlen($this->user_agent)
  985. && !$this->PutLine('User-Agent: '.$this->user_agent))
  986. || (strlen($this->accept)
  987. && !$this->PutLine('Accept: '.$this->accept))
  988. || (IsSet($arguments['Headers']['Proxy-Authorization'])
  989. && !$this->PutLine('Proxy-Authorization: '.$arguments['Headers']['Proxy-Authorization']))
  990. || !$this->PutLine(''))
  991. {
  992. $this->Disconnect();
  993. return($this->error);
  994. }
  995. $this->state = "ConnectSent";
  996. if(strlen($error=$this->ReadReplyHeadersResponse($headers)))
  997. return($error);
  998. $proxy_authorization="";
  999. while(!strcmp($this->response_status, "100"))
  1000. {
  1001. $this->state="ConnectSent";
  1002. if(strlen($error=$this->ReadReplyHeadersResponse($headers)))
  1003. return($error);
  1004. }
  1005. switch($this->response_status)
  1006. {
  1007. case "200":
  1008. if(!@stream_socket_enable_crypto($this->connection, 1, STREAM_CRYPTO_METHOD_SSLv23_CLIENT))
  1009. {
  1010. $this->SetPHPError('it was not possible to start a SSL encrypted connection via this proxy', $php_errormsg, HTTP_CLIENT_ERROR_COMMUNICATION_FAILURE);
  1011. $this->Disconnect();
  1012. return($this->error);
  1013. }
  1014. $this->state = "Connected";
  1015. break;
  1016. case "407":
  1017. 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)))
  1018. return($error);
  1019. break;
  1020. default:
  1021. return($this->SetError("unable to send request via proxy", HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
  1022. }
  1023. return("");
  1024. }
  1025. Function SendRequest($arguments)
  1026. {
  1027. if(strlen($this->error))
  1028. return($this->error);
  1029. if(IsSet($arguments["ProxyUser"]))
  1030. $this->proxy_request_user=$arguments["ProxyUser"];
  1031. elseif(IsSet($this->proxy_user))
  1032. $this->proxy_request_user=$this->proxy_user;
  1033. if(IsSet($arguments["ProxyPassword"]))
  1034. $this->proxy_request_password=$arguments["ProxyPassword"];
  1035. elseif(IsSet($this->proxy_password))
  1036. $this->proxy_request_password=$this->proxy_password;
  1037. if(IsSet($arguments["ProxyRealm"]))
  1038. $this->proxy_request_realm=$arguments["ProxyRealm"];
  1039. elseif(IsSet($this->proxy_realm))
  1040. $this->proxy_request_realm=$this->proxy_realm;
  1041. if(IsSet($arguments["ProxyWorkstation"]))
  1042. $this->proxy_request_workstation=$arguments["ProxyWorkstation"];
  1043. elseif(IsSet($this->proxy_workstation))
  1044. $this->proxy_request_workstation=$this->proxy_workstation;
  1045. switch($this->state)
  1046. {
  1047. case "Disconnected":
  1048. return($this->SetError("connection was not yet established", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
  1049. case "Connected":
  1050. $connect = 0;
  1051. break;
  1052. case "ConnectedToProxy":
  1053. if(strlen($error = $this->ConnectFromProxy($arguments, $headers)))
  1054. return($error);
  1055. $connect = 1;
  1056. break;
  1057. default:
  1058. return($this->SetError("can not send request in the current connection state", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
  1059. }
  1060. if(IsSet($arguments["RequestMethod"]))
  1061. $this->request_method=$arguments["RequestMethod"];
  1062. if(IsSet($arguments["User-Agent"]))
  1063. $this->user_agent=$arguments["User-Agent"];
  1064. if(!IsSet($arguments["Headers"]["User-Agent"])
  1065. && strlen($this->user_agent))
  1066. $arguments["Headers"]["User-Agent"]=$this->user_agent;
  1067. if(IsSet($arguments["KeepAlive"]))
  1068. $this->keep_alive=intval($arguments["KeepAlive"]);
  1069. if(!IsSet($arguments["Headers"]["Connection"])
  1070. && $this->keep_alive)
  1071. $arguments["Headers"]["Connection"]='Keep-Alive';
  1072. if(IsSet($arguments["Accept"]))
  1073. $this->user_agent=$arguments["Accept"];
  1074. if(!IsSet($arguments["Headers"]["Accept"])
  1075. && strlen($this->accept))
  1076. $arguments["Headers"]["Accept"]=$this->accept;
  1077. if(strlen($this->request_method)==0)
  1078. return($this->SetError("it was not specified a valid request method", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
  1079. if(IsSet($arguments["RequestURI"]))
  1080. $this->request_uri=$arguments["RequestURI"];
  1081. if(strlen($this->request_uri)==0
  1082. || substr($this->request_uri,0,1)!="/")
  1083. return($this->SetError("it was not specified a valid request URI", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
  1084. $this->request_arguments=$arguments;
  1085. $this->request_headers=(IsSet($arguments["Headers"]) ? $arguments["Headers"] : array());
  1086. $body_length=0;
  1087. $this->request_body="";
  1088. $get_body=1;
  1089. if($this->request_method=="POST"
  1090. || $this->request_method=="PUT")
  1091. {
  1092. if(IsSet($arguments['StreamRequest']))
  1093. {
  1094. $get_body = 0;
  1095. $this->request_headers["Transfer-Encoding"]="chunked";
  1096. }
  1097. elseif(IsSet($arguments["PostFiles"])
  1098. || ($this->force_multipart_form_post
  1099. && IsSet($arguments["PostValues"])))
  1100. {
  1101. $boundary="--".md5(uniqid(time()));
  1102. $this->request_headers["Content-Type"]="multipart/form-data; boundary=".$boundary.(IsSet($arguments["CharSet"]) ? "; charset=".$arguments["CharSet"] : "");
  1103. $post_parts=array();
  1104. if(IsSet($arguments["PostValues"]))
  1105. {
  1106. $values=$arguments["PostValues"];
  1107. if(GetType($values)!="array")
  1108. return($this->SetError("it was not specified a valid POST method values array", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
  1109. for(Reset($values),$value=0;$value<count($values);Next($values),$value++)
  1110. {
  1111. $input=Key($values);
  1112. $headers="--".$boundary."\r\nContent-Disposition: form-data; name=\"".$input."\"\r\n\r\n";
  1113. $data=$values[$input];
  1114. $post_parts[]=array("HEADERS"=>$headers,"DATA"=>$data);
  1115. $body_length+=strlen($headers)+strlen($data)+strlen("\r\n");
  1116. }
  1117. }
  1118. $body_length+=strlen("--".$boundary."--\r\n");
  1119. $files=(IsSet($arguments["PostFiles"]) ? $arguments["PostFiles"] : array());
  1120. Reset($files);
  1121. $end=(GetType($input=Key($files))!="string");
  1122. for(;!$end;)
  1123. {
  1124. if(strlen($error=$this->GetFileDefinition($files[$input],$definition)))
  1125. return("3 ".$error);
  1126. $headers="--".$boundary."\r\nContent-Disposition: form-data; name=\"".$input."\"; filename=\"".$definition["NAME"]."\"\r\nContent-Type: ".$definition["Content-Type"]."\r\n\r\n";
  1127. $part=count($post_parts);
  1128. $post_parts[$part]=array("HEADERS"=>$headers);
  1129. if(IsSet($definition["FILENAME"]))
  1130. {
  1131. $post_parts[$part]["FILENAME"]=$definition["FILENAME"];
  1132. $data="";
  1133. }
  1134. else
  1135. $data=$definition["DATA"];
  1136. $post_parts[$part]["DATA"]=$data;
  1137. $body_length+=strlen($headers)+$definition["Content-Length"]+strlen("\r\n");
  1138. Next($files);
  1139. $end=(GetType($input=Key($files))!="string");
  1140. }
  1141. $get_body=0;
  1142. }
  1143. elseif(IsSet($arguments["PostValues"]))
  1144. {
  1145. $values=$arguments["PostValues"];
  1146. if(GetType($values)!="array")
  1147. return($this->SetError("it was not specified a valid POST method values array", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
  1148. for(Reset($values),$value=0;$value<count($values);Next($values),$value++)
  1149. {
  1150. $k=Key($values);
  1151. if(GetType($values[$k])=="array")
  1152. {
  1153. for($v = 0; $v < count($values[$k]); $v++)
  1154. {
  1155. if($value+$v>0)
  1156. $this->request_body.="&";
  1157. $this->request_body.=UrlEncode($k)."=".UrlEncode($values[$k][$v]);
  1158. }
  1159. }
  1160. else
  1161. {
  1162. if($value>0)
  1163. $this->request_body.="&";
  1164. $this->request_body.=UrlEncode($k)."=".UrlEncode($values[$k]);
  1165. }
  1166. }
  1167. $this->request_headers["Content-Type"]="application/x-www-form-urlencoded".(IsSet($arguments["CharSet"]) ? "; charset=".$arguments["CharSet"] : "");
  1168. $get_body=0;
  1169. }
  1170. }
  1171. if($get_body
  1172. && (IsSet($arguments["Body"])
  1173. || IsSet($arguments["BodyStream"])))
  1174. {
  1175. if(IsSet($arguments["Body"]))
  1176. $this->request_body=$arguments["Body"];
  1177. else
  1178. {
  1179. $stream=$arguments["BodyStream"];
  1180. $this->request_body="";
  1181. for($part=0; $part<count($stream); $part++)
  1182. {
  1183. if(IsSet($stream[$part]["Data"]))
  1184. $this->request_body.=$stream[$part]["Data"];
  1185. elseif(IsSet($stream[$part]["File"]))
  1186. {
  1187. if(!($file=@fopen($stream[$part]["File"],"rb")))
  1188. return($this->SetPHPError("could not open upload file ".$stream[$part]["File"], $php_errormsg, HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE));
  1189. while(!feof($file))
  1190. {
  1191. if(GetType($block=@fread($file,$this->file_buffer_length))!="string")
  1192. {
  1193. $error=$this->SetPHPError("could not read body stream file ".$stream[$part]["File"], $php_errormsg, HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
  1194. fclose($file);
  1195. return($error);
  1196. }
  1197. $this->request_body.=$block;
  1198. }
  1199. fclose($file);
  1200. }
  1201. else
  1202. return("5 it was not specified a valid file or data body stream element at position ".$part);
  1203. }
  1204. }
  1205. if(!IsSet($this->request_headers["Content-Type"]))
  1206. $this->request_headers["Content-Type"]="application/octet-stream".(IsSet($arguments["CharSet"]) ? "; charset=".$arguments["CharSet"] : "");
  1207. }
  1208. if(IsSet($arguments["AuthUser"]))
  1209. $this->request_user=$arguments["AuthUser"];
  1210. elseif(IsSet($this->user))
  1211. $this->request_user=$this->user;
  1212. if(IsSet($arguments["AuthPassword"]))
  1213. $this->request_password=$arguments["AuthPassword"];
  1214. elseif(IsSet($this->password))
  1215. $this->request_password=$this->password;
  1216. if(IsSet($arguments["AuthRealm"]))
  1217. $this->request_realm=$arguments["AuthRealm"];
  1218. elseif(IsSet($this->realm))
  1219. $this->request_realm=$this->realm;
  1220. if(IsSet($arguments["AuthWorkstation"]))
  1221. $this->request_workstation=$arguments["AuthWorkstation"];
  1222. elseif(IsSet($this->workstation))
  1223. $this->request_workstation=$this->workstation;
  1224. if(strlen($this->proxy_host_name)==0
  1225. || $connect)
  1226. $request_uri=$this->request_uri;
  1227. else
  1228. {
  1229. switch(strtolower($this->protocol))
  1230. {
  1231. case "http":
  1232. $default_port=80;
  1233. break;
  1234. case "https":
  1235. $default_port=443;
  1236. break;
  1237. }
  1238. $request_uri=strtolower($this->protocol)."://".$this->host_name.(($this->host_port==0 || $this->host_port==$default_port) ? "" : ":".$this->host_port).$this->request_uri;
  1239. }
  1240. if($this->use_curl)
  1241. {
  1242. $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"));
  1243. $curl_version=100000*intval($this->Tokenize($version,"."))+1000*intval($this->Tokenize("."))+intval($this->Tokenize(""));
  1244. $protocol_version=($curl_version<713002 ? "1.0" : $this->protocol_version);
  1245. }
  1246. else
  1247. $protocol_version=$this->protocol_version;
  1248. $this->request=$this->request_method." ".$request_uri." HTTP/".$protocol_version;
  1249. if($body_length
  1250. || ($body_length=strlen($this->request_body))
  1251. || !strcmp($this->request_method, 'POST'))
  1252. $this->request_headers["Content-Length"]=$body_length;
  1253. for($headers=array(),$host_set=0,Reset($this->request_headers),$header=0;$header<count($this->request_headers);Next($this->request_headers),$header++)
  1254. {
  1255. $header_name=Key($this->request_headers);
  1256. $header_value=$this->request_headers[$header_name];
  1257. if(GetType($header_value)=="array")
  1258. {
  1259. for(Reset($header_value),$value=0;$value<count($header_value);Next($header_value),$value++)
  1260. $headers[]=$header_name.": ".$header_value[Key($header_value)];
  1261. }
  1262. else
  1263. $headers[]=$header_name.": ".$header_value;
  1264. if(strtolower(Key($this->request_headers))=="host")
  1265. {
  1266. $this->request_host=strtolower($header_value);
  1267. $host_set=1;
  1268. }
  1269. }
  1270. if(!$host_set)
  1271. {
  1272. $headers[]="Host: ".$this->host_name;
  1273. $this->request_host=strtolower($this->host_name);
  1274. }
  1275. if(count($this->cookies))
  1276. {
  1277. $cookies=array();
  1278. $this->PickCookies($cookies,0);
  1279. if(strtolower($this->protocol)=="https")
  1280. $this->PickCookies($cookies,1);
  1281. if(count($cookies))
  1282. {
  1283. $h=count($headers);
  1284. $headers[$h]="Cookie:";
  1285. for(Reset($cookies),$cookie=0;$cookie<count($cookies);Next($cookies),$cookie++)
  1286. {
  1287. $cookie_name=Key($cookies);
  1288. $headers[$h].=" ".$cookie_name."=".$cookies[$cookie_name]["value"].";";
  1289. }
  1290. }
  1291. }
  1292. $next_state = "RequestSent";
  1293. if($this->use_curl)
  1294. {
  1295. if(IsSet($arguments['StreamRequest']))
  1296. return($this->SetError("Streaming request data is not supported when using Curl", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
  1297. if($body_length
  1298. && strlen($this->request_body)==0)
  1299. {
  1300. for($request_body="",$success=1,$part=0;$part<count($post_parts);$part++)
  1301. {
  1302. $request_body.=$post_parts[$part]["HEADERS"].$post_parts[$part]["DATA"];
  1303. if(IsSet($post_parts[$part]["FILENAME"]))
  1304. {
  1305. if(!($file=@fopen($post_parts[$part]["FILENAME"],"rb")))
  1306. {
  1307. $this->SetPHPError("could not open upload file ".$post_parts[$part]["FILENAME"], $php_errormsg, HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
  1308. $success=0;
  1309. break;
  1310. }
  1311. while(!feof($file))
  1312. {
  1313. if(GetType($block=@fread($file,$this->file_buffer_length))!="string")
  1314. {
  1315. $this->SetPHPError("could not read upload file", $php_errormsg, HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
  1316. $success=0;
  1317. break;
  1318. }
  1319. $request_body.=$block;
  1320. }
  1321. fclose($file);
  1322. if(!$success)
  1323. break;
  1324. }
  1325. $request_body.="\r\n";
  1326. }
  1327. $request_body.="--".$boundary."--\r\n";
  1328. }
  1329. else
  1330. $request_body=$this->request_body;
  1331. curl_setopt($this->connection,CURLOPT_HEADER,1);
  1332. curl_setopt($this->connection,CURLOPT_RETURNTRANSFER,1);
  1333. if($this->timeout)
  1334. curl_setopt($this->connection,CURLOPT_TIMEOUT,$this->timeout);
  1335. curl_setopt($this->connection,CURLOPT_SSL_VERIFYPEER,0);
  1336. curl_setopt($this->connection,CURLOPT_SSL_VERIFYHOST,0);
  1337. $request=$this->request."\r\n".implode("\r\n",$headers)."\r\n\r\n".$request_body;
  1338. curl_setopt($this->connection,CURLOPT_CUSTOMREQUEST,$request);
  1339. if($this->debug)
  1340. $this->OutputDebug("C ".$request);
  1341. if(!($success=(strlen($this->response=curl_exec($this->connection))!=0)))
  1342. {
  1343. $error=curl_error($this->connection);
  1344. $this->SetError("Could not execute the request".(strlen($error) ? ": ".$error : ""), HTTP_CLIENT_ERROR_PROTOCOL_FAILURE);
  1345. }
  1346. }
  1347. else
  1348. {
  1349. if(($success=$this->PutLine($this->request)))
  1350. {
  1351. for($header=0;$header<count($headers);$header++)
  1352. {
  1353. if(!$success=$this->PutLine($headers[$header]))
  1354. break;
  1355. }
  1356. if($success
  1357. && ($success=$this->PutLine("")))
  1358. {
  1359. if(IsSet($arguments['StreamRequest']))
  1360. $next_state = "SendingRequestBody";
  1361. elseif($body_length)
  1362. {
  1363. if(strlen($this->request_body))
  1364. $success=$this->PutData($this->request_body);
  1365. else
  1366. {
  1367. for($part=0;$part<count($post_parts);$part++)
  1368. {
  1369. if(!($success=$this->PutData($post_parts[$part]["HEADERS"]))
  1370. || !($success=$this->PutData($post_parts[$part]["DATA"])))
  1371. break;
  1372. if(IsSet($post_parts[$part]["FILENAME"]))
  1373. {
  1374. if(!($file=@fopen($post_parts[$part]["FILENAME"],"rb")))
  1375. {
  1376. $this->SetPHPError("could not open upload file ".$post_parts[$part]["FILENAME"], $php_errormsg, HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
  1377. $success=0;
  1378. break;
  1379. }
  1380. while(!feof($file))
  1381. {
  1382. if(GetType($block=@fread($file,$this->file_buffer_length))!="string")
  1383. {
  1384. $this->SetPHPError("could not read upload file", $php_errormsg, HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
  1385. $success=0;
  1386. break;
  1387. }
  1388. if(!($success=$this->PutData($block)))
  1389. break;
  1390. }
  1391. fclose($file);
  1392. if(!$success)
  1393. break;
  1394. }
  1395. if(!($success=$this->PutLine("")))
  1396. break;
  1397. }
  1398. if($success)
  1399. $success=$this->PutLine("--".$boundary."--");
  1400. }
  1401. if($success)
  1402. $sucess=$this->FlushData();
  1403. }
  1404. }
  1405. }
  1406. }
  1407. if(!$success)
  1408. return($this->SetError("could not send the HTTP request: ".$this->error, $this->error_code));
  1409. $this->state=$next_state;
  1410. return("");
  1411. }
  1412. Function SetCookie($name, $value, $expires="" , $path="/" , $domain="" , $secure=0, $verbatim=0)
  1413. {
  1414. if(strlen($this->error))
  1415. return($this->error);
  1416. if(strlen($name)==0)
  1417. return($this->SetError("it was not specified a valid cookie name", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
  1418. if(strlen($path)==0
  1419. || strcmp($path[0],"/"))
  1420. return($this->SetError($path." is not a valid path for setting cookie ".$name, HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
  1421. if($domain==""
  1422. || !strpos($domain,".",$domain[0]=="." ? 1 : 0))
  1423. return($this->SetError($domain." is not a valid domain for setting cookie ".$name, HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
  1424. $domain=strtolower($domain);
  1425. if(!strcmp($domain[0],"."))
  1426. $domain=substr($domain,1);
  1427. if(!$verbatim)
  1428. {
  1429. $name=$this->CookieEncode($name,1);
  1430. $value=$this->CookieEncode($value,0);
  1431. }
  1432. $secure=intval($secure);
  1433. $this->cookies[$secure][$domain][$path][$name]=array(
  1434. "name"=>$name,
  1435. "value"=>$value,
  1436. "domain"=>$domain,
  1437. "path"=>$path,
  1438. "expires"=>$expires,
  1439. "secure"=>$secure
  1440. );
  1441. return("");
  1442. }
  1443. Function SendRequestBody($data, $end_of_data)
  1444. {
  1445. if(strlen($this->error))
  1446. return($this->error);
  1447. switch($this->state)
  1448. {
  1449. case "Disconnected":
  1450. return($this->SetError("connection was not yet established", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
  1451. case "Connected":
  1452. case "ConnectedToProxy":
  1453. return($this->SetError("request was not sent", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
  1454. case "SendingRequestBody":
  1455. break;
  1456. case "RequestSent":
  1457. return($this->SetError("request body was already sent", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
  1458. default:
  1459. return($this->SetError("can not send the request body in the current connection state", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
  1460. }
  1461. $length = strlen($data);
  1462. if($length)
  1463. {
  1464. $size = dechex($length)."\r\n";
  1465. if(!$this->PutData($size)
  1466. || !$this->PutData($data))
  1467. return($this->error);
  1468. }
  1469. if($end_of_data)
  1470. {
  1471. $size = "0\r\n";
  1472. if(!$this->PutData($size))
  1473. return($this->error);
  1474. $this->state = "RequestSent";
  1475. }
  1476. return("");
  1477. }
  1478. Function ReadReplyHeadersResponse(&$headers)
  1479. {
  1480. $headers=array();
  1481. if(strlen($this->error))
  1482. return($this->error);
  1483. switch($this->state)
  1484. {
  1485. case "Disconnected":
  1486. return($this->SetError("connection was not yet established", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
  1487. case "Connected":
  1488. return($this->SetError("request was not sent", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
  1489. case "ConnectedToProxy":
  1490. return($this->SetError("connection from the remote server from the proxy was not yet established", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
  1491. case "SendingRequestBody":
  1492. return($this->SetError("request body data was not completely sent", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
  1493. case "ConnectSent":
  1494. $connect = 1;
  1495. break;
  1496. case "RequestSent":
  1497. $connect = 0;
  1498. break;
  1499. default:
  1500. return($this->SetError("can not get request headers in the current connection state", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
  1501. }
  1502. $this->content_length=$this->read_length=$this->read_response=$this->remaining_chunk=0;
  1503. $this->content_length_set=$this->chunked=$this->last_chunk_read=$chunked=0;
  1504. $this->force_close = $this->connection_close=0;
  1505. for($this->response_status="";;)
  1506. {
  1507. $line=$this->GetLine();
  1508. if(GetType($line)!="string")
  1509. return($this->SetError("could not read request reply: ".$this->error, $this->error_code));
  1510. if(strlen($this->response_status)==0)
  1511. {
  1512. if(!preg_match($match="/^http\\/[0-9]+\\.[0-9]+[ \t]+([0-9]+)[ \t]*(.*)\$/i",$line,$matches))
  1513. return($this->SetError("it was received an unexpected HTTP response status", HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
  1514. $this->response_status=$matches[1];
  1515. $this->response_message=$matches[2];
  1516. }
  1517. if($line=="")
  1518. {
  1519. if(strlen($this->response_status)==0)
  1520. return($this->SetError("it was not received HTTP response status", HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
  1521. $this->state=($connect ? "GotConnectHeaders" : "GotReplyHeaders");
  1522. break;
  1523. }
  1524. $header_name=strtolower($this->Tokenize($line,":"));
  1525. $header_value=Trim(Chop($this->Tokenize("\r\n")));
  1526. if(IsSet($headers[$header_name]))
  1527. {
  1528. if(GetType($headers[$header_name])=="string")
  1529. $headers[$header_name]=array($headers[$header_name]);
  1530. $headers[$header_name][]=$header_value;
  1531. }
  1532. else
  1533. $headers[$header_name]=$header_value;
  1534. if(!$connect)
  1535. {
  1536. switch($header_name)
  1537. {
  1538. case "content-length":
  1539. $this->content_length=intval($headers[$header_name]);
  1540. $this->content_length_set=1;
  1541. break;
  1542. case "transfer-encoding":
  1543. $encoding=$this->Tokenize($header_value,"; \t");
  1544. if(!$this->use_curl
  1545. && !strcmp($encoding,"chunked"))
  1546. $chunked=1;
  1547. break;
  1548. case "set-cookie":
  1549. if($this->support_cookies)
  1550. {
  1551. if(GetType($headers[$header_name])=="array")
  1552. $cookie_headers=$headers[$header_name];
  1553. else
  1554. $cookie_headers=array($headers[$header_name]);
  1555. for($cookie=0;$cookie<count($cookie_headers);$cookie++)
  1556. {
  1557. $cookie_name=trim($this->Tokenize($cookie_headers[$cookie],"="));
  1558. $cookie_value=$this->Tokenize(";");
  1559. $domain=$this->request_host;
  1560. $path="/";
  1561. $expires="";
  1562. $secure=0;
  1563. while(($name = strtolower(trim(UrlDecode($this->Tokenize("=")))))!="")
  1564. {
  1565. $value=UrlDecode($this->Tokenize(";"));
  1566. switch($name)
  1567. {
  1568. case "domain":
  1569. $domain=$value;
  1570. break;
  1571. case "path":
  1572. $path=$value;
  1573. break;
  1574. case "expires":
  1575. 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))
  1576. {
  1577. $year=intval($matches[5]);
  1578. if($year<1900)
  1579. $year+=($year<70 ? 2000 : 1900);
  1580. $expires="$year-".$this->months[$matches[4]]."-".$matches[3]." ".$matches[6].":".$matches[7].":".$matches[8];
  1581. }
  1582. break;
  1583. case "secure":
  1584. $secure=1;
  1585. break;
  1586. }
  1587. }
  1588. if(strlen($this->SetCookie($cookie_name, $cookie_value, $expires, $path , $domain, $secure, 1)))
  1589. $this->error="";
  1590. }
  1591. }
  1592. break;
  1593. case "connection":
  1594. $this->force_close = $this->connection_close=!strcmp(strtolower($header_value),"close");
  1595. break;
  1596. }
  1597. }
  1598. }
  1599. $this->chunked=$chunked;
  1600. if($this->content_length_set)
  1601. $this->connection_close=0;
  1602. return("");
  1603. }
  1604. Function Redirect(&$headers)
  1605. {
  1606. if($this->follow_redirect)
  1607. {
  1608. if(!IsSet($headers["location"])
  1609. || (GetType($headers["location"])!="array"
  1610. && strlen($location=$headers["location"])==0)
  1611. || (GetType($headers["location"])=="array"
  1612. && strlen($location=$headers["location"][0])==0))
  1613. return($this->SetError("it was received a redirect without location URL", HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
  1614. if(strcmp($location[0],"/"))
  1615. {
  1616. if(!($location_arguments=@parse_url($location)))
  1617. return($this->SetError("the server did not return a valid redirection location URL", HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
  1618. if(!IsSet($location_arguments["scheme"]))
  1619. $location=((GetType($end=strrpos($this->request_uri,"/"))=="integer" && $end>1) ? substr($this->request_uri,0,$end) : "")."/".$location;
  1620. }
  1621. if(!strcmp($location[0],"/"))
  1622. $location=$this->protocol."://".$this->host_name.($this->host_port ? ":".$this->host_port : "").$location;
  1623. $error=$this->GetRequestArguments($location,$arguments);
  1624. if(strlen($error))
  1625. return($this->SetError("could not process redirect url: ".$error, HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
  1626. $arguments["RequestMethod"]="GET";
  1627. if(strlen($error=$this->Close())==0
  1628. && strlen($error=$this->Open($arguments))==0
  1629. && strlen($error=$this->SendRequest($arguments))==0)
  1630. {
  1631. $this->redirection_level++;
  1632. if($this->redirection_level>$this->redirection_limit)
  1633. {
  1634. $error="it was exceeded the limit of request redirections";
  1635. $this->error_code = HTTP_CLIENT_ERROR_PROTOCOL_FAILURE;
  1636. }
  1637. else
  1638. $error=$this->ReadReplyHeaders($headers);
  1639. $this->redirection_level--;
  1640. }
  1641. if(strlen($error))
  1642. return($this->SetError($error, $this->error_code));
  1643. }
  1644. return("");
  1645. }
  1646. Function Authenticate(&$headers, $proxy, &$proxy_authorization, &$user, &$password, &$realm, &$workstation)
  1647. {
  1648. if($proxy)
  1649. {
  1650. $authenticate_header="proxy-authenticate";
  1651. $authorization_header="Proxy-Authorization";
  1652. $authenticate_status="407";
  1653. $authentication_mechanism=$this->proxy_authentication_mechanism;
  1654. }
  1655. else
  1656. {
  1657. $authenticate_header="www-authenticate";
  1658. $authorization_header="Authorization";
  1659. $authenticate_status="401";
  1660. $authentication_mechanism=$this->authentication_mechanism;
  1661. }
  1662. if(IsSet($headers[$authenticate_header])
  1663. && $this->sasl_authenticate)
  1664. {
  1665. if(function_exists("class_exists")
  1666. && !class_exists("sasl_client_class"))
  1667. 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));
  1668. if(GetType($headers[$authenticate_header])=="array")
  1669. $authenticate=$headers[$authenticate_header];
  1670. else
  1671. $authenticate=array($headers[$authenticate_header]);
  1672. for($response="", $mechanisms=array(),$m=0;$m<count($authenticate);$m++)
  1673. {
  1674. $mechanism=$this->Tokenize($authenticate[$m]," ");
  1675. $response=$this->Tokenize("");
  1676. if(strlen($authentication_mechanism))
  1677. {
  1678. if(!strcmp($authentication_mechanism,$mechanism))
  1679. {
  1680. $mechanisms[]=$mechanism;
  1681. break;
  1682. }
  1683. }
  1684. else
  1685. $mechanisms[]=$mechanism;
  1686. }
  1687. $sasl=new sasl_client_class;
  1688. if(IsSet($user))
  1689. $sasl->SetCredential("user",$user);
  1690. if(IsSet($password))
  1691. $sasl->SetCredential("password",$password);
  1692. if(IsSet($realm))
  1693. $sasl->SetCredential("realm",$realm);
  1694. if(IsSet($workstation))
  1695. $sasl->SetCredential("workstation",$workstation);
  1696. $sasl->SetCredential("uri",$this->request_uri);
  1697. $sasl->SetCredential("method",$this->request_method);
  1698. $sasl->SetCredential("session",$this->session);
  1699. do
  1700. {
  1701. $status=$sasl->Start($mechanisms,$message,$interactions);
  1702. }
  1703. while($status==SASL_INTERACT);
  1704. switch($status)
  1705. {
  1706. case SASL_CONTINUE:
  1707. break;
  1708. case SASL_NOMECH:
  1709. 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));
  1710. default:
  1711. return($this->SetError("Could not start the SASL ".($proxy ? "proxy " : "")."authentication client: ".$sasl->error, HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
  1712. }
  1713. if($proxy >= 0)
  1714. {
  1715. for(;;)
  1716. {
  1717. if(strlen($error=$this->ReadReplyBody($body,$this->file_buffer_length)))
  1718. return($error);
  1719. if(strlen($body)==0)
  1720. break;
  1721. }
  1722. }
  1723. $authorization_value=$sasl->mechanism.(IsSet($message) ? " ".($sasl->encode_response ? base64_encode($message) : $message) : "");
  1724. $request_arguments=$this->request_arguments;
  1725. $arguments=$request_arguments;
  1726. $arguments["Headers"][$authorization_header]=$authorization_value;
  1727. if(!$proxy
  1728. && strlen($proxy_authorization))
  1729. $arguments["Headers"]["Proxy-Authorization"]=$proxy_authorization;
  1730. if(strlen($error=$this->Close())
  1731. || strlen($error=$this->Open($arguments)))
  1732. return($this->SetError($error, $this->error_code));
  1733. $authenticated=0;
  1734. if(IsSet($message))
  1735. {
  1736. if($proxy < 0)
  1737. {
  1738. if(strlen($error=$this->ConnectFromProxy($arguments, $headers)))
  1739. return($this->SetError($error, $this->error_code));
  1740. }
  1741. else
  1742. {
  1743. if(strlen($error=$this->SendRequest($arguments))
  1744. || strlen($error=$this->ReadReplyHeadersResponse($headers)))
  1745. return($this->SetError($error, $this->error_code));
  1746. }
  1747. if(!IsSet($headers[$authenticate_header]))
  1748. $authenticate=array();
  1749. elseif(GetType($headers[$authenticate_header])=="array")
  1750. $authenticate=$headers[$authenticate_header];
  1751. else
  1752. $authenticate=array($headers[$authenticate_header]);
  1753. for($mechanism=0;$mechanism<count($authenticate);$mechanism++)
  1754. {
  1755. if(!strcmp($this->Tokenize($authenticate[$mechanism]," "),$sasl->mechanism))
  1756. {
  1757. $response=$this->Tokenize("");
  1758. break;
  1759. }
  1760. }
  1761. switch($this->response_status)
  1762. {
  1763. case $authenticate_status:
  1764. break;
  1765. case "301":
  1766. case "302":
  1767. case "303":
  1768. case "307":
  1769. if($proxy >= 0)
  1770. return($this->Redirect($headers));
  1771. default:
  1772. if(intval($this->response_status/100)==2)
  1773. {
  1774. if($proxy)
  1775. $proxy_authorization=$authorization_value;
  1776. $authenticated=1;
  1777. break;
  1778. }
  1779. if($proxy
  1780. && !strcmp($this->response_status,"401"))
  1781. {
  1782. $proxy_authorization=$authorization_value;
  1783. $authenticated=1;
  1784. break;
  1785. }
  1786. return($this->SetError(($proxy ? "proxy " : "")."authentication error: ".$this->response_status." ".$this->response_message, HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
  1787. }
  1788. }
  1789. for(;!$authenticated;)
  1790. {
  1791. do
  1792. {
  1793. $status=$sasl->Step($response,$message,$interactions);
  1794. }
  1795. while($status==SASL_INTERACT);
  1796. switch($status)
  1797. {
  1798. case SASL_CONTINUE:
  1799. $authorization_value=$sasl->mechanism.(IsSet($message) ? " ".($sasl->encode_response ? base64_encode($message) : $message) : "");
  1800. $arguments=$request_arguments;
  1801. $arguments["Headers"][$authorization_header]=$authorization_value;
  1802. if(!$proxy
  1803. && strlen($proxy_authorization))
  1804. $arguments["Headers"]["Proxy-Authorization"]=$proxy_authorization;
  1805. if($proxy < 0)
  1806. {
  1807. if(strlen($error=$this->ConnectFromProxy($arguments, $headers)))
  1808. return($this->SetError($error, $this->error_code));
  1809. }
  1810. else
  1811. {
  1812. if(strlen($error=$this->SendRequest($arguments))
  1813. || strlen($error=$this->ReadReplyHeadersResponse($headers)))
  1814. return($this->SetError($error, $this->error_code));
  1815. }
  1816. switch($this->response_status)
  1817. {
  1818. case $authenticate_status:
  1819. if(GetType($headers[$authenticate_header])=="array")
  1820. $authenticate=$headers[$authenticate_header];
  1821. else
  1822. $authenticate=array($headers[$authenticate_header]);
  1823. for($response="",$mechanism=0;$mechanism<count($authenticate);$mechanism++)
  1824. {
  1825. if(!strcmp($this->Tokenize($authenticate[$mechanism]," "),$sasl->mechanism))
  1826. {
  1827. $response=$this->Tokenize("");
  1828. break;
  1829. }
  1830. }
  1831. if($proxy >= 0)
  1832. {
  1833. for(;;)
  1834. {
  1835. if(strlen($error=$this->ReadReplyBody($body,$this->file_buffer_length)))
  1836. return($error);
  1837. if(strlen($body)==0)
  1838. break;
  1839. }
  1840. }
  1841. $this->state="Connected";
  1842. break;
  1843. case "301":
  1844. case "302":
  1845. case "303":
  1846. case "307":
  1847. if($proxy >= 0)
  1848. return($this->Redirect($headers));
  1849. default:
  1850. if(intval($this->response_status/100)==2)
  1851. {
  1852. if($proxy)
  1853. $proxy_authorization=$authorization_value;
  1854. $authenticated=1;
  1855. break;
  1856. }
  1857. if($proxy
  1858. && !strcmp($this->response_status,"401"))
  1859. {
  1860. $proxy_authorization=$authorization_value;
  1861. $authenticated=1;
  1862. break;
  1863. }
  1864. return($this->SetError(($proxy ? "proxy " : "")."authentication error: ".$this->response_status." ".$this->response_message));
  1865. }
  1866. break;
  1867. default:
  1868. return($this->SetError("Could not process the SASL ".($proxy ? "proxy " : "")."authentication step: ".$sasl->error, HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
  1869. }
  1870. }
  1871. }
  1872. return("");
  1873. }
  1874. Function ReadReplyHeaders(&$headers)
  1875. {
  1876. if(strlen($error=$this->ReadReplyHeadersResponse($headers)))
  1877. return($error);
  1878. $proxy_authorization="";
  1879. while(!strcmp($this->response_status, "100"))
  1880. {
  1881. $this->state="RequestSent";
  1882. if(strlen($error=$this->ReadReplyHeadersResponse($headers)))
  1883. return($error);
  1884. }
  1885. switch($this->response_status)
  1886. {
  1887. case "301":
  1888. case "302":
  1889. case "303":
  1890. case "307":
  1891. if(strlen($error=$this->Redirect($headers)))
  1892. return($error);
  1893. break;
  1894. case "407":
  1895. 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)))
  1896. return($error);
  1897. if(strcmp($this->response_status,"401"))
  1898. return("");
  1899. case "401":
  1900. return($this->Authenticate($headers, 0, $proxy_authorization, $this->request_user, $this->request_password, $this->request_realm, $this->request_workstation));
  1901. }
  1902. return("");
  1903. }
  1904. Function ReadReplyBody(&$body,$length)
  1905. {
  1906. $body="";
  1907. if(strlen($this->error))
  1908. return($this->error);
  1909. switch($this->state)
  1910. {
  1911. case "Disconnected":
  1912. return($this->SetError("connection was not yet established", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
  1913. case "Connected":
  1914. case "ConnectedToProxy":
  1915. return($this->SetError("request was not sent", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
  1916. case "RequestSent":
  1917. if(($error=$this->ReadReplyHeaders($headers))!="")
  1918. return($error);
  1919. break;
  1920. case "GotReplyHeaders":
  1921. break;
  1922. case 'ResponseReceived':
  1923. $body = '';
  1924. return('');
  1925. default:
  1926. return($this->SetError("can not get request headers in the current connection state", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
  1927. }
  1928. if($this->content_length_set)
  1929. $length=min($this->content_length-$this->read_length,$length);
  1930. $body = '';
  1931. if($length>0)
  1932. {
  1933. if(!$this->EndOfInput()
  1934. && ($body=$this->ReadBytes($length))=="")
  1935. {
  1936. if(strlen($this->error))
  1937. return($this->SetError("could not get the request reply body: ".$this->error, $this->error_code));
  1938. }
  1939. $this->read_length+=strlen($body);
  1940. if($this->EndOfInput())
  1941. $this->state = 'ResponseReceived';
  1942. }
  1943. return("");
  1944. }
  1945. Function ReadWholeReplyBody(&$body)
  1946. {
  1947. $body = '';
  1948. for(;;)
  1949. {
  1950. if(strlen($error = $this->ReadReplyBody($block, $this->file_buffer_length)))
  1951. return($error);
  1952. if(strlen($block) == 0)
  1953. return('');
  1954. $body .= $block;
  1955. }
  1956. }
  1957. Function ReadWholeReplyIntoTemporaryFile(&$file)
  1958. {
  1959. if(!($file = tmpfile()))
  1960. return $this->SetPHPError('could not create the temporary file to save the response', $php_errormsg, HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
  1961. for(;;)
  1962. {
  1963. if(strlen($error = $this->ReadReplyBody($block, $this->file_buffer_length)))
  1964. {
  1965. fclose($file);
  1966. return($error);
  1967. }
  1968. if(strlen($block) == 0)
  1969. {
  1970. if(@fseek($file, 0) != 0)
  1971. {
  1972. $error = $this->SetPHPError('could not seek to the beginning of temporary file with the response', $php_errormsg, HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
  1973. fclose($file);
  1974. return $error;
  1975. }
  1976. return('');
  1977. }
  1978. if(!@fwrite($file, $block))
  1979. {
  1980. $error = $this->SetPHPError('could not write to the temporary file to save the response', $php_errormsg, HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE);
  1981. fclose($file);
  1982. return $error;
  1983. }
  1984. }
  1985. }
  1986. Function SaveCookies(&$cookies, $domain='', $secure_only=0, $persistent_only=0)
  1987. {
  1988. $now=gmdate("Y-m-d H-i-s");
  1989. $cookies=array();
  1990. for($secure_cookies=0,Reset($this->cookies);$secure_cookies<count($this->cookies);Next($this->cookies),$secure_cookies++)
  1991. {
  1992. $secure=Key($this->cookies);
  1993. if(!$secure_only
  1994. || $secure)
  1995. {
  1996. for($cookie_domain=0,Reset($this->cookies[$secure]);$cookie_domain<count($this->cookies[$secure]);Next($this->cookies[$secure]),$cookie_domain++)
  1997. {
  1998. $domain_pattern=Key($this->cookies[$secure]);
  1999. $match=strlen($domain)-strlen($domain_pattern);
  2000. if(strlen($domain)==0
  2001. || ($match>=0
  2002. && !strcmp($domain_pattern,substr($domain,$match))
  2003. && ($match==0
  2004. || $domain_pattern[0]=="."
  2005. || $domain[$match-1]==".")))
  2006. {
  2007. 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++)
  2008. {
  2009. $path=Key($this->cookies[$secure][$domain_pattern]);
  2010. 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++)
  2011. {
  2012. $cookie_name=Key($this->cookies[$secure][$domain_pattern][$path]);
  2013. $expires=$this->cookies[$secure][$domain_pattern][$path][$cookie_name]["expires"];
  2014. if((!$persistent_only
  2015. && strlen($expires)==0)
  2016. || (strlen($expires)
  2017. && strcmp($now,$expires)<0))
  2018. $cookies[$secure][$domain_pattern][$path][$cookie_name]=$this->cookies[$secure][$domain_pattern][$path][$cookie_name];
  2019. }
  2020. }
  2021. }
  2022. }
  2023. }
  2024. }
  2025. }
  2026. Function SavePersistentCookies(&$cookies, $domain='', $secure_only=0)
  2027. {
  2028. $this->SaveCookies($cookies, $domain, $secure_only, 1);
  2029. }
  2030. Function GetPersistentCookies(&$cookies, $domain='', $secure_only=0)
  2031. {
  2032. $this->SavePersistentCookies($cookies, $domain, $secure_only);
  2033. }
  2034. Function RestoreCookies($cookies, $clear=1)
  2035. {
  2036. $new_cookies=($clear ? array() : $this->cookies);
  2037. for($secure_cookies=0, Reset($cookies); $secure_cookies<count($cookies); Next($cookies), $secure_cookies++)
  2038. {
  2039. $secure=Key($cookies);
  2040. if(GetType($secure)!="integer")
  2041. return($this->SetError("invalid cookie secure value type (".serialize($secure).")", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
  2042. for($cookie_domain=0,Reset($cookies[$secure]);$cookie_domain<count($cookies[$secure]);Next($cookies[$secure]),$cookie_domain++)
  2043. {
  2044. $domain_pattern=Key($cookies[$secure]);
  2045. if(GetType($domain_pattern)!="string")
  2046. return($this->SetError("invalid cookie domain value type (".serialize($domain_pattern).")", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
  2047. for(Reset($cookies[$secure][$domain_pattern]),$path_part=0;$path_part<count($cookies[$secure][$domain_pattern]);Next($cookies[$secure][$domain_pattern]),$path_part++)
  2048. {
  2049. $path=Key($cookies[$secure][$domain_pattern]);
  2050. if(GetType($path)!="string"
  2051. || strcmp(substr($path, 0, 1), "/"))
  2052. return($this->SetError("invalid cookie path value type (".serialize($path).")", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
  2053. for(Reset($cookies[$secure][$domain_pattern][$path]),$cookie=0;$cookie<count($cookies[$secure][$domain_pattern][$path]);Next($cookies[$secure][$domain_pattern][$path]),$cookie++)
  2054. {
  2055. $cookie_name=Key($cookies[$secure][$domain_pattern][$path]);
  2056. $expires=$cookies[$secure][$domain_pattern][$path][$cookie_name]["expires"];
  2057. $value=$cookies[$secure][$domain_pattern][$path][$cookie_name]["value"];
  2058. if(GetType($expires)!="string"
  2059. || (strlen($expires)
  2060. && !preg_match("/^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}\$/", $expires)))
  2061. return($this->SetError("invalid cookie expiry value type (".serialize($expires).")", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
  2062. $new_cookies[$secure][$domain_pattern][$path][$cookie_name]=array(
  2063. "name"=>$cookie_name,
  2064. "value"=>$value,
  2065. "domain"=>$domain_pattern,
  2066. "path"=>$path,
  2067. "expires"=>$expires,
  2068. "secure"=>$secure
  2069. );
  2070. }
  2071. }
  2072. }
  2073. }
  2074. $this->cookies=$new_cookies;
  2075. return("");
  2076. }
  2077. };
  2078. ?>