code:
<?php

namespace Http\Message\Authentication;

use Http\Message\Authentication;
use Http\Message\RequestMatcher\CallbackRequestMatcher;
use Psr\Http\Message\RequestInterface;

@trigger_error('The '.__NAMESPACE__.'\Matching class is deprecated since version 1.2 and will be removed in 2.0. Use Http\Message\Authentication\RequestConditional instead.', E_USER_DEPRECATED);

/**
 * Authenticate a PSR-7 Request if the request is matching.
 *
 * @author Márk Sági-Kazár <mark.sagikazar@gmail.com>
 *
 * @deprecated since since version 1.2, and will be removed in 2.0. Use {@link RequestConditional} instead.
 */
final class Matching implements Authentication
{
    /**
     * @var Authentication
     */
    private $authentication;

    /**
     * @var CallbackRequestMatcher
     */
    private $matcher;

    /**
     * @param Authentication $authentication
     * @param callable|null  $matcher
     */
    public function __construct(Authentication $authentication, callable $matcher = null)
    {
        if (is_null($matcher)) {
            $matcher = function () {
                return true;
            };
        }

        $this->authentication = $authentication;
        $this->matcher = new CallbackRequestMatcher($matcher);
    }

    /**
     * {@inheritdoc}
     */
    public function authenticate(RequestInterface $request)
    {
        if ($this->matcher->matches($request)) {
            return $this->authentication->authenticate($request);
        }

        return $request;
    }

    /**
     * Creates a matching authentication for an URL.
     *
     * @param Authentication $authentication
     * @param string         $url
     *
     * @return self
     */
    public static function createUrlMatcher(Authentication $authentication, $url)
    {
        $matcher = function (RequestInterface $request) use ($url) {
            return preg_match($url, $request->getRequestTarget());
        };

        return new static($authentication, $matcher);
    }
}


code:
<?php

namespace Http\Message\Authentication;

use Http\Message\Authentication;
use Psr\Http\Message\RequestInterface;

/**
 * Authenticate a PSR-7 Request by adding parameters to its query.
 *
 * Note: Although in some cases it can be useful, we do not recommend using query parameters for authentication.
 * Credentials in the URL is generally unsafe as they are not encrypted, anyone can see them.
 *
 * @author Márk Sági-Kazár <mark.sagikazar@gmail.com>
 */
final class QueryParam implements Authentication
{
    /**
     * @var array
     */
    private $params = [];

    /**
     * @param array $params
     */
    public function __construct(array $params)
    {
        $this->params = $params;
    }

    /**
     * {@inheritdoc}
     */
    public function authenticate(RequestInterface $request)
    {
        $uri = $request->getUri();
        $query = $uri->getQuery();
        $params = [];

        parse_str($query, $params);

        $params = array_merge($params, $this->params);

        $query = http_build_query($params, null, '&');

        $uri = $uri->withQuery($query);

        return $request->withUri($uri);
    }
}

repo_name: spookie/gnu

license: mit


code:
<?php

namespace Http\Message\Authentication;

use Http\Message\Authentication;
use Http\Message\RequestMatcher;
use Psr\Http\Message\RequestInterface;

/**
 * Authenticate a PSR-7 Request if the request is matching the given request matcher.
 *
 * @author Márk Sági-Kazár <mark.sagikazar@gmail.com>
 */
final class RequestConditional implements Authentication
{
    /**
     * @var RequestMatcher
     */
    private $requestMatcher;

    /**
     * @var Authentication
     */
    private $authentication;

    /**
     * @param RequestMatcher $requestMatcher
     * @param Authentication $authentication
     */
    public function __construct(RequestMatcher $requestMatcher, Authentication $authentication)
    {
        $this->requestMatcher = $requestMatcher;
        $this->authentication = $authentication;
    }

    /**
     * {@inheritdoc}
     */
    public function authenticate(RequestInterface $request)
    {
        if ($this->requestMatcher->matches($request)) {
            return $this->authentication->authenticate($request);
        }

        return $request;
    }
}


code:
<?php

namespace Http\Message\Authentication;

use Http\Message\Authentication;
use Psr\Http\Message\RequestInterface;

/**
 * Authenticate a PSR-7 Request using WSSE.
 *
 * @author Márk Sági-Kazár <mark.sagikazar@gmail.com>
 */
final class Wsse implements Authentication
{
    /**
     * @var string
     */
    private $username;

    /**
     * @var string
     */
    private $password;

    /**
     * @param string $username
     * @param string $password
     */
    public function __construct($username, $password)
    {
        $this->username = $username;
        $this->password = $password;
    }

    /**
     * {@inheritdoc}
     */
    public function authenticate(RequestInterface $request)
    {
        // TODO: generate better nonce?
        $nonce = substr(md5(uniqid(uniqid().'_', true)), 0, 16);
        $created = date('c');
        $digest = base64_encode(sha1(base64_decode($nonce).$created.$this->password, true));

        $wsse = sprintf(
            'UsernameToken Username="%s", PasswordDigest="%s", Nonce="%s", Created="%s"',
            $this->username,
            $digest,
            $nonce,
            $created
        );

        return $request
            ->withHeader('Authorization', 'WSSE profile="UsernameToken"')
            ->withHeader('X-WSSE', $wsse)
        ;
    }
}


code:
<?php

namespace Http\Message\Builder;

use Psr\Http\Message\ResponseInterface;

/**
 * Fills response object with values.
 */
class ResponseBuilder
{
    /**
     * The response to be built.
     *
     * @var ResponseInterface
     */
    protected $response;

    /**
     * Create builder for the given response.
     *
     * @param ResponseInterface $response
     */
    public function __construct(ResponseInterface $response)
    {
        $this->response = $response;
    }

    /**
     * Return response.
     *
     * @return ResponseInterface
     */
    public function getResponse()
    {
        return $this->response;
    }

    /**
     * Add headers represented by an array of header lines.
     *
     * @param string[] $headers Response headers as array of header lines.
     *
     * @return $this
     *
     * @throws \UnexpectedValueException For invalid header values.
     * @throws \InvalidArgumentException For invalid status code arguments.
     */
    public function setHeadersFromArray(array $headers)
    {
        $status = array_shift($headers);
        $this->setStatus($status);

        foreach ($headers as $headerLine) {
            $headerLine = trim($headerLine);
            if ('' === $headerLine) {
                continue;
            }

            $this->addHeader($headerLine);
        }

        return $this;
    }

    /**
     * Add headers represented by a single string.
     *
     * @param string $headers Response headers as single string.
     *
     * @return $this
     *
     * @throws \InvalidArgumentException if $headers is not a string on object with __toString()
     * @throws \UnexpectedValueException For invalid header values.
     */
    public function setHeadersFromString($headers)
    {
        if (!(is_string($headers)
            || (is_object($headers) && method_exists($headers, '__toString')))
        ) {
            throw new \InvalidArgumentException(
                sprintf(
                    '%s expects parameter 1 to be a string, %s given',
                    __METHOD__,
                    is_object($headers) ? get_class($headers) : gettype($headers)
                )
            );
        }

        $this->setHeadersFromArray(explode("\r\n", $headers));

        return $this;
    }

    /**
     * Set response status from a status string.
     *
     * @param string $statusLine Response status as a string.
     *
     * @return $this
     *
     * @throws \InvalidArgumentException For invalid status line.
     */
    public function setStatus($statusLine)
    {
        $parts = explode(' ', $statusLine, 3);
        if (count($parts) < 2 || 0 !== strpos(strtolower($parts[0]), 'http/')) {
            throw new \InvalidArgumentException(
                sprintf('"%s" is not a valid HTTP status line', $statusLine)
            );
        }

        $reasonPhrase = count($parts) > 2 ? $parts[2] : '';
        $this->response = $this->response
            ->withStatus((int) $parts[1], $reasonPhrase)
            ->withProtocolVersion(substr($parts[0], 5));

        return $this;
    }

    /**
     * Add header represented by a string.
     *
     * @param string $headerLine Response header as a string.
     *
     * @return $this
     *
     * @throws \InvalidArgumentException For invalid header names or values.
     */
    public function addHeader($headerLine)
    {
        $parts = explode(':', $headerLine, 2);
        if (2 !== count($parts)) {
            throw new \InvalidArgumentException(
                sprintf('"%s" is not a valid HTTP header line', $headerLine)
            );
        }
        $name = trim($parts[0]);
        $value = trim($parts[1]);
        if ($this->response->hasHeader($name)) {
            $this->response = $this->response->withAddedHeader($name, $value);
        } else {
            $this->response = $this->response->withHeader($name, $value);
        }

        return $this;
    }
}


code:
<?php

namespace Http\Message;

/**
 * Cookie Value Object.
 *
 * @author Márk Sági-Kazár <mark.sagikazar@gmail.com>
 *
 * @see http://tools.ietf.org/search/rfc6265
 */
final class Cookie
{
    /**
     * @var string
     */
    private $name;

    /**
     * @var string|null
     */
    private $value;

    /**
     * @var int|null
     */
    private $maxAge;

    /**
     * @var string|null
     */
    private $domain;

    /**
     * @var string
     */
    private $path;

    /**
     * @var bool
     */
    private $secure;

    /**
     * @var bool
     */
    private $httpOnly;

    /**
     * Expires attribute is HTTP 1.0 only and should be avoided.
     *
     * @var \DateTime|null
     */
    private $expires;

    /**
     * @param string         $name
     * @param string|null    $value
     * @param int|null       $maxAge
     * @param string|null    $domain
     * @param string|null    $path
     * @param bool           $secure
     * @param bool           $httpOnly
     * @param \DateTime|null $expires  Expires attribute is HTTP 1.0 only and should be avoided.
     *
     * @throws \InvalidArgumentException If name, value or max age is not valid.
     */
    public function __construct(
        $name,
        $value = null,
        $maxAge = null,
        $domain = null,
        $path = null,
        $secure = false,
        $httpOnly = false,
        \DateTime $expires = null
    ) {
        $this->validateName($name);
        $this->validateValue($value);
        $this->validateMaxAge($maxAge);

        $this->name = $name;
        $this->value = $value;
        $this->maxAge = $maxAge;
        $this->expires = $expires;
        $this->domain = $this->normalizeDomain($domain);
        $this->path = $this->normalizePath($path);
        $this->secure = (bool) $secure;
        $this->httpOnly = (bool) $httpOnly;
    }

