diff options
Diffstat (limited to 'vendor/fguillot/picofeed/lib/PicoFeed/Client/Stream.php')
m--------- | vendor/fguillot/picofeed | 0 | ||||
-rw-r--r-- | vendor/fguillot/picofeed/lib/PicoFeed/Client/Stream.php | 181 |
2 files changed, 181 insertions, 0 deletions
diff --git a/vendor/fguillot/picofeed b/vendor/fguillot/picofeed deleted file mode 160000 -Subproject 0a1d0d3950f7f047dc8fb1d80aa6296e15f306d diff --git a/vendor/fguillot/picofeed/lib/PicoFeed/Client/Stream.php b/vendor/fguillot/picofeed/lib/PicoFeed/Client/Stream.php new file mode 100644 index 000000000..b80e731d6 --- /dev/null +++ b/vendor/fguillot/picofeed/lib/PicoFeed/Client/Stream.php @@ -0,0 +1,181 @@ +<?php + +namespace PicoFeed\Client; + +use PicoFeed\Logging\Logger; + +/** + * Stream context HTTP client + * + * @author Frederic Guillot + * @package Client + */ +class Stream extends Client +{ + /** + * Prepare HTTP headers + * + * @access private + * @return string[] + */ + private function prepareHeaders() + { + $headers = array( + 'Connection: close', + 'User-Agent: '.$this->user_agent, + ); + + if (function_exists('gzdecode')) { + $headers[] = 'Accept-Encoding: gzip'; + } + + if ($this->etag) { + $headers[] = 'If-None-Match: '.$this->etag; + } + + if ($this->last_modified) { + $headers[] = 'If-Modified-Since: '.$this->last_modified; + } + + if ($this->proxy_username) { + $headers[] = 'Proxy-Authorization: Basic '.base64_encode($this->proxy_username.':'.$this->proxy_password); + } + + if ($this->username && $this->password) { + $headers[] = 'Authorization: Basic '.base64_encode($this->username.':'.$this->password); + } + + return $headers; + } + + /** + * Prepare stream context + * + * @access private + * @return array + */ + private function prepareContext() + { + $context = array( + 'http' => array( + 'method' => 'GET', + 'protocol_version' => 1.1, + 'timeout' => $this->timeout, + 'follow_location' => 0, + ) + ); + + if ($this->proxy_hostname) { + + Logger::setMessage(get_called_class().' Proxy: '.$this->proxy_hostname.':'.$this->proxy_port); + + $context['http']['proxy'] = 'tcp://'.$this->proxy_hostname.':'.$this->proxy_port; + $context['http']['request_fulluri'] = true; + + if ($this->proxy_username) { + Logger::setMessage(get_called_class().' Proxy credentials: Yes'); + } + else { + Logger::setMessage(get_called_class().' Proxy credentials: No'); + } + } + + $context['http']['header'] = implode("\r\n", $this->prepareHeaders()); + + return $context; + } + + /** + * Do the HTTP request + * + * @access public + * @param bool $follow_location Flag used when there is an open_basedir restriction + * @return array HTTP response ['body' => ..., 'status' => ..., 'headers' => ...] + */ + public function doRequest($follow_location = false) + { + // Create context + $context = stream_context_create($this->prepareContext()); + + // Make HTTP request + $stream = @fopen($this->url, 'r', false, $context); + if (! is_resource($stream)) { + throw new InvalidUrlException('Unable to establish a connection'); + } + + // Get the entire body until the max size + $body = stream_get_contents($stream, $this->max_body_size + 1); + + // If the body size is too large abort everything + if (strlen($body) > $this->max_body_size) { + throw new MaxSizeException('Content size too large'); + } + + // Get HTTP headers response + $metadata = stream_get_meta_data($stream); + + if ($metadata['timed_out']) { + throw new TimeoutException('Operation timeout'); + } + + list($status, $headers) = HttpHeaders::parse($metadata['wrapper_data']); + + fclose($stream); + + // Do redirect manual to get only the headers of the last request and + // the final url + if ($status == 301 || $status == 302) { + return $this->handleRedirection($headers['Location']); + } + + return array( + 'status' => $status, + 'body' => $this->decodeBody($body, $headers), + 'headers' => $headers + ); + } + + /** + * Decode body response according to the HTTP headers + * + * @access public + * @param string $body Raw body + * @param HttpHeaders $headers HTTP headers + * @return string + */ + public function decodeBody($body, HttpHeaders $headers) + { + if (isset($headers['Transfer-Encoding']) && $headers['Transfer-Encoding'] === 'chunked') { + $body = $this->decodeChunked($body); + } + + if (isset($headers['Content-Encoding']) && $headers['Content-Encoding'] === 'gzip') { + $body = @gzdecode($body); + } + + return $body; + } + + /** + * Decode a chunked body + * + * @access public + * @param string $str Raw body + * @return string Decoded body + */ + public function decodeChunked($str) + { + for ($result = ''; ! empty($str); $str = trim($str)) { + + // Get the chunk length + $pos = strpos($str, "\r\n"); + $len = hexdec(substr($str, 0, $pos)); + + // Append the chunk to the result + $result .= substr($str, $pos + 2, $len); + $str = substr($str, $pos + 2 + $len); + } + + return $result; + } +} |