Seditio Source
Root |
./othercms/croogo-4.0.7/vendor/cakephp/cakephp/src/Http/Client/Response.php
<?php
/**
 * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
 * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
 *
 * Licensed under The MIT License
 * Redistributions of files must retain the above copyright notice.
 *
 * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
 * @link          https://cakephp.org CakePHP(tm) Project
 * @since         3.0.0
 * @license       https://opensource.org/licenses/mit-license.php MIT License
 */
namespace Cake\Http\Client;

// This alias is necessary to avoid class name conflicts
// with the deprecated class in this namespace.
use Cake\Http\Cookie\CookieCollection as CookiesCollection;
use
Cake\Http\Cookie\CookieInterface;
use
Psr\Http\Message\ResponseInterface;
use
RuntimeException;
use
Zend\Diactoros\MessageTrait;
use
Zend\Diactoros\Stream;

/**
 * Implements methods for HTTP responses.
 *
 * All of the following examples assume that `$response` is an
 * instance of this class.
 *
 * ### Get header values
 *
 * Header names are case-insensitive, but normalized to Title-Case
 * when the response is parsed.
 *
 * ```
 * $val = $response->getHeaderLine('content-type');
 * ```
 *
 * Will read the Content-Type header. You can get all set
 * headers using:
 *
 * ```
 * $response->getHeaders();
 * ```
 *
 * ### Get the response body
 *
 * You can access the response body stream using:
 *
 * ```
 * $content = $response->getBody();
 * ```
 *
 * You can get the body string using:
 *
 * ```
 * $content = $response->getStringBody();
 * ```
 *
 * If your response body is in XML or JSON you can use
 * special content type specific accessors to read the decoded data.
 * JSON data will be returned as arrays, while XML data will be returned
 * as SimpleXML nodes:
 *
 * ```
 * // Get as xml
 * $content = $response->getXml()
 * // Get as json
 * $content = $response->getJson()
 * ```
 *
 * If the response cannot be decoded, null will be returned.
 *
 * ### Check the status code
 *
 * You can access the response status code using:
 *
 * ```
 * $content = $response->getStatusCode();
 * ```
 */