    /**
     * Creates a new cookie without any attribute validation.
     *
     * @param string         $name
     * @param string|null    $value
     * @param int            $maxAge
     * @param string|null    $domain
     * @param string|null    $path
     * @param bool           $secure
     * @param bool           $httpOnly
     * @param \DateTime|null $expires  Expires attribute is HTTP 1.0 only and should be avoided.
     */
    public static function createWithoutValidation(
        $name,
        $value = null,
        $maxAge = null,
        $domain = null,
        $path = null,
        $secure = false,
        $httpOnly = false,
        \DateTime $expires = null
    ) {
        $cookie = new self('name', null, null, $domain, $path, $secure, $httpOnly, $expires);
        $cookie->name = $name;
        $cookie->value = $value;
        $cookie->maxAge = $maxAge;

        return $cookie;
    }

    /**
     * Returns the name.
     *
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Returns the value.
     *
     * @return string|null
     */
    public function getValue()
    {
        return $this->value;
    }

    /**
     * Checks if there is a value.
     *
     * @return bool
     */
    public function hasValue()
    {
        return isset($this->value);
    }

    /**
     * Sets the value.
     *
     * @param string|null $value
     *
     * @return Cookie
     */
    public function withValue($value)
    {
        $this->validateValue($value);

        $new = clone $this;
        $new->value = $value;

        return $new;
    }

    /**
     * Returns the max age.
     *
     * @return int|null
     */
    public function getMaxAge()
    {
        return $this->maxAge;
    }

    /**
     * Checks if there is a max age.
     *
     * @return bool
     */
    public function hasMaxAge()
    {
        return isset($this->maxAge);
    }

    /**
     * Sets the max age.
     *
     * @param int|null $maxAge
     *
     * @return Cookie
     */
    public function withMaxAge($maxAge)
    {
        $this->validateMaxAge($maxAge);

        $new = clone $this;
        $new->maxAge = $maxAge;

        return $new;
    }

    /**
     * Returns the expiration time.
     *
     * @return \DateTime|null
     */
    public function getExpires()
    {
        return $this->expires;
    }

    /**
     * Checks if there is an expiration time.
     *
     * @return bool
     */
    public function hasExpires()
    {
        return isset($this->expires);
    }

    /**
     * Sets the expires.
     *
     * @param \DateTime|null $expires
     *
     * @return Cookie
     */
    public function withExpires(\DateTime $expires = null)
    {
        $new = clone $this;
        $new->expires = $expires;

        return $new;
    }

    /**
     * Checks if the cookie is expired.
     *
     * @return bool
     */
    public function isExpired()
    {
        return isset($this->expires) and $this->expires < new \DateTime();
    }

    /**
     * Returns the domain.
     *
     * @return string|null
     */
    public function getDomain()
    {
        return $this->domain;
    }

    /**
     * Checks if there is a domain.
     *
     * @return bool
     */
    public function hasDomain()
    {
        return isset($this->domain);
    }

    /**
     * Sets the domain.
     *
     * @param string|null $domain
     *
     * @return Cookie
     */
    public function withDomain($domain)
    {
        $new = clone $this;
        $new->domain = $this->normalizeDomain($domain);

        return $new;
    }

    /**
     * Checks whether this cookie is meant for this domain.
     *
     * @see http://tools.ietf.org/html/rfc6265#section-5.1.3
     *
     * @param string $domain
     *
     * @return bool
     */
    public function matchDomain($domain)
    {
        // Domain is not set or exact match
        if (!$this->hasDomain() || 0 === strcasecmp($domain, $this->domain)) {
            return true;
        }

        // Domain is not an IP address
        if (filter_var($domain, FILTER_VALIDATE_IP)) {
            return false;
        }

        return (bool) preg_match(sprintf('/\b%s$/i', preg_quote($this->domain)), $domain);
    }

    /**
     * Returns the path.
     *
     * @return string
     */
    public function getPath()
    {
        return $this->path;
    }

    /**
     * Sets the path.
     *
     * @param string|null $path
     *
     * @return Cookie
     */
    public function withPath($path)
    {
        $new = clone $this;
        $new->path = $this->normalizePath($path);

        return $new;
    }

    /**
     * Checks whether this cookie is meant for this path.
     *
     * @see http://tools.ietf.org/html/rfc6265#section-5.1.4
     *
     * @param string $path
     *
     * @return bool
     */
    public function matchPath($path)
    {
        return $this->path === $path || (0 === strpos($path, rtrim($this->path, '/').'/'));
    }

    /**
     * Checks whether this cookie may only be sent over HTTPS.
     *
     * @return bool
     */
    public function isSecure()
    {
        return $this->secure;
    }

    /**
     * Sets whether this cookie should only be sent over HTTPS.
     *
     * @param bool $secure
     *
     * @return Cookie
     */
    public function withSecure($secure)
    {
        $new = clone $this;
        $new->secure = (bool) $secure;

        return $new;
    }

    /**
     * Check whether this cookie may not be accessed through Javascript.
     *
     * @return bool
     */
    public function isHttpOnly()
    {
        return $this->httpOnly;
    }

    /**
     * Sets whether this cookie may not be accessed through Javascript.
     *
     * @param bool $httpOnly
     *
     * @return Cookie
     */
    public function withHttpOnly($httpOnly)
    {
        $new = clone $this;
        $new->httpOnly = (bool) $httpOnly;

        return $new;
    }

    /**
     * Checks if this cookie represents the same cookie as $cookie.
     *
     * This does not compare the values, only name, domain and path.
     *
     * @param Cookie $cookie
     *
     * @return bool
     */
    public function match(self $cookie)
    {
        return $this->name === $cookie->name && $this->domain === $cookie->domain and $this->path === $cookie->path;
    }

    /**
     * Validates cookie attributes.
     *
     * @return bool
     */
    public function isValid()
    {
        try {
            $this->validateName($this->name);
            $this->validateValue($this->value);
            $this->validateMaxAge($this->maxAge);
        } catch (\InvalidArgumentException $e) {
            return false;
        }

        return true;
    }

    /**
     * Validates the name attribute.
     *
     * @see http://tools.ietf.org/search/rfc2616#section-2.2
     *
     * @param string $name
     *
     * @throws \InvalidArgumentException If the name is empty or contains invalid characters.
     */
    private function validateName($name)
    {
        if (strlen($name) < 1) {
            throw new \InvalidArgumentException('The name cannot be empty');
        }

        // Name attribute is a token as per spec in RFC 2616
        if (preg_match('/[\x00-\x20\x22\x28-\x29\x2C\x2F\x3A-\x40\x5B-\x5D\x7B\x7D\x7F]/', $name)) {
            throw new \InvalidArgumentException(sprintf('The cookie name "%s" contains invalid characters.', $name));
        }
    }

    /**
     * Validates a value.
     *
     * @see http://tools.ietf.org/html/rfc6265#section-4.1.1
     *
     * @param string|null $value
     *
     * @throws \InvalidArgumentException If the value contains invalid characters.
     */
    private function validateValue($value)
    {
        if (isset($value)) {
            if (preg_match('/[^\x21\x23-\x2B\x2D-\x3A\x3C-\x5B\x5D-\x7E]/', $value)) {
                throw new \InvalidArgumentException(sprintf('The cookie value "%s" contains invalid characters.', $value));
            }
        }
    }

    /**
     * Validates a Max-Age attribute.
     *
     * @param int|null $maxAge
     *
     * @throws \InvalidArgumentException If the Max-Age is not an empty or integer value.
     */
    private function validateMaxAge($maxAge)
    {
        if (isset($maxAge)) {
            if (!is_int($maxAge)) {
                throw new \InvalidArgumentException('Max-Age must be integer');
            }
        }
    }

    /**
     * Remove the leading '.' and lowercase the domain as per spec in RFC 6265.
     *
     * @see http://tools.ietf.org/html/rfc6265#section-4.1.2.3
     * @see http://tools.ietf.org/html/rfc6265#section-5.1.3
     * @see http://tools.ietf.org/html/rfc6265#section-5.2.3
     *
     * @param string|null $domain
     *
     * @return string
     */
    private function normalizeDomain($domain)
    {
        if (isset($domain)) {
            $domain = ltrim(strtolower($domain), '.');
        }

        return $domain;
    }

    /**
     * Processes path as per spec in RFC 6265.
     *
     * @see http://tools.ietf.org/html/rfc6265#section-5.1.4
     * @see http://tools.ietf.org/html/rfc6265#section-5.2.4
     *
     * @param string|null $path
     *
     * @return string
     */
    private function normalizePath($path)
    {
        $path = rtrim($path, '/');

        if (empty($path) or '/' !== substr($path, 0, 1)) {
            $path = '/';
        }

        return $path;
    }
}


code:
<?php

namespace Http\Message;

/**
 * Cookie Jar holds a set of Cookies.
 *
 * @author Márk Sági-Kazár <mark.sagikazar@gmail.com>
 */
final class CookieJar implements \Countable, \IteratorAggregate
{
    /**
     * @var \SplObjectStorage
     */
    protected $cookies;

    public function __construct()
    {
        $this->cookies = new \SplObjectStorage();
    }

    /**
     * Checks if there is a cookie.
     *
     * @param Cookie $cookie
     *
     * @return bool
     */
    public function hasCookie(Cookie $cookie)
    {
        return $this->cookies->contains($cookie);
    }

    /**
     * Adds a cookie.
     *
     * @param Cookie $cookie
     */
    public function addCookie(Cookie $cookie)
    {
        if (!$this->hasCookie($cookie)) {
            $cookies = $this->getMatchingCookies($cookie);

            foreach ($cookies as $matchingCookie) {
                if ($cookie->getValue() !== $matchingCookie->getValue() || $cookie->getMaxAge() > $matchingCookie->getMaxAge()) {
                    $this->removeCookie($matchingCookie);

                    continue;
                }
            }

            if ($cookie->hasValue()) {
                $this->cookies->attach($cookie);
            }
        }
    }

    /**
     * Removes a cookie.
     *
     * @param Cookie $cookie
     */
    public function removeCookie(Cookie $cookie)
    {
        $this->cookies->detach($cookie);
    }

    /**
     * Returns the cookies.
     *
     * @return Cookie[]
     */
    public function getCookies()
    {
        $match = function ($matchCookie) {
            return true;
        };

        return $this->findMatchingCookies($match);
    }

    /**
     * Returns all matching cookies.
     *
     * @param Cookie $cookie
     *
     * @return Cookie[]
     */
    public function getMatchingCookies(Cookie $cookie)
    {
        $match = function ($matchCookie) use ($cookie) {
            return $matchCookie->match($cookie);
        };

        return $this->findMatchingCookies($match);
    }

    /**
     * Finds matching cookies based on a callable.
     *
     * @param callable $match
     *
     * @return Cookie[]
     */
    protected function findMatchingCookies(callable $match)
    {
        $cookies = [];

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

        return $cookies;
    }

    /**
     * Checks if there are cookies.
     *
     * @return bool
     */
    public function hasCookies()
    {
        return $this->cookies->count() > 0;
    }

