From 3aa223946bbad0cbada74adf072b9869a0281a8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20FIDRY?= Date: Thu, 1 Jun 2017 22:45:22 +0100 Subject: [PATCH] Update API doc and deprecations (#19) --- composer.json | 5 +- src/{Humbug => }/FileGetContents.php | 127 +++++++++++++++++++++------ src/function.php | 43 +++++---- src/functions.php | 68 ++++++++++++++ 4 files changed, 192 insertions(+), 51 deletions(-) rename src/{Humbug => }/FileGetContents.php (71%) create mode 100644 src/functions.php diff --git a/composer.json b/composer.json index c4dbaf3..d00ddea 100644 --- a/composer.json +++ b/composer.json @@ -25,10 +25,11 @@ "autoload": { "psr-4": { - "Humbug\\": "src/Humbug/" + "Humbug\\": "src/" }, "files": [ - "src/function.php" + "src/function.php", + "src/functions.php" ] }, "autoload-dev": { diff --git a/src/Humbug/FileGetContents.php b/src/FileGetContents.php similarity index 71% rename from src/Humbug/FileGetContents.php rename to src/FileGetContents.php index 3c3865a..1c4230e 100644 --- a/src/Humbug/FileGetContents.php +++ b/src/FileGetContents.php @@ -19,8 +19,18 @@ */ class FileGetContents { + /** + * @var array|null + * + * @private + */ protected static $lastResponseHeaders; + /** + * @var array|null + * + * @private + */ protected static $nextRequestHeaders; protected $options = array('http' => array()); @@ -31,36 +41,68 @@ public function __construct() $this->options = array_replace_recursive($this->options, $options); } + /** + * @param string $filename Name of the file to read. + * @param resource|array|null $context A valid context resource created with `stream_context_create()`. If you don't + * need to use a custom context, you can skip this parameter. + * + * @return bool|string The read data or `false` on failure. + */ public function get($filename, $context = null) { $context = $this->getStreamContext($filename); - self::setHttpHeaders($context); + $context = self::setHttpHeaders($context); + $result = file_get_contents($filename, null, $context); + self::setLastResponseHeaders($http_response_header); return $result; } + /** + * @param array $headers HTTP response headers. + * + * @final Since 1.1.0 + */ public static function setLastResponseHeaders($headers) { self::$lastResponseHeaders = $headers; } + /** + * @return array|null HTTP response headers for the last response recorded or `null` if none has been recorded. + * + * @final Since 1.1.0 + */ public static function getLastResponseHeaders() { return self::$lastResponseHeaders; } - + + /** + * @param array $headers An indexed or associative array. + * + * @final since 1.1.0 + */ public static function setNextRequestHeaders(array $headers) { self::$nextRequestHeaders = $headers; } + /** + * @return bool + * + * @final since 1.1.0 + */ public static function hasNextRequestHeaders() { - return !empty(self::$nextRequestHeaders); + return null !== self::$nextRequestHeaders; } + /** + * @return array|null An indexed or associative array whence there is any headers, `null` otherwise. + */ public static function getNextRequestHeaders() { $return = self::$nextRequestHeaders; @@ -69,33 +111,56 @@ public static function getNextRequestHeaders() return $return; } + /** + * @param resource|array|null $context A valid context resource created with `stream_context_create()`. If you don't + * need to use a custom context, you can skip this parameter. + * + * @return resource|array|null Context to which the headers has been set. + * + * @private since 1.1.0 + * + * TODO (2.0.0): change the name to reflect on the immutable side. + */ public static function setHttpHeaders($context) { $headers = self::getNextRequestHeaders(); - if (!empty($headers)) { - $options = stream_context_get_options($context); - if (!isset($options['http'])) { - $options['http'] = array('header'=>array()); - } elseif (!isset($options['http']['header'])) { - $options['http']['header'] = array(); - } elseif (is_string($options['http']['header'])) { - $options['http']['header'] = explode("\r\n", $options['http']['header']); - } - $headers = empty($options['http']['headers']) ? $headers : array_merge($options['http']['headers'], $headers); - stream_context_set_option( - $context, - 'http', - 'header', - $headers - ); + + if (empty($headers)) { + return $context; + } + + $options = stream_context_get_options($context); + if (!isset($options['http'])) { + $options['http'] = array('header' => array()); + } elseif (!isset($options['http']['header'])) { + $options['http']['header'] = array(); + } elseif (is_string($options['http']['header'])) { + $options['http']['header'] = explode("\r\n", $options['http']['header']); } + $headers = empty($options['http']['headers']) ? $headers : array_merge($options['http']['headers'], $headers); + + stream_context_set_option( + $context, + 'http', + 'header', + $headers + ); + return $context; } + /** + * @param string $url URL path to access to the file to read. + * + * @return resource + * + * @final since 1.1.0 + */ protected function getStreamContext($url) { $host = parse_url($url, PHP_URL_HOST); + if (PHP_VERSION_ID < 50600) { $this->options['ssl']['CN_match'] = $host; $this->options['ssl']['SNI_server_name'] = $host; @@ -110,6 +175,9 @@ protected function getStreamContext($url) * @return array * * @private since 1.1.0 + * + * TODO (2.0.0): remove argument (unnused in the codebase) and rename this method as an `init*` as is used in the + * constructor anymore */ protected function getTlsStreamContextDefaults($cafile) { @@ -198,6 +266,8 @@ protected function getTlsStreamContextDefaults($cafile) * @throws \RuntimeException If https proxy required and OpenSSL uninstalled * * @return resource Default context + * + * @final since 1.1.0 */ protected function getMergedStreamContext($url) { @@ -210,11 +280,11 @@ protected function getMergedStreamContext($url) } if (!empty($proxy)) { - $proxyURL = isset($proxy['scheme']) ? $proxy['scheme'] . '://' : ''; + $proxyURL = isset($proxy['scheme']) ? $proxy['scheme'].'://' : ''; $proxyURL .= isset($proxy['host']) ? $proxy['host'] : ''; if (isset($proxy['port'])) { - $proxyURL .= ':' . $proxy['port']; + $proxyURL .= ':'.$proxy['port']; } elseif ('http://' == substr($proxyURL, 0, 7)) { $proxyURL .= ':80'; } elseif ('https://' == substr($proxyURL, 0, 8)) { @@ -229,7 +299,7 @@ protected function getMergedStreamContext($url) } $options['http'] = array( - 'proxy' => $proxyURL, + 'proxy' => $proxyURL, ); // enabled request_fulluri unless it is explicitly disabled @@ -252,7 +322,7 @@ protected function getMergedStreamContext($url) if (isset($proxy['user'])) { $auth = urldecode($proxy['user']); if (isset($proxy['pass'])) { - $auth .= ':' . urldecode($proxy['pass']); + $auth .= ':'.urldecode($proxy['pass']); } $auth = base64_encode($auth); @@ -264,19 +334,24 @@ protected function getMergedStreamContext($url) } /** - * @deprecated + * @deprecated since 1.1.0 and will be removed in 2.0.0. */ public static function getSystemCaRootBundlePath() { + @trigger_error( + 'Deprecated since 1.1.0. Use `Composer\CaBundle\CaBundle::getSystemCaRootBundlePath()` instead.', + E_USER_DEPRECATED + ); + return CaBundle::getSystemCaRootBundlePath(); } /** - * @deprecated + * @deprecated since 1.1.0 and will be removed in 2.0.0. */ protected static function validateCaFile($contents) { - // assume the CA is valid if php is vulnerable to + // Assumes the CA is valid if PHP is vulnerable to // https://www.sektioneins.de/advisories/advisory-012013-php-openssl_x509_parse-memory-corruption-vulnerability.html if (!CaBundle::isOpensslParseSafe()) { return !empty($contents); diff --git a/src/function.php b/src/function.php index 5bb7811..4badafc 100644 --- a/src/function.php +++ b/src/function.php @@ -9,44 +9,41 @@ * file that was distributed with this source code. */ -use Humbug\FileGetContents; - if (!function_exists('humbug_get_contents')) { function humbug_get_contents($filename, $use_include_path = false, $context = null) { - static $fileGetContents = null; - - if ('https' == parse_url($filename, PHP_URL_SCHEME) && PHP_VERSION_ID < 50600) { - if (!isset($fileGetContents)) { - $fileGetContents = new FileGetContents(); - } - - return $fileGetContents->get($filename, $context); - } elseif (FileGetContents::hasNextRequestHeaders()) { - if ($context === null) { - $context = stream_context_create(); - } - $context = FileGetContents::setHttpHeaders($context); - } - $return = file_get_contents($filename, $use_include_path, $context); - if (isset($http_response_header)) { - FileGetContents::setLastResponseHeaders($http_response_header); - } + @trigger_error( + 'humbug_get_contents() is deprecated since 1.1.0 and will be removed in 4.0.0. Use ' + .'Humbug/get_contents() instead.', + E_USER_DEPRECATED + ); - return $return; + return Humbug\get_contents($filename, $use_include_path, $context); } } if (!function_exists('humbug_get_headers')) { function humbug_get_headers() { - return FileGetContents::getLastResponseHeaders(); + @trigger_error( + 'humbug_get_headers() is deprecated since 1.1.0 and will be removed in 4.0.0. Use ' + .'Humbug/get_headers() instead.', + E_USER_DEPRECATED + ); + + return Humbug\get_headers(); } } if (!function_exists('humbug_set_headers')) { function humbug_set_headers(array $headers) { - FileGetContents::setNextRequestHeaders($headers); + @trigger_error( + 'humbug_set_headers() is deprecated since 1.1.0 and will be removed in 4.0.0. Use ' + .'Humbug/get_headers() instead.', + E_USER_DEPRECATED + ); + + Humbug\set_headers($headers); } } diff --git a/src/functions.php b/src/functions.php new file mode 100644 index 0000000..897e57a --- /dev/null +++ b/src/functions.php @@ -0,0 +1,68 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Humbug; + +/** + * Reads entire file into a string. + * + * @param string $filename Name of the file to read. + * @param bool $use_include_path + * @param resource|array|null $context A valid context resource created with `stream_context_create()`. If you don't + * need to use a custom context, you can skip this parameter. + * + * @return string|bool The read data or `false` on failure. + */ +function get_contents($filename, $use_include_path = false, $context = null) +{ + static $fileGetContents = null; + + if ('https' == parse_url($filename, PHP_URL_SCHEME) && PHP_VERSION_ID < 50600) { + if (!isset($fileGetContents)) { + $fileGetContents = new FileGetContents(); + } + + return $fileGetContents->get($filename, $context); + } elseif (FileGetContents::hasNextRequestHeaders()) { + if ($context === null) { + $context = stream_context_create(); + } + + $context = FileGetContents::setHttpHeaders($context); + } + + $return = file_get_contents($filename, $use_include_path, $context); + + if (isset($http_response_header)) { + FileGetContents::setLastResponseHeaders($http_response_header); + } + + return $return; +} + +/** + * Fetches all the headers sent by the server in response to a HTTPS request triggered by `get_contents()`. + * + * @return array|null Returns an indexed or associative array with the headers, or `null` on failure or if no request + * has been made yet. + */ +function get_headers() +{ + return FileGetContents::getLastResponseHeaders(); +} + +/** + * @param array $headers An indexed or associative array. + */ +function set_headers(array $headers) +{ + FileGetContents::setNextRequestHeaders($headers); +}