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