    /**
     * Sets the cookies and removes any previous one.
     *
     * @param Cookie[] $cookies
     */
    public function setCookies(array $cookies)
    {
        $this->clear();
        $this->addCookies($cookies);
    }

    /**
     * Adds some cookies.
     *
     * @param Cookie[] $cookies
     */
    public function addCookies(array $cookies)
    {
        foreach ($cookies as $cookie) {
            $this->addCookie($cookie);
        }
    }

    /**
     * Removes some cookies.
     *
     * @param Cookie[] $cookies
     */
    public function removeCookies(array $cookies)
    {
        foreach ($cookies as $cookie) {
            $this->removeCookie($cookie);
        }
    }

    /**
     * Removes cookies which match the given parameters.
     *
     * Null means that parameter should not be matched
     *
     * @param string|null $name
     * @param string|null $domain
     * @param string|null $path
     */
    public function removeMatchingCookies($name = null, $domain = null, $path = null)
    {
        $match = function ($cookie) use ($name, $domain, $path) {
            $match = true;

            if (isset($name)) {
                $match = $match && ($cookie->getName() === $name);
            }

            if (isset($domain)) {
                $match = $match && $cookie->matchDomain($domain);
            }

            if (isset($path)) {
                $match = $match && $cookie->matchPath($path);
            }

            return $match;
        };

        $cookies = $this->findMatchingCookies($match);

        $this->removeCookies($cookies);
    }

    /**
     * Removes all cookies.
     */
    public function clear()
    {
        $this->cookies = new \SplObjectStorage();
    }

    /**
     * {@inheritdoc}
     */
    public function count()
    {
        return $this->cookies->count();
    }

    /**
     * {@inheritdoc}
     */
    public function getIterator()
    {
        return clone $this->cookies;
    }
}


code:
<?php

namespace Http\Message;

use Http\Message\Exception\UnexpectedValueException;

final class CookieUtil
{
    /**
     * Handles dates as defined by RFC 2616 section 3.3.1, and also some other
     * non-standard, but common formats.
     *
     * @var array
     */
    private static $dateFormats = [
        'D, d M y H:i:s T',
        'D, d M Y H:i:s T',
        'D, d-M-y H:i:s T',
        'D, d-M-Y H:i:s T',
        'D, d-m-y H:i:s T',
        'D, d-m-Y H:i:s T',
        'D M j G:i:s Y',
        'D M d H:i:s Y T',
    ];

    /**
     * @see https://github.com/symfony/symfony/blob/master/src/Symfony/Component/BrowserKit/Cookie.php
     *
     * @param string $dateValue
     *
     * @return \DateTime
     *
     * @throws UnexpectedValueException if we cannot parse the cookie date string.
     */
    public static function parseDate($dateValue)
    {
        foreach (self::$dateFormats as $dateFormat) {
            if (false !== $date = \DateTime::createFromFormat($dateFormat, $dateValue, new \DateTimeZone('GMT'))) {
                return $date;
            }
        }

        // attempt a fallback for unusual formatting
        if (false !== $date = date_create($dateValue, new \DateTimeZone('GMT'))) {
            return $date;
        }

        throw new UnexpectedValueException(sprintf(
            'Unparseable cookie date string "%s"',
            $dateValue
        ));
    }
}


code:
<?php

namespace Http\Message\Decorator;

use Psr\Http\Message\MessageInterface;
use Psr\Http\Message\StreamInterface;

/**
 * @author Márk Sági-Kazár <mark.sagikazar@gmail.com>
 */
trait MessageDecorator
{
    /**
     * @var MessageInterface
     */
    private $message;

    /**
     * Returns the decorated message.
     *
     * Since the underlying Message is immutable as well
     * exposing it is not an issue, because it's state cannot be altered
     *
     * @return MessageInterface
     */
    public function getMessage()
    {
        return $this->message;
    }

    /**
     * {@inheritdoc}
     */
    public function getProtocolVersion()
    {
        return $this->message->getProtocolVersion();
    }

    /**
     * {@inheritdoc}
     */
    public function withProtocolVersion($version)
    {
        $new = clone $this;
        $new->message = $this->message->withProtocolVersion($version);

        return $new;
    }

    /**
     * {@inheritdoc}
     */
    public function getHeaders()
    {
        return $this->message->getHeaders();
    }

    /**
     * {@inheritdoc}
     */
    public function hasHeader($header)
    {
        return $this->message->hasHeader($header);
    }

    /**
     * {@inheritdoc}
     */
    public function getHeader($header)
    {
        return $this->message->getHeader($header);
    }

    /**
     * {@inheritdoc}
     */
    public function getHeaderLine($header)
    {
        return $this->message->getHeaderLine($header);
    }

    /**
     * {@inheritdoc}
     */
    public function withHeader($header, $value)
    {
        $new = clone $this;
        $new->message = $this->message->withHeader($header, $value);

        return $new;
    }

    /**
     * {@inheritdoc}
     */
    public function withAddedHeader($header, $value)
    {
        $new = clone $this;
        $new->message = $this->message->withAddedHeader($header, $value);

        return $new;
    }

    /**
     * {@inheritdoc}
     */
    public function withoutHeader($header)
    {
        $new = clone $this;
        $new->message = $this->message->withoutHeader($header);

        return $new;
    }

    /**
     * {@inheritdoc}
     */
    public function getBody()
    {
        return $this->message->getBody();
    }

    /**
     * {@inheritdoc}
     */
    public function withBody(StreamInterface $body)
    {
        $new = clone $this;
        $new->message = $this->message->withBody($body);

        return $new;
    }
}


code:
<?php

namespace Http\Message\Decorator;

use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\UriInterface;

/**
 * @author Márk Sági-Kazár <mark.sagikazar@gmail.com>
 */
trait RequestDecorator
{
    use MessageDecorator {
        getMessage as getRequest;
    }

    /**
     * Exchanges the underlying request with another.
     *
     * @param RequestInterface $request
     *
     * @return self
     */
    public function withRequest(RequestInterface $request)
    {
        $new = clone $this;
        $new->message = $request;

        return $new;
    }

    /**
     * {@inheritdoc}
     */
    public function getRequestTarget()
    {
        return $this->message->getRequestTarget();
    }

    /**
     * {@inheritdoc}
     */
    public function withRequestTarget($requestTarget)
    {
        $new = clone $this;
        $new->message = $this->message->withRequestTarget($requestTarget);

        return $new;
    }

    /**
     * {@inheritdoc}
     */
    public function getMethod()
    {
        return $this->message->getMethod();
    }

    /**
     * {@inheritdoc}
     */
    public function withMethod($method)
    {
        $new = clone $this;
        $new->message = $this->message->withMethod($method);

        return $new;
    }

    /**
     * {@inheritdoc}
     */
    public function getUri()
    {
        return $this->message->getUri();
    }

    /**
     * {@inheritdoc}
     */
    public function withUri(UriInterface $uri, $preserveHost = false)
    {
        $new = clone $this;
        $new->message = $this->message->withUri($uri, $preserveHost);

        return $new;
    }
}


code:
<?php

namespace Http\Message\Decorator;

use Psr\Http\Message\ResponseInterface;

/**
 * @author Márk Sági-Kazár <mark.sagikazar@gmail.com>
 */
trait ResponseDecorator
{
    use MessageDecorator {
        getMessage as getResponse;
    }

    /**
     * Exchanges the underlying response with another.
     *
     * @param ResponseInterface $response
     *
     * @return self
     */
    public function withResponse(ResponseInterface $response)
    {
        $new = clone $this;
        $new->message = $response;

        return $new;
    }

    /**
     * {@inheritdoc}
     */
    public function getStatusCode()
    {
        return $this->message->getStatusCode();
    }

    /**
     * {@inheritdoc}
     */
    public function withStatus($code, $reasonPhrase = '')
    {
        $new = clone $this;
        $new->message = $this->message->withStatus($code, $reasonPhrase);

        return $new;
    }

    /**
     * {@inheritdoc}
     */
    public function getReasonPhrase()
    {
        return $this->message->getReasonPhrase();
    }
}


code:
<?php

namespace Http\Message\Decorator;

use Psr\Http\Message\StreamInterface;

/**
 * Decorates a stream.
 *
 * @author Márk Sági-Kazár <mark.sagikazar@gmail.com>
 */
trait StreamDecorator
{
    /**
     * @var StreamInterface
     */
    protected $stream;

    /**
     * {@inheritdoc}
     */
    public function __toString()
    {
        return $this->stream->__toString();
    }

    /**
     * {@inheritdoc}
     */
    public function close()
    {
        $this->stream->close();
    }

    /**
     * {@inheritdoc}
     */
    public function detach()
    {
        return $this->stream->detach();
    }

    /**
     * {@inheritdoc}
     */
    public function getSize()
    {
        return $this->stream->getSize();
    }

    /**
     * {@inheritdoc}
     */
    public function tell()
    {
        return $this->stream->tell();
    }

    /**
     * {@inheritdoc}
     */
    public function eof()
    {
        return $this->stream->eof();
    }

    /**
     * {@inheritdoc}
     */
    public function isSeekable()
    {
        return $this->stream->isSeekable();
    }

    /**
     * {@inheritdoc}
     */
    public function seek($offset, $whence = SEEK_SET)
    {
        $this->stream->seek($offset, $whence);
    }

    /**
     * {@inheritdoc}
     */
    public function rewind()
    {
        $this->stream->rewind();
    }

    /**
     * {@inheritdoc}
     */
    public function isWritable()
    {
        return $this->stream->isWritable();
    }

    /**
     * {@inheritdoc}
     */
    public function write($string)
    {
        return $this->stream->write($string);
    }

    /**
     * {@inheritdoc}
     */
    public function isReadable()
    {
        return $this->stream->isReadable();
    }

    /**
     * {@inheritdoc}
     */
    public function read($length)
    {
        return $this->stream->read($length);
    }

    /**
     * {@inheritdoc}
     */
    public function getContents()
    {
        return $this->stream->getContents();
    }

    /**
     * {@inheritdoc}
     */
    public function getMetadata($key = null)
    {
        return $this->stream->getMetadata($key);
    }
}


code:
<?php

namespace Http\Message\Encoding;

/**
 * Transform a regular stream into a chunked one.
 *
 * @author Joel Wurtz <joel.wurtz@gmail.com>
 */
class ChunkStream extends FilteredStream
{
    /**
     * {@inheritdoc}
     */
    protected function readFilter()
    {
        return 'chunk';
    }

    /**
     * {@inheritdoc}
     */
    protected function writeFilter()
    {
        return 'dechunk';
    }

