PageRenderTime 63ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/public/external/pydio/core/classes/http_class/http_class.php

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