PageRenderTime 63ms CodeModel.GetById 4ms app.highlight 47ms RepoModel.GetById 1ms 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

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

   1<?php
   2/*
   3 * http.php
   4 *
   5 * @(#) $Header: /opt2/ena/metal/http/http.php,v 1.88 2011/10/24 08:26:56 mlemos Exp $
   6 *
   7 */
   8
   9define('HTTP_CLIENT_ERROR_UNSPECIFIED_ERROR',       -1);
  10define('HTTP_CLIENT_ERROR_NO_ERROR',                 0);
  11define('HTTP_CLIENT_ERROR_INVALID_SERVER_ADDRESS',   1);
  12define('HTTP_CLIENT_ERROR_CANNOT_CONNECT',           2);
  13define('HTTP_CLIENT_ERROR_COMMUNICATION_FAILURE',    3);
  14define('HTTP_CLIENT_ERROR_CANNOT_ACCESS_LOCAL_FILE', 4);
  15define('HTTP_CLIENT_ERROR_PROTOCOL_FAILURE',         5);
  16define('HTTP_CLIENT_ERROR_INVALID_PARAMETERS',       6);
  17
  18class http_class
  19{
  20    public $host_name="";
  21    public $host_port=0;
  22    public $proxy_host_name="";
  23    public $proxy_host_port=80;
  24    public $socks_host_name = '';
  25    public $socks_host_port = 1080;
  26    public $socks_version = '5';
  27
  28    public $protocol="http";
  29    public $request_method="GET";
  30    public $user_agent='httpclient (http://www.phpclasses.org/httpclient $Revision: 1.88 $)';
  31    public $accept='';
  32    public $authentication_mechanism="";
  33    public $user;
  34    public $password;
  35    public $realm;
  36    public $workstation;
  37    public $proxy_authentication_mechanism="";
  38    public $proxy_user;
  39    public $proxy_password;
  40    public $proxy_realm;
  41    public $proxy_workstation;
  42    public $request_uri="";
  43    public $request="";
  44    public $request_headers=array();
  45    public $request_user;
  46    public $request_password;
  47    public $request_realm;
  48    public $request_workstation;
  49    public $proxy_request_user;
  50    public $proxy_request_password;
  51    public $proxy_request_realm;
  52    public $proxy_request_workstation;
  53    public $request_body="";
  54    public $request_arguments=array();
  55    public $protocol_version="1.1";
  56    public $timeout=0;
  57    public $data_timeout=0;
  58    public $debug=0;
  59    public $log_debug=0;
  60    public $debug_response_body=1;
  61    public $html_debug=0;
  62    public $support_cookies=1;
  63    public $cookies=array();
  64    public $error="";
  65    public $error_code = HTTP_CLIENT_ERROR_NO_ERROR;
  66    public $exclude_address="";
  67    public $follow_redirect=0;
  68    public $redirection_limit=5;
  69    public $response_status="";
  70    public $response_message="";
  71    public $file_buffer_length=8000;
  72    public $force_multipart_form_post=0;
  73    public $prefer_curl = 0;
  74    public $keep_alive = 1;
  75
  76    /* private variables - DO NOT ACCESS */
  77
  78    public $state="Disconnected";
  79    public $use_curl=0;
  80    public $connection=0;
  81    public $content_length=0;
  82    public $response="";
  83    public $read_response=0;
  84    public $read_length=0;
  85    public $request_host="";
  86    public $next_token="";
  87    public $redirection_level=0;
  88    public $chunked=0;
  89    public $remaining_chunk=0;
  90    public $last_chunk_read=0;
  91    public $months=array(
  92        "Jan"=>"01",
  93        "Feb"=>"02",
  94        "Mar"=>"03",
  95        "Apr"=>"04",
  96        "May"=>"05",
  97        "Jun"=>"06",
  98        "Jul"=>"07",
  99        "Aug"=>"08",
 100        "Sep"=>"09",
 101        "Oct"=>"10",
 102        "Nov"=>"11",
 103        "Dec"=>"12");
 104    public $session='';
 105    public $connection_close=0;
 106    public $force_close = 0;
 107    public $connected_host = '';
 108    public $connected_port = -1;
 109    public $connected_ssl = 0;
 110
 111    /* Private methods - DO NOT CALL */
 112
 113    public Function Tokenize($string,$separator="")
 114    {
 115        if (!strcmp($separator,"")) {
 116            $separator=$string;
 117            $string=$this->next_token;
 118        }
 119        for ($character=0;$character<strlen($separator);$character++) {
 120            if(GetType($position=strpos($string,$separator[$character]))=="integer")
 121                $found=(IsSet($found) ? min($found,$position) : $position);
 122        }
 123        if (IsSet($found)) {
 124            $this->next_token=substr($string,$found+1);
 125            return(substr($string,0,$found));
 126        } else {
 127            $this->next_token="";
 128            return($string);
 129        }
 130    }
 131
 132    public Function CookieEncode($value, $name)
 133    {
 134        return($name ? str_replace("=", "%25", $value) : str_replace(";", "%3B", $value));
 135    }
 136
 137    public Function SetError($error, $error_code = HTTP_CLIENT_ERROR_UNSPECIFIED_ERROR)
 138    {
 139        $this->error_code = $error_code;
 140        return($this->error=$error);
 141    }
 142
 143    public Function SetPHPError($error, &$php_error_message, $error_code = HTTP_CLIENT_ERROR_UNSPECIFIED_ERROR)
 144    {
 145        if(IsSet($php_error_message)
 146        && strlen($php_error_message))
 147            $error.=": ".$php_error_message;
 148        return($this->SetError($error, $error_code));
 149    }
 150
 151    public Function SetDataAccessError($error,$check_connection=0)
 152    {
 153        $this->error=$error;
 154        $this->error_code = HTTP_CLIENT_ERROR_COMMUNICATION_FAILURE;
 155        if(!$this->use_curl
 156        && function_exists("socket_get_status"))
 157        {
 158            $status=socket_get_status($this->connection);
 159            if($status["timed_out"])
 160                $this->error.=": data access time out";
 161            elseif ($status["eof"]) {
 162                if($check_connection)
 163                    $this->error="";
 164                else
 165                    $this->error.=": the server disconnected";
 166            }
 167        }
 168    }
 169
 170    public Function OutputDebug($message)
 171    {
 172        if($this->log_debug)
 173            error_log($message);
 174        else {
 175            $message.="\n";
 176            if($this->html_debug)
 177                $message=str_replace("\n","<br />\n",HtmlEntities($message));
 178            echo $message;
 179            flush();
 180        }
 181    }
 182
 183    public Function GetLine()
 184    {
 185        for ($line="";;) {
 186            if ($this->use_curl) {
 187                $eol=strpos($this->response,"\n",$this->read_response);
 188                $data=($eol ? substr($this->response,$this->read_response,$eol+1-$this->read_response) : "");
 189                $this->read_response+=strlen($data);
 190            } else {
 191                if (feof($this->connection)) {
 192                    $this->SetDataAccessError("reached the end of data while reading from the HTTP server connection");
 193                    return(0);
 194                }
 195                $data=fgets($this->connection,100);
 196            }
 197            if(GetType($data)!="string"
 198            || strlen($data)==0)
 199            {
 200                $this->SetDataAccessError("it was not possible to read line from the HTTP server");
 201                return(0);
 202            }
 203            $line.=$data;
 204            $length=strlen($line);
 205            if($length
 206            && !strcmp(substr($line,$length-1,1),"\n"))
 207            {
 208                $length-=(($length>=2 && !strcmp(substr($line,$length-2,1),"\r")) ? 2 : 1);
 209                $line=substr($line,0,$length);
 210                if($this->debug)
 211                    $this->OutputDebug("S $line");
 212                return($line);
 213            }
 214        }
 215    }
 216
 217    public Function PutLine($line)
 218    {
 219        if($this->debug)
 220            $this->OutputDebug("C $line");
 221        if (!fputs($this->connection,$line."\r\n")) {
 222            $this->SetDataAccessError("it was not possible to send a line to the HTTP server");
 223            return(0);
 224        }
 225        return(1);
 226    }
 227
 228    public Function PutData($data)
 229    {
 230        if (strlen($data)) {
 231            if($this->debug)
 232                $this->OutputDebug('C '.$data);
 233            if (!fputs($this->connection,$data)) {
 234                $this->SetDataAccessError("it was not possible to send data to the HTTP server");
 235                return(0);
 236            }
 237        }
 238        return(1);
 239    }
 240
 241    public Function FlushData()
 242    {
 243        if (!fflush($this->connection)) {
 244            $this->SetDataAccessError("it was not possible to send data to the HTTP server");
 245            return(0);
 246        }
 247        return(1);
 248    }
 249
 250    public Function ReadChunkSize()
 251    {
 252        if ($this->remaining_chunk==0) {
 253            $debug=$this->debug;
 254            if(!$this->debug_response_body)
 255                $this->debug=0;
 256            $line=$this->GetLine();
 257            $this->debug=$debug;
 258            if(GetType($line)!="string")
 259                return($this->SetError("could not read chunk start: ".$this->error, $this->error_code));
 260            $this->remaining_chunk=hexdec($line);
 261            if ($this->remaining_chunk == 0) {
 262                if(!$this->debug_response_body)
 263                    $this->debug=0;
 264                $line=$this->GetLine();
 265                $this->debug=$debug;
 266                if(GetType($line)!="string")
 267                    return($this->SetError("could not read chunk end: ".$this->error, $this->error_code));
 268            }
 269        }
 270        return("");
 271    }
 272
 273    public Function ReadBytes($length)
 274    {
 275        if ($this->use_curl) {
 276            $bytes=substr($this->response,$this->read_response,min($length,strlen($this->response)-$this->read_response));
 277            $this->read_response+=strlen($bytes);
 278            if($this->debug
 279            && $this->debug_response_body
 280            && strlen($bytes))
 281                $this->OutputDebug("S ".$bytes);
 282        } else {
 283            if ($this->chunked) {
 284                for ($bytes="",$remaining=$length;$remaining;) {
 285                    if(strlen($this->ReadChunkSize()))
 286                        return("");
 287                    if ($this->remaining_chunk==0) {
 288                        $this->last_chunk_read=1;
 289                        break;
 290                    }
 291                    $ask=min($this->remaining_chunk,$remaining);
 292                    $chunk=@fread($this->connection,$ask);
 293                    $read=strlen($chunk);
 294                    if ($read==0) {
 295                        $this->SetDataAccessError("it was not possible to read data chunk from the HTTP server");
 296                        return("");
 297                    }
 298                    if($this->debug
 299                    && $this->debug_response_body)
 300                        $this->OutputDebug("S ".$chunk);
 301                    $bytes.=$chunk;
 302                    $this->remaining_chunk-=$read;
 303                    $remaining-=$read;
 304                    if ($this->remaining_chunk==0) {
 305                        if(feof($this->connection))
 306                            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));
 307                        $data=@fread($this->connection,2);
 308                        if (strcmp($data,"\r\n")) {
 309                            $this->SetDataAccessError("it was not possible to read end of data chunk from the HTTP server");
 310                            return("");
 311                        }
 312                    }
 313                }
 314            } else {
 315                $bytes=@fread($this->connection,$length);
 316                if (strlen($bytes)) {
 317                    if($this->debug
 318                    && $this->debug_response_body)
 319                        $this->OutputDebug("S ".$bytes);
 320                } else
 321                    $this->SetDataAccessError("it was not possible to read data from the HTTP server", $this->connection_close);
 322            }
 323        }
 324        return($bytes);
 325    }
 326
 327    public Function EndOfInput()
 328    {
 329        if($this->use_curl)
 330            return($this->read_response>=strlen($this->response));
 331        if($this->chunked)
 332            return($this->last_chunk_read);
 333        if($this->content_length_set)
 334            return($this->content_length <= $this->read_length);
 335        return(feof($this->connection));
 336    }
 337
 338    public Function Resolve($domain, &$ip, $server_type)
 339    {
 340        if(preg_match('/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/',$domain))
 341            $ip=$domain;
 342        else {
 343            if($this->debug)
 344                $this->OutputDebug('Resolving '.$server_type.' server domain "'.$domain.'"...');
 345            if(!strcmp($ip=@gethostbyname($domain),$domain))
 346                $ip="";
 347        }
 348        if(strlen($ip)==0
 349        || (strlen($this->exclude_address)
 350        && !strcmp(@gethostbyname($this->exclude_address),$ip)))
 351            return($this->SetError("could not resolve the host domain \"".$domain."\"", HTTP_CLIENT_ERROR_INVALID_SERVER_ADDRESS));
 352        return('');
 353    }
 354
 355    public Function Connect($host_name, $host_port, $ssl, $server_type = 'HTTP')
 356    {
 357        $domain=$host_name;
 358        $port = $host_port;
 359        if(strlen($error = $this->Resolve($domain, $ip, $server_type)))
 360            return($error);
 361        if (strlen($this->socks_host_name)) {
 362            switch ($this->socks_version) {
 363                case '4':
 364                    $version = 4;
 365                    break;
 366                case '5':
 367                    $version = 5;
 368                    break;
 369                default:
 370                    return('it was not specified a supported SOCKS protocol version');
 371                    break;
 372            }
 373            $host_ip = $ip;
 374            $port = $this->socks_host_port;
 375            $host_server_type = $server_type;
 376            $server_type = 'SOCKS';
 377            if(strlen($error = $this->Resolve($this->socks_host_name, $ip, $server_type)))
 378                return($error);
 379        }
 380        if($this->debug)
 381            $this->OutputDebug('Connecting to '.$server_type.' server IP '.$ip.' port '.$port.'...');
 382        if($ssl)
 383            $ip="ssl://".$host_name;
 384        if (($this->connection=($this->timeout ? @fsockopen($ip, $port, $errno, $error, $this->timeout) : @fsockopen($ip, $port, $errno)))==0) {
 385            $error_code = HTTP_CLIENT_ERROR_CANNOT_CONNECT;
 386            switch ($errno) {
 387                case -3:
 388                    return($this->SetError("socket could not be created", $error_code));
 389                case -4:
 390                    return($this->SetError("dns lookup on hostname \"".$host_name."\" failed", $error_code));
 391                case -5:
 392                    return($this->SetError("connection refused or timed out", $error_code));
 393                case -6:
 394                    return($this->SetError("fdopen() call failed", $error_code));
 395                case -7:
 396                    return($this->SetError("setvbuf() call failed", $error_code));
 397                default:
 398                    return($this->SetPHPError($errno." could not connect to the host \"".$host_name."\"",$php_errormsg, $error_code));
 399            }
 400        } else {
 401            if($this->data_timeout
 402            && function_exists("socket_set_timeout"))
 403                socket_set_timeout($this->connection,$this->data_timeout,0);
 404            if (strlen($this->socks_host_name)) {
 405                if($this->debug)
 406                    $this->OutputDebug('Connected to the SOCKS server '.$this->socks_host_name);
 407                $send_error = 'it was not possible to send data to the SOCKS server';
 408                $receive_error = 'it was not possible to receive data from the SOCKS server';
 409                switch ($version) {
 410                    case 4:
 411                        $command = 1;
 412                        $user = '';
 413                        if(!fputs($this->connection, chr($version).chr($command).pack('nN', $host_port, ip2long($host_ip)).$user.Chr(0)))
 414                            $error = $this->SetDataAccessError($send_error);
 415                        else {
 416                            $response = fgets($this->connection, 9);
 417                            if(strlen($response) != 8)
 418                                $error = $this->SetDataAccessError($receive_error);
 419                            else {
 420                                $socks_errors = array(
 421                                    "\x5a"=>'',
 422                                    "\x5b"=>'request rejected',
 423                                    "\x5c"=>'request failed because client is not running identd (or not reachable from the server)',
 424                                    "\x5d"=>'request failed because client\'s identd could not confirm the user ID string in the request',
 425                                );
 426                                $error_code = $response[1];
 427                                $error = (IsSet($socks_errors[$error_code]) ? $socks_errors[$error_code] : 'unknown');
 428                                if(strlen($error))
 429                                    $error = 'SOCKS error: '.$error;
 430                            }
 431                        }
 432                        break;
 433                    case 5:
 434                        if($this->debug)
 435                            $this->OutputDebug('Negotiating the authentication method ...');
 436                        $methods = 1;
 437                        $method = 0;
 438                        if(!fputs($this->connection, chr($version).chr($methods).chr($method)))
 439                            $error = $this->SetDataAccessError($send_error);
 440                        else {
 441                            $response = fgets($this->connection, 3);
 442                            if(strlen($response) != 2)
 443                                $error = $this->SetDataAccessError($receive_error);
 444                            elseif(Ord($response[1]) != $method)
 445                                $error = 'the SOCKS server requires an authentication method that is not yet supported';
 446                            else {
 447                                if($this->debug)
 448                                    $this->OutputDebug('Connecting to '.$host_server_type.' server IP '.$host_ip.' port '.$host_port.'...');
 449                                $command = 1;
 450                                $address_type = 1;
 451                                if(!fputs($this->connection, chr($version).chr($command)."\x00".chr($address_type).pack('Nn', ip2long($host_ip), $host_port)))
 452                                    $error = $this->SetDataAccessError($send_error);
 453                                else {
 454                                    $response = fgets($this->connection, 11);
 455                                    if(strlen($response) != 10)
 456                                        $error = $this->SetDataAccessError($receive_error);
 457                                    else {
 458                                        $socks_errors = array(
 459                                            "\x00"=>'',
 460                                            "\x01"=>'general SOCKS server failure',
 461                                            "\x02"=>'connection not allowed by ruleset',
 462                                            "\x03"=>'Network unreachable',
 463                                            "\x04"=>'Host unreachable',
 464                                            "\x05"=>'Connection refused',
 465                                            "\x06"=>'TTL expired',
 466                                            "\x07"=>'Command not supported',
 467                                            "\x08"=>'Address type not supported'
 468                                        );
 469                                        $error_code = $response[1];
 470                                        $error = (IsSet($socks_errors[$error_code]) ? $socks_errors[$error_code] : 'unknown');
 471                                        if(strlen($error))
 472                                            $error = 'SOCKS error: '.$error;
 473                                    }
 474                                }
 475                            }
 476                        }
 477                        break;
 478                    default:
 479                        $error = 'support for SOCKS protocol version '.$this->socks_version.' is not yet implemented';
 480                        break;
 481                }
 482                if (strlen($error)) {
 483                    fclose($this->connection);
 484                    return($error);
 485                }
 486            }
 487            if($this->debug)
 488                $this->OutputDebug("Connected to $host_name");
 489            if(strlen($this->proxy_host_name)
 490            && !strcmp(strtolower($this->protocol), 'https'))
 491            {
 492                if(function_exists('stream_socket_enable_crypto')
 493                && in_array('ssl', stream_get_transports()))
 494                    $this->state = "ConnectedToProxy";
 495                else {
 496                    $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.");
 497                    $this->state="Connected";
 498                }
 499            } else
 500                $this->state="Connected";
 501            return("");
 502        }
 503    }
 504
 505    public Function Disconnect()
 506    {
 507        if($this->debug)
 508            $this->OutputDebug("Disconnected from ".$this->connected_host);
 509        if ($this->use_curl) {
 510            curl_close($this->connection);
 511            $this->response="";
 512        } else
 513            fclose($this->connection);
 514        $this->state="Disconnected";
 515        return("");
 516    }
 517
 518    /* Public methods */
 519
 520    public Function GetRequestArguments($url, &$arguments)
 521    {
 522        $this->error = '';
 523        $this->error_code = HTTP_CLIENT_ERROR_NO_ERROR;
 524        $arguments=array();
 525        $url = str_replace(' ', '%20', $url);
 526        $parameters=@parse_url($url);
 527        if(!$parameters)
 528            return($this->SetError("it was not specified a valid URL", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
 529        if(!IsSet($parameters["scheme"]))
 530            return($this->SetError("it was not specified the protocol type argument", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
 531        switch (strtolower($parameters["scheme"])) {
 532            case "http":
 533            case "https":
 534                $arguments["Protocol"]=$parameters["scheme"];
 535                break;
 536            default:
 537                return($parameters["scheme"]." connection scheme is not yet supported");
 538        }
 539        if(!IsSet($parameters["host"]))
 540            return($this->SetError("it was not specified the connection host argument", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
 541        $arguments["HostName"]=$parameters["host"];
 542        $arguments["Headers"]=array("Host"=>$parameters["host"].(IsSet($parameters["port"]) ? ":".$parameters["port"] : ""));
 543        if (IsSet($parameters["user"])) {
 544            $arguments["AuthUser"]=UrlDecode($parameters["user"]);
 545            if(!IsSet($parameters["pass"]))
 546                $arguments["AuthPassword"]="";
 547        }
 548        if (IsSet($parameters["pass"])) {
 549            if(!IsSet($parameters["user"]))
 550                $arguments["AuthUser"]="";
 551            $arguments["AuthPassword"]=UrlDecode($parameters["pass"]);
 552        }
 553        if (IsSet($parameters["port"])) {
 554            if(strcmp($parameters["port"],strval(intval($parameters["port"]))))
 555                return($this->SetError("it was not specified a valid connection host argument", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
 556            $arguments["HostPort"]=intval($parameters["port"]);
 557        } else
 558            $arguments["HostPort"]=0;
 559        $arguments["RequestURI"]=(IsSet($parameters["path"]) ? $parameters["path"] : "/").(IsSet($parameters["query"]) ? "?".$parameters["query"] : "");
 560        if(strlen($this->user_agent))
 561            $arguments["Headers"]["User-Agent"]=$this->user_agent;
 562        if(strlen($this->accept))
 563            $arguments["Headers"]["Accept"]=$this->accept;
 564        return("");
 565    }
 566
 567    public Function Open($arguments)
 568    {
 569        if(strlen($this->error))
 570            return($this->error);
 571        $error_code = HTTP_CLIENT_ERROR_UNSPECIFIED_ERROR;
 572        if(IsSet($arguments["HostName"]))
 573            $this->host_name=$arguments["HostName"];
 574        if(IsSet($arguments["HostPort"]))
 575            $this->host_port=$arguments["HostPort"];
 576        if(IsSet($arguments["ProxyHostName"]))
 577            $this->proxy_host_name=$arguments["ProxyHostName"];
 578        if(IsSet($arguments["ProxyHostPort"]))
 579            $this->proxy_host_port=$arguments["ProxyHostPort"];
 580        if(IsSet($arguments["SOCKSHostName"]))
 581            $this->socks_host_name=$arguments["SOCKSHostName"];
 582        if(IsSet($arguments["SOCKSHostPort"]))
 583            $this->socks_host_port=$arguments["SOCKSHostPort"];
 584        if(IsSet($arguments["SOCKSVersion"]))
 585            $this->socks_version=$arguments["SOCKSVersion"];
 586        if(IsSet($arguments["Protocol"]))
 587            $this->protocol=$arguments["Protocol"];
 588        switch (strtolower($this->protocol)) {
 589            case "http":
 590                $default_port=80;
 591                break;
 592            case "https":
 593                $default_port=443;
 594                break;
 595            default:
 596                return($this->SetError("it was not specified a valid connection protocol", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
 597        }
 598        if (strlen($this->proxy_host_name)==0) {
 599            if(strlen($this->host_name)==0)
 600                return($this->SetError("it was not specified a valid hostname", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
 601            $host_name=$this->host_name;
 602            $host_port=($this->host_port ? $this->host_port : $default_port);
 603            $server_type = 'HTTP';
 604        } else {
 605            $host_name=$this->proxy_host_name;
 606            $host_port=$this->proxy_host_port;
 607            $server_type = 'HTTP proxy';
 608        }
 609        $ssl=(strtolower($this->protocol)=="https" && strlen($this->proxy_host_name)==0);
 610        if($ssl
 611        && strlen($this->socks_host_name))
 612            return($this->SetError('establishing SSL connections via a SOCKS server is not yet supported', HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
 613        $this->use_curl=($ssl && $this->prefer_curl && function_exists("curl_init"));
 614        switch ($this->state) {
 615            case 'Connected':
 616                if(!strcmp($host_name, $this->connected_host)
 617                && intval($host_port) == $this->connected_port
 618                && intval($ssl) == $this->connected_ssl)
 619                {
 620                    if($this->debug)
 621                        $this->OutputDebug("Reusing connection to ".$this->connected_host);
 622                    return('');
 623                }
 624                if(strlen($error = $this->Disconnect()))
 625                    return($error);
 626            case "Disconnected":
 627                break;
 628            default:
 629                return("1 already connected");
 630        }
 631        if($this->debug)
 632            $this->OutputDebug("Connecting to ".$this->host_name);
 633        if ($this->use_curl) {
 634            $error=(($this->connection=curl_init($this->protocol."://".$this->host_name.($host_port==$default_port ? "" : ":".strval($host_port))."/")) ? "" : "Could not initialize a CURL session");
 635            if (strlen($error)==0) {
 636                if(IsSet($arguments["SSLCertificateFile"]))
 637                    curl_setopt($this->connection,CURLOPT_SSLCERT,$arguments["SSLCertificateFile"]);
 638                if(IsSet($arguments["SSLCertificatePassword"]))
 639                    curl_setopt($this->connection,CURLOPT_SSLCERTPASSWD,$arguments["SSLCertificatePassword"]);
 640                if(IsSet($arguments["SSLKeyFile"]))
 641                    curl_setopt($this->connection,CURLOPT_SSLKEY,$arguments["SSLKeyFile"]);
 642                if(IsSet($arguments["SSLKeyPassword"]))
 643                    curl_setopt($this->connection,CURLOPT_SSLKEYPASSWD,$arguments["SSLKeyPassword"]);
 644            }
 645            $this->state="Connected";
 646        } else {
 647            $error="";
 648            if(strlen($this->proxy_host_name)
 649            && (IsSet($arguments["SSLCertificateFile"])
 650            || IsSet($arguments["SSLCertificateFile"])))
 651                $error="establishing SSL connections using certificates or private keys via non-SSL proxies is not supported";
 652            else {
 653                if ($ssl) {
 654                    if(IsSet($arguments["SSLCertificateFile"]))
 655                        $error="establishing SSL connections using certificates is only supported when the cURL extension is enabled";
 656                    elseif(IsSet($arguments["SSLKeyFile"]))
 657                        $error="establishing SSL connections using a private key is only supported when the cURL extension is enabled";
 658                    else {
 659                        $version=explode(".",function_exists("phpversion") ? phpversion() : "3.0.7");
 660                        $php_version=intval($version[0])*1000000+intval($version[1])*1000+intval($version[2]);
 661                        if($php_version<4003000)
 662                            $error="establishing SSL connections requires at least PHP version 4.3.0 or having the cURL extension enabled";
 663                        elseif(!function_exists("extension_loaded")
 664                        || !extension_loaded("openssl"))
 665                            $error="establishing SSL connections requires the OpenSSL extension enabled";
 666                    }
 667                }
 668                if (strlen($error)==0) {
 669                    $error=$this->Connect($host_name, $host_port, $ssl, $server_type);
 670                    $error_code = $this->error_code;
 671                }
 672            }
 673        }
 674        if(strlen($error))
 675            return($this->SetError($error, $error_code));
 676        $this->session=md5(uniqid(""));
 677        $this->connected_host = $host_name;
 678        $this->connected_port = intval($host_port);
 679        $this->connected_ssl = intval($ssl);
 680        return("");
 681    }
 682
 683    public Function Close($force = 0)
 684    {
 685        if($this->state=="Disconnected")
 686            return("1 already disconnected");
 687        if(!$this->force_close
 688        && $this->keep_alive
 689        && !$force
 690        && $this->state == 'ResponseReceived')
 691        {
 692            if($this->debug)
 693                $this->OutputDebug('Keeping the connection alive to '.$this->connected_host);
 694            $this->state = 'Connected';
 695            return('');
 696        }
 697        return($this->Disconnect());
 698    }
 699
 700    public Function PickCookies(&$cookies,$secure)
 701    {
 702        if (IsSet($this->cookies[$secure])) {
 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                $domain_pattern=Key($this->cookies[$secure]);
 706                $match=strlen($this->request_host)-strlen($domain_pattern);
 707                if($match>=0
 708                && !strcmp($domain_pattern,substr($this->request_host,$match))
 709                && ($match==0
 710                || $domain_pattern[0]=="."
 711                || $this->request_host[$match-1]=="."))
 712                {
 713                    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++) {
 714                        $path=Key($this->cookies[$secure][$domain_pattern]);
 715                        if(strlen($this->request_uri)>=strlen($path)
 716                        && substr($this->request_uri,0,strlen($path))==$path)
 717                        {
 718                            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++) {
 719                                $cookie_name=Key($this->cookies[$secure][$domain_pattern][$path]);
 720                                $expires=$this->cookies[$secure][$domain_pattern][$path][$cookie_name]["expires"];
 721                                if($expires==""
 722                                || strcmp($now,$expires)<0)
 723                                    $cookies[$cookie_name]=$this->cookies[$secure][$domain_pattern][$path][$cookie_name];
 724                            }
 725                        }
 726                    }
 727                }
 728            }
 729        }
 730    }
 731
 732    public Function GetFileDefinition($file, &$definition)
 733    {
 734        $name="";
 735        if(IsSet($file["FileName"]))
 736            $name=basename($file["FileName"]);
 737        if(IsSet($file["Name"]))
 738            $name=$file["Name"];
 739        if(strlen($name)==0)
 740            return("it was not specified the file part name");
 741        if (IsSet($file["Content-Type"])) {
 742            $content_type=$file["Content-Type"];
 743            $type=$this->Tokenize(strtolower($content_type),"/");
 744            $sub_type=$this->Tokenize("");
 745            switch ($type) {
 746                case "text":
 747                case "image":
 748                case "audio":
 749                case "video":
 750                case "application":
 751                case "message":
 752                    break;
 753                case "automatic":
 754                    switch ($sub_type) {
 755                        case "name":
 756                            switch (GetType($dot=strrpos($name,"."))=="integer" ? strtolower(substr($name,$dot)) : "") {
 757                                case ".xls":
 758                                    $content_type="application/excel";
 759                                    break;
 760                                case ".hqx":
 761                                    $content_type="application/macbinhex40";
 762                                    break;
 763                                case ".doc":
 764                                case ".dot":
 765                                case ".wrd":
 766                                    $content_type="application/msword";
 767                                    break;
 768                                case ".pdf":
 769                                    $content_type="application/pdf";
 770                                    break;
 771                                case ".pgp":
 772                                    $content_type="application/pgp";
 773                                    break;
 774                                case ".ps":
 775                                case ".eps":
 776                                case ".ai":
 777                                    $content_type="application/postscript";
 778                                    break;
 779                                case ".ppt":
 780                                    $content_type="application/powerpoint";
 781                                    break;
 782                                case ".rtf":
 783                                    $content_type="application/rtf";
 784                                    break;
 785                                case ".tgz":
 786                                case ".gtar":
 787                                    $content_type="application/x-gtar";
 788                                    break;
 789                                case ".gz":
 790                                    $content_type="application/x-gzip";
 791                                    break;
 792                                case ".php":
 793                                case ".php3":
 794                                    $content_type="application/x-httpd-php";
 795                                    break;
 796                                case ".js":
 797                                    $content_type="application/x-javascript";
 798                                    break;
 799                                case ".ppd":
 800                                case ".psd":
 801                                    $content_type="application/x-photoshop";
 802                                    break;
 803                                case ".swf":
 804                                case ".swc":
 805                                case ".rf":
 806                                    $content_type="application/x-shockwave-flash";
 807                                    break;
 808                                case ".tar":
 809                                    $content_type="application/x-tar";
 810                                    break;
 811                                case ".zip":
 812                                    $content_type="application/zip";
 813                                    break;
 814                                case ".mid":
 815                                case ".midi":
 816                                case ".kar":
 817                                    $content_type="audio/midi";
 818                                    break;
 819                                case ".mp2":
 820                                case ".mp3":
 821                                case ".mpga":
 822                                    $content_type="audio/mpeg";
 823                                    break;
 824                                case ".ra":
 825                                    $content_type="audio/x-realaudio";
 826                                    break;
 827                                case ".wav":
 828                                    $content_type="audio/wav";
 829                                    break;
 830                                case ".bmp":
 831                                    $content_type="image/bitmap";
 832                                    break;
 833                                case ".gif":
 834                                    $content_type="image/gif";
 835                                    break;
 836                                case ".iff":
 837                                    $content_type="image/iff";
 838                                    break;
 839                                case ".jb2":
 840                                    $content_type="image/jb2";
 841                                    break;
 842                                case ".jpg":
 843                                case ".jpe":
 844                                case ".jpeg":
 845                                    $content_type="image/jpeg";
 846                                    break;
 847                                case ".jpx":
 848                                    $content_type="image/jpx";
 849                                    break;
 850                                case ".png":
 851                                    $content_type="image/png";
 852                                    break;
 853                                case ".tif":
 854                                case ".tiff":
 855                                    $content_type="image/tiff";
 856                                    break;
 857                                case ".wbmp":
 858                                    $content_type="image/vnd.wap.wbmp";
 859                                    break;
 860                                case ".xbm":
 861                                    $content_type="image/xbm";
 862                                    break;
 863                                case ".css":
 864                                    $content_type="text/css";
 865                                    break;
 866                                case ".txt":
 867                                    $content_type="text/plain";
 868                                    break;
 869                                case ".htm":
 870                                case ".html":
 871                                    $content_type="text/html";
 872                                    break;
 873                                case ".xml":
 874                                    $content_type="text/xml";
 875                                    break;
 876                                case ".mpg":
 877                                case ".mpe":
 878                                case ".mpeg":
 879                                    $content_type="video/mpeg";
 880                                    break;
 881                                case ".qt":
 882                                case ".mov":
 883                                    $content_type="video/quicktime";
 884                                    break;
 885                                case ".avi":
 886                                    $content_type="video/x-ms-video";
 887                                    break;
 888                                case ".eml":
 889                                    $content_type="message/rfc822";
 890                                    break;
 891                                default:
 892                                    $content_type="application/octet-stream";
 893                                    break;
 894                            }
 895                            break;
 896                        default:
 897                            return($content_type." is not a supported automatic content type detection method");
 898                    }
 899                    break;
 900                default:
 901                    return($content_type." is not a supported file content type");
 902            }
 903        } else
 904            $content_type="application/octet-stream";
 905        $definition=array(
 906            "Content-Type"=>$content_type,
 907            "NAME"=>$name
 908        );
 909        if (IsSet($file["FileName"])) {
 910            if (GetType($length=@filesize($file["FileName"]))!="integer") {
 911                $error="it was not possible to determine the length of the file ".$file["FileName"];
 912                if(IsSet($php_errormsg)
 913                && strlen($php_errormsg))
 914                    $error.=": ".$php_errormsg;
 915                if(!file_exists($file["FileName"]))
 916                    $error="it was not possible to access the file ".$file["FileName"];
 917                return($error);
 918            }
 919            $definition["FILENAME"]=$file["FileName"];
 920            $definition["Content-Length"]=$length;
 921        } elseif(IsSet($file["Data"]))
 922            $definition["Content-Length"]=strlen($definition["DATA"]=$file["Data"]);
 923        else
 924            return("it was not specified a valid file name");
 925        return("");
 926    }
 927
 928    public Function ConnectFromProxy($arguments, &$headers)
 929    {
 930        if(!$this->PutLine('CONNECT '.$this->host_name.':'.($this->host_port ? $this->host_port : 443).' HTTP/1.0')
 931        || (strlen($this->user_agent)
 932        && !$this->PutLine('User-Agent: '.$this->user_agent))
 933        || (strlen($this->accept)
 934        && !$this->PutLine('Accept: '.$this->accept))
 935        || (IsSet($arguments['Headers']['Proxy-Authorization'])
 936        && !$this->PutLine('Proxy-Authorization: '.$arguments['Headers']['Proxy-Authorization']))
 937        || !$this->PutLine(''))
 938        {
 939            $this->Disconnect();
 940            return($this->error);
 941        }
 942        $this->state = "ConnectSent";
 943        if(strlen($error=$this->ReadReplyHeadersResponse($headers)))
 944            return($error);
 945        $proxy_authorization="";
 946        while (!strcmp($this->response_status, "100")) {
 947            $this->state="ConnectSent";
 948            if(strlen($error=$this->ReadReplyHeadersResponse($headers)))
 949                return($error);
 950        }
 951        switch ($this->response_status) {
 952            case "200":
 953                if (!@stream_socket_enable_crypto($this->connection, 1, STREAM_CRYPTO_METHOD_SSLv23_CLIENT)) {
 954                    $this->SetPHPError('it was not possible to start a SSL encrypted connection via this proxy', $php_errormsg, HTTP_CLIENT_ERROR_COMMUNICATION_FAILURE);
 955                    $this->Disconnect();
 956                    return($this->error);
 957                }
 958                $this->state = "Connected";
 959                break;
 960            case "407":
 961                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)))
 962                    return($error);
 963                break;
 964            default:
 965                return($this->SetError("unable to send request via proxy", HTTP_CLIENT_ERROR_PROTOCOL_FAILURE));
 966        }
 967        return("");
 968    }
 969
 970    public Function SendRequest($arguments)
 971    {
 972        if(strlen($this->error))
 973            return($this->error);
 974        if(IsSet($arguments["ProxyUser"]))
 975            $this->proxy_request_user=$arguments["ProxyUser"];
 976        elseif(IsSet($this->proxy_user))
 977            $this->proxy_request_user=$this->proxy_user;
 978        if(IsSet($arguments["ProxyPassword"]))
 979            $this->proxy_request_password=$arguments["ProxyPassword"];
 980        elseif(IsSet($this->proxy_password))
 981            $this->proxy_request_password=$this->proxy_password;
 982        if(IsSet($arguments["ProxyRealm"]))
 983            $this->proxy_request_realm=$arguments["ProxyRealm"];
 984        elseif(IsSet($this->proxy_realm))
 985            $this->proxy_request_realm=$this->proxy_realm;
 986        if(IsSet($arguments["ProxyWorkstation"]))
 987            $this->proxy_request_workstation=$arguments["ProxyWorkstation"];
 988        elseif(IsSet($this->proxy_workstation))
 989            $this->proxy_request_workstation=$this->proxy_workstation;
 990        switch ($this->state) {
 991            case "Disconnected":
 992                return($this->SetError("connection was not yet established", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
 993            case "Connected":
 994                $connect = 0;
 995                break;
 996            case "ConnectedToProxy":
 997                if(strlen($error = $this->ConnectFromProxy($arguments, $headers)))
 998                    return($error);
 999                $connect = 1;
1000                break;
1001            default:
1002                return($this->SetError("can not send request in the current connection state", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
1003        }
1004        if(IsSet($arguments["RequestMethod"]))
1005            $this->request_method=$arguments["RequestMethod"];
1006        if(IsSet($arguments["User-Agent"]))
1007            $this->user_agent=$arguments["User-Agent"];
1008        if(!IsSet($arguments["Headers"]["User-Agent"])
1009        && strlen($this->user_agent))
1010            $arguments["Headers"]["User-Agent"]=$this->user_agent;
1011        if(IsSet($arguments["KeepAlive"]))
1012            $this->keep_alive=intval($arguments["KeepAlive"]);
1013        if(!IsSet($arguments["Headers"]["Connection"])
1014        && $this->keep_alive)
1015            $arguments["Headers"]["Connection"]='Keep-Alive';
1016        if(IsSet($arguments["Accept"]))
1017            $this->user_agent=$arguments["Accept"];
1018        if(!IsSet($arguments["Headers"]["Accept"])
1019        && strlen($this->accept))
1020            $arguments["Headers"]["Accept"]=$this->accept;
1021        if(strlen($this->request_method)==0)
1022            return($this->SetError("it was not specified a valid request method", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
1023        if(IsSet($arguments["RequestURI"]))
1024            $this->request_uri=$arguments["RequestURI"];
1025        if(strlen($this->request_uri)==0
1026        || substr($this->request_uri,0,1)!="/")
1027            return($this->SetError("it was not specified a valid request URI", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
1028        $this->request_arguments=$arguments;
1029        $this->request_headers=(IsSet($arguments["Headers"]) ? $arguments["Headers"] : array());
1030        $body_length=0;
1031        $this->request_body="";
1032        $get_body=1;
1033        if($this->request_method=="POST"
1034        || $this->request_method=="PUT")
1035        {
1036            if (IsSet($arguments['StreamRequest'])) {
1037                $get_body = 0;
1038                $this->request_headers["Transfer-Encoding"]="chunked";
1039            } elseif(IsSet($arguments["PostFiles"])
1040            || ($this->force_multipart_form_post
1041            && IsSet($arguments["PostValues"])))
1042            {
1043                $boundary="--".md5(uniqid(time()));
1044                $this->request_headers["Content-Type"]="multipart/form-data; boundary=".$boundary.(IsSet($arguments["CharSet"]) ? "; charset=".$arguments["CharSet"] : "");
1045                $post_parts=array();
1046                if (IsSet($arguments["PostValues"])) {
1047                    $values=$arguments["PostValues"];
1048                    if(GetType($values)!="array")
1049                        return($this->SetError("it was not specified a valid POST method values array", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
1050                    for (Reset($values),$value=0;$value<count($values);Next($values),$value++) {
1051                        $input=Key($values);
1052                        $headers="--".$boundary."\r\nContent-Disposition: form-data; name=\"".$input."\"\r\n\r\n";
1053                        $data=$values[$input];
1054                        $post_parts[]=array("HEADERS"=>$headers,"DATA"=>$data);
1055                        $body_length+=strlen($headers)+strlen($data)+strlen("\r\n");
1056                    }
1057                }
1058                $body_length+=strlen("--".$boundary."--\r\n");
1059                $files=(IsSet($arguments["PostFiles"]) ? $arguments["PostFiles"] : array());
1060                Reset($files);
1061                $end=(GetType($input=Key($files))!="string");
1062                for (;!$end;) {
1063                    if(strlen($error=$this->GetFileDefinition($files[$input],$definition)))
1064                        return("3 ".$error);
1065                    $headers="--".$boundary."\r\nContent-Disposition: form-data; name=\"".$input."\"; filename=\"".$definition["NAME"]."\"\r\nContent-Type: ".$definition["Content-Type"]."\r\n\r\n";
1066                    $part=count($post_parts);
1067                    $post_parts[$part]=array("HEADERS"=>$headers);
1068                    if (IsSet($definition["FILENAME"])) {
1069                        $post_parts[$part]["FILENAME"]=$definition["FILENAME"];
1070                        $data="";
1071                    } else
1072                        $data=$definition["DATA"];
1073                    $post_parts[$part]["DATA"]=$data;
1074                    $body_length+=strlen($headers)+$definition["Content-Length"]+strlen("\r\n");
1075                    Next($files);
1076                    $end=(GetType($input=Key($files))!="string");
1077                }
1078                $get_body=0;
1079            } elseif (IsSet($arguments["PostValues"])) {
1080                $values=$arguments["PostValues"];
1081                if(GetType($values)!="array")
1082                    return($this->SetError("it was not specified a valid POST method values array", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
1083                for (Reset($values),$value=0;$value<count($values);Next($values),$value++) {
1084                    $k=Key($values);
1085                    if (GetType($values[$k])=="array") {
1086                        for ($v = 0; $v < count($values[$k]); $v++) {
1087                            if($value+$v>0)
1088                                $this->request_body.="&";
1089                            $this->request_body.=UrlEncode($k)."=".UrlEncode($values[$k][$v]);
1090                        }
1091                    } else {
1092                        if($value>0)
1093                            $this->request_body.="&";
1094                        $this->request_body.

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