    /**
     * {@inheritdoc}
     */
    protected function fill()
    {
        parent::fill();

        if ($this->stream->eof()) {
            $this->buffer .= "0\r\n\r\n";
        }
    }
}


code:
<?php

namespace Http\Message\Encoding;

use Clue\StreamFilter as Filter;
use Psr\Http\Message\StreamInterface;

/**
 * Stream compress (RFC 1950).
 *
 * @author Joel Wurtz <joel.wurtz@gmail.com>
 */
class CompressStream extends FilteredStream
{
    /**
     * @param StreamInterface $stream
     * @param int             $level
     */
    public function __construct(StreamInterface $stream, $level = -1)
    {
        if (!extension_loaded('zlib')) {
            throw new \RuntimeException('The zlib extension must be enabled to use this stream');
        }

        parent::__construct($stream, ['window' => 15, 'level' => $level]);

        // @deprecated will be removed in 2.0
        $this->writeFilterCallback = Filter\fun($this->writeFilter(), ['window' => 15]);
    }

    /**
     * {@inheritdoc}
     */
    protected function readFilter()
    {
        return 'zlib.deflate';
    }

    /**
     * {@inheritdoc}
     */
    protected function writeFilter()
    {
        return 'zlib.inflate';
    }
}


code:
<?php

namespace Http\Message\Encoding;

/**
 * Decorate a stream which is chunked.
 *
 * Allow to decode a chunked stream
 *
 * @author Joel Wurtz <joel.wurtz@gmail.com>
 */
class DechunkStream extends FilteredStream
{
    /**
     * {@inheritdoc}
     */
    protected function readFilter()
    {
        return 'dechunk';
    }

    /**
     * {@inheritdoc}
     */
    protected function writeFilter()
    {
        return 'chunk';
    }
}


code:
<?php

namespace Http\Message\Encoding;

use Clue\StreamFilter as Filter;
use Psr\Http\Message\StreamInterface;

/**
 * Stream decompress (RFC 1950).
 *
 * @author Joel Wurtz <joel.wurtz@gmail.com>
 */
class DecompressStream extends FilteredStream
{
    /**
     * @param StreamInterface $stream
     * @param int             $level
     */
    public function __construct(StreamInterface $stream, $level = -1)
    {
        if (!extension_loaded('zlib')) {
            throw new \RuntimeException('The zlib extension must be enabled to use this stream');
        }

        parent::__construct($stream, ['window' => 15]);

        // @deprecated will be removed in 2.0
        $this->writeFilterCallback = Filter\fun($this->writeFilter(), ['window' => 15, 'level' => $level]);
    }

    /**
     * {@inheritdoc}
     */
    protected function readFilter()
    {
        return 'zlib.inflate';
    }

    /**
     * {@inheritdoc}
     */
    protected function writeFilter()
    {
        return 'zlib.deflate';
    }
}


code:
<?php

namespace Http\Message\Encoding;

use Clue\StreamFilter as Filter;
use Psr\Http\Message\StreamInterface;

/**
 * Stream deflate (RFC 1951).
 *
 * @author Joel Wurtz <joel.wurtz@gmail.com>
 */
class DeflateStream extends FilteredStream
{
    /**
     * @param StreamInterface $stream
     * @param int             $level
     */
    public function __construct(StreamInterface $stream, $level = -1)
    {
        parent::__construct($stream, ['window' => -15, 'level' => $level]);

        // @deprecated will be removed in 2.0
        $this->writeFilterCallback = Filter\fun($this->writeFilter(), ['window' => -15]);
    }

    /**
     * {@inheritdoc}
     */
    protected function readFilter()
    {
        return 'zlib.deflate';
    }

    /**
     * {@inheritdoc}
     */
    protected function writeFilter()
    {
        return 'zlib.inflate';
    }
}


code:
<?php

namespace Http\Message\Encoding\Filter;

/**
 * Userland implementation of the chunk stream filter.
 *
 * @author Joel Wurtz <joel.wurtz@gmail.com>
 */
class Chunk extends \php_user_filter
{
    /**
     * {@inheritdoc}
     */
    public function filter($in, $out, &$consumed, $closing)
    {
        while ($bucket = stream_bucket_make_writeable($in)) {
            $lenbucket = stream_bucket_new($this->stream, dechex($bucket->datalen)."\r\n");
            stream_bucket_append($out, $lenbucket);

            $consumed += $bucket->datalen;
            stream_bucket_append($out, $bucket);

            $lenbucket = stream_bucket_new($this->stream, "\r\n");
            stream_bucket_append($out, $lenbucket);
        }

        return PSFS_PASS_ON;
    }
}


code:
<?php

namespace Http\Message\Encoding;

use Clue\StreamFilter as Filter;
use Http\Message\Decorator\StreamDecorator;
use Psr\Http\Message\StreamInterface;

/**
 * A filtered stream has a filter for filtering output and a filter for filtering input made to a underlying stream.
 *
 * @author Joel Wurtz <joel.wurtz@gmail.com>
 */
abstract class FilteredStream implements StreamInterface
{
    const BUFFER_SIZE = 8192;

    use StreamDecorator {
        rewind as private doRewind;
        seek as private doSeek;
    }

    /**
     * @var callable
     */
    protected $readFilterCallback;

    /**
     * @var resource
     *
     * @deprecated since version 1.5, will be removed in 2.0
     */
    protected $readFilter;

    /**
     * @var callable
     *
     * @deprecated since version 1.5, will be removed in 2.0
     */
    protected $writeFilterCallback;

    /**
     * @var resource
     *
     * @deprecated since version 1.5, will be removed in 2.0
     */
    protected $writeFilter;

    /**
     * Internal buffer.
     *
     * @var string
     */
    protected $buffer = '';

    /**
     * @param StreamInterface $stream
     * @param mixed|null      $readFilterOptions
     * @param mixed|null      $writeFilterOptions deprecated since 1.5, will be removed in 2.0
     */
    public function __construct(StreamInterface $stream, $readFilterOptions = null, $writeFilterOptions = null)
    {
        if (null !== $readFilterOptions) {
            $this->readFilterCallback = Filter\fun($this->readFilter(), $readFilterOptions);
        } else {
            $this->readFilterCallback = Filter\fun($this->readFilter());
        }

        if (null !== $writeFilterOptions) {
            $this->writeFilterCallback = Filter\fun($this->writeFilter(), $writeFilterOptions);

            @trigger_error('The $writeFilterOptions argument is deprecated since version 1.5 and will be removed in 2.0.', E_USER_DEPRECATED);
        } else {
            $this->writeFilterCallback = Filter\fun($this->writeFilter());
        }

        $this->stream = $stream;
    }

    /**
     * {@inheritdoc}
     */
    public function read($length)
    {
        if (strlen($this->buffer) >= $length) {
            $read = substr($this->buffer, 0, $length);
            $this->buffer = substr($this->buffer, $length);

            return $read;
        }

        if ($this->stream->eof()) {
            $buffer = $this->buffer;
            $this->buffer = '';

            return $buffer;
        }

        $read = $this->buffer;
        $this->buffer = '';
        $this->fill();

        return $read.$this->read($length - strlen($read));
    }

    /**
     * {@inheritdoc}
     */
    public function eof()
    {
        return $this->stream->eof() && '' === $this->buffer;
    }

    /**
     * Buffer is filled by reading underlying stream.
     *
     * Callback is reading once more even if the stream is ended.
     * This allow to get last data in the PHP buffer otherwise this
     * bug is present : https://bugs.php.net/bug.php?id=48725
     */
    protected function fill()
    {
        $readFilterCallback = $this->readFilterCallback;
        $this->buffer .= $readFilterCallback($this->stream->read(self::BUFFER_SIZE));

        if ($this->stream->eof()) {
            $this->buffer .= $readFilterCallback();
        }
    }

    /**
     * {@inheritdoc}
     */
    public function getContents()
    {
        $buffer = '';

        while (!$this->eof()) {
            $buf = $this->read(self::BUFFER_SIZE);
            // Using a loose equality here to match on '' and false.
            if (null == $buf) {
                break;
            }

            $buffer .= $buf;
        }

        return $buffer;
    }

    /**
     * Always returns null because we can't tell the size of a stream when we filter.
     */
    public function getSize()
    {
        return null;
    }

    /**
     * {@inheritdoc}
     */
    public function __toString()
    {
        return $this->getContents();
    }

    /**
     * Filtered streams are not seekable.
     *
     * We would need to buffer and process everything to allow seeking.
     */
    public function isSeekable()
    {
        return false;
    }

    /**
     * {@inheritdoc}
     */
    public function rewind()
    {
        @trigger_error('Filtered streams are not seekable. This method will start raising an exception in the next major version', E_USER_DEPRECATED);
        $this->doRewind();
    }

    /**
     * {@inheritdoc}
     */
    public function seek($offset, $whence = SEEK_SET)
    {
        @trigger_error('Filtered streams are not seekable. This method will start raising an exception in the next major version', E_USER_DEPRECATED);
        $this->doSeek($offset, $whence);
    }

    /**
     * Returns the read filter name.
     *
     * @return string
     *
     * @deprecated since version 1.5, will be removed in 2.0
     */
    public function getReadFilter()
    {
        @trigger_error('The '.__CLASS__.'::'.__METHOD__.' method is deprecated since version 1.5 and will be removed in 2.0.', E_USER_DEPRECATED);

        return $this->readFilter();
    }

    /**
     * Returns the write filter name.
     *
     * @return string
     */
    abstract protected function readFilter();

    /**
     * Returns the write filter name.
     *
     * @return string
     *
     * @deprecated since version 1.5, will be removed in 2.0
     */
    public function getWriteFilter()
    {
        @trigger_error('The '.__CLASS__.'::'.__METHOD__.' method is deprecated since version 1.5 and will be removed in 2.0.', E_USER_DEPRECATED);

        return $this->writeFilter();
    }

    /**
     * Returns the write filter name.
     *
     * @return string
     */
    abstract protected function writeFilter();
}


code:
<?php

namespace Http\Message\Encoding;

use Clue\StreamFilter as Filter;
use Psr\Http\Message\StreamInterface;

/**
 * Stream for decoding from gzip format (RFC 1952).
 *
 * @author Joel Wurtz <joel.wurtz@gmail.com>
 */
class GzipDecodeStream extends FilteredStream
{
    /**
     * @param StreamInterface $stream
     * @param int             $level
     */
    public function __construct(StreamInterface $stream, $level = -1)
    {
        if (!extension_loaded('zlib')) {
            throw new \RuntimeException('The zlib extension must be enabled to use this stream');
        }

        parent::__construct($stream, ['window' => 31]);

        // @deprecated will be removed in 2.0
        $this->writeFilterCallback = Filter\fun($this->writeFilter(), ['window' => 31, 'level' => $level]);
    }