class Response extends Message implements ResponseInterface
{
    use
MessageTrait;

   
/**
     * The status code of the response.
     *
     * @var int
     */
   
protected $code;

   
/**
     * Cookie Collection instance
     *
     * @var \Cake\Http\Cookie\CookieCollection
     */
   
protected $cookies;

   
/**
     * The reason phrase for the status code
     *
     * @var string
     */
   
protected $reasonPhrase;

   
/**
     * Cached decoded XML data.
     *
     * @var \SimpleXMLElement
     */
   
protected $_xml;

   
/**
     * Cached decoded JSON data.
     *
     * @var array
     */
   
protected $_json;

   
/**
     * Map of public => property names for __get()
     *
     * @var array
     */
   
protected $_exposedProperties = [
       
'cookies' => '_getCookies',
       
'body' => '_getBody',
       
'code' => 'code',
       
'json' => '_getJson',
       
'xml' => '_getXml',
       
'headers' => '_getHeaders',
    ];

   
/**
     * Map of deprecated magic properties.
     *
     * @var array
     * @internal
     */
   
protected $_deprecatedMagicProperties = [
       
'cookies' => 'getCookies()',
       
'body' => 'getStringBody()',
       
'json' => 'getJson()',
       
'xml' => 'getXml()',
       
'headers' => 'getHeaders()',
    ];

   
/**
     * Constructor
     *
     * @param array $headers Unparsed headers.
     * @param string $body The response body.
     */
   
public function __construct($headers = [], $body = '')
    {
       
$this->_parseHeaders($headers);
        if (
$this->getHeaderLine('Content-Encoding') === 'gzip') {
           
$body = $this->_decodeGzipBody($body);
        }
       
$stream = new Stream('php://memory', 'wb+');
       
$stream->write($body);
       
$stream->rewind();
       
$this->stream = $stream;
    }

   
/**
     * Uncompress a gzip response.
     *
     * Looks for gzip signatures, and if gzinflate() exists,
     * the body will be decompressed.
     *
     * @param string $body Gzip encoded body.
     * @return string
     * @throws \RuntimeException When attempting to decode gzip content without gzinflate.
     */
   
protected function _decodeGzipBody($body)
    {
        if (!
function_exists('gzinflate')) {
            throw new
RuntimeException('Cannot decompress gzip response body without gzinflate()');
        }
       
$offset = 0;
       
// Look for gzip 'signature'
       
if (substr($body, 0, 2) === "\x1f\x8b") {
           
$offset = 2;
        }
       
// Check the format byte
       
if (substr($body, $offset, 1) === "\x08") {
            return
gzinflate(substr($body, $offset + 8));
        }
    }

   
/**
     * Parses headers if necessary.
     *
     * - Decodes the status code and reasonphrase.
     * - Parses and normalizes header names + values.
     *
     * @param array $headers Headers to parse.
     * @return void
     */
   
protected function _parseHeaders($headers)
    {
        foreach (
$headers as $key => $value) {
            if (
substr($value, 0, 5) === 'HTTP/') {
               
preg_match('/HTTP\/([\d.]+) ([0-9]+)(.*)/i', $value, $matches);
               
$this->protocol = $matches[1];
               
$this->code = (int)$matches[2];
               
$this->reasonPhrase = trim($matches[3]);
                continue;
            }
            if (
strpos($value, ':') === false) {
                continue;
            }
            list(
$name, $value) = explode(':', $value, 2);
           
$value = trim($value);
           
$name = trim($name);

           
$normalized = strtolower($name);

            if (isset(
$this->headers[$name])) {
               
$this->headers[$name][] = $value;
            } else {
               
$this->headers[$name] = (array)$value;
               
$this->headerNames[$normalized] = $name;
            }
        }
    }

   
/**
     * Check if the response was OK
     *
     * @return bool
     */
   
public function isOk()
    {
       
$codes = [
            static::
STATUS_OK,
            static::
STATUS_CREATED,
            static::
STATUS_ACCEPTED,
            static::
STATUS_NON_AUTHORITATIVE_INFORMATION,
            static::
STATUS_NO_CONTENT,
        ];

        return
in_array($this->code, $codes);
    }

   
/**
     * Check if the response had a redirect status code.
     *
     * @return bool
     */
   
public function isRedirect()
    {
       
$codes = [
            static::
STATUS_MOVED_PERMANENTLY,
            static::
STATUS_FOUND,
            static::
STATUS_SEE_OTHER,
            static::
STATUS_TEMPORARY_REDIRECT,
        ];

        return (
           
in_array($this->code, $codes) &&
           
$this->getHeaderLine('Location')
        );
    }

   
/**
     * Get the status code from the response
     *
     * @return int
     * @deprecated 3.3.0 Use getStatusCode() instead.
     */
   
public function statusCode()
    {
       
deprecationWarning(
           
'Response::statusCode() is deprecated. ' .
           
'Use Response::getStatusCode() instead.'
       
);

        return
$this->code;
    }

   
/**
     * {@inheritdoc}
     *
     * @return int The status code.
     */
   
public function getStatusCode()
    {
        return
$this->code;
    }

   
/**
     * {@inheritdoc}
     *
     * @param int $code The status code to set.
     * @param string $reasonPhrase The status reason phrase.
     * @return $this A copy of the current object with an updated status code.
     */
   
public function withStatus($code, $reasonPhrase = '')
    {
       
$new = clone $this;
       
$new->code = $code;
       
$new->reasonPhrase = $reasonPhrase;

        return
$new;
    }

   
/**
     * {@inheritdoc}
     *
     * @return string The current reason phrase.
     */
   
public function getReasonPhrase()
    {
        return
$this->reasonPhrase;
    }

   
/**
     * Get the encoding if it was set.
     *
     * @return string|null
     * @deprecated 3.3.0 Use getEncoding() instead.
     */
   
public function encoding()
    {
       
deprecationWarning(
           
'Response::encoding() is deprecated. ' .
           
'Use Response::getEncoding() instead.'
       
);

        return
$this->getEncoding();
    }

   
/**
     * Get the encoding if it was set.
     *
     * @return string|null
     */
   
public function getEncoding()
    {
       
$content = $this->getHeaderLine('content-type');
        if (!
$content) {
            return
null;
        }
       
preg_match('/charset\s?=\s?[\'"]?([a-z0-9-_]+)[\'"]?/i', $content, $matches);
        if (empty(
$matches[1])) {
            return
null;
        }

        return
$matches[1];
    }

   
/**
     * Read single/multiple header value(s) out.
     *
     * @param string|null $name The name of the header you want. Leave
     *   null to get all headers.
     * @return mixed Null when the header doesn't exist. An array
     *   will be returned when getting all headers or when getting
     *   a header that had multiple values set. Otherwise a string
     *   will be returned.
     * @deprecated 3.3.0 Use getHeader() and getHeaderLine() instead.
     */
   
public function header($name = null)
    {
       
deprecationWarning(
           
'Response::header() is deprecated. ' .
           
'Use Response::getHeader() and getHeaderLine() instead.'
       
);

        if (
$name === null) {
            return
$this->_getHeaders();
        }
       
$header = $this->getHeader($name);
        if (
count($header) === 1) {
            return
$header[0];
        }

        return
$header;
    }

   
/**
     * Read single/multiple cookie values out.
     *
     * *Note* This method will only provide access to cookies that
     * were added as part of the constructor. If cookies are added post
     * construction they will not be accessible via this method.
     *
     * @param string|null $name The name of the cookie you want. Leave
     *   null to get all cookies.
     * @param bool $all Get all parts of the cookie. When false only
     *   the value will be returned.
     * @return mixed
     * @deprecated 3.3.0 Use getCookie(), getCookieData() or getCookies() instead.
     */
   
public function cookie($name = null, $all = false)
    {
       
deprecationWarning(
           
'Response::cookie() is deprecated. ' .
           
'Use Response::getCookie(), getCookieData() or getCookies() instead.'
       
);

        if (
$name === null) {
            return
$this->getCookies();
        }
        if (
$all) {
            return
$this->getCookieData($name);
        }

        return
$this->getCookie($name);
    }

   
/**
     * Get the all cookie data.
     *
     * @return array The cookie data
     */
   
public function getCookies()
    {
        return
$this->_getCookies();
    }

   
/**
     * Get the cookie collection from this response.
     *
     * This method exposes the response's CookieCollection
     * instance allowing you to interact with cookie objects directly.
     *
     * @return \Cake\Http\Cookie\CookieCollection
     */
   
public function getCookieCollection()
    {
       
$this->buildCookieCollection();

        return
$this->cookies;
    }

   
/**
     * Get the value of a single cookie.
     *
     * @param string $name The name of the cookie value.
     * @return string|array|null Either the cookie's value or null when the cookie is undefined.
     */
   
public function getCookie($name)
    {
       
$this->buildCookieCollection();
        if (!
$this->cookies->has($name)) {
            return
null;
        }

        return
$this->cookies->get($name)->getValue();
    }

   
/**
     * Get the full data for a single cookie.
     *
     * @param string $name The name of the cookie value.
     * @return array|null Either the cookie's data or null when the cookie is undefined.
     */
   
public function getCookieData($name)
    {
       
$this->buildCookieCollection();

        if (!
$this->cookies->has($name)) {
            return
null;
        }

       
$cookie = $this->cookies->get($name);

        return
$this->convertCookieToArray($cookie);
    }

   
/**
     * Convert the cookie into an array of its properties.
     *
     * This method is compatible with older client code that
     * expects date strings instead of timestamps.
     *
     * @param \Cake\Http\Cookie\CookieInterface $cookie Cookie object.
     * @return array
     */
   
protected function convertCookieToArray(CookieInterface $cookie)
    {
        return [
           
'name' => $cookie->getName(),
           
'value' => $cookie->getValue(),
           
'path' => $cookie->getPath(),
           
'domain' => $cookie->getDomain(),
           
'secure' => $cookie->isSecure(),
           
'httponly' => $cookie->isHttpOnly(),
           
'expires' => $cookie->getFormattedExpires(),
        ];
    }

   
/**
     * Lazily build the CookieCollection and cookie objects from the response header
     *
     * @return void
     */
   
protected function buildCookieCollection()
    {
        if (
$this->cookies) {
            return;
        }
       
$this->cookies = CookiesCollection::createFromHeader($this->getHeader('Set-Cookie'));
    }

   
/**
     * Property accessor for `$this->cookies`
     *
     * @return array Array of Cookie data.
     */
   
protected function _getCookies()
    {
       
$this->buildCookieCollection();

       
$cookies = [];
        foreach (
$this->cookies as $cookie) {
           
$cookies[$cookie->getName()] = $this->convertCookieToArray($cookie);
        }

        return
$cookies;
    }

   
/**
     * Get the HTTP version used.
     *
     * @return string
     * @deprecated 3.3.0 Use getProtocolVersion()
     */
   
public function version()
    {
       
deprecationWarning(
           
'Response::version() is deprecated. ' .
           
'Use Response::getProtocolVersion() instead.'
       
);

        return
$this->protocol;
    }

   
/**
     * Get the response body.
     *
     * By passing in a $parser callable, you can get the decoded
     * response content back.
     *
     * For example to get the json data as an object:
     *
     * ```
     * $body = $response->body('json_decode');
     * ```
     *
     * @param callable|null $parser The callback to use to decode
     *   the response body.
     * @return mixed The response body.
     * @deprecated 3.7.0 Use getStringBody()/getJson()/getXml() instead.
     */
   
public function body($parser = null)
    {
       
deprecationWarning(
           
'Response::body() is deprecated. Use getStringBody()/getJson()/getXml() instead.'
       
);

       
$stream = $this->stream;
       
$stream->rewind();
        if (
$parser) {
            return
$parser($stream->getContents());
        }

        return
$stream->getContents();
    }

   
/**
     * Get the response body as string.
     *
     * @return string
     */
   
public function getStringBody()
    {
        return
$this->_getBody();
    }

   
/**
     * Get the response body as JSON decoded data.
     *
     * @return array|null
     */
   
public function getJson()
    {
        return
$this->_getJson();
    }

   
/**
     * Get the response body as JSON decoded data.
     *
     * @return array|null
     */
   
protected function _getJson()
    {
        if (
$this->_json) {
            return
$this->_json;
        }

        return
$this->_json = json_decode($this->_getBody(), true);
    }

   
/**
     * Get the response body as XML decoded data.
     *
     * @return \SimpleXMLElement|null
     */
   
public function getXml()
    {
        return
$this->_getXml();
    }

   
/**
     * Get the response body as XML decoded data.
     *
     * @return \SimpleXMLElement|null
     */
   
protected function _getXml()
    {
        if (
$this->_xml) {
            return
$this->_xml;
        }
       
libxml_use_internal_errors();
       
$data = simplexml_load_string($this->_getBody());
        if (
$data) {
           
$this->_xml = $data;

            return
$this->_xml;
        }

        return
null;
    }

   
/**
     * Provides magic __get() support.
     *
     * @return array
     */
   
protected function _getHeaders()
    {
       
$out = [];
        foreach (
$this->headers as $key => $values) {
           
$out[$key] = implode(',', $values);
        }

        return
$out;
    }

   
/**
     * Provides magic __get() support.
     *
     * @return string
     */
   
protected function _getBody()
    {
       
$this->stream->rewind();

        return
$this->stream->getContents();
    }

   
/**
     * Read values as properties.
     *
     * @param string $name Property name.
     * @return mixed
     */
   
public function __get($name)
    {
        if (!isset(
$this->_exposedProperties[$name])) {
            return
false;
        }
       
$key = $this->_exposedProperties[$name];
        if (
substr($key, 0, 4) === '_get') {
           
deprecationWarning(sprintf(
               
'Response::%s is deprecated. Use Response::%s instead.',
               
$name,
               
$this->_deprecatedMagicProperties[$name]
            ));

            return
$this->{$key}();
        }

        if (
$key === 'code') {
           
deprecationWarning(
               
'Response::code() is deprecated. ' .
               
'Use Response::getStatusCode() instead.'
           
);
        }

        return
$this->{$key};
    }

   
/**
     * isset/empty test with -> syntax.
     *
     * @param string $name Property name.
     * @return bool
     */
   
public function __isset($name)
    {
        if (!isset(
$this->_exposedProperties[$name])) {
            return
false;
        }
       
$key = $this->_exposedProperties[$name];
        if (
substr($key, 0, 4) === '_get') {
           
deprecationWarning(sprintf(
               
'Response::%s is deprecated. Use Response::%s instead.',
               
$name,
               
$this->_deprecatedMagicProperties[$name]
            ));

           
$val = $this->{$key}();

            return
$val !== null;
        }

        if (
$key === 'code') {
           
deprecationWarning(
               
'Response::code() is deprecated. ' .
               
'Use Response::getStatusCode() instead.'
           
);
        }

        return isset(
$this->{$key});
    }
}

// @deprecated 3.4.0 Add backwards compat alias.
class_alias('Cake\Http\Client\Response', 'Cake\Network\Http\Response');