/** * Parse the header content and return a new instance of the HTTPHeader class. * * @param string|array $content The raw header content * @param bool $lowerCase Whether cookies and headers should be referenced using a lower case key * * @return HTTPHeader[] An array of HTTPHeader instances containing the parsed data (One instance per header part) */ public static function parseHeader($content, $lowerCase = false) { $data = array(); if (!is_array($content)) { $content = explode("\r\n\r\n", $content); } foreach ($content as $header) { $header = trim($header); if (!$header) { continue; } $header = explode("\r\n", $header); $headerInstance = new HTTPHeader(); foreach ($header as $lineIndex => $line) { if ($lineIndex == 0) { if (preg_match("/^HTTP\\/([0-9\\.]+) ([0-9]+) (.*)/", $line, $matches)) { $headerInstance->version = $matches[1]; $headerInstance->statusCode = (int) $matches[2]; $headerInstance->statusText = $matches[3]; } continue; } $headerLine = explode(":", trim($line), 2); if (count($headerLine) < 2) { continue; } list($headerKey, $headerValue) = $headerLine; $headerKey = trim($headerKey); if (strtolower($headerKey) == "set-cookie") { $cookie = new HTTPCookie(); $cookie->parse($headerValue); if ($lowerCase) { $key = strtolower($cookie->name); } else { $key = $cookie->name; } $headerInstance->cookies[$key] = $cookie; } else { if ($lowerCase) { $headerKey = strtolower($headerKey); } $headerInstance->headers[$headerKey] = trim($headerValue); } } $data[] = $headerInstance; } return $data; }
/** * Set cookie for the application's client. * @param HTTPCookie $cookie */ public function set_cookie(HTTPCookie $cookie) { setcookie($cookie->get_name(), $cookie->get_value(), $cookie->get_expiration_date(), $cookie->get_path(), $cookie->get_domain(), $cookie->get_secure(), $cookie->get_httponly()); }
/** * 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; }