    /**
     * {@inheritdoc}
     */
    protected function readFilter()
    {
        return 'zlib.inflate';
    }

    /**
     * {@inheritdoc}
     */
    protected function writeFilter()
    {
        return 'zlib.deflate';
    }
}


code:
<?php

namespace Http\Message\Encoding;

use Clue\StreamFilter as Filter;
use Psr\Http\Message\StreamInterface;

/**
 * Stream for encoding to gzip format (RFC 1952).
 *
 * @author Joel Wurtz <joel.wurtz@gmail.com>
 */
class GzipEncodeStream extends FilteredStream
{
    /**
     * @param StreamInterface $stream
     * @param int             $level
     */
    public function __construct(StreamInterface $stream, $level = -1)
    {
        if (!extension_loaded('zlib')) {
            throw new \RuntimeException('The zlib extension must be enabled to use this stream');
        }

        parent::__construct($stream, ['window' => 31, 'level' => $level]);

        // @deprecated will be removed in 2.0
        $this->writeFilterCallback = Filter\fun($this->writeFilter(), ['window' => 31]);
    }

    /**
     * {@inheritdoc}
     */
    protected function readFilter()
    {
        return 'zlib.deflate';
    }

    /**
     * {@inheritdoc}
     */
    protected function writeFilter()
    {
        return 'zlib.inflate';
    }
}


code:
<?php

namespace Http\Message\Encoding;

use Clue\StreamFilter as Filter;
use Psr\Http\Message\StreamInterface;

/**
 * Stream inflate (RFC 1951).
 *
 * @author Joel Wurtz <joel.wurtz@gmail.com>
 */
class InflateStream extends FilteredStream
{
    /**
     * @param StreamInterface $stream
     * @param int             $level
     */
    public function __construct(StreamInterface $stream, $level = -1)
    {
        if (!extension_loaded('zlib')) {
            throw new \RuntimeException('The zlib extension must be enabled to use this stream');
        }

        parent::__construct($stream, ['window' => -15]);

        // @deprecated will be removed in 2.0
        $this->writeFilterCallback = Filter\fun($this->writeFilter(), ['window' => -15, 'level' => $level]);
    }

    /**
     * {@inheritdoc}
     */
    protected function readFilter()
    {
        return 'zlib.inflate';
    }

    /**
     * {@inheritdoc}
     */
    protected function writeFilter()
    {
        return 'zlib.deflate';
    }
}


code:
<?php

namespace Http\Message;

/**
 * An interface implemented by all HTTP message related exceptions.
 */
interface Exception
{
}


code:
<?php

namespace Http\Message\Exception;

use Http\Message\Exception;

final class UnexpectedValueException extends \UnexpectedValueException implements Exception
{
}


code:
<?php

namespace Http\Message;

use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;

/**
 * Formats a request and/or a response as a string.
 *
 * @author Márk Sági-Kazár <mark.sagikazar@gmail.com>
 */
interface Formatter
{
    /**
     * Formats a request.
     *
     * @param RequestInterface $request
     *
     * @return string
     */
    public function formatRequest(RequestInterface $request);

    /**
     * Formats a response.
     *
     * @param ResponseInterface $response
     *
     * @return string
     */
    public function formatResponse(ResponseInterface $response);
}


code:
<?php

namespace Http\Message\Formatter;

use Http\Message\Formatter;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;

/**
 * A formatter that prints a cURL command for HTTP requests.
 *
 * @author Tobias Nyholm <tobias.nyholm@gmail.com>
 */
class CurlCommandFormatter implements Formatter
{
    /**
     * {@inheritdoc}
     */
    public function formatRequest(RequestInterface $request)
    {
        $command = sprintf('curl %s', escapeshellarg((string) $request->getUri()->withFragment('')));
        if ('1.0' === $request->getProtocolVersion()) {
            $command .= ' --http1.0';
        } elseif ('2.0' === $request->getProtocolVersion()) {
            $command .= ' --http2';
        }

        $method = strtoupper($request->getMethod());
        if ('HEAD' === $method) {
            $command .= ' --head';
        } elseif ('GET' !== $method) {
            $command .= ' --request '.$method;
        }

        $command .= $this->getHeadersAsCommandOptions($request);

        $body = $request->getBody();
        if ($body->getSize() > 0) {
            // escapeshellarg argument max length on Windows, but longer body in curl command would be impractical anyways
            if ($body->getSize() > 8192) {
                $data = '[too long stream omitted]';
            } elseif ($body->isSeekable()) {
                $data = $body->__toString();
                $body->rewind();
                if (preg_match('/[\x00-\x1F\x7F]/', $data)) {
                    $data = '[binary stream omitted]';
                }
            } else {
                $data = '[non-seekable stream omitted]';
            }
            $escapedData = @escapeshellarg($data);
            if (empty($escapedData)) {
                $escapedData = 'We couldn\'t not escape the data properly';
            }

            $command .= sprintf(' --data %s', $escapedData);
        }

        return $command;
    }

    /**
     * {@inheritdoc}
     */
    public function formatResponse(ResponseInterface $response)
    {
        return '';
    }

    /**
     * @param RequestInterface $request
     *
     * @return string
     */
    private function getHeadersAsCommandOptions(RequestInterface $request)
    {
        $command = '';
        foreach ($request->getHeaders() as $name => $values) {
            if ('host' === strtolower($name) && $values[0] === $request->getUri()->getHost()) {
                continue;
            }

            if ('user-agent' === strtolower($name)) {
                $command .= sprintf(' -A %s', escapeshellarg($values[0]));

                continue;
            }

            $command .= sprintf(' -H %s', escapeshellarg($name.': '.$request->getHeaderLine($name)));
        }

        return $command;
    }
}


code:
<?php

namespace Http\Message\Formatter;

use Http\Message\Formatter;
use Psr\Http\Message\MessageInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;

/**
 * A formatter that prints the complete HTTP message.
 *
 * @author Tobias Nyholm <tobias.nyholm@gmail.com>
 */
class FullHttpMessageFormatter implements Formatter
{
    /**
     * The maximum length of the body.
     *
     * @var int|null
     */
    private $maxBodyLength;

    /**
     * @param int|null $maxBodyLength
     */
    public function __construct($maxBodyLength = 1000)
    {
        $this->maxBodyLength = $maxBodyLength;
    }

    /**
     * {@inheritdoc}
     */
    public function formatRequest(RequestInterface $request)
    {
        $message = sprintf(
            "%s %s HTTP/%s\n",
            $request->getMethod(),
            $request->getRequestTarget(),
            $request->getProtocolVersion()
        );

        foreach ($request->getHeaders() as $name => $values) {
            $message .= $name.': '.implode(', ', $values)."\n";
        }

        return $this->addBody($request, $message);
    }

    /**
     * {@inheritdoc}
     */
    public function formatResponse(ResponseInterface $response)
    {
        $message = sprintf(
            "HTTP/%s %s %s\n",
            $response->getProtocolVersion(),
            $response->getStatusCode(),
            $response->getReasonPhrase()
        );

        foreach ($response->getHeaders() as $name => $values) {
            $message .= $name.': '.implode(', ', $values)."\n";
        }

        return $this->addBody($response, $message);
    }

    /**
     * Add the message body if the stream is seekable.
     *
     * @param MessageInterface $request
     * @param string           $message
     *
     * @return string
     */
    private function addBody(MessageInterface $request, $message)
    {
        $stream = $request->getBody();
        if (!$stream->isSeekable() || 0 === $this->maxBodyLength) {
            // Do not read the stream
            return $message."\n";
        }

        if (null === $this->maxBodyLength) {
            $message .= "\n".$stream->__toString();
        } else {
            $message .= "\n".mb_substr($stream->__toString(), 0, $this->maxBodyLength);
        }

        $stream->rewind();

        return $message;
    }
}


code:
<?php

namespace Http\Message\Formatter;

use Http\Message\Formatter;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;

/**
 * Normalize a request or a response into a string or an array.
 *
 * @author Joel Wurtz <joel.wurtz@gmail.com>
 * @author Márk Sági-Kazár <mark.sagikazar@gmail.com>
 */
class SimpleFormatter implements Formatter
{
    /**
     * {@inheritdoc}
     */
    public function formatRequest(RequestInterface $request)
    {
        return sprintf(
            '%s %s %s',
            $request->getMethod(),
            $request->getUri()->__toString(),
            $request->getProtocolVersion()
        );
    }

    /**
     * {@inheritdoc}
     */
    public function formatResponse(ResponseInterface $response)
    {
        return sprintf(
            '%s %s %s',
            $response->getStatusCode(),
            $response->getReasonPhrase(),
            $response->getProtocolVersion()
        );
    }
}


code:
<?php

namespace Http\Message\MessageFactory;

use Http\Message\StreamFactory\DiactorosStreamFactory;
use Http\Message\MessageFactory;
use Zend\Diactoros\Request;
use Zend\Diactoros\Response;

/**
 * Creates Diactoros messages.
 *
 * @author GeLo <geloen.eric@gmail.com>
 */
final class DiactorosMessageFactory implements MessageFactory
{
    /**
     * @var DiactorosStreamFactory
     */
    private $streamFactory;

    public function __construct()
    {
        $this->streamFactory = new DiactorosStreamFactory();
    }

    /**
     * {@inheritdoc}
     */
    public function createRequest(
        $method,
        $uri,
        array $headers = [],
        $body = null,
        $protocolVersion = '1.1'
    ) {
        return (new Request(
            $uri,
            $method,
            $this->streamFactory->createStream($body),
            $headers
        ))->withProtocolVersion($protocolVersion);
    }

    /**
     * {@inheritdoc}
     */
    public function createResponse(
        $statusCode = 200,
        $reasonPhrase = null,
        array $headers = [],
        $body = null,
        $protocolVersion = '1.1'
    ) {
        return (new Response(
            $this->streamFactory->createStream($body),
            $statusCode,
            $headers
        ))->withProtocolVersion($protocolVersion);
    }
}


code:
<?php

namespace Http\Message\MessageFactory;

use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Response;
use Http\Message\MessageFactory;

/**
 * Creates Guzzle messages.
 *
 * @author Márk Sági-Kazár <mark.sagikazar@gmail.com>
 */
final class GuzzleMessageFactory implements MessageFactory
{
    /**
     * {@inheritdoc}
     */
    public function createRequest(
        $method,
        $uri,
        array $headers = [],
        $body = null,
        $protocolVersion = '1.1'
    ) {
        return new Request(
            $method,
            $uri,
            $headers,
            $body,
            $protocolVersion
        );
    }

