/** * 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; }