miniflux-legacy/vendor/fguillot/picofeed/lib/PicoFeed/Client/Stream.php

210 lines
5.7 KiB
PHP
Raw Normal View History

2013-07-17 01:54:44 +02:00
<?php
namespace PicoFeed\Client;
2013-07-17 01:54:44 +02:00
use PicoFeed\Logging\Logger;
2013-07-17 01:54:44 +02:00
2014-03-17 02:35:57 +01:00
/**
* Stream context HTTP client
*
* @author Frederic Guillot
* @package Client
2014-03-17 02:35:57 +01:00
*/
2014-05-20 20:20:27 +02:00
class Stream extends Client
2013-07-17 01:54:44 +02:00
{
2014-03-17 02:35:57 +01:00
/**
2014-10-19 20:42:31 +02:00
* Prepare HTTP headers
2014-03-17 02:35:57 +01:00
*
2014-10-19 20:42:31 +02:00
* @access private
* @return string[]
2014-03-17 02:35:57 +01:00
*/
2014-10-19 20:42:31 +02:00
private function prepareHeaders()
2013-07-17 01:54:44 +02:00
{
$headers = array(
'Connection: close',
'User-Agent: '.$this->user_agent,
);
2015-02-06 03:16:34 +01:00
// disable compression in passthrough mode. It could result in double
// compressed content which isn't decodeable by browsers
if (function_exists('gzdecode') && ! $this->isPassthroughEnabled()) {
2014-05-20 20:20:27 +02:00
$headers[] = 'Accept-Encoding: gzip';
}
if ($this->etag) {
$headers[] = 'If-None-Match: '.$this->etag;
}
if ($this->last_modified) {
$headers[] = 'If-Modified-Since: '.$this->last_modified;
}
2013-07-17 01:54:44 +02:00
2014-10-19 20:42:31 +02:00
if ($this->proxy_username) {
$headers[] = 'Proxy-Authorization: Basic '.base64_encode($this->proxy_username.':'.$this->proxy_password);
}
2014-12-24 19:50:20 +01:00
if ($this->username && $this->password) {
$headers[] = 'Authorization: Basic '.base64_encode($this->username.':'.$this->password);
}
2015-04-11 02:34:48 +02:00
$headers = array_merge($headers, $this->request_headers);
2014-10-19 20:42:31 +02:00
return $headers;
}
2015-02-01 20:48:05 +01:00
/**
* Construct the final URL from location headers
*
* @access private
* @param array $headers List of HTTP response header
*/
private function setEffectiveUrl($headers)
{
foreach($headers as $header) {
if (stripos($header, 'Location') === 0) {
list($name, $value) = explode(': ', $header);
$this->url = Url::resolve($value, $this->url);
}
}
}
2014-10-19 20:42:31 +02:00
/**
* Prepare stream context
*
* @access private
* @return array
*/
private function prepareContext()
{
$context = array(
2013-07-17 01:54:44 +02:00
'http' => array(
'method' => 'GET',
'protocol_version' => 1.1,
'timeout' => $this->timeout,
2015-02-01 20:48:05 +01:00
'max_redirects' => $this->max_redirects,
2013-07-17 01:54:44 +02:00
)
);
2014-05-20 20:20:27 +02:00
if ($this->proxy_hostname) {
Logger::setMessage(get_called_class().' Proxy: '.$this->proxy_hostname.':'.$this->proxy_port);
2014-05-20 20:20:27 +02:00
2014-10-19 20:42:31 +02:00
$context['http']['proxy'] = 'tcp://'.$this->proxy_hostname.':'.$this->proxy_port;
$context['http']['request_fulluri'] = true;
2013-09-24 01:22:13 +02:00
2014-05-20 20:20:27 +02:00
if ($this->proxy_username) {
Logger::setMessage(get_called_class().' Proxy credentials: Yes');
2013-09-24 01:22:13 +02:00
}
2014-05-20 20:20:27 +02:00
else {
Logger::setMessage(get_called_class().' Proxy credentials: No');
2014-05-20 20:20:27 +02:00
}
2013-09-24 01:22:13 +02:00
}
2014-10-19 20:42:31 +02:00
$context['http']['header'] = implode("\r\n", $this->prepareHeaders());
return $context;
}
/**
* Do the HTTP request
*
* @access public
2015-02-01 20:48:05 +01:00
* @return array HTTP response ['body' => ..., 'status' => ..., 'headers' => ...]
2014-10-19 20:42:31 +02:00
*/
2015-02-01 20:48:05 +01:00
public function doRequest()
2014-10-19 20:42:31 +02:00
{
2015-02-06 03:16:34 +01:00
$body = '';
2014-10-19 20:42:31 +02:00
// Create context
$context = stream_context_create($this->prepareContext());
2013-07-17 01:54:44 +02:00
// Make HTTP request
$stream = @fopen($this->url, 'r', false, $context);
2014-10-19 20:42:31 +02:00
if (! is_resource($stream)) {
throw new InvalidUrlException('Unable to establish a connection');
2014-10-19 20:42:31 +02:00
}
2013-07-17 01:54:44 +02:00
// Get HTTP headers response
$metadata = stream_get_meta_data($stream);
2015-02-06 03:16:34 +01:00
list($status, $headers) = HttpHeaders::parse($metadata['wrapper_data']);
2013-07-17 01:54:44 +02:00
2015-02-06 03:16:34 +01:00
if ($this->isPassthroughEnabled()) {
header(':', true, $status);
if (isset($headers['Content-Type'])) {
header('Content-Type: '.$headers['Content-Type']);
}
2015-02-01 20:48:05 +01:00
2015-02-06 03:16:34 +01:00
fpassthru($stream);
}
2015-02-06 03:16:34 +01:00
else {
// Get the entire body until the max size
$body = stream_get_contents($stream, $this->max_body_size + 1);
2015-02-06 03:16:34 +01:00
// If the body size is too large abort everything
if (strlen($body) > $this->max_body_size) {
throw new MaxSizeException('Content size too large');
}
2013-07-17 01:54:44 +02:00
2015-02-06 03:16:34 +01:00
if ($metadata['timed_out']) {
throw new TimeoutException('Operation timeout');
}
}
fclose($stream);
$this->setEffectiveUrl($metadata['wrapper_data']);
2015-01-28 02:13:16 +01:00
2014-10-19 20:42:31 +02:00
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
2014-10-19 20:42:31 +02:00
* @return string
*/
public function decodeBody($body, HttpHeaders $headers)
2014-10-19 20:42:31 +02:00
{
if (isset($headers['Transfer-Encoding']) && $headers['Transfer-Encoding'] === 'chunked') {
$body = $this->decodeChunked($body);
}
2014-03-17 02:35:57 +01:00
if (isset($headers['Content-Encoding']) && $headers['Content-Encoding'] === 'gzip') {
$body = @gzdecode($body);
2014-03-17 02:35:57 +01:00
}
2014-10-19 20:42:31 +02:00
return $body;
2013-07-17 01:54:44 +02:00
}
2014-03-17 02:35:57 +01:00
/**
* 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;
}
2014-03-17 02:35:57 +01:00
}