    /**
     * {@inheritdoc}
     */
    public function createResponse(
        $statusCode = 200,
        $reasonPhrase = null,
        array $headers = [],
        $body = null,
        $protocolVersion = '1.1'
    ) {
        return new Response(
            $statusCode,
            $headers,
            $body,
            $protocolVersion,
            $reasonPhrase
        );
    }
}


code:
<?php

namespace Http\Message\MessageFactory;

use Http\Message\StreamFactory\SlimStreamFactory;
use Http\Message\UriFactory\SlimUriFactory;
use Http\Message\MessageFactory;
use Slim\Http\Request;
use Slim\Http\Response;
use Slim\Http\Headers;

/**
 * Creates Slim 3 messages.
 *
 * @author Mika Tuupola <tuupola@appelsiini.net>
 */
final class SlimMessageFactory implements MessageFactory
{
    /**
     * @var SlimStreamFactory
     */
    private $streamFactory;

    /**
     * @var SlimUriFactory
     */
    private $uriFactory;

    public function __construct()
    {
        $this->streamFactory = new SlimStreamFactory();
        $this->uriFactory = new SlimUriFactory();
    }

    /**
     * {@inheritdoc}
     */
    public function createRequest(
        $method,
        $uri,
        array $headers = [],
        $body = null,
        $protocolVersion = '1.1'
    ) {
        return (new Request(
            $method,
            $this->uriFactory->createUri($uri),
            new Headers($headers),
            [],
            [],
            $this->streamFactory->createStream($body),
            []
        ))->withProtocolVersion($protocolVersion);
    }

    /**
     * {@inheritdoc}
     */
    public function createResponse(
        $statusCode = 200,
        $reasonPhrase = null,
        array $headers = [],
        $body = null,
        $protocolVersion = '1.1'
    ) {
        return (new Response(
            $statusCode,
            new Headers($headers),
            $this->streamFactory->createStream($body)
        ))->withProtocolVersion($protocolVersion);
    }
}


code:
<?php

namespace Http\Message;

use Psr\Http\Message\RequestInterface;

/**
 * Match a request.
 *
 * PSR-7 equivalent of Symfony's RequestMatcher
 *
 * @see https://github.com/symfony/symfony/blob/master/src/Symfony/Component/HttpFoundation/RequestMatcherInterface.php
 *
 * @author Joel Wurtz <joel.wurtz@gmail.com>
 */
interface RequestMatcher
{
    /**
     * Decides whether the rule(s) implemented by the strategy matches the supplied request.
     *
     * @param RequestInterface $request The PSR7 request to check for a match
     *
     * @return bool true if the request matches, false otherwise
     */
    public function matches(RequestInterface $request);
}


code:
<?php

namespace Http\Message\RequestMatcher;

use Http\Message\RequestMatcher;
use Psr\Http\Message\RequestInterface;

/**
 * Match a request with a callback.
 *
 * @author Márk Sági-Kazár <mark.sagikazar@gmail.com>
 */
final class CallbackRequestMatcher implements RequestMatcher
{
    /**
     * @var callable
     */
    private $callback;

    /**
     * @param callable $callback
     */
    public function __construct(callable $callback)
    {
        $this->callback = $callback;
    }

    /**
     * {@inheritdoc}
     */
    public function matches(RequestInterface $request)
    {
        return (bool) call_user_func($this->callback, $request);
    }
}


code:
<?php

namespace Http\Message\RequestMatcher;

use Http\Message\RequestMatcher;
use Psr\Http\Message\RequestInterface;

@trigger_error('The '.__NAMESPACE__.'\RegexRequestMatcher class is deprecated since version 1.2 and will be removed in 2.0. Use Http\Message\RequestMatcher\RequestMatcher instead.', E_USER_DEPRECATED);

/**
 * Match a request with a regex on the uri.
 *
 * @author Joel Wurtz <joel.wurtz@gmail.com>
 *
 * @deprecated since version 1.2 and will be removed in 2.0. Use {@link RequestMatcher} instead.
 */
final class RegexRequestMatcher implements RequestMatcher
{
    /**
     * Matching regex.
     *
     * @var string
     */
    private $regex;

    /**
     * @param string $regex
     */
    public function __construct($regex)
    {
        $this->regex = $regex;
    }

    /**
     * {@inheritdoc}
     */
    public function matches(RequestInterface $request)
    {
        return (bool) preg_match($this->regex, (string) $request->getUri());
    }
}


code:
<?php

namespace Http\Message\RequestMatcher;

use Http\Message\RequestMatcher as RequestMatcherInterface;
use Psr\Http\Message\RequestInterface;

/**
 * A port of the Symfony RequestMatcher for PSR-7.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 * @author Joel Wurtz <joel.wurtz@gmail.com>
 */
final class RequestMatcher implements RequestMatcherInterface
{
    /**
     * @var string
     */
    private $path;

    /**
     * @var string
     */
    private $host;

    /**
     * @var array
     */
    private $methods = [];

    /**
     * @var string[]
     */
    private $schemes = [];

    /**
     * The regular expressions used for path or host must be specified without delimiter.
     * You do not need to escape the forward slash / to match it.
     *
     * @param string|null          $path    Regular expression for the path
     * @param string|null          $host    Regular expression for the hostname
     * @param string|string[]|null $methods Method or list of methods to match
     * @param string|string[]|null $schemes Scheme or list of schemes to match (e.g. http or https)
     */
    public function __construct($path = null, $host = null, $methods = [], $schemes = [])
    {
        $this->path = $path;
        $this->host = $host;
        $this->methods = array_map('strtoupper', (array) $methods);
        $this->schemes = array_map('strtolower', (array) $schemes);
    }

    /**
     * {@inheritdoc}
     *
     * @api
     */
    public function matches(RequestInterface $request)
    {
        if ($this->schemes && !in_array($request->getUri()->getScheme(), $this->schemes)) {
            return false;
        }

        if ($this->methods && !in_array($request->getMethod(), $this->methods)) {
            return false;
        }

        if (null !== $this->path && !preg_match('{'.$this->path.'}', rawurldecode($request->getUri()->getPath()))) {
            return false;
        }

        if (null !== $this->host && !preg_match('{'.$this->host.'}i', $request->getUri()->getHost())) {
            return false;
        }

        return true;
    }
}


code:
<?php

namespace Http\Message\Stream;

use Psr\Http\Message\StreamInterface;

/**
 * Decorator to make any stream seekable.
 *
 * Internally it buffers an existing StreamInterface into a php://temp resource (or memory). By default it will use
 * 2 megabytes of memory before writing to a temporary disk file.
 *
 * Due to this, very large stream can suffer performance issue (i/o slowdown).
 */
class BufferedStream implements StreamInterface
{
    /** @var resource The buffered resource used to seek previous data */
    private $resource;

    /** @var int size of the stream if available */
    private $size;

    /** @var StreamInterface The underlying stream decorated by this class */
    private $stream;

    /** @var int How many bytes were written */
    private $written = 0;

    /**
     * @param StreamInterface $stream        Decorated stream
     * @param bool            $useFileBuffer Whether to use a file buffer (write to a file, if data exceed a certain size)
     *                                       by default, set this to false to only use memory
     * @param int             $memoryBuffer  In conjunction with using file buffer, limit (in bytes) from which it begins to buffer
     *                                       the data in a file
     */
    public function __construct(StreamInterface $stream, $useFileBuffer = true, $memoryBuffer = 2097152)
    {
        $this->stream = $stream;
        $this->size = $stream->getSize();

        if ($useFileBuffer) {
            $this->resource = fopen('php://temp/maxmemory:'.$memoryBuffer, 'rw+');
        } else {
            $this->resource = fopen('php://memory', 'rw+');
        }

        if (false === $this->resource) {
            throw new \RuntimeException('Cannot create a resource over temp or memory implementation');
        }
    }

    /**
     * {@inheritdoc}
     */
    public function __toString()
    {
        try {
            $this->rewind();

            return $this->getContents();
        } catch (\Throwable $throwable) {
            return '';
        } catch (\Exception $exception) { // Layer to be BC with PHP 5, remove this when we only support PHP 7+
            return '';
        }
    }

    /**
     * {@inheritdoc}
     */
    public function close()
    {
        if (null === $this->resource) {
            throw new \RuntimeException('Cannot close on a detached stream');
        }

        $this->stream->close();
        fclose($this->resource);
    }

    /**
     * {@inheritdoc}
     */
    public function detach()
    {
        if (null === $this->resource) {
            return;
        }

        // Force reading the remaining data of the stream
        $this->getContents();

        $resource = $this->resource;
        $this->stream->close();
        $this->stream = null;
        $this->resource = null;

        return $resource;
    }

    /**
     * {@inheritdoc}
     */
    public function getSize()
    {
        if (null === $this->resource) {
            return;
        }

        if (null === $this->size && $this->stream->eof()) {
            return $this->written;
        }

        return $this->size;
    }

    /**
     * {@inheritdoc}
     */
    public function tell()
    {
        if (null === $this->resource) {
            throw new \RuntimeException('Cannot tell on a detached stream');
        }

        return ftell($this->resource);
    }

    /**
     * {@inheritdoc}
     */
    public function eof()
    {
        if (null === $this->resource) {
            throw new \RuntimeException('Cannot call eof on a detached stream');
        }

        // We are at the end only when both our resource and underlying stream are at eof
        return $this->stream->eof() && (ftell($this->resource) === $this->written);
    }

    /**
     * {@inheritdoc}
     */
    public function isSeekable()
    {
        return null !== $this->resource;
    }

    /**
     * {@inheritdoc}
     */
    public function seek($offset, $whence = SEEK_SET)
    {
        if (null === $this->resource) {
            throw new \RuntimeException('Cannot seek on a detached stream');
        }

        fseek($this->resource, $offset, $whence);
    }

    /**
     * {@inheritdoc}
     */
    public function rewind()
    {
        if (null === $this->resource) {
            throw new \RuntimeException('Cannot rewind on a detached stream');
        }

        rewind($this->resource);
    }

    /**
     * {@inheritdoc}
     */
    public function isWritable()
    {
        return false;
    }

    /**
     * {@inheritdoc}
     */
    public function write($string)
    {
        throw new \RuntimeException('Cannot write on this stream');
    }

    /**
     * {@inheritdoc}
     */
    public function isReadable()
    {
        return null !== $this->resource;
    }

    /**
     * {@inheritdoc}
     */
    public function read($length)
    {
        if (null === $this->resource) {
            throw new \RuntimeException('Cannot read on a detached stream');
        }

        $read = '';

        // First read from the resource
        if (ftell($this->resource) !== $this->written) {
            $read = fread($this->resource, $length);
        }

        $bytesRead = strlen($read);

        if ($bytesRead < $length) {
            $streamRead = $this->stream->read($length - $bytesRead);

            // Write on the underlying stream what we read
            $this->written += fwrite($this->resource, $streamRead);
            $read .= $streamRead;
        }

        return $read;
    }

