Esempio n. 1
0
File: net.php Progetto: poppa/PLib
 /**
  * Do an arbitrary HTTP action
  *
  * @throws HTTPMaxRedirectException
  * @throws HTTPRequestException
  * @throws HTTPResponseException
  *
  * @param string $method
  *  What method to use: `GET`, `POST`, `PROPPATCH`...
  * @param string $url
  *  Where to send the request. A full URI: http://server.com/path/
  * @param array $vars
  *  Query variables to send. An associative array with key/value pairs
  * @param array $headers
  *  Additional request headers
  * @param string $data
  *  Data to send as raw data in a SOAP call for instance
  *
  * @return HTTPResponse
  */
 public function do_method($method, $uri, $vars = array(), $headers = array(), $data = null)
 {
     $host = null;
     $port = null;
     $path = null;
     $query = null;
     $body = null;
     $sock = null;
     $method = strtoupper($method);
     if ($this->recursions >= $this->max_redirects) {
         throw new HTTPMaxRedirectException("Redirect limit ({$this->max_redirects}) exceeded!");
     }
     $request = array();
     // It's an assignment
     if (!($request = parse_url($uri))) {
         throw new HTTPRequestException("Bad URL ({$uri}) as argument");
     }
     if (!isset($request['host'])) {
         throw new HTTPRequestException("Missing host in URL ({$uri}) argument");
     }
     $port = 0;
     $protocol = isset($request['scheme']) ? $request['scheme'] : false;
     if ($protocol != 'http') {
         switch ($protocol) {
             case 'https':
                 if (!isset($request['port'])) {
                     $port = 443;
                 }
                 break;
         }
     }
     $host = $request['host'];
     $query = isset($request['query']) ? $request['query'] : null;
     if (!$port) {
         $port = isset($request['port']) ? (int) $request['port'] : 80;
     }
     if (isset($request['user'])) {
         $this->username = $request['user'];
     }
     if (isset($request['pass'])) {
         $this->password = $request['pass'];
     }
     if (!empty($vars)) {
         $query = http_build_query($vars);
     }
     //! Default the request path to root
     $path = isset($request['path']) ? $request['path'] : '/';
     $add_header = "";
     if (!empty($headers)) {
         $this->request_headers = $headers + $this->request_headers;
     }
     foreach ($this->request_headers as $key => $val) {
         if (!is_string($key)) {
             throw new HTTPRequestException("Malformed header, missing key.");
         }
         if (empty($val)) {
             throw new HTTPRequestException("Malformed header, missing value " . "for key \"{$key}\"");
         }
         //! Due to a bug in PHP5.2?
         if ($key == 'Accept-Encoding') {
             continue;
         }
         $add_header .= "{$key}: {$val}\r\n";
     }
     if ($this->username && $this->password) {
         $add_header .= "Authorization: Basic " . base64_encode($this->username . ':' . $this->password);
     }
     if ($this->cookie) {
         $c = $this->cookie->create_header($port == 443, $host, $path);
         if ($c !== false) {
             $add_header .= $c;
         }
     }
     switch ($method) {
         case 'GET':
             $path .= $query ? '?' . $query : '';
             break;
         case 'POST':
             $body = empty($data) ? $query : urlencode($data);
             if (!isset($this->headers['Content-Type'])) {
                 $add_header .= "Content-Type: application/x-www-form-urlencoded\r\n";
             }
             $add_header .= "Content-Length: " . strlen($body) . "\r\n\r\n" . $body;
             break;
         default:
             $body = $data;
             if (!isset($this->headers['Content-Type'])) {
                 $add_header .= "Content-Type: text/plain\r\n";
             }
             $add_header .= "Content-Length: " . strlen($body) . "\r\n\r\n" . $body;
             break;
     }
     $header = "{$method} {$path} HTTP/{$this->version}\r\n" . "Host: {$host}\r\n{$add_header}\r\n";
     // print ($header);
     $rawresponse = false;
     if ($this->cache > 0) {
         $rawresponse = $this->get_cache($header);
     }
     if ($rawresponse === false) {
         $errno = 0;
         $errstr = null;
         $proto = 'tcp';
         switch ($protocol) {
             case 'https':
                 $proto = 'ssl';
                 break;
             case 'ftp':
                 $proto = 'ftp';
                 break;
         }
         //echo "+ Request: $proto://$host:$port$path\n";
         if (!($sock = @stream_socket_client("{$proto}://{$host}:{$port}", $errno, $errstr, $this->timeout))) {
             $m = "Couldn't fetch {$host}! {$errstr} (errno: {$errno})";
             throw new HTTPRequestException($m);
         }
         if (!is_resource($sock)) {
             throw new HTTPRequestException("Couldn't connect to {$host}");
         }
         fputs($sock, $header);
         $rawresponse = "";
         while (!feof($sock)) {
             $rawresponse .= fgets($sock, 512);
         }
     } else {
         $rawresponse = file_get_contents($rawresponse);
     }
     $resp = new HTTPResponse($rawresponse);
     $cookie = null;
     // It's an assignment
     if ($this->cookie && ($cookie = $resp->get_header('set-cookie'))) {
         $this->cookie->set($host, $cookie);
     }
     $status = $resp->status();
     if ($status != 200) {
         //print_r ($resp);
         if ($status == 302 || $status == 301) {
             $location = $resp->get_header('location');
             if ($location != $path && !strpos($location, '://')) {
                 $url = $protocol . "://" . $host . $location;
             } else {
                 $url = $location;
             }
             $headers["Referer"] = $url;
             if ($cookie) {
                 $headers["Cookie"] = $cookie;
             }
             $this->recursions++;
             $vars = array();
             //print_r ($headers);
             return $this->do_method($method, $url, $vars, $headers, $data);
         }
     }
     if ($this->cache > 0) {
         $this->write_cache($header, $rawresponse, $resp->status());
     }
     $this->recursions = 0;
     return $resp;
 }