    /**
     * {@inheritdoc}
     */
    public function getContents()
    {
        if (null === $this->resource) {
            throw new \RuntimeException('Cannot read on a detached stream');
        }

        $read = '';

        while (!$this->eof()) {
            $read .= $this->read(8192);
        }

        return $read;
    }

    /**
     * {@inheritdoc}
     */
    public function getMetadata($key = null)
    {
        if (null === $this->resource) {
            if (null === $key) {
                return [];
            }

            return;
        }

        $metadata = stream_get_meta_data($this->resource);

        if (null === $key) {
            return $metadata;
        }

        if (!array_key_exists($key, $metadata)) {
            return;
        }

        return $metadata[$key];
    }
}


code:
<?php

namespace Http\Message\StreamFactory;

use Http\Message\StreamFactory;
use Psr\Http\Message\StreamInterface;
use Zend\Diactoros\Stream;

/**
 * Creates Diactoros streams.
 *
 * @author Михаил Красильников <m.krasilnikov@yandex.ru>
 */
final class DiactorosStreamFactory implements StreamFactory
{
    /**
     * {@inheritdoc}
     */
    public function createStream($body = null)
    {
        if ($body instanceof StreamInterface) {
            return $body;
        }

        if (is_resource($body)) {
            return new Stream($body);
        }

        $stream = new Stream('php://memory', 'rw');
        if (null !== $body && '' !== $body) {
            $stream->write((string) $body);
        }

        return $stream;
    }
}


code:
<?php

namespace Http\Message\StreamFactory;

use Http\Message\StreamFactory;

/**
 * Creates Guzzle streams.
 *
 * @author Михаил Красильников <m.krasilnikov@yandex.ru>
 */
final class GuzzleStreamFactory implements StreamFactory
{
    /**
     * {@inheritdoc}
     */
    public function createStream($body = null)
    {
        return \GuzzleHttp\Psr7\stream_for($body);
    }
}


code:
<?php

namespace Http\Message\StreamFactory;

use Http\Message\StreamFactory;
use Psr\Http\Message\StreamInterface;
use Slim\Http\Stream;

/**
 * Creates Slim 3 streams.
 *
 * @author Mika Tuupola <tuupola@appelsiini.net>
 */
final class SlimStreamFactory implements StreamFactory
{
    /**
     * {@inheritdoc}
     */
    public function createStream($body = null)
    {
        if ($body instanceof StreamInterface) {
            return $body;
        }

        if (is_resource($body)) {
            return new Stream($body);
        }

        $resource = fopen('php://memory', 'r+');
        $stream = new Stream($resource);
        if (null !== $body && '' !== $body) {
            $stream->write((string) $body);
        }

        return $stream;
    }
}


code:
<?php

namespace Http\Message\UriFactory;

use Http\Message\UriFactory;
use Psr\Http\Message\UriInterface;
use Zend\Diactoros\Uri;

/**
 * Creates Diactoros URI.
 *
 * @author David de Boer <david@ddeboer.nl>
 */
final class DiactorosUriFactory implements UriFactory
{
    /**
     * {@inheritdoc}
     */
    public function createUri($uri)
    {
        if ($uri instanceof UriInterface) {
            return $uri;
        } elseif (is_string($uri)) {
            return new Uri($uri);
        }

        throw new \InvalidArgumentException('URI must be a string or UriInterface');
    }
}


code:
<?php

namespace Http\Message\UriFactory;

use GuzzleHttp\Psr7;
use Http\Message\UriFactory;

/**
 * Creates Guzzle URI.
 *
 * @author David de Boer <david@ddeboer.nl>
 */
final class GuzzleUriFactory implements UriFactory
{
    /**
     * {@inheritdoc}
     */
    public function createUri($uri)
    {
        return Psr7\uri_for($uri);
    }
}


code:
<?php

namespace Http\Message\UriFactory;

use Http\Message\UriFactory;
use Psr\Http\Message\UriInterface;
use Slim\Http\Uri;

/**
 * Creates Slim 3 URI.
 *
 * @author Mika Tuupola <tuupola@appelsiini.net>
 */
final class SlimUriFactory implements UriFactory
{
    /**
     * {@inheritdoc}
     */
    public function createUri($uri)
    {
        if ($uri instanceof UriInterface) {
            return $uri;
        }

        if (is_string($uri)) {
            return Uri::createFromString($uri);
        }

        throw new \InvalidArgumentException('URI must be a string or UriInterface');
    }
}


code:
<?php

// Register chunk filter if not found
if (!array_key_exists('chunk', stream_get_filters())) {
    stream_filter_register('chunk', 'Http\Message\Encoding\Filter\Chunk');
}


code:
# Change Log

## 1.0.0 - 2016-01-26

### Removed

- PSR-7 dependency

## 1.0.0-RC1 - 2016-01-12

### Added

- Tests for full coverage

## Changed

- Updated package files
- Clarified wait method behavior
- Contributing guide moved to the documentation

## 0.1.1 - 2015-12-24

## Added

- Fulfilled and Rejected promise implementations

## 0.1.0 - 2015-12-13

## Added

- Promise interface


code:
# Promise

[![Latest Version](https://img.shields.io/github/release/php-http/promise.svg?style=flat-square)](https://github.com/php-http/promise/releases)
[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE)
[![Build Status](https://img.shields.io/travis/php-http/promise.svg?style=flat-square)](https://travis-ci.org/php-http/promise)
[![Code Coverage](https://img.shields.io/scrutinizer/coverage/g/php-http/promise.svg?style=flat-square)](https://scrutinizer-ci.com/g/php-http/promise)
[![Quality Score](https://img.shields.io/scrutinizer/g/php-http/promise.svg?style=flat-square)](https://scrutinizer-ci.com/g/php-http/promise)
[![Total Downloads](https://img.shields.io/packagist/dt/php-http/promise.svg?style=flat-square)](https://packagist.org/packages/php-http/promise)

**Promise used for asynchronous HTTP requests.**

**Note:** This will eventually be removed/deprecated and replaced with the upcoming Promise PSR.

## Install

Via Composer

``` bash
$ composer require php-http/promise
```

## Documentation

Please see the [official documentation](http://docs.php-http.org).

## Testing

``` bash
$ composer test
```

## Contributing

Please see our [contributing guide](http://docs.php-http.org/en/latest/development/contributing.html).

## Security

If you discover any security related issues, please contact us at [security@httplug.io](mailto:security@httplug.io)
or [security@php-http.org](mailto:security@php-http.org).

## License

The MIT License (MIT). Please see [License File](LICENSE) for more information.


php-http/promise

description: Promise used for asynchronous HTTP requests

license: MIT

Http\Promise\: src/

test: vendor/bin/phpspec run

test-ci: vendor/bin/phpspec run -c phpspec.yml.ci


code:
<?php

namespace Http\Promise;

/**
 * A promise already fulfilled.
 *
 * @author Joel Wurtz <joel.wurtz@gmail.com>
 */
final class FulfilledPromise implements Promise
{
    /**
     * @var mixed
     */
    private $result;

    /**
     * @param $result
     */
    public function __construct($result)
    {
        $this->result = $result;
    }

    /**
     * {@inheritdoc}
     */
    public function then(callable $onFulfilled = null, callable $onRejected = null)
    {
        if (null === $onFulfilled) {
            return $this;
        }

        try {
            return new self($onFulfilled($this->result));
        } catch (\Exception $e) {
            return new RejectedPromise($e);
        }
    }

    /**
     * {@inheritdoc}
     */
    public function getState()
    {
        return Promise::FULFILLED;
    }

    /**
     * {@inheritdoc}
     */
    public function wait($unwrap = true)
    {
        if ($unwrap) {
            return $this->result;
        }
    }
}


code:
<?php

namespace Http\Promise;

/**
 * Promise represents a value that may not be available yet, but will be resolved at some point in future.
 * It acts like a proxy to the actual value.
 *
 * This interface is an extension of the promises/a+ specification.
 *
 * @see https://promisesaplus.com/
 *
 * @author Joel Wurtz <joel.wurtz@gmail.com>
 * @author Márk Sági-Kazár <mark.sagikazar@gmail.com>
 */
interface Promise
{
    /**
     * Promise has not been fulfilled or rejected.
     */
    const PENDING = 'pending';

    /**
     * Promise has been fulfilled.
     */
    const FULFILLED = 'fulfilled';

    /**
     * Promise has been rejected.
     */
    const REJECTED = 'rejected';

    /**
     * Adds behavior for when the promise is resolved or rejected (response will be available, or error happens).
     *
     * If you do not care about one of the cases, you can set the corresponding callable to null
     * The callback will be called when the value arrived and never more than once.
     *
     * @param callable $onFulfilled Called when a response will be available.
     * @param callable $onRejected  Called when an exception occurs.
     *
     * @return Promise A new resolved promise with value of the executed callback (onFulfilled / onRejected).
     */
    public function then(callable $onFulfilled = null, callable $onRejected = null);

    /**
     * Returns the state of the promise, one of PENDING, FULFILLED or REJECTED.
     *
     * @return string
     */
    public function getState();

    /**
     * Wait for the promise to be fulfilled or rejected.
     *
     * When this method returns, the request has been resolved and if callables have been
     * specified, the appropriate one has terminated.
     *
     * When $unwrap is true (the default), the response is returned, or the exception thrown
     * on failure. Otherwise, nothing is returned or thrown.
     *
     * @param bool $unwrap Whether to return resolved value / throw reason or not
     *
     * @return mixed Resolved value, null if $unwrap is set to false
     *
     * @throws \Exception The rejection reason if $unwrap is set to true and the request failed.
     */
    public function wait($unwrap = true);
}


code:
<?php

namespace Http\Promise;

/**
 * A rejected promise.
 *
 * @author Joel Wurtz <joel.wurtz@gmail.com>
 */
final class RejectedPromise implements Promise
{
    /**
     * @var \Exception
     */
    private $exception;

    /**
     * @param \Exception $exception
     */
    public function __construct(\Exception $exception)
    {
        $this->exception = $exception;
    }

    /**
     * {@inheritdoc}
     */
    public function then(callable $onFulfilled = null, callable $onRejected = null)
    {
        if (null === $onRejected) {
            return $this;
        }

        try {
            return new FulfilledPromise($onRejected($this->exception));
        } catch (\Exception $e) {
            return new self($e);
        }
    }

    /**
     * {@inheritdoc}
     */
    public function getState()
    {
        return Promise::REJECTED;
    }

    /**
     * {@inheritdoc}
     */
    public function wait($unwrap = true)
    {
        if ($unwrap) {
            throw $this->exception;
        }
    }
}


code:
phpseclib Lead Developer:  TerraFrost (Jim Wigginton)

phpseclib Developers:      monnerat (Patrick Monnerat)
                           bantu (Andreas Fischer)
                           petrich (Hans-Jürgen Petrich)
                           GrahamCampbell (Graham Campbell)

path: vendor/phpseclib/phpseclib/AUTHORS


code:
# phpseclib - PHP Secure Communications Library

[![Build Status](https://travis-ci.org/phpseclib/phpseclib.svg?branch=master)](https://travis-ci.org/phpseclib/phpseclib)

MIT-licensed pure-PHP implementations of an arbitrary-precision integer
arithmetic library, fully PKCS#1 (v2.1) compliant RSA, DES, 3DES, RC4, Rijndael,
AES, Blowfish, Twofish, SSH-1, SSH-2, SFTP, and X.509

* [Download (1.0.2)](http://sourceforge.net/projects/phpseclib/files/phpseclib1.0.2.zip/download)
* [Browse Git](https://github.com/phpseclib/phpseclib)
* [Code Coverage Report](http://phpseclib.bantux.org/code_coverage/master/latest/)

<img src="http://phpseclib.sourceforge.net/pear-icon.png" alt="PEAR Channel" width="16" height="16">
PEAR Channel: [phpseclib.sourceforge.net](http://phpseclib.sourceforge.net/pear.htm)

## Documentation

* [Documentation / Manual](http://phpseclib.sourceforge.net/)
* [API Documentation](http://phpseclib.bantux.org/api/master/) (generated by Sami)

## Support

Need Support?

* [Checkout Questions and Answers on Stack Overflow](http://stackoverflow.com/questions/tagged/phpseclib)
* [Create a Support Ticket on GitHub](https://github.com/phpseclib/phpseclib/issues/new)
* [Browse the Support Forum](http://www.frostjedi.com/phpbb/viewforum.php?f=46) (no longer in use)

## Installing Development Dependencies

Dependencies are managed via Composer.

1. Download the [`composer.phar`](https://getcomposer.org/composer.phar) executable as per the
   [Composer Download Instructions](https://getcomposer.org/download/), e.g. by running

    ``` sh
    curl -sS https://getcomposer.org/installer | php
    ```

2. Install Dependencies

    ``` sh
    php composer.phar install
    ```

## Contributing

1. Fork the Project

2. Install Development Dependencies

3. Create a Feature Branch

4. (Recommended) Run the Test Suite

    ``` sh
    vendor/bin/phpunit
    ```
5. (Recommended) Check whether your code conforms to our Coding Standards by running

    ``` sh
    vendor/bin/phing -f build/build.xml sniff
    ```

6. Send us a Pull Request


phpseclib/phpseclib

type: library

description: PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.

keywords: security crypto cryptography encryption signature signing rsa aes blowfish twofish ssh sftp x509 x.509 asn1 asn.1 BigInteger

Jim Wigginton

role: Lead Developer

Patrick Monnerat

role: Developer

ext-libsodium: SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.

ext-openssl: Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations.

ext-mcrypt: Install the Mcrypt extension in order to speed up a few other cryptographic operations.

ext-gmp: Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.

phpseclib\: phpseclib/


_readme: This file locks the dependencies of your project to a known state

_readme: Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file

type: git

type: zip

ParagonIE\ConstantTime\: src/

Paragon Initiative Enterprises

role: Maintainer

Steve 'Sc00bz' Thomas

role: Original Developer

description: Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)

ext-libsodium: Provides a modern crypto API that can be used to generate random bytes.

description: PHP 5.x polyfill for random_bytes() and random_int() from PHP 7

keywords: csprng pseudorandom random

doctrine/instantiator

Doctrine\Instantiator\: src/Doctrine/Instantiator/

description: A small, lightweight utility to instantiate objects in PHP without invoking their constructors

keywords: constructor instantiate

michelf/php-markdown

description: PHP Markdown

nikic/php-parser

PHPParser: lib/

description: A PHP parser written in PHP

keywords: parser php

phing/phing

pear/http_request2: dev-trunk

pear/net_growl: dev-trunk

pdepend/pdepend: PHP version of JDepend

pear/archive_tar: Tar file management class

pear/versioncontrol_git: A library that provides OO interface to handle Git repository

pear/versioncontrol_svn: A simple OO-style interface for Subversion, the free/open-source version control system

phpdocumentor/phpdocumentor: Documentation Generator for PHP

phploc/phploc: A tool for quickly measuring the size of a PHP project

phpmd/phpmd: PHP version of PMD tool

phpunit/phpunit: The PHP Unit Testing Framework

sebastian/phpcpd: Copy/Paste Detector (CPD) for PHP code

tedivm/jshrink: Javascript Minifier built in PHP

description: PHing Is Not GNU make; it's a PHP project build system or build tool based on Apache Ant.

keywords: build phing task tool

phpspec/prophecy

Prophecy\: src/

description: Highly opinionated mocking framework for PHP 5.3+

keywords: Double Dummy fake mock spy stub

phpunit/php-code-coverage

Sebastian Bergmann

role: lead

description: Library that provides collection, processing, and rendering functionality for PHP code coverage information.

keywords: coverage testing xunit

phpunit/php-file-iterator

description: FilterIterator implementation that filters files based on a list of suffixes.

keywords: filesystem iterator

phpunit/php-text-template

description: Simple template engine.

phpunit/php-timer

description: Utility class for timing

phpunit/php-token-stream

description: Wrapper around PHP's tokenizer extension.

phpunit/phpunit

description: The PHP Unit Testing framework.

keywords: phpunit testing xunit

phpunit/phpunit-mock-objects

description: Mock Object library for PHPUnit

keywords: mock xunit

pimple/pimple

Pimple: src/

description: Pimple is a simple Dependency Injection Container for PHP 5.3

keywords:
container
dependency injection

sami/sami

type: application

description: Sami, an API documentation generator

sebastian/comparator

description: Provides the functionality to compare PHP values for equality

keywords: comparator compare equality

sebastian/diff

description: Diff implementation

sebastian/environment

description: Provides functionality to handle HHVM/PHP environments

keywords: Xdebug environment hhvm

sebastian/exporter

description: Provides the functionality to export PHP variables for visualization

keywords: export exporter

sebastian/global-state

description: Snapshotting of global state

sebastian/recursion-context

description: Provides functionality to recursively process PHP variables

sebastian/version

description: Library that helps with managing the version number of Git-hosted PHP projects

description: PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.

symfony/console

description: Symfony Console Component

symfony/filesystem

description: Symfony Filesystem Component

symfony/finder

description: Symfony Finder Component

symfony/polyfill-mbstring

description: Symfony polyfill for the Mbstring extension

keywords: compatibility mbstring polyfill portable shim

symfony/process

description: Symfony Process Component

symfony/yaml

description: Symfony Yaml Component

twig/twig

description: Twig, the flexible, fast, and secure template language for PHP


code:
<?php

/**
 * Pure-PHP implementation of AES.
 *
 * Uses mcrypt, if available/possible, and an internal implementation, otherwise.
 *
 * PHP version 5
 *
 * NOTE: Since AES.php is (for compatibility and phpseclib-historical reasons) virtually
 * just a wrapper to Rijndael.php you may consider using Rijndael.php instead of
 * to save one include_once().
 *
 * If {@link self::setKeyLength() setKeyLength()} isn't called, it'll be calculated from
 * {@link self::setKey() setKey()}.  ie. if the key is 128-bits, the key length will be 128-bits.  If it's 136-bits
 * it'll be null-padded to 192-bits and 192 bits will be the key length until {@link self::setKey() setKey()}
 * is called, again, at which point, it'll be recalculated.
 *
 * Since \phpseclib\Crypt\AES extends \phpseclib\Crypt\Rijndael, some functions are available to be called that, in the context of AES, don't
 * make a whole lot of sense.  {@link self::setBlockLength() setBlockLength()}, for instance.  Calling that function,
 * however possible, won't do anything (AES has a fixed block length whereas Rijndael has a variable one).
 *
 * Here's a short example of how to use this library:
 * <code>
 * <?php
 *    include 'vendor/autoload.php';
 *
 *    $aes = new \phpseclib\Crypt\AES();
 *
 *    $aes->setKey('abcdefghijklmnop');
 *
 *    $size = 10 * 1024;
 *    $plaintext = '';
 *    for ($i = 0; $i < $size; $i++) {
 *        $plaintext.= 'a';
 *    }
 *
 *    echo $aes->decrypt($aes->encrypt($plaintext));
 * ?>
 * </code>
 *
 * @category  Crypt
 * @package   AES
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2008 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib\Crypt;

/**
 * Pure-PHP implementation of AES.
 *
 * @package AES
 * @author  Jim Wigginton <terrafrost@php.net>
 * @access  public
 */
class AES extends Rijndael
{
    /**
     * Dummy function
     *
     * Since \phpseclib\Crypt\AES extends \phpseclib\Crypt\Rijndael, this function is, technically, available, but it doesn't do anything.
     *
     * @see \phpseclib\Crypt\Rijndael::setBlockLength()
     * @access public
     * @param int $length
     * @throws \BadMethodCallException anytime it's called
     */
    function setBlockLength($length)
    {
        throw new \BadMethodCallException('The block length cannot be set for AES.');
    }

    /**
     * Sets the key length
     *
     * Valid key lengths are 128, 192, and 256.  Set the link to bool(false) to disable a fixed key length
     *
     * @see \phpseclib\Crypt\Rijndael:setKeyLength()
     * @access public
     * @param int $length
     * @throws \LengthException if the key length isn't supported
     */
    function setKeyLength($length)
    {
        switch ($length) {
            case 128:
            case 192:
            case 256:
                break;
            default:
                throw new \LengthException('Key of size ' . $length . ' not supported by this algorithm. Only keys of sizes 128, 192 or 256 supported');
        }
        parent::setKeyLength($length);
    }

    /**
     * Sets the key.
     *
     * Rijndael supports five different key lengths, AES only supports three.
     *
     * @see \phpseclib\Crypt\Rijndael:setKey()
     * @see setKeyLength()
     * @access public
     * @param string $key
     * @throws \LengthException if the key length isn't supported
     */
    function setKey($key)
    {
        switch (strlen($key)) {
            case 16:
            case 24:
            case 32:
                break;
            default:
                throw new \LengthException('Key of size ' . strlen($key) . ' not supported by this algorithm. Only keys of sizes 16, 24 or 32 supported');
        }

        parent::setKey($key);
    }
}