Update to drupal 8.0.0-rc1. For more information, see https://www.drupal.org/node/2582663
This commit is contained in:
parent
eb34d130a8
commit
f32e58e4b1
8476 changed files with 211648 additions and 170042 deletions
152
vendor/zendframework/zend-diactoros/src/AbstractSerializer.php
vendored
Normal file
152
vendor/zendframework/zend-diactoros/src/AbstractSerializer.php
vendored
Normal file
|
@ -0,0 +1,152 @@
|
|||
<?php
|
||||
/**
|
||||
* Zend Framework (http://framework.zend.com/)
|
||||
*
|
||||
* @see http://github.com/zendframework/zend-diactoros for the canonical source repository
|
||||
* @copyright Copyright (c) 2015 Zend Technologies USA Inc. (http://www.zend.com)
|
||||
* @license https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License
|
||||
*/
|
||||
|
||||
namespace Zend\Diactoros;
|
||||
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
use UnexpectedValueException;
|
||||
|
||||
/**
|
||||
* Provides base functionality for request and response de/serialization
|
||||
* strategies, including functionality for retrieving a line at a time from
|
||||
* the message, splitting headers from the body, and serializing headers.
|
||||
*/
|
||||
abstract class AbstractSerializer
|
||||
{
|
||||
const CR = "\r";
|
||||
const EOL = "\r\n";
|
||||
const LF = "\n";
|
||||
|
||||
/**
|
||||
* Retrieve a single line from the stream.
|
||||
*
|
||||
* Retrieves a line from the stream; a line is defined as a sequence of
|
||||
* characters ending in a CRLF sequence.
|
||||
*
|
||||
* @param StreamInterface $stream
|
||||
* @return string
|
||||
* @throws UnexpectedValueException if the sequence contains a CR or LF in
|
||||
* isolation, or ends in a CR.
|
||||
*/
|
||||
protected static function getLine(StreamInterface $stream)
|
||||
{
|
||||
$line = '';
|
||||
$crFound = false;
|
||||
while (! $stream->eof()) {
|
||||
$char = $stream->read(1);
|
||||
|
||||
if ($crFound && $char === self::LF) {
|
||||
$crFound = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// CR NOT followed by LF
|
||||
if ($crFound && $char !== self::LF) {
|
||||
throw new UnexpectedValueException('Unexpected carriage return detected');
|
||||
}
|
||||
|
||||
// LF in isolation
|
||||
if (! $crFound && $char === self::LF) {
|
||||
throw new UnexpectedValueException('Unexpected line feed detected');
|
||||
}
|
||||
|
||||
// CR found; do not append
|
||||
if ($char === self::CR) {
|
||||
$crFound = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Any other character: append
|
||||
$line .= $char;
|
||||
}
|
||||
|
||||
// CR found at end of stream
|
||||
if ($crFound) {
|
||||
throw new UnexpectedValueException("Unexpected end of headers");
|
||||
}
|
||||
|
||||
return $line;
|
||||
}
|
||||
|
||||
/**
|
||||
* Split the stream into headers and body content.
|
||||
*
|
||||
* Returns an array containing two elements
|
||||
*
|
||||
* - The first is an array of headers
|
||||
* - The second is a StreamInterface containing the body content
|
||||
*
|
||||
* @param StreamInterface $stream
|
||||
* @return array
|
||||
* @throws UnexpectedValueException For invalid headers.
|
||||
*/
|
||||
protected static function splitStream(StreamInterface $stream)
|
||||
{
|
||||
$headers = [];
|
||||
$currentHeader = false;
|
||||
|
||||
while ($line = self::getLine($stream)) {
|
||||
if (preg_match(';^(?P<name>[!#$%&\'*+.^_`\|~0-9a-zA-Z-]+):(?P<value>.*)$;', $line, $matches)) {
|
||||
$currentHeader = $matches['name'];
|
||||
if (! isset($headers[$currentHeader])) {
|
||||
$headers[$currentHeader] = [];
|
||||
}
|
||||
$headers[$currentHeader][] = ltrim($matches['value']);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! $currentHeader) {
|
||||
throw new UnexpectedValueException('Invalid header detected');
|
||||
}
|
||||
|
||||
if (! preg_match('#^[ \t]#', $line)) {
|
||||
throw new UnexpectedValueException('Invalid header continuation');
|
||||
}
|
||||
|
||||
// Append continuation to last header value found
|
||||
$value = array_pop($headers[$currentHeader]);
|
||||
$headers[$currentHeader][] = $value . ltrim($line);
|
||||
}
|
||||
|
||||
// use RelativeStream to avoid copying initial stream into memory
|
||||
return [$headers, new RelativeStream($stream, $stream->tell())];
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize headers to string values.
|
||||
*
|
||||
* @param array $headers
|
||||
* @return string
|
||||
*/
|
||||
protected static function serializeHeaders(array $headers)
|
||||
{
|
||||
$lines = [];
|
||||
foreach ($headers as $header => $values) {
|
||||
$normalized = self::filterHeader($header);
|
||||
foreach ($values as $value) {
|
||||
$lines[] = sprintf('%s: %s', $normalized, $value);
|
||||
}
|
||||
}
|
||||
|
||||
return implode("\r\n", $lines);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter a header name to wordcase
|
||||
*
|
||||
* @param string $header
|
||||
* @return string
|
||||
*/
|
||||
protected static function filterHeader($header)
|
||||
{
|
||||
$filtered = str_replace('-', ' ', $header);
|
||||
$filtered = ucwords($filtered);
|
||||
return str_replace(' ', '-', $filtered);
|
||||
}
|
||||
}
|
19
vendor/zendframework/zend-diactoros/src/Exception/DeprecatedMethodException.php
vendored
Normal file
19
vendor/zendframework/zend-diactoros/src/Exception/DeprecatedMethodException.php
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
/**
|
||||
* Zend Framework (http://framework.zend.com/)
|
||||
*
|
||||
* @see http://github.com/zendframework/zend-diactoros for the canonical source repository
|
||||
* @copyright Copyright (c) 2015 Zend Technologies USA Inc. (http://www.zend.com)
|
||||
* @license https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License
|
||||
*/
|
||||
|
||||
namespace Zend\Diactoros\Exception;
|
||||
|
||||
use BadMethodCallException;
|
||||
|
||||
/**
|
||||
* Exception indicating a deprecated method.
|
||||
*/
|
||||
class DeprecatedMethodException extends BadMethodCallException implements ExceptionInterface
|
||||
{
|
||||
}
|
17
vendor/zendframework/zend-diactoros/src/Exception/ExceptionInterface.php
vendored
Normal file
17
vendor/zendframework/zend-diactoros/src/Exception/ExceptionInterface.php
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
/**
|
||||
* Zend Framework (http://framework.zend.com/)
|
||||
*
|
||||
* @see http://github.com/zendframework/zend-diactoros for the canonical source repository
|
||||
* @copyright Copyright (c) 2015 Zend Technologies USA Inc. (http://www.zend.com)
|
||||
* @license https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License
|
||||
*/
|
||||
|
||||
namespace Zend\Diactoros\Exception;
|
||||
|
||||
/**
|
||||
* Marker interface for package-specific exceptions.
|
||||
*/
|
||||
interface ExceptionInterface
|
||||
{
|
||||
}
|
149
vendor/zendframework/zend-diactoros/src/HeaderSecurity.php
vendored
Normal file
149
vendor/zendframework/zend-diactoros/src/HeaderSecurity.php
vendored
Normal file
|
@ -0,0 +1,149 @@
|
|||
<?php
|
||||
/**
|
||||
* Zend Framework (http://framework.zend.com/)
|
||||
*
|
||||
* @see http://github.com/zendframework/zend-diactoros for the canonical source repository
|
||||
* @copyright Copyright (c) 2015 Zend Technologies USA Inc. (http://www.zend.com)
|
||||
* @license https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License
|
||||
*/
|
||||
|
||||
namespace Zend\Diactoros;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Provide security tools around HTTP headers to prevent common injection vectors.
|
||||
*
|
||||
* Code is largely lifted from the Zend\Http\Header\HeaderValue implementation in
|
||||
* Zend Framework, released with the copyright and license below.
|
||||
*
|
||||
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
|
||||
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||||
*/
|
||||
final class HeaderSecurity
|
||||
{
|
||||
/**
|
||||
* Private constructor; non-instantiable.
|
||||
*/
|
||||
private function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter a header value
|
||||
*
|
||||
* Ensures CRLF header injection vectors are filtered.
|
||||
*
|
||||
* Per RFC 7230, only VISIBLE ASCII characters, spaces, and horizontal
|
||||
* tabs are allowed in values; header continuations MUST consist of
|
||||
* a single CRLF sequence followed by a space or horizontal tab.
|
||||
*
|
||||
* This method filters any values not allowed from the string, and is
|
||||
* lossy.
|
||||
*
|
||||
* @see http://en.wikipedia.org/wiki/HTTP_response_splitting
|
||||
* @param string $value
|
||||
* @return string
|
||||
*/
|
||||
public static function filter($value)
|
||||
{
|
||||
$value = (string) $value;
|
||||
$length = strlen($value);
|
||||
$string = '';
|
||||
for ($i = 0; $i < $length; $i += 1) {
|
||||
$ascii = ord($value[$i]);
|
||||
|
||||
// Detect continuation sequences
|
||||
if ($ascii === 13) {
|
||||
$lf = ord($value[$i + 1]);
|
||||
$ws = ord($value[$i + 2]);
|
||||
if ($lf === 10 && in_array($ws, [9, 32], true)) {
|
||||
$string .= $value[$i] . $value[$i + 1];
|
||||
$i += 1;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Non-visible, non-whitespace characters
|
||||
// 9 === horizontal tab
|
||||
// 32-126, 128-254 === visible
|
||||
// 127 === DEL
|
||||
// 255 === null byte
|
||||
if (($ascii < 32 && $ascii !== 9)
|
||||
|| $ascii === 127
|
||||
|| $ascii > 254
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$string .= $value[$i];
|
||||
}
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a header value.
|
||||
*
|
||||
* Per RFC 7230, only VISIBLE ASCII characters, spaces, and horizontal
|
||||
* tabs are allowed in values; header continuations MUST consist of
|
||||
* a single CRLF sequence followed by a space or horizontal tab.
|
||||
*
|
||||
* @see http://en.wikipedia.org/wiki/HTTP_response_splitting
|
||||
* @param string $value
|
||||
* @return bool
|
||||
*/
|
||||
public static function isValid($value)
|
||||
{
|
||||
$value = (string) $value;
|
||||
|
||||
// Look for:
|
||||
// \n not preceded by \r, OR
|
||||
// \r not followed by \n, OR
|
||||
// \r\n not followed by space or horizontal tab; these are all CRLF attacks
|
||||
if (preg_match("#(?:(?:(?<!\r)\n)|(?:\r(?!\n))|(?:\r\n(?![ \t])))#", $value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Non-visible, non-whitespace characters
|
||||
// 9 === horizontal tab
|
||||
// 10 === line feed
|
||||
// 13 === carriage return
|
||||
// 32-126, 128-254 === visible
|
||||
// 127 === DEL (disallowed)
|
||||
// 255 === null byte (disallowed)
|
||||
if (preg_match('/[^\x09\x0a\x0d\x20-\x7E\x80-\xFE]/', $value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert a header value is valid.
|
||||
*
|
||||
* @param string $value
|
||||
* @throws InvalidArgumentException for invalid values
|
||||
*/
|
||||
public static function assertValid($value)
|
||||
{
|
||||
if (! self::isValid($value)) {
|
||||
throw new InvalidArgumentException('Invalid header value');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert whether or not a header name is valid.
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc7230#section-3.2
|
||||
* @param mixed $name
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public static function assertValidName($name)
|
||||
{
|
||||
if (! preg_match('/^[a-zA-Z0-9\'`#$%&*+.^_|~!-]+$/', $name)) {
|
||||
throw new InvalidArgumentException('Invalid header name');
|
||||
}
|
||||
}
|
||||
}
|
383
vendor/zendframework/zend-diactoros/src/MessageTrait.php
vendored
Normal file
383
vendor/zendframework/zend-diactoros/src/MessageTrait.php
vendored
Normal file
|
@ -0,0 +1,383 @@
|
|||
<?php
|
||||
/**
|
||||
* Zend Framework (http://framework.zend.com/)
|
||||
*
|
||||
* @see http://github.com/zendframework/zend-diactoros for the canonical source repository
|
||||
* @copyright Copyright (c) 2015 Zend Technologies USA Inc. (http://www.zend.com)
|
||||
* @license https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License
|
||||
*/
|
||||
|
||||
namespace Zend\Diactoros;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
|
||||
/**
|
||||
* Trait implementing the various methods defined in MessageInterface.
|
||||
*
|
||||
* @see https://github.com/php-fig/http-message/tree/master/src/MessageInterface.php
|
||||
*/
|
||||
trait MessageTrait
|
||||
{
|
||||
/**
|
||||
* List of all registered headers, as key => array of values.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $headers = [];
|
||||
|
||||
/**
|
||||
* Map of normalized header name to original name used to register header.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $headerNames = [];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $protocol = '1.1';
|
||||
|
||||
/**
|
||||
* @var StreamInterface
|
||||
*/
|
||||
private $stream;
|
||||
|
||||
/**
|
||||
* Retrieves the HTTP protocol version as a string.
|
||||
*
|
||||
* The string MUST contain only the HTTP version number (e.g., "1.1", "1.0").
|
||||
*
|
||||
* @return string HTTP protocol version.
|
||||
*/
|
||||
public function getProtocolVersion()
|
||||
{
|
||||
return $this->protocol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an instance with the specified HTTP protocol version.
|
||||
*
|
||||
* The version string MUST contain only the HTTP version number (e.g.,
|
||||
* "1.1", "1.0").
|
||||
*
|
||||
* This method MUST be implemented in such a way as to retain the
|
||||
* immutability of the message, and MUST return an instance that has the
|
||||
* new protocol version.
|
||||
*
|
||||
* @param string $version HTTP protocol version
|
||||
* @return static
|
||||
*/
|
||||
public function withProtocolVersion($version)
|
||||
{
|
||||
$new = clone $this;
|
||||
$new->protocol = $version;
|
||||
return $new;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all message headers.
|
||||
*
|
||||
* The keys represent the header name as it will be sent over the wire, and
|
||||
* each value is an array of strings associated with the header.
|
||||
*
|
||||
* // Represent the headers as a string
|
||||
* foreach ($message->getHeaders() as $name => $values) {
|
||||
* echo $name . ": " . implode(", ", $values);
|
||||
* }
|
||||
*
|
||||
* // Emit headers iteratively:
|
||||
* foreach ($message->getHeaders() as $name => $values) {
|
||||
* foreach ($values as $value) {
|
||||
* header(sprintf('%s: %s', $name, $value), false);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* @return array Returns an associative array of the message's headers. Each
|
||||
* key MUST be a header name, and each value MUST be an array of strings.
|
||||
*/
|
||||
public function getHeaders()
|
||||
{
|
||||
return $this->headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a header exists by the given case-insensitive name.
|
||||
*
|
||||
* @param string $header Case-insensitive header name.
|
||||
* @return bool Returns true if any header names match the given header
|
||||
* name using a case-insensitive string comparison. Returns false if
|
||||
* no matching header name is found in the message.
|
||||
*/
|
||||
public function hasHeader($header)
|
||||
{
|
||||
return array_key_exists(strtolower($header), $this->headerNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a message header value by the given case-insensitive name.
|
||||
*
|
||||
* This method returns an array of all the header values of the given
|
||||
* case-insensitive header name.
|
||||
*
|
||||
* If the header does not appear in the message, this method MUST return an
|
||||
* empty array.
|
||||
*
|
||||
* @param string $header Case-insensitive header field name.
|
||||
* @return string[] An array of string values as provided for the given
|
||||
* header. If the header does not appear in the message, this method MUST
|
||||
* return an empty array.
|
||||
*/
|
||||
public function getHeader($header)
|
||||
{
|
||||
if (! $this->hasHeader($header)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$header = $this->headerNames[strtolower($header)];
|
||||
$value = $this->headers[$header];
|
||||
$value = is_array($value) ? $value : [$value];
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a comma-separated string of the values for a single header.
|
||||
*
|
||||
* This method returns all of the header values of the given
|
||||
* case-insensitive header name as a string concatenated together using
|
||||
* a comma.
|
||||
*
|
||||
* NOTE: Not all header values may be appropriately represented using
|
||||
* comma concatenation. For such headers, use getHeader() instead
|
||||
* and supply your own delimiter when concatenating.
|
||||
*
|
||||
* If the header does not appear in the message, this method MUST return
|
||||
* an empty string.
|
||||
*
|
||||
* @param string $name Case-insensitive header field name.
|
||||
* @return string A string of values as provided for the given header
|
||||
* concatenated together using a comma. If the header does not appear in
|
||||
* the message, this method MUST return an empty string.
|
||||
*/
|
||||
public function getHeaderLine($name)
|
||||
{
|
||||
$value = $this->getHeader($name);
|
||||
if (empty($value)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return implode(',', $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an instance with the provided header, replacing any existing
|
||||
* values of any headers with the same case-insensitive name.
|
||||
*
|
||||
* While header names are case-insensitive, the casing of the header will
|
||||
* be preserved by this function, and returned from getHeaders().
|
||||
*
|
||||
* This method MUST be implemented in such a way as to retain the
|
||||
* immutability of the message, and MUST return an instance that has the
|
||||
* new and/or updated header and value.
|
||||
*
|
||||
* @param string $header Case-insensitive header field name.
|
||||
* @param string|string[] $value Header value(s).
|
||||
* @return static
|
||||
* @throws \InvalidArgumentException for invalid header names or values.
|
||||
*/
|
||||
public function withHeader($header, $value)
|
||||
{
|
||||
if (is_string($value)) {
|
||||
$value = [$value];
|
||||
}
|
||||
|
||||
if (! is_array($value) || ! $this->arrayContainsOnlyStrings($value)) {
|
||||
throw new InvalidArgumentException(
|
||||
'Invalid header value; must be a string or array of strings'
|
||||
);
|
||||
}
|
||||
|
||||
HeaderSecurity::assertValidName($header);
|
||||
self::assertValidHeaderValue($value);
|
||||
|
||||
$normalized = strtolower($header);
|
||||
|
||||
$new = clone $this;
|
||||
$new->headerNames[$normalized] = $header;
|
||||
$new->headers[$header] = $value;
|
||||
|
||||
return $new;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an instance with the specified header appended with the
|
||||
* given value.
|
||||
*
|
||||
* Existing values for the specified header will be maintained. The new
|
||||
* value(s) will be appended to the existing list. If the header did not
|
||||
* exist previously, it will be added.
|
||||
*
|
||||
* This method MUST be implemented in such a way as to retain the
|
||||
* immutability of the message, and MUST return an instance that has the
|
||||
* new header and/or value.
|
||||
*
|
||||
* @param string $header Case-insensitive header field name to add.
|
||||
* @param string|string[] $value Header value(s).
|
||||
* @return static
|
||||
* @throws \InvalidArgumentException for invalid header names or values.
|
||||
*/
|
||||
public function withAddedHeader($header, $value)
|
||||
{
|
||||
if (is_string($value)) {
|
||||
$value = [ $value ];
|
||||
}
|
||||
|
||||
if (! is_array($value) || ! $this->arrayContainsOnlyStrings($value)) {
|
||||
throw new InvalidArgumentException(
|
||||
'Invalid header value; must be a string or array of strings'
|
||||
);
|
||||
}
|
||||
|
||||
HeaderSecurity::assertValidName($header);
|
||||
self::assertValidHeaderValue($value);
|
||||
|
||||
if (! $this->hasHeader($header)) {
|
||||
return $this->withHeader($header, $value);
|
||||
}
|
||||
|
||||
$normalized = strtolower($header);
|
||||
$header = $this->headerNames[$normalized];
|
||||
|
||||
$new = clone $this;
|
||||
$new->headers[$header] = array_merge($this->headers[$header], $value);
|
||||
return $new;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an instance without the specified header.
|
||||
*
|
||||
* Header resolution MUST be done without case-sensitivity.
|
||||
*
|
||||
* This method MUST be implemented in such a way as to retain the
|
||||
* immutability of the message, and MUST return an instance that removes
|
||||
* the named header.
|
||||
*
|
||||
* @param string $header Case-insensitive header field name to remove.
|
||||
* @return static
|
||||
*/
|
||||
public function withoutHeader($header)
|
||||
{
|
||||
if (! $this->hasHeader($header)) {
|
||||
return clone $this;
|
||||
}
|
||||
|
||||
$normalized = strtolower($header);
|
||||
$original = $this->headerNames[$normalized];
|
||||
|
||||
$new = clone $this;
|
||||
unset($new->headers[$original], $new->headerNames[$normalized]);
|
||||
return $new;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the body of the message.
|
||||
*
|
||||
* @return StreamInterface Returns the body as a stream.
|
||||
*/
|
||||
public function getBody()
|
||||
{
|
||||
return $this->stream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an instance with the specified message body.
|
||||
*
|
||||
* The body MUST be a StreamInterface object.
|
||||
*
|
||||
* This method MUST be implemented in such a way as to retain the
|
||||
* immutability of the message, and MUST return a new instance that has the
|
||||
* new body stream.
|
||||
*
|
||||
* @param StreamInterface $body Body.
|
||||
* @return static
|
||||
* @throws \InvalidArgumentException When the body is not valid.
|
||||
*/
|
||||
public function withBody(StreamInterface $body)
|
||||
{
|
||||
$new = clone $this;
|
||||
$new->stream = $body;
|
||||
return $new;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that an array contains only strings
|
||||
*
|
||||
* @param array $array
|
||||
* @return bool
|
||||
*/
|
||||
private function arrayContainsOnlyStrings(array $array)
|
||||
{
|
||||
return array_reduce($array, [__CLASS__, 'filterStringValue'], true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter a set of headers to ensure they are in the correct internal format.
|
||||
*
|
||||
* Used by message constructors to allow setting all initial headers at once.
|
||||
*
|
||||
* @param array $originalHeaders Headers to filter.
|
||||
* @return array Filtered headers and names.
|
||||
*/
|
||||
private function filterHeaders(array $originalHeaders)
|
||||
{
|
||||
$headerNames = $headers = [];
|
||||
foreach ($originalHeaders as $header => $value) {
|
||||
if (! is_string($header)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! is_array($value) && ! is_string($value)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! is_array($value)) {
|
||||
$value = [ $value ];
|
||||
}
|
||||
|
||||
$headerNames[strtolower($header)] = $header;
|
||||
$headers[$header] = $value;
|
||||
}
|
||||
|
||||
return [$headerNames, $headers];
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if a value is a string
|
||||
*
|
||||
* Used with array_reduce.
|
||||
*
|
||||
* @param bool $carry
|
||||
* @param mixed $item
|
||||
* @return bool
|
||||
*/
|
||||
private static function filterStringValue($carry, $item)
|
||||
{
|
||||
if (! is_string($item)) {
|
||||
return false;
|
||||
}
|
||||
return $carry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the provided header values are valid.
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc7230#section-3.2
|
||||
* @param string[] $values
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
private static function assertValidHeaderValue(array $values)
|
||||
{
|
||||
array_walk($values, __NAMESPACE__ . '\HeaderSecurity::assertValid');
|
||||
}
|
||||
}
|
93
vendor/zendframework/zend-diactoros/src/PhpInputStream.php
vendored
Normal file
93
vendor/zendframework/zend-diactoros/src/PhpInputStream.php
vendored
Normal file
|
@ -0,0 +1,93 @@
|
|||
<?php
|
||||
/**
|
||||
* Zend Framework (http://framework.zend.com/)
|
||||
*
|
||||
* @see http://github.com/zendframework/zend-diactoros for the canonical source repository
|
||||
* @copyright Copyright (c) 2015 Zend Technologies USA Inc. (http://www.zend.com)
|
||||
* @license https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License
|
||||
*/
|
||||
|
||||
namespace Zend\Diactoros;
|
||||
|
||||
/**
|
||||
* Caching version of php://input
|
||||
*/
|
||||
class PhpInputStream extends Stream
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $cache = '';
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $reachedEof = false;
|
||||
|
||||
/**
|
||||
* @param string|resource $stream
|
||||
* @param string $mode
|
||||
*/
|
||||
public function __construct($stream = 'php://input', $mode = 'r')
|
||||
{
|
||||
$mode = 'r';
|
||||
parent::__construct($stream, $mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
if ($this->reachedEof) {
|
||||
return $this->cache;
|
||||
}
|
||||
|
||||
$this->getContents();
|
||||
return $this->cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isWritable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function read($length)
|
||||
{
|
||||
$content = parent::read($length);
|
||||
if ($content && ! $this->reachedEof) {
|
||||
$this->cache .= $content;
|
||||
}
|
||||
|
||||
if ($this->eof()) {
|
||||
$this->reachedEof = true;
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getContents($maxLength = -1)
|
||||
{
|
||||
if ($this->reachedEof) {
|
||||
return $this->cache;
|
||||
}
|
||||
|
||||
$contents = stream_get_contents($this->resource, $maxLength);
|
||||
$this->cache .= $contents;
|
||||
|
||||
if ($maxLength === -1 || $this->eof()) {
|
||||
$this->reachedEof = true;
|
||||
}
|
||||
|
||||
return $contents;
|
||||
}
|
||||
}
|
168
vendor/zendframework/zend-diactoros/src/RelativeStream.php
vendored
Normal file
168
vendor/zendframework/zend-diactoros/src/RelativeStream.php
vendored
Normal file
|
@ -0,0 +1,168 @@
|
|||
<?php
|
||||
/**
|
||||
* Zend Framework (http://framework.zend.com/)
|
||||
*
|
||||
* @see http://github.com/zendframework/zend-diactoros for the canonical source repository
|
||||
* @copyright Copyright (c) 2015 Zend Technologies USA Inc. (http://www.zend.com)
|
||||
* @license https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License
|
||||
*/
|
||||
|
||||
namespace Zend\Diactoros;
|
||||
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
|
||||
/**
|
||||
* Class RelativeStream
|
||||
*
|
||||
* Wrapper for default Stream class, representing subpart (starting from given offset) of initial stream.
|
||||
* It can be used to avoid copying full stream, conserving memory.
|
||||
* @example see Zend\Diactoros\AbstractSerializer::splitStream()
|
||||
*/
|
||||
final class RelativeStream implements StreamInterface
|
||||
{
|
||||
/**
|
||||
* @var StreamInterface
|
||||
*/
|
||||
private $decoratedStream;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $offset;
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param StreamInterface $decoratedStream
|
||||
* @param int $offset
|
||||
*/
|
||||
public function __construct(StreamInterface $decoratedStream, $offset)
|
||||
{
|
||||
$this->decoratedStream = $decoratedStream;
|
||||
$this->offset = (int)$offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
$this->seek(0);
|
||||
return $this->getContents();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
$this->decoratedStream->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function detach()
|
||||
{
|
||||
return $this->decoratedStream->detach();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSize()
|
||||
{
|
||||
return $this->decoratedStream->getSize() - $this->offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function tell()
|
||||
{
|
||||
return $this->decoratedStream->tell() - $this->offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function eof()
|
||||
{
|
||||
return $this->decoratedStream->eof();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isSeekable()
|
||||
{
|
||||
return $this->decoratedStream->isSeekable();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function seek($offset, $whence = SEEK_SET)
|
||||
{
|
||||
if ($whence == SEEK_SET) {
|
||||
return $this->decoratedStream->seek($offset + $this->offset, $whence);
|
||||
}
|
||||
return $this->decoratedStream->seek($offset, $whence);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function rewind()
|
||||
{
|
||||
return $this->seek(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isWritable()
|
||||
{
|
||||
return $this->decoratedStream->isWritable();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function write($string)
|
||||
{
|
||||
return $this->decoratedStream->write($string);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isReadable()
|
||||
{
|
||||
return $this->decoratedStream->isReadable();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function read($length)
|
||||
{
|
||||
return $this->decoratedStream->read($length);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getContents()
|
||||
{
|
||||
return $this->decoratedStream->getContents();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getMetadata($key = null)
|
||||
{
|
||||
return $this->decoratedStream->getMetadata($key);
|
||||
}
|
||||
}
|
74
vendor/zendframework/zend-diactoros/src/Request.php
vendored
Normal file
74
vendor/zendframework/zend-diactoros/src/Request.php
vendored
Normal file
|
@ -0,0 +1,74 @@
|
|||
<?php
|
||||
/**
|
||||
* Zend Framework (http://framework.zend.com/)
|
||||
*
|
||||
* @see http://github.com/zendframework/zend-diactoros for the canonical source repository
|
||||
* @copyright Copyright (c) 2015 Zend Technologies USA Inc. (http://www.zend.com)
|
||||
* @license https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License
|
||||
*/
|
||||
|
||||
namespace Zend\Diactoros;
|
||||
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
|
||||
/**
|
||||
* HTTP Request encapsulation
|
||||
*
|
||||
* Requests are considered immutable; all methods that might change state are
|
||||
* implemented such that they retain the internal state of the current
|
||||
* message and return a new instance that contains the changed state.
|
||||
*/
|
||||
class Request implements RequestInterface
|
||||
{
|
||||
use MessageTrait, RequestTrait;
|
||||
|
||||
/**
|
||||
* @param null|string $uri URI for the request, if any.
|
||||
* @param null|string $method HTTP method for the request, if any.
|
||||
* @param string|resource|StreamInterface $body Message body, if any.
|
||||
* @param array $headers Headers for the message, if any.
|
||||
* @throws \InvalidArgumentException for any invalid value.
|
||||
*/
|
||||
public function __construct($uri = null, $method = null, $body = 'php://temp', array $headers = [])
|
||||
{
|
||||
$this->initialize($uri, $method, $body, $headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getHeaders()
|
||||
{
|
||||
$headers = $this->headers;
|
||||
if (! $this->hasHeader('host')
|
||||
&& ($this->uri && $this->uri->getHost())
|
||||
) {
|
||||
$headers['Host'] = [$this->getHostFromUri()];
|
||||
}
|
||||
|
||||
return $headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getHeader($header)
|
||||
{
|
||||
if (! $this->hasHeader($header)) {
|
||||
if (strtolower($header) === 'host'
|
||||
&& ($this->uri && $this->uri->getHost())
|
||||
) {
|
||||
return [$this->getHostFromUri()];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
$header = $this->headerNames[strtolower($header)];
|
||||
$value = $this->headers[$header];
|
||||
$value = is_array($value) ? $value : [$value];
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
147
vendor/zendframework/zend-diactoros/src/Request/Serializer.php
vendored
Normal file
147
vendor/zendframework/zend-diactoros/src/Request/Serializer.php
vendored
Normal file
|
@ -0,0 +1,147 @@
|
|||
<?php
|
||||
/**
|
||||
* Zend Framework (http://framework.zend.com/)
|
||||
*
|
||||
* @see http://github.com/zendframework/zend-diactoros for the canonical source repository
|
||||
* @copyright Copyright (c) 2015 Zend Technologies USA Inc. (http://www.zend.com)
|
||||
* @license https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License
|
||||
*/
|
||||
|
||||
namespace Zend\Diactoros\Request;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
use UnexpectedValueException;
|
||||
use Zend\Diactoros\AbstractSerializer;
|
||||
use Zend\Diactoros\Request;
|
||||
use Zend\Diactoros\Stream;
|
||||
use Zend\Diactoros\Uri;
|
||||
|
||||
/**
|
||||
* Serialize (cast to string) or deserialize (cast string to Request) messages.
|
||||
*
|
||||
* This class provides functionality for serializing a RequestInterface instance
|
||||
* to a string, as well as the reverse operation of creating a Request instance
|
||||
* from a string/stream representing a message.
|
||||
*/
|
||||
final class Serializer extends AbstractSerializer
|
||||
{
|
||||
/**
|
||||
* Deserialize a request string to a request instance.
|
||||
*
|
||||
* Internally, casts the message to a stream and invokes fromStream().
|
||||
*
|
||||
* @param string $message
|
||||
* @return Request
|
||||
* @throws UnexpectedValueException when errors occur parsing the message.
|
||||
*/
|
||||
public static function fromString($message)
|
||||
{
|
||||
$stream = new Stream('php://temp', 'wb+');
|
||||
$stream->write($message);
|
||||
return self::fromStream($stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserialize a request stream to a request instance.
|
||||
*
|
||||
* @param StreamInterface $stream
|
||||
* @return Request
|
||||
* @throws UnexpectedValueException when errors occur parsing the message.
|
||||
*/
|
||||
public static function fromStream(StreamInterface $stream)
|
||||
{
|
||||
if (! $stream->isReadable() || ! $stream->isSeekable()) {
|
||||
throw new InvalidArgumentException('Message stream must be both readable and seekable');
|
||||
}
|
||||
|
||||
$stream->rewind();
|
||||
|
||||
list($method, $requestTarget, $version) = self::getRequestLine($stream);
|
||||
$uri = self::createUriFromRequestTarget($requestTarget);
|
||||
|
||||
list($headers, $body) = self::splitStream($stream);
|
||||
|
||||
return (new Request($uri, $method, $body, $headers))
|
||||
->withProtocolVersion($version)
|
||||
->withRequestTarget($requestTarget);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize a request message to a string.
|
||||
*
|
||||
* @param RequestInterface $request
|
||||
* @return string
|
||||
*/
|
||||
public static function toString(RequestInterface $request)
|
||||
{
|
||||
$headers = self::serializeHeaders($request->getHeaders());
|
||||
$body = (string) $request->getBody();
|
||||
$format = '%s %s HTTP/%s%s%s';
|
||||
|
||||
if (! empty($headers)) {
|
||||
$headers = "\r\n" . $headers;
|
||||
}
|
||||
if (! empty($body)) {
|
||||
$headers .= "\r\n\r\n";
|
||||
}
|
||||
|
||||
return sprintf(
|
||||
$format,
|
||||
$request->getMethod(),
|
||||
$request->getRequestTarget(),
|
||||
$request->getProtocolVersion(),
|
||||
$headers,
|
||||
$body
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the components of the request line.
|
||||
*
|
||||
* Retrieves the first line of the stream and parses it, raising an
|
||||
* exception if it does not follow specifications; if valid, returns a list
|
||||
* with the method, target, and version, in that order.
|
||||
*
|
||||
* @param StreamInterface $stream
|
||||
* @return array
|
||||
*/
|
||||
private static function getRequestLine(StreamInterface $stream)
|
||||
{
|
||||
$requestLine = self::getLine($stream);
|
||||
|
||||
if (! preg_match(
|
||||
'#^(?P<method>[!\#$%&\'*+.^_`|~a-zA-Z0-9-]+) (?P<target>[^\s]+) HTTP/(?P<version>[1-9]\d*\.\d+)$#',
|
||||
$requestLine,
|
||||
$matches
|
||||
)) {
|
||||
throw new UnexpectedValueException('Invalid request line detected');
|
||||
}
|
||||
|
||||
return [$matches['method'], $matches['target'], $matches['version']];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return a Uri instance based on the provided request target.
|
||||
*
|
||||
* If the request target is of authority or asterisk form, an empty Uri
|
||||
* instance is returned; otherwise, the value is used to create and return
|
||||
* a new Uri instance.
|
||||
*
|
||||
* @param string $requestTarget
|
||||
* @return Uri
|
||||
*/
|
||||
private static function createUriFromRequestTarget($requestTarget)
|
||||
{
|
||||
if (preg_match('#^https?://#', $requestTarget)) {
|
||||
return new Uri($requestTarget);
|
||||
}
|
||||
|
||||
if (preg_match('#^(\*|[^/])#', $requestTarget)) {
|
||||
return new Uri();
|
||||
}
|
||||
|
||||
return new Uri($requestTarget);
|
||||
}
|
||||
}
|
309
vendor/zendframework/zend-diactoros/src/RequestTrait.php
vendored
Normal file
309
vendor/zendframework/zend-diactoros/src/RequestTrait.php
vendored
Normal file
|
@ -0,0 +1,309 @@
|
|||
<?php
|
||||
/**
|
||||
* Zend Framework (http://framework.zend.com/)
|
||||
*
|
||||
* @see http://github.com/zendframework/zend-diactoros for the canonical source repository
|
||||
* @copyright Copyright (c) 2015 Zend Technologies USA Inc. (http://www.zend.com)
|
||||
* @license https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License
|
||||
*/
|
||||
|
||||
namespace Zend\Diactoros;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
|
||||
/**
|
||||
* Trait with common request behaviors.
|
||||
*
|
||||
* Server and client-side requests differ slightly in how the Host header is
|
||||
* handled; on client-side, it should be calculated on-the-fly from the
|
||||
* composed URI (if present), while on server-side, it will be calculated from
|
||||
* the environment. As such, this trait exists to provide the common code
|
||||
* between both client-side and server-side requests, and each can then
|
||||
* use the headers functionality required by their implementations.
|
||||
*
|
||||
* @property array $headers
|
||||
* @property array $headerNames
|
||||
* @property StreamInterface $stream
|
||||
* @method bool hasHeader(string $header)
|
||||
*/
|
||||
trait RequestTrait
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $method = '';
|
||||
|
||||
/**
|
||||
* The request-target, if it has been provided or calculated.
|
||||
*
|
||||
* @var null|string
|
||||
*/
|
||||
private $requestTarget;
|
||||
|
||||
/**
|
||||
* @var null|UriInterface
|
||||
*/
|
||||
private $uri;
|
||||
|
||||
/**
|
||||
* Initialize request state.
|
||||
*
|
||||
* Used by constructors.
|
||||
*
|
||||
* @param null|string $uri URI for the request, if any.
|
||||
* @param null|string $method HTTP method for the request, if any.
|
||||
* @param string|resource|StreamInterface $body Message body, if any.
|
||||
* @param array $headers Headers for the message, if any.
|
||||
* @throws InvalidArgumentException for any invalid value.
|
||||
*/
|
||||
private function initialize($uri = null, $method = null, $body = 'php://memory', array $headers = [])
|
||||
{
|
||||
if (! $uri instanceof UriInterface && ! is_string($uri) && null !== $uri) {
|
||||
throw new InvalidArgumentException(
|
||||
'Invalid URI provided; must be null, a string, or a Psr\Http\Message\UriInterface instance'
|
||||
);
|
||||
}
|
||||
|
||||
$this->validateMethod($method);
|
||||
|
||||
if (! is_string($body) && ! is_resource($body) && ! $body instanceof StreamInterface) {
|
||||
throw new InvalidArgumentException(
|
||||
'Body must be a string stream resource identifier, '
|
||||
. 'an actual stream resource, '
|
||||
. 'or a Psr\Http\Message\StreamInterface implementation'
|
||||
);
|
||||
}
|
||||
|
||||
if (is_string($uri)) {
|
||||
$uri = new Uri($uri);
|
||||
}
|
||||
|
||||
$this->method = $method ?: '';
|
||||
$this->uri = $uri ?: new Uri();
|
||||
$this->stream = ($body instanceof StreamInterface) ? $body : new Stream($body, 'wb+');
|
||||
|
||||
list($this->headerNames, $headers) = $this->filterHeaders($headers);
|
||||
$this->assertHeaders($headers);
|
||||
$this->headers = $headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the message's request target.
|
||||
*
|
||||
* Retrieves the message's request-target either as it will appear (for
|
||||
* clients), as it appeared at request (for servers), or as it was
|
||||
* specified for the instance (see withRequestTarget()).
|
||||
*
|
||||
* In most cases, this will be the origin-form of the composed URI,
|
||||
* unless a value was provided to the concrete implementation (see
|
||||
* withRequestTarget() below).
|
||||
*
|
||||
* If no URI is available, and no request-target has been specifically
|
||||
* provided, this method MUST return the string "/".
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRequestTarget()
|
||||
{
|
||||
if (null !== $this->requestTarget) {
|
||||
return $this->requestTarget;
|
||||
}
|
||||
|
||||
if (! $this->uri) {
|
||||
return '/';
|
||||
}
|
||||
|
||||
$target = $this->uri->getPath();
|
||||
if ($this->uri->getQuery()) {
|
||||
$target .= '?' . $this->uri->getQuery();
|
||||
}
|
||||
|
||||
if (empty($target)) {
|
||||
$target = '/';
|
||||
}
|
||||
|
||||
return $target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance with a specific request-target.
|
||||
*
|
||||
* If the request needs a non-origin-form request-target — e.g., for
|
||||
* specifying an absolute-form, authority-form, or asterisk-form —
|
||||
* this method may be used to create an instance with the specified
|
||||
* request-target, verbatim.
|
||||
*
|
||||
* This method MUST be implemented in such a way as to retain the
|
||||
* immutability of the message, and MUST return a new instance that has the
|
||||
* changed request target.
|
||||
*
|
||||
* @link http://tools.ietf.org/html/rfc7230#section-2.7 (for the various
|
||||
* request-target forms allowed in request messages)
|
||||
* @param mixed $requestTarget
|
||||
* @return static
|
||||
* @throws InvalidArgumentException if the request target is invalid.
|
||||
*/
|
||||
public function withRequestTarget($requestTarget)
|
||||
{
|
||||
if (preg_match('#\s#', $requestTarget)) {
|
||||
throw new InvalidArgumentException(
|
||||
'Invalid request target provided; cannot contain whitespace'
|
||||
);
|
||||
}
|
||||
|
||||
$new = clone $this;
|
||||
$new->requestTarget = $requestTarget;
|
||||
return $new;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the HTTP method of the request.
|
||||
*
|
||||
* @return string Returns the request method.
|
||||
*/
|
||||
public function getMethod()
|
||||
{
|
||||
return $this->method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an instance with the provided HTTP method.
|
||||
*
|
||||
* While HTTP method names are typically all uppercase characters, HTTP
|
||||
* method names are case-sensitive and thus implementations SHOULD NOT
|
||||
* modify the given string.
|
||||
*
|
||||
* This method MUST be implemented in such a way as to retain the
|
||||
* immutability of the message, and MUST return an instance that has the
|
||||
* changed request method.
|
||||
*
|
||||
* @param string $method Case-insensitive method.
|
||||
* @return static
|
||||
* @throws InvalidArgumentException for invalid HTTP methods.
|
||||
*/
|
||||
public function withMethod($method)
|
||||
{
|
||||
$this->validateMethod($method);
|
||||
$new = clone $this;
|
||||
$new->method = $method;
|
||||
return $new;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the URI instance.
|
||||
*
|
||||
* This method MUST return a UriInterface instance.
|
||||
*
|
||||
* @link http://tools.ietf.org/html/rfc3986#section-4.3
|
||||
* @return UriInterface Returns a UriInterface instance
|
||||
* representing the URI of the request, if any.
|
||||
*/
|
||||
public function getUri()
|
||||
{
|
||||
return $this->uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an instance with the provided URI.
|
||||
*
|
||||
* This method will update the Host header of the returned request by
|
||||
* default if the URI contains a host component. If the URI does not
|
||||
* contain a host component, any pre-existing Host header will be carried
|
||||
* over to the returned request.
|
||||
*
|
||||
* You can opt-in to preserving the original state of the Host header by
|
||||
* setting `$preserveHost` to `true`. When `$preserveHost` is set to
|
||||
* `true`, the returned request will not update the Host header of the
|
||||
* returned message -- even if the message contains no Host header. This
|
||||
* means that a call to `getHeader('Host')` on the original request MUST
|
||||
* equal the return value of a call to `getHeader('Host')` on the returned
|
||||
* request.
|
||||
*
|
||||
* This method MUST be implemented in such a way as to retain the
|
||||
* immutability of the message, and MUST return an instance that has the
|
||||
* new UriInterface instance.
|
||||
*
|
||||
* @link http://tools.ietf.org/html/rfc3986#section-4.3
|
||||
* @param UriInterface $uri New request URI to use.
|
||||
* @param bool $preserveHost Preserve the original state of the Host header.
|
||||
* @return static
|
||||
*/
|
||||
public function withUri(UriInterface $uri, $preserveHost = false)
|
||||
{
|
||||
$new = clone $this;
|
||||
$new->uri = $uri;
|
||||
|
||||
if ($preserveHost && $this->hasHeader('Host')) {
|
||||
return $new;
|
||||
}
|
||||
|
||||
if (! $uri->getHost()) {
|
||||
return $new;
|
||||
}
|
||||
|
||||
$host = $uri->getHost();
|
||||
if ($uri->getPort()) {
|
||||
$host .= ':' . $uri->getPort();
|
||||
}
|
||||
|
||||
$new->headerNames['host'] = 'Host';
|
||||
$new->headers['Host'] = [$host];
|
||||
|
||||
return $new;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the HTTP method
|
||||
*
|
||||
* @param null|string $method
|
||||
* @throws InvalidArgumentException on invalid HTTP method.
|
||||
*/
|
||||
private function validateMethod($method)
|
||||
{
|
||||
if (null === $method) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (! is_string($method)) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'Unsupported HTTP method; must be a string, received %s',
|
||||
(is_object($method) ? get_class($method) : gettype($method))
|
||||
));
|
||||
}
|
||||
|
||||
if (! preg_match('/^[!#$%&\'*+.^_`\|~0-9a-z-]+$/i', $method)) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'Unsupported HTTP method "%s" provided',
|
||||
$method
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the host from the URI instance
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getHostFromUri()
|
||||
{
|
||||
$host = $this->uri->getHost();
|
||||
$host .= $this->uri->getPort() ? ':' . $this->uri->getPort() : '';
|
||||
return $host;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure header names and values are valid.
|
||||
*
|
||||
* @param array $headers
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
private function assertHeaders(array $headers)
|
||||
{
|
||||
foreach ($headers as $name => $headerValues) {
|
||||
HeaderSecurity::assertValidName($name);
|
||||
array_walk($headerValues, __NAMESPACE__ . '\HeaderSecurity::assertValid');
|
||||
}
|
||||
}
|
||||
}
|
202
vendor/zendframework/zend-diactoros/src/Response.php
vendored
Normal file
202
vendor/zendframework/zend-diactoros/src/Response.php
vendored
Normal file
|
@ -0,0 +1,202 @@
|
|||
<?php
|
||||
/**
|
||||
* Zend Framework (http://framework.zend.com/)
|
||||
*
|
||||
* @see http://github.com/zendframework/zend-diactoros for the canonical source repository
|
||||
* @copyright Copyright (c) 2015 Zend Technologies USA Inc. (http://www.zend.com)
|
||||
* @license https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License
|
||||
*/
|
||||
|
||||
namespace Zend\Diactoros;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
|
||||
/**
|
||||
* HTTP response encapsulation.
|
||||
*
|
||||
* Responses are considered immutable; all methods that might change state are
|
||||
* implemented such that they retain the internal state of the current
|
||||
* message and return a new instance that contains the changed state.
|
||||
*/
|
||||
class Response implements ResponseInterface
|
||||
{
|
||||
use MessageTrait;
|
||||
|
||||
/**
|
||||
* Map of standard HTTP status code/reason phrases
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $phrases = [
|
||||
// INFORMATIONAL CODES
|
||||
100 => 'Continue',
|
||||
101 => 'Switching Protocols',
|
||||
102 => 'Processing',
|
||||
// SUCCESS CODES
|
||||
200 => 'OK',
|
||||
201 => 'Created',
|
||||
202 => 'Accepted',
|
||||
203 => 'Non-Authoritative Information',
|
||||
204 => 'No Content',
|
||||
205 => 'Reset Content',
|
||||
206 => 'Partial Content',
|
||||
207 => 'Multi-status',
|
||||
208 => 'Already Reported',
|
||||
// REDIRECTION CODES
|
||||
300 => 'Multiple Choices',
|
||||
301 => 'Moved Permanently',
|
||||
302 => 'Found',
|
||||
303 => 'See Other',
|
||||
304 => 'Not Modified',
|
||||
305 => 'Use Proxy',
|
||||
306 => 'Switch Proxy', // Deprecated
|
||||
307 => 'Temporary Redirect',
|
||||
// CLIENT ERROR
|
||||
400 => 'Bad Request',
|
||||
401 => 'Unauthorized',
|
||||
402 => 'Payment Required',
|
||||
403 => 'Forbidden',
|
||||
404 => 'Not Found',
|
||||
405 => 'Method Not Allowed',
|
||||
406 => 'Not Acceptable',
|
||||
407 => 'Proxy Authentication Required',
|
||||
408 => 'Request Time-out',
|
||||
409 => 'Conflict',
|
||||
410 => 'Gone',
|
||||
411 => 'Length Required',
|
||||
412 => 'Precondition Failed',
|
||||
413 => 'Request Entity Too Large',
|
||||
414 => 'Request-URI Too Large',
|
||||
415 => 'Unsupported Media Type',
|
||||
416 => 'Requested range not satisfiable',
|
||||
417 => 'Expectation Failed',
|
||||
418 => 'I\'m a teapot',
|
||||
422 => 'Unprocessable Entity',
|
||||
423 => 'Locked',
|
||||
424 => 'Failed Dependency',
|
||||
425 => 'Unordered Collection',
|
||||
426 => 'Upgrade Required',
|
||||
428 => 'Precondition Required',
|
||||
429 => 'Too Many Requests',
|
||||
431 => 'Request Header Fields Too Large',
|
||||
// SERVER ERROR
|
||||
500 => 'Internal Server Error',
|
||||
501 => 'Not Implemented',
|
||||
502 => 'Bad Gateway',
|
||||
503 => 'Service Unavailable',
|
||||
504 => 'Gateway Time-out',
|
||||
505 => 'HTTP Version not supported',
|
||||
506 => 'Variant Also Negotiates',
|
||||
507 => 'Insufficient Storage',
|
||||
508 => 'Loop Detected',
|
||||
511 => 'Network Authentication Required',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $reasonPhrase = '';
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $statusCode = 200;
|
||||
|
||||
/**
|
||||
* @param string|resource|StreamInterface $stream Stream identifier and/or actual stream resource
|
||||
* @param int $status Status code for the response, if any.
|
||||
* @param array $headers Headers for the response, if any.
|
||||
* @throws InvalidArgumentException on any invalid element.
|
||||
*/
|
||||
public function __construct($body = 'php://memory', $status = 200, array $headers = [])
|
||||
{
|
||||
if (! is_string($body) && ! is_resource($body) && ! $body instanceof StreamInterface) {
|
||||
throw new InvalidArgumentException(
|
||||
'Stream must be a string stream resource identifier, '
|
||||
. 'an actual stream resource, '
|
||||
. 'or a Psr\Http\Message\StreamInterface implementation'
|
||||
);
|
||||
}
|
||||
|
||||
if (null !== $status) {
|
||||
$this->validateStatus($status);
|
||||
}
|
||||
|
||||
$this->stream = ($body instanceof StreamInterface) ? $body : new Stream($body, 'wb+');
|
||||
$this->statusCode = $status ? (int) $status : 200;
|
||||
|
||||
list($this->headerNames, $headers) = $this->filterHeaders($headers);
|
||||
$this->assertHeaders($headers);
|
||||
$this->headers = $headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getStatusCode()
|
||||
{
|
||||
return $this->statusCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getReasonPhrase()
|
||||
{
|
||||
if (! $this->reasonPhrase
|
||||
&& isset($this->phrases[$this->statusCode])
|
||||
) {
|
||||
$this->reasonPhrase = $this->phrases[$this->statusCode];
|
||||
}
|
||||
|
||||
return $this->reasonPhrase;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function withStatus($code, $reasonPhrase = '')
|
||||
{
|
||||
$this->validateStatus($code);
|
||||
$new = clone $this;
|
||||
$new->statusCode = (int) $code;
|
||||
$new->reasonPhrase = $reasonPhrase;
|
||||
return $new;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a status code.
|
||||
*
|
||||
* @param int|string $code
|
||||
* @throws InvalidArgumentException on an invalid status code.
|
||||
*/
|
||||
private function validateStatus($code)
|
||||
{
|
||||
if (! is_numeric($code)
|
||||
|| is_float($code)
|
||||
|| $code < 100
|
||||
|| $code >= 600
|
||||
) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'Invalid status code "%s"; must be an integer between 100 and 599, inclusive',
|
||||
(is_scalar($code) ? $code : gettype($code))
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure header names and values are valid.
|
||||
*
|
||||
* @param array $headers
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
private function assertHeaders(array $headers)
|
||||
{
|
||||
foreach ($headers as $name => $headerValues) {
|
||||
HeaderSecurity::assertValidName($name);
|
||||
array_walk($headerValues, __NAMESPACE__ . '\HeaderSecurity::assertValid');
|
||||
}
|
||||
}
|
||||
}
|
32
vendor/zendframework/zend-diactoros/src/Response/EmitterInterface.php
vendored
Normal file
32
vendor/zendframework/zend-diactoros/src/Response/EmitterInterface.php
vendored
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
/**
|
||||
* Zend Framework (http://framework.zend.com/)
|
||||
*
|
||||
* @see http://github.com/zendframework/zend-diactoros for the canonical source repository
|
||||
* @copyright Copyright (c) 2015 Zend Technologies USA Inc. (http://www.zend.com)
|
||||
* @license https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License
|
||||
*/
|
||||
|
||||
namespace Zend\Diactoros\Response;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
interface EmitterInterface
|
||||
{
|
||||
/**
|
||||
* Emit a response.
|
||||
*
|
||||
* Emits a response, including status line, headers, and the message body,
|
||||
* according to the environment.
|
||||
*
|
||||
* Implementations of this method may be written in such a way as to have
|
||||
* side effects, such as usage of header() or pushing output to the
|
||||
* output buffer.
|
||||
*
|
||||
* Implementations MAY raise exceptions if they are unable to emit the
|
||||
* response; e.g., if headers have already been sent.
|
||||
*
|
||||
* @param ResponseInterface $response
|
||||
*/
|
||||
public function emit(ResponseInterface $response);
|
||||
}
|
42
vendor/zendframework/zend-diactoros/src/Response/EmptyResponse.php
vendored
Normal file
42
vendor/zendframework/zend-diactoros/src/Response/EmptyResponse.php
vendored
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
/**
|
||||
* Zend Framework (http://framework.zend.com/)
|
||||
*
|
||||
* @see http://github.com/zendframework/zend-diactoros for the canonical source repository
|
||||
* @copyright Copyright (c) 2015 Zend Technologies USA Inc. (http://www.zend.com)
|
||||
* @license https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License
|
||||
*/
|
||||
|
||||
namespace Zend\Diactoros\Response;
|
||||
|
||||
use Zend\Diactoros\Response;
|
||||
use Zend\Diactoros\Stream;
|
||||
|
||||
/**
|
||||
* A class representing empty HTTP responses.
|
||||
*/
|
||||
class EmptyResponse extends Response
|
||||
{
|
||||
/**
|
||||
* Create an empty response with the given status code.
|
||||
*
|
||||
* @param int $status Status code for the response, if any.
|
||||
* @param array $headers Headers for the response, if any.
|
||||
*/
|
||||
public function __construct($status = 204, array $headers = [])
|
||||
{
|
||||
$body = new Stream('php://temp', 'r');
|
||||
parent::__construct($body, $status, $headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an empty response with the given headers.
|
||||
*
|
||||
* @param array $headers Headers for the response.
|
||||
* @return EmptyResponse
|
||||
*/
|
||||
public static function withHeaders(array $headers)
|
||||
{
|
||||
return new static(204, $headers);
|
||||
}
|
||||
}
|
73
vendor/zendframework/zend-diactoros/src/Response/HtmlResponse.php
vendored
Normal file
73
vendor/zendframework/zend-diactoros/src/Response/HtmlResponse.php
vendored
Normal file
|
@ -0,0 +1,73 @@
|
|||
<?php
|
||||
/**
|
||||
* Zend Framework (http://framework.zend.com/)
|
||||
*
|
||||
* @see http://github.com/zendframework/zend-diactoros for the canonical source repository
|
||||
* @copyright Copyright (c) 2015 Zend Technologies USA Inc. (http://www.zend.com)
|
||||
* @license https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License
|
||||
*/
|
||||
|
||||
namespace Zend\Diactoros\Response;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
use Zend\Diactoros\Response;
|
||||
use Zend\Diactoros\Stream;
|
||||
|
||||
/**
|
||||
* HTML response.
|
||||
*
|
||||
* Allows creating a response by passing an HTML string to the constructor;
|
||||
* by default, sets a status code of 200 and sets the Content-Type header to
|
||||
* text/html.
|
||||
*/
|
||||
class HtmlResponse extends Response
|
||||
{
|
||||
use InjectContentTypeTrait;
|
||||
|
||||
/**
|
||||
* Create an HTML response.
|
||||
*
|
||||
* Produces an HTML response with a Content-Type of text/html and a default
|
||||
* status of 200.
|
||||
*
|
||||
* @param string|StreamInterface $html HTML or stream for the message body.
|
||||
* @param int $status Integer status code for the response; 200 by default.
|
||||
* @param array $headers Array of headers to use at initialization.
|
||||
* @throws InvalidArgumentException if $html is neither a string or stream.
|
||||
*/
|
||||
public function __construct($html, $status = 200, array $headers = [])
|
||||
{
|
||||
parent::__construct(
|
||||
$this->createBody($html),
|
||||
$status,
|
||||
$this->injectContentType('text/html', $headers)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the message body.
|
||||
*
|
||||
* @param string|StreamInterface $html
|
||||
* @return StreamInterface
|
||||
* @throws InvalidArgumentException if $html is neither a string or stream.
|
||||
*/
|
||||
private function createBody($html)
|
||||
{
|
||||
if ($html instanceof StreamInterface) {
|
||||
return $html;
|
||||
}
|
||||
|
||||
if (! is_string($html)) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'Invalid content (%s) provided to %s',
|
||||
(is_object($html) ? get_class($html) : gettype($html)),
|
||||
__CLASS__
|
||||
));
|
||||
}
|
||||
|
||||
$body = new Stream('php://temp', 'wb+');
|
||||
$body->write($html);
|
||||
return $body;
|
||||
}
|
||||
}
|
33
vendor/zendframework/zend-diactoros/src/Response/InjectContentTypeTrait.php
vendored
Normal file
33
vendor/zendframework/zend-diactoros/src/Response/InjectContentTypeTrait.php
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
/**
|
||||
* Zend Framework (http://framework.zend.com/)
|
||||
*
|
||||
* @see http://github.com/zendframework/zend-diactoros for the canonical source repository
|
||||
* @copyright Copyright (c) 2015 Zend Technologies USA Inc. (http://www.zend.com)
|
||||
* @license https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License
|
||||
*/
|
||||
|
||||
namespace Zend\Diactoros\Response;
|
||||
|
||||
trait InjectContentTypeTrait
|
||||
{
|
||||
/**
|
||||
* Inject the provided Content-Type, if none is already present.
|
||||
*
|
||||
* @param string $contentType
|
||||
* @param array $headers
|
||||
* @return array Headers with injected Content-Type
|
||||
*/
|
||||
private function injectContentType($contentType, array $headers)
|
||||
{
|
||||
$hasContentType = array_reduce(array_keys($headers), function ($carry, $item) {
|
||||
return $carry ?: (strtolower($item) === 'content-type');
|
||||
}, false);
|
||||
|
||||
if (! $hasContentType) {
|
||||
$headers['content-type'] = [$contentType];
|
||||
}
|
||||
|
||||
return $headers;
|
||||
}
|
||||
}
|
83
vendor/zendframework/zend-diactoros/src/Response/JsonResponse.php
vendored
Normal file
83
vendor/zendframework/zend-diactoros/src/Response/JsonResponse.php
vendored
Normal file
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
/**
|
||||
* Zend Framework (http://framework.zend.com/)
|
||||
*
|
||||
* @see http://github.com/zendframework/zend-diactoros for the canonical source repository
|
||||
* @copyright Copyright (c) 2015 Zend Technologies USA Inc. (http://www.zend.com)
|
||||
* @license https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License
|
||||
*/
|
||||
|
||||
namespace Zend\Diactoros\Response;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Zend\Diactoros\Response;
|
||||
use Zend\Diactoros\Stream;
|
||||
|
||||
/**
|
||||
* JSON response.
|
||||
*
|
||||
* Allows creating a response by passing data to the constructor; by default,
|
||||
* serializes the data to JSON, sets a status code of 200 and sets the
|
||||
* Content-Type header to application/json.
|
||||
*/
|
||||
class JsonResponse extends Response
|
||||
{
|
||||
use InjectContentTypeTrait;
|
||||
|
||||
/**
|
||||
* Create a JSON response with the given data.
|
||||
*
|
||||
* Default JSON encoding is performed with the following options, which
|
||||
* produces RFC4627-compliant JSON, capable of embedding into HTML.
|
||||
*
|
||||
* - JSON_HEX_TAG
|
||||
* - JSON_HEX_APOS
|
||||
* - JSON_HEX_AMP
|
||||
* - JSON_HEX_QUOT
|
||||
*
|
||||
* @param mixed $data Data to convert to JSON.
|
||||
* @param int $status Integer status code for the response; 200 by default.
|
||||
* @param array $headers Array of headers to use at initialization.
|
||||
* @param int $encodingOptions JSON encoding options to use.
|
||||
* @throws InvalidArgumentException if unable to encode the $data to JSON.
|
||||
*/
|
||||
public function __construct($data, $status = 200, array $headers = [], $encodingOptions = 15)
|
||||
{
|
||||
$body = new Stream('php://temp', 'wb+');
|
||||
$body->write($this->jsonEncode($data, $encodingOptions));
|
||||
|
||||
$headers = $this->injectContentType('application/json', $headers);
|
||||
|
||||
parent::__construct($body, $status, $headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode the provided data to JSON.
|
||||
*
|
||||
* @param mixed $data
|
||||
* @param int $encodingOptions
|
||||
* @return string
|
||||
* @throws InvalidArgumentException if unable to encode the $data to JSON.
|
||||
*/
|
||||
private function jsonEncode($data, $encodingOptions)
|
||||
{
|
||||
if (is_resource($data)) {
|
||||
throw new InvalidArgumentException('Cannot JSON encode resources');
|
||||
}
|
||||
|
||||
// Clear json_last_error()
|
||||
json_encode(null);
|
||||
|
||||
$json = json_encode($data, $encodingOptions);
|
||||
|
||||
if (JSON_ERROR_NONE !== json_last_error()) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'Unable to encode data to JSON in %s: %s',
|
||||
__CLASS__,
|
||||
json_last_error_msg()
|
||||
));
|
||||
}
|
||||
|
||||
return $json;
|
||||
}
|
||||
}
|
47
vendor/zendframework/zend-diactoros/src/Response/RedirectResponse.php
vendored
Normal file
47
vendor/zendframework/zend-diactoros/src/Response/RedirectResponse.php
vendored
Normal file
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
/**
|
||||
* Zend Framework (http://framework.zend.com/)
|
||||
*
|
||||
* @see http://github.com/zendframework/zend-diactoros for the canonical source repository
|
||||
* @copyright Copyright (c) 2015 Zend Technologies USA Inc. (http://www.zend.com)
|
||||
* @license https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License
|
||||
*/
|
||||
|
||||
namespace Zend\Diactoros\Response;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
use Zend\Diactoros\Response;
|
||||
use Zend\Diactoros\Stream;
|
||||
|
||||
/**
|
||||
* Produce a redirect response.
|
||||
*/
|
||||
class RedirectResponse extends Response
|
||||
{
|
||||
/**
|
||||
* Create a redirect response.
|
||||
*
|
||||
* Produces a redirect response with a Location header and the given status
|
||||
* (302 by default).
|
||||
*
|
||||
* Note: this method overwrites the `location` $headers value.
|
||||
*
|
||||
* @param string|UriInterface $uri URI for the Location header.
|
||||
* @param int $status Integer status code for the redirect; 302 by default.
|
||||
* @param array $headers Array of headers to use at initialization.
|
||||
*/
|
||||
public function __construct($uri, $status = 302, array $headers = [])
|
||||
{
|
||||
if (! is_string($uri) && ! $uri instanceof UriInterface) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'Uri provided to %s MUST be a string or Psr\Http\Message\UriInterface instance; received "%s"',
|
||||
__CLASS__,
|
||||
(is_object($uri) ? get_class($uri) : gettype($uri))
|
||||
));
|
||||
}
|
||||
|
||||
$headers['location'] = [(string) $uri];
|
||||
parent::__construct('php://temp', $status, $headers);
|
||||
}
|
||||
}
|
116
vendor/zendframework/zend-diactoros/src/Response/SapiEmitter.php
vendored
Normal file
116
vendor/zendframework/zend-diactoros/src/Response/SapiEmitter.php
vendored
Normal file
|
@ -0,0 +1,116 @@
|
|||
<?php
|
||||
/**
|
||||
* Zend Framework (http://framework.zend.com/)
|
||||
*
|
||||
* @see http://github.com/zendframework/zend-diactoros for the canonical source repository
|
||||
* @copyright Copyright (c) 2015 Zend Technologies USA Inc. (http://www.zend.com)
|
||||
* @license https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License
|
||||
*/
|
||||
|
||||
namespace Zend\Diactoros\Response;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use RuntimeException;
|
||||
|
||||
class SapiEmitter implements EmitterInterface
|
||||
{
|
||||
/**
|
||||
* Emits a response for a PHP SAPI environment.
|
||||
*
|
||||
* Emits the status line and headers via the header() function, and the
|
||||
* body content via the output buffer.
|
||||
*
|
||||
* @param ResponseInterface $response
|
||||
* @param null|int $maxBufferLevel Maximum output buffering level to unwrap.
|
||||
*/
|
||||
public function emit(ResponseInterface $response, $maxBufferLevel = null)
|
||||
{
|
||||
if (headers_sent()) {
|
||||
throw new RuntimeException('Unable to emit response; headers already sent');
|
||||
}
|
||||
|
||||
$this->emitStatusLine($response);
|
||||
$this->emitHeaders($response);
|
||||
$this->emitBody($response, $maxBufferLevel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit the status line.
|
||||
*
|
||||
* Emits the status line using the protocol version and status code from
|
||||
* the response; if a reason phrase is availble, it, too, is emitted.
|
||||
*
|
||||
* @param ResponseInterface $response
|
||||
*/
|
||||
private function emitStatusLine(ResponseInterface $response)
|
||||
{
|
||||
$reasonPhrase = $response->getReasonPhrase();
|
||||
header(sprintf(
|
||||
'HTTP/%s %d%s',
|
||||
$response->getProtocolVersion(),
|
||||
$response->getStatusCode(),
|
||||
($reasonPhrase ? ' ' . $reasonPhrase : '')
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit response headers.
|
||||
*
|
||||
* Loops through each header, emitting each; if the header value
|
||||
* is an array with multiple values, ensures that each is sent
|
||||
* in such a way as to create aggregate headers (instead of replace
|
||||
* the previous).
|
||||
*
|
||||
* @param ResponseInterface $response
|
||||
*/
|
||||
private function emitHeaders(ResponseInterface $response)
|
||||
{
|
||||
foreach ($response->getHeaders() as $header => $values) {
|
||||
$name = $this->filterHeader($header);
|
||||
$first = true;
|
||||
foreach ($values as $value) {
|
||||
header(sprintf(
|
||||
'%s: %s',
|
||||
$name,
|
||||
$value
|
||||
), $first);
|
||||
$first = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit the message body.
|
||||
*
|
||||
* Loops through the output buffer, flushing each, before emitting
|
||||
* the response body using `echo()`.
|
||||
*
|
||||
* @param ResponseInterface $response
|
||||
* @param int $maxBufferLevel Flush up to this buffer level.
|
||||
*/
|
||||
private function emitBody(ResponseInterface $response, $maxBufferLevel)
|
||||
{
|
||||
if (null === $maxBufferLevel) {
|
||||
$maxBufferLevel = ob_get_level();
|
||||
}
|
||||
|
||||
while (ob_get_level() > $maxBufferLevel) {
|
||||
ob_end_flush();
|
||||
}
|
||||
|
||||
echo $response->getBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter a header name to wordcase
|
||||
*
|
||||
* @param string $header
|
||||
* @return string
|
||||
*/
|
||||
private function filterHeader($header)
|
||||
{
|
||||
$filtered = str_replace('-', ' ', $header);
|
||||
$filtered = ucwords($filtered);
|
||||
return str_replace(' ', '-', $filtered);
|
||||
}
|
||||
}
|
111
vendor/zendframework/zend-diactoros/src/Response/Serializer.php
vendored
Normal file
111
vendor/zendframework/zend-diactoros/src/Response/Serializer.php
vendored
Normal file
|
@ -0,0 +1,111 @@
|
|||
<?php
|
||||
/**
|
||||
* Zend Framework (http://framework.zend.com/)
|
||||
*
|
||||
* @see http://github.com/zendframework/zend-diactoros for the canonical source repository
|
||||
* @copyright Copyright (c) 2015 Zend Technologies USA Inc. (http://www.zend.com)
|
||||
* @license https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License
|
||||
*/
|
||||
|
||||
namespace Zend\Diactoros\Response;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
use UnexpectedValueException;
|
||||
use Zend\Diactoros\AbstractSerializer;
|
||||
use Zend\Diactoros\Response;
|
||||
use Zend\Diactoros\Stream;
|
||||
|
||||
final class Serializer extends AbstractSerializer
|
||||
{
|
||||
/**
|
||||
* Deserialize a response string to a response instance.
|
||||
*
|
||||
* @param string $message
|
||||
* @return Response
|
||||
* @throws UnexpectedValueException when errors occur parsing the message.
|
||||
*/
|
||||
public static function fromString($message)
|
||||
{
|
||||
$stream = new Stream('php://temp', 'wb+');
|
||||
$stream->write($message);
|
||||
return static::fromStream($stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a response from a stream.
|
||||
*
|
||||
* @param StreamInterface $stream
|
||||
* @return ResponseInterface
|
||||
* @throws InvalidArgumentException when the stream is not readable.
|
||||
* @throws UnexpectedValueException when errors occur parsing the message.
|
||||
*/
|
||||
public static function fromStream(StreamInterface $stream)
|
||||
{
|
||||
if (! $stream->isReadable() || ! $stream->isSeekable()) {
|
||||
throw new InvalidArgumentException('Message stream must be both readable and seekable');
|
||||
}
|
||||
|
||||
$stream->rewind();
|
||||
|
||||
list($version, $status, $reasonPhrase) = self::getStatusLine($stream);
|
||||
list($headers, $body) = self::splitStream($stream);
|
||||
|
||||
return (new Response($body, $status, $headers))
|
||||
->withProtocolVersion($version)
|
||||
->withStatus($status, $reasonPhrase);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a string representation of a response.
|
||||
*
|
||||
* @param ResponseInterface $response
|
||||
* @return string
|
||||
*/
|
||||
public static function toString(ResponseInterface $response)
|
||||
{
|
||||
$reasonPhrase = $response->getReasonPhrase();
|
||||
$headers = self::serializeHeaders($response->getHeaders());
|
||||
$body = (string) $response->getBody();
|
||||
$format = 'HTTP/%s %d%s%s%s';
|
||||
|
||||
if (! empty($headers)) {
|
||||
$headers = "\r\n" . $headers;
|
||||
}
|
||||
if (! empty($body)) {
|
||||
$headers .= "\r\n\r\n";
|
||||
}
|
||||
|
||||
return sprintf(
|
||||
$format,
|
||||
$response->getProtocolVersion(),
|
||||
$response->getStatusCode(),
|
||||
($reasonPhrase ? ' ' . $reasonPhrase : ''),
|
||||
$headers,
|
||||
$body
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the status line for the message.
|
||||
*
|
||||
* @param StreamInterface $stream
|
||||
* @return array Array with three elements: 0 => version, 1 => status, 2 => reason
|
||||
* @throws UnexpectedValueException if line is malformed
|
||||
*/
|
||||
private static function getStatusLine(StreamInterface $stream)
|
||||
{
|
||||
$line = self::getLine($stream);
|
||||
|
||||
if (! preg_match(
|
||||
'#^HTTP/(?P<version>[1-9]\d*\.\d) (?P<status>[1-5]\d{2})(\s+(?P<reason>.+))?$#',
|
||||
$line,
|
||||
$matches
|
||||
)) {
|
||||
throw new UnexpectedValueException('No status line detected');
|
||||
}
|
||||
|
||||
return [$matches['version'], $matches['status'], isset($matches['reason']) ? $matches['reason'] : ''];
|
||||
}
|
||||
}
|
188
vendor/zendframework/zend-diactoros/src/Server.php
vendored
Normal file
188
vendor/zendframework/zend-diactoros/src/Server.php
vendored
Normal file
|
@ -0,0 +1,188 @@
|
|||
<?php
|
||||
/**
|
||||
* Zend Framework (http://framework.zend.com/)
|
||||
*
|
||||
* @see http://github.com/zendframework/zend-diactoros for the canonical source repository
|
||||
* @copyright Copyright (c) 2015 Zend Technologies USA Inc. (http://www.zend.com)
|
||||
* @license https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License
|
||||
*/
|
||||
|
||||
namespace Zend\Diactoros;
|
||||
|
||||
use OutOfBoundsException;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
/**
|
||||
* "Serve" incoming HTTP requests
|
||||
*
|
||||
* Given a callback, takes an incoming request, dispatches it to the
|
||||
* callback, and then sends a response.
|
||||
*/
|
||||
class Server
|
||||
{
|
||||
/**
|
||||
* @var callable
|
||||
*/
|
||||
private $callback;
|
||||
|
||||
/**
|
||||
* Response emitter to use; by default, uses Response\SapiEmitter.
|
||||
*
|
||||
* @var Response\EmitterInterface
|
||||
*/
|
||||
private $emitter;
|
||||
|
||||
/**
|
||||
* @var ServerRequestInterface
|
||||
*/
|
||||
private $request;
|
||||
|
||||
/**
|
||||
* @var ResponseInterface
|
||||
*/
|
||||
private $response;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* Given a callback, a request, and a response, we can create a server.
|
||||
*
|
||||
* @param callable $callback
|
||||
* @param ServerRequestInterface $request
|
||||
* @param ResponseInterface $response
|
||||
*/
|
||||
public function __construct(
|
||||
callable $callback,
|
||||
ServerRequestInterface $request,
|
||||
ResponseInterface $response
|
||||
) {
|
||||
$this->callback = $callback;
|
||||
$this->request = $request;
|
||||
$this->response = $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow retrieving the request, response and callback as properties
|
||||
*
|
||||
* @param string $name
|
||||
* @return mixed
|
||||
* @throws OutOfBoundsException for invalid properties
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
if (! property_exists($this, $name)) {
|
||||
throw new OutOfBoundsException('Cannot retrieve arbitrary properties from server');
|
||||
}
|
||||
return $this->{$name};
|
||||
}
|
||||
|
||||
/**
|
||||
* Set alternate response emitter to use.
|
||||
*
|
||||
* @param Response\EmitterInterface $emitter
|
||||
*/
|
||||
public function setEmitter(Response\EmitterInterface $emitter)
|
||||
{
|
||||
$this->emitter = $emitter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Server instance
|
||||
*
|
||||
* Creates a server instance from the callback and the following
|
||||
* PHP environmental values:
|
||||
*
|
||||
* - server; typically this will be the $_SERVER superglobal
|
||||
* - query; typically this will be the $_GET superglobal
|
||||
* - body; typically this will be the $_POST superglobal
|
||||
* - cookies; typically this will be the $_COOKIE superglobal
|
||||
* - files; typically this will be the $_FILES superglobal
|
||||
*
|
||||
* @param callable $callback
|
||||
* @param array $server
|
||||
* @param array $query
|
||||
* @param array $body
|
||||
* @param array $cookies
|
||||
* @param array $files
|
||||
* @return static
|
||||
*/
|
||||
public static function createServer(
|
||||
callable $callback,
|
||||
array $server,
|
||||
array $query,
|
||||
array $body,
|
||||
array $cookies,
|
||||
array $files
|
||||
) {
|
||||
$request = ServerRequestFactory::fromGlobals($server, $query, $body, $cookies, $files);
|
||||
$response = new Response();
|
||||
return new static($callback, $request, $response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Server instance from an existing request object
|
||||
*
|
||||
* Provided a callback, an existing request object, and optionally an
|
||||
* existing response object, create and return the Server instance.
|
||||
*
|
||||
* If no Response object is provided, one will be created.
|
||||
*
|
||||
* @param callable $callback
|
||||
* @param ServerRequestInterface $request
|
||||
* @param null|ResponseInterface $response
|
||||
* @return static
|
||||
*/
|
||||
public static function createServerFromRequest(
|
||||
callable $callback,
|
||||
ServerRequestInterface $request,
|
||||
ResponseInterface $response = null
|
||||
) {
|
||||
if (! $response) {
|
||||
$response = new Response();
|
||||
}
|
||||
return new static($callback, $request, $response);
|
||||
}
|
||||
|
||||
/**
|
||||
* "Listen" to an incoming request
|
||||
*
|
||||
* If provided a $finalHandler, that callable will be used for
|
||||
* incomplete requests.
|
||||
*
|
||||
* Output buffering is enabled prior to invoking the attached
|
||||
* callback; any output buffered will be sent prior to any
|
||||
* response body content.
|
||||
*
|
||||
* @param null|callable $finalHandler
|
||||
*/
|
||||
public function listen(callable $finalHandler = null)
|
||||
{
|
||||
$callback = $this->callback;
|
||||
|
||||
ob_start();
|
||||
$bufferLevel = ob_get_level();
|
||||
|
||||
$response = $callback($this->request, $this->response, $finalHandler);
|
||||
if (! $response instanceof ResponseInterface) {
|
||||
$response = $this->response;
|
||||
}
|
||||
$this->getEmitter()->emit($response, $bufferLevel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the current response emitter.
|
||||
*
|
||||
* If none has been registered, lazy-loads a Response\SapiEmitter.
|
||||
*
|
||||
* @return Response\EmitterInterface
|
||||
*/
|
||||
private function getEmitter()
|
||||
{
|
||||
if (! $this->emitter) {
|
||||
$this->emitter = new Response\SapiEmitter();
|
||||
}
|
||||
|
||||
return $this->emitter;
|
||||
}
|
||||
}
|
297
vendor/zendframework/zend-diactoros/src/ServerRequest.php
vendored
Normal file
297
vendor/zendframework/zend-diactoros/src/ServerRequest.php
vendored
Normal file
|
@ -0,0 +1,297 @@
|
|||
<?php
|
||||
/**
|
||||
* Zend Framework (http://framework.zend.com/)
|
||||
*
|
||||
* @see http://github.com/zendframework/zend-diactoros for the canonical source repository
|
||||
* @copyright Copyright (c) 2015 Zend Technologies USA Inc. (http://www.zend.com)
|
||||
* @license https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License
|
||||
*/
|
||||
|
||||
namespace Zend\Diactoros;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
use Psr\Http\Message\UploadedFileInterface;
|
||||
|
||||
/**
|
||||
* Server-side HTTP request
|
||||
*
|
||||
* Extends the Request definition to add methods for accessing incoming data,
|
||||
* specifically server parameters, cookies, matched path parameters, query
|
||||
* string arguments, body parameters, and upload file information.
|
||||
*
|
||||
* "Attributes" are discovered via decomposing the request (and usually
|
||||
* specifically the URI path), and typically will be injected by the application.
|
||||
*
|
||||
* Requests are considered immutable; all methods that might change state are
|
||||
* implemented such that they retain the internal state of the current
|
||||
* message and return a new instance that contains the changed state.
|
||||
*/
|
||||
class ServerRequest implements ServerRequestInterface
|
||||
{
|
||||
use MessageTrait, RequestTrait;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $attributes = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $cookieParams = [];
|
||||
|
||||
/**
|
||||
* @var null|array|object
|
||||
*/
|
||||
private $parsedBody;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $queryParams = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $serverParams;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $uploadedFiles;
|
||||
|
||||
/**
|
||||
* @param array $serverParams Server parameters, typically from $_SERVER
|
||||
* @param array $uploadedFiles Upload file information, a tree of UploadedFiles
|
||||
* @param null|string $uri URI for the request, if any.
|
||||
* @param null|string $method HTTP method for the request, if any.
|
||||
* @param string|resource|StreamInterface $body Message body, if any.
|
||||
* @param array $headers Headers for the message, if any.
|
||||
* @throws InvalidArgumentException for any invalid value.
|
||||
*/
|
||||
public function __construct(
|
||||
array $serverParams = [],
|
||||
array $uploadedFiles = [],
|
||||
$uri = null,
|
||||
$method = null,
|
||||
$body = 'php://input',
|
||||
array $headers = []
|
||||
) {
|
||||
$this->validateUploadedFiles($uploadedFiles);
|
||||
|
||||
$body = $this->getStream($body);
|
||||
$this->initialize($uri, $method, $body, $headers);
|
||||
$this->serverParams = $serverParams;
|
||||
$this->uploadedFiles = $uploadedFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getServerParams()
|
||||
{
|
||||
return $this->serverParams;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUploadedFiles()
|
||||
{
|
||||
return $this->uploadedFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function withUploadedFiles(array $uploadedFiles)
|
||||
{
|
||||
$this->validateUploadedFiles($uploadedFiles);
|
||||
$new = clone $this;
|
||||
$new->uploadedFiles = $uploadedFiles;
|
||||
return $new;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCookieParams()
|
||||
{
|
||||
return $this->cookieParams;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function withCookieParams(array $cookies)
|
||||
{
|
||||
$new = clone $this;
|
||||
$new->cookieParams = $cookies;
|
||||
return $new;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getQueryParams()
|
||||
{
|
||||
return $this->queryParams;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function withQueryParams(array $query)
|
||||
{
|
||||
$new = clone $this;
|
||||
$new->queryParams = $query;
|
||||
return $new;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getParsedBody()
|
||||
{
|
||||
return $this->parsedBody;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function withParsedBody($data)
|
||||
{
|
||||
$new = clone $this;
|
||||
$new->parsedBody = $data;
|
||||
return $new;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getAttributes()
|
||||
{
|
||||
return $this->attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getAttribute($attribute, $default = null)
|
||||
{
|
||||
if (! array_key_exists($attribute, $this->attributes)) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
return $this->attributes[$attribute];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function withAttribute($attribute, $value)
|
||||
{
|
||||
$new = clone $this;
|
||||
$new->attributes[$attribute] = $value;
|
||||
return $new;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function withoutAttribute($attribute)
|
||||
{
|
||||
if (! isset($this->attributes[$attribute])) {
|
||||
return clone $this;
|
||||
}
|
||||
|
||||
$new = clone $this;
|
||||
unset($new->attributes[$attribute]);
|
||||
return $new;
|
||||
}
|
||||
|
||||
/**
|
||||
* Proxy to receive the request method.
|
||||
*
|
||||
* This overrides the parent functionality to ensure the method is never
|
||||
* empty; if no method is present, it returns 'GET'.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getMethod()
|
||||
{
|
||||
if (empty($this->method)) {
|
||||
return 'GET';
|
||||
}
|
||||
return $this->method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the request method.
|
||||
*
|
||||
* Unlike the regular Request implementation, the server-side
|
||||
* normalizes the method to uppercase to ensure consistency
|
||||
* and make checking the method simpler.
|
||||
*
|
||||
* This methods returns a new instance.
|
||||
*
|
||||
* @param string $method
|
||||
* @return self
|
||||
*/
|
||||
public function withMethod($method)
|
||||
{
|
||||
$this->validateMethod($method);
|
||||
$new = clone $this;
|
||||
$new->method = $method;
|
||||
return $new;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the body stream
|
||||
*
|
||||
* @param string|resource|StreamInterface $stream
|
||||
* @return StreamInterface
|
||||
*/
|
||||
private function getStream($stream)
|
||||
{
|
||||
if ($stream === 'php://input') {
|
||||
return new PhpInputStream();
|
||||
}
|
||||
|
||||
if (! is_string($stream) && ! is_resource($stream) && ! $stream instanceof StreamInterface) {
|
||||
throw new InvalidArgumentException(
|
||||
'Stream must be a string stream resource identifier, '
|
||||
. 'an actual stream resource, '
|
||||
. 'or a Psr\Http\Message\StreamInterface implementation'
|
||||
);
|
||||
}
|
||||
|
||||
if (! $stream instanceof StreamInterface) {
|
||||
return new Stream($stream, 'r');
|
||||
}
|
||||
|
||||
return $stream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively validate the structure in an uploaded files array.
|
||||
*
|
||||
* @param array $uploadedFiles
|
||||
* @throws InvalidArgumentException if any leaf is not an UploadedFileInterface instance.
|
||||
*/
|
||||
private function validateUploadedFiles(array $uploadedFiles)
|
||||
{
|
||||
foreach ($uploadedFiles as $file) {
|
||||
if (is_array($file)) {
|
||||
$this->validateUploadedFiles($file);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! $file instanceof UploadedFileInterface) {
|
||||
throw new InvalidArgumentException('Invalid leaf in uploaded files structure');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
458
vendor/zendframework/zend-diactoros/src/ServerRequestFactory.php
vendored
Normal file
458
vendor/zendframework/zend-diactoros/src/ServerRequestFactory.php
vendored
Normal file
|
@ -0,0 +1,458 @@
|
|||
<?php
|
||||
/**
|
||||
* Zend Framework (http://framework.zend.com/)
|
||||
*
|
||||
* @see http://github.com/zendframework/zend-diactoros for the canonical source repository
|
||||
* @copyright Copyright (c) 2015 Zend Technologies USA Inc. (http://www.zend.com)
|
||||
* @license https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License
|
||||
*/
|
||||
|
||||
namespace Zend\Diactoros;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Message\MessageInterface;
|
||||
use Psr\Http\Message\UploadedFileInterface;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Class for marshaling a request object from the current PHP environment.
|
||||
*
|
||||
* Logic largely refactored from the ZF2 Zend\Http\PhpEnvironment\Request class.
|
||||
*
|
||||
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
|
||||
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||||
*/
|
||||
abstract class ServerRequestFactory
|
||||
{
|
||||
/**
|
||||
* Function to use to get apache request headers; present only to simplify mocking.
|
||||
*
|
||||
* @var callable
|
||||
*/
|
||||
private static $apacheRequestHeaders = 'apache_request_headers';
|
||||
|
||||
/**
|
||||
* Create a request from the supplied superglobal values.
|
||||
*
|
||||
* If any argument is not supplied, the corresponding superglobal value will
|
||||
* be used.
|
||||
*
|
||||
* The ServerRequest created is then passed to the fromServer() method in
|
||||
* order to marshal the request URI and headers.
|
||||
*
|
||||
* @see fromServer()
|
||||
* @param array $server $_SERVER superglobal
|
||||
* @param array $query $_GET superglobal
|
||||
* @param array $body $_POST superglobal
|
||||
* @param array $cookies $_COOKIE superglobal
|
||||
* @param array $files $_FILES superglobal
|
||||
* @return ServerRequest
|
||||
* @throws InvalidArgumentException for invalid file values
|
||||
*/
|
||||
public static function fromGlobals(
|
||||
array $server = null,
|
||||
array $query = null,
|
||||
array $body = null,
|
||||
array $cookies = null,
|
||||
array $files = null
|
||||
) {
|
||||
$server = static::normalizeServer($server ?: $_SERVER);
|
||||
$files = static::normalizeFiles($files ?: $_FILES);
|
||||
$headers = static::marshalHeaders($server);
|
||||
$request = new ServerRequest(
|
||||
$server,
|
||||
$files,
|
||||
static::marshalUriFromServer($server, $headers),
|
||||
static::get('REQUEST_METHOD', $server, 'GET'),
|
||||
'php://input',
|
||||
$headers
|
||||
);
|
||||
|
||||
return $request
|
||||
->withCookieParams($cookies ?: $_COOKIE)
|
||||
->withQueryParams($query ?: $_GET)
|
||||
->withParsedBody($body ?: $_POST);
|
||||
}
|
||||
|
||||
/**
|
||||
* Access a value in an array, returning a default value if not found
|
||||
*
|
||||
* Will also do a case-insensitive search if a case sensitive search fails.
|
||||
*
|
||||
* @param string $key
|
||||
* @param array $values
|
||||
* @param mixed $default
|
||||
* @return mixed
|
||||
*/
|
||||
public static function get($key, array $values, $default = null)
|
||||
{
|
||||
if (array_key_exists($key, $values)) {
|
||||
return $values[$key];
|
||||
}
|
||||
|
||||
return $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for a header value.
|
||||
*
|
||||
* Does a case-insensitive search for a matching header.
|
||||
*
|
||||
* If found, it is returned as a string, using comma concatenation.
|
||||
*
|
||||
* If not, the $default is returned.
|
||||
*
|
||||
* @param string $header
|
||||
* @param array $headers
|
||||
* @param mixed $default
|
||||
* @return string
|
||||
*/
|
||||
public static function getHeader($header, array $headers, $default = null)
|
||||
{
|
||||
$header = strtolower($header);
|
||||
$headers = array_change_key_case($headers, CASE_LOWER);
|
||||
if (array_key_exists($header, $headers)) {
|
||||
$value = is_array($headers[$header]) ? implode(', ', $headers[$header]) : $headers[$header];
|
||||
return $value;
|
||||
}
|
||||
|
||||
return $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marshal the $_SERVER array
|
||||
*
|
||||
* Pre-processes and returns the $_SERVER superglobal.
|
||||
*
|
||||
* @param array $server
|
||||
* @return array
|
||||
*/
|
||||
public static function normalizeServer(array $server)
|
||||
{
|
||||
// This seems to be the only way to get the Authorization header on Apache
|
||||
$apacheRequestHeaders = self::$apacheRequestHeaders;
|
||||
if (isset($server['HTTP_AUTHORIZATION'])
|
||||
|| ! is_callable($apacheRequestHeaders)
|
||||
) {
|
||||
return $server;
|
||||
}
|
||||
|
||||
$apacheRequestHeaders = $apacheRequestHeaders();
|
||||
if (isset($apacheRequestHeaders['Authorization'])) {
|
||||
$server['HTTP_AUTHORIZATION'] = $apacheRequestHeaders['Authorization'];
|
||||
return $server;
|
||||
}
|
||||
|
||||
if (isset($apacheRequestHeaders['authorization'])) {
|
||||
$server['HTTP_AUTHORIZATION'] = $apacheRequestHeaders['authorization'];
|
||||
return $server;
|
||||
}
|
||||
|
||||
return $server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize uploaded files
|
||||
*
|
||||
* Transforms each value into an UploadedFileInterface instance, and ensures
|
||||
* that nested arrays are normalized.
|
||||
*
|
||||
* @param array $files
|
||||
* @return array
|
||||
* @throws InvalidArgumentException for unrecognized values
|
||||
*/
|
||||
public static function normalizeFiles(array $files)
|
||||
{
|
||||
$normalized = [];
|
||||
foreach ($files as $key => $value) {
|
||||
if ($value instanceof UploadedFileInterface) {
|
||||
$normalized[$key] = $value;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_array($value) && isset($value['tmp_name'])) {
|
||||
$normalized[$key] = self::createUploadedFileFromSpec($value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_array($value)) {
|
||||
$normalized[$key] = self::normalizeFiles($value);
|
||||
continue;
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException('Invalid value in files specification');
|
||||
}
|
||||
return $normalized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marshal headers from $_SERVER
|
||||
*
|
||||
* @param array $server
|
||||
* @return array
|
||||
*/
|
||||
public static function marshalHeaders(array $server)
|
||||
{
|
||||
$headers = [];
|
||||
foreach ($server as $key => $value) {
|
||||
if (strpos($key, 'HTTP_COOKIE') === 0) {
|
||||
// Cookies are handled using the $_COOKIE superglobal
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($value && strpos($key, 'HTTP_') === 0) {
|
||||
$name = strtr(substr($key, 5), '_', ' ');
|
||||
$name = strtr(ucwords(strtolower($name)), ' ', '-');
|
||||
$name = strtolower($name);
|
||||
|
||||
$headers[$name] = $value;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($value && strpos($key, 'CONTENT_') === 0) {
|
||||
$name = substr($key, 8); // Content-
|
||||
$name = 'Content-' . (($name == 'MD5') ? $name : ucfirst(strtolower($name)));
|
||||
$name = strtolower($name);
|
||||
$headers[$name] = $value;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return $headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marshal the URI from the $_SERVER array and headers
|
||||
*
|
||||
* @param array $server
|
||||
* @param array $headers
|
||||
* @return Uri
|
||||
*/
|
||||
public static function marshalUriFromServer(array $server, array $headers)
|
||||
{
|
||||
$uri = new Uri('');
|
||||
|
||||
// URI scheme
|
||||
$scheme = 'http';
|
||||
$https = self::get('HTTPS', $server);
|
||||
if (($https && 'off' !== $https)
|
||||
|| self::getHeader('x-forwarded-proto', $headers, false) === 'https'
|
||||
) {
|
||||
$scheme = 'https';
|
||||
}
|
||||
if (! empty($scheme)) {
|
||||
$uri = $uri->withScheme($scheme);
|
||||
}
|
||||
|
||||
// Set the host
|
||||
$accumulator = (object) ['host' => '', 'port' => null];
|
||||
self::marshalHostAndPortFromHeaders($accumulator, $server, $headers);
|
||||
$host = $accumulator->host;
|
||||
$port = $accumulator->port;
|
||||
if (! empty($host)) {
|
||||
$uri = $uri->withHost($host);
|
||||
if (! empty($port)) {
|
||||
$uri = $uri->withPort($port);
|
||||
}
|
||||
}
|
||||
|
||||
// URI path
|
||||
$path = self::marshalRequestUri($server);
|
||||
$path = self::stripQueryString($path);
|
||||
|
||||
// URI query
|
||||
$query = '';
|
||||
if (isset($server['QUERY_STRING'])) {
|
||||
$query = ltrim($server['QUERY_STRING'], '?');
|
||||
}
|
||||
|
||||
return $uri
|
||||
->withPath($path)
|
||||
->withQuery($query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Marshal the host and port from HTTP headers and/or the PHP environment
|
||||
*
|
||||
* @param stdClass $accumulator
|
||||
* @param array $server
|
||||
* @param array $headers
|
||||
*/
|
||||
public static function marshalHostAndPortFromHeaders(stdClass $accumulator, array $server, array $headers)
|
||||
{
|
||||
if (self::getHeader('host', $headers, false)) {
|
||||
self::marshalHostAndPortFromHeader($accumulator, self::getHeader('host', $headers));
|
||||
return;
|
||||
}
|
||||
|
||||
if (! isset($server['SERVER_NAME'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$accumulator->host = $server['SERVER_NAME'];
|
||||
if (isset($server['SERVER_PORT'])) {
|
||||
$accumulator->port = (int) $server['SERVER_PORT'];
|
||||
}
|
||||
|
||||
if (! isset($server['SERVER_ADDR']) || ! preg_match('/^\[[0-9a-fA-F\:]+\]$/', $accumulator->host)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Misinterpreted IPv6-Address
|
||||
// Reported for Safari on Windows
|
||||
self::marshalIpv6HostAndPort($accumulator, $server);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect the base URI for the request
|
||||
*
|
||||
* Looks at a variety of criteria in order to attempt to autodetect a base
|
||||
* URI, including rewrite URIs, proxy URIs, etc.
|
||||
*
|
||||
* From ZF2's Zend\Http\PhpEnvironment\Request class
|
||||
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
|
||||
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||||
*
|
||||
* @param array $server
|
||||
* @return string
|
||||
*/
|
||||
public static function marshalRequestUri(array $server)
|
||||
{
|
||||
// IIS7 with URL Rewrite: make sure we get the unencoded url
|
||||
// (double slash problem).
|
||||
$iisUrlRewritten = self::get('IIS_WasUrlRewritten', $server);
|
||||
$unencodedUrl = self::get('UNENCODED_URL', $server, '');
|
||||
if ('1' == $iisUrlRewritten && ! empty($unencodedUrl)) {
|
||||
return $unencodedUrl;
|
||||
}
|
||||
|
||||
$requestUri = self::get('REQUEST_URI', $server);
|
||||
|
||||
// Check this first so IIS will catch.
|
||||
$httpXRewriteUrl = self::get('HTTP_X_REWRITE_URL', $server);
|
||||
if ($httpXRewriteUrl !== null) {
|
||||
$requestUri = $httpXRewriteUrl;
|
||||
}
|
||||
|
||||
// Check for IIS 7.0 or later with ISAPI_Rewrite
|
||||
$httpXOriginalUrl = self::get('HTTP_X_ORIGINAL_URL', $server);
|
||||
if ($httpXOriginalUrl !== null) {
|
||||
$requestUri = $httpXOriginalUrl;
|
||||
}
|
||||
|
||||
if ($requestUri !== null) {
|
||||
return preg_replace('#^[^/:]+://[^/]+#', '', $requestUri);
|
||||
}
|
||||
|
||||
$origPathInfo = self::get('ORIG_PATH_INFO', $server);
|
||||
if (empty($origPathInfo)) {
|
||||
return '/';
|
||||
}
|
||||
|
||||
return $origPathInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Strip the query string from a path
|
||||
*
|
||||
* @param mixed $path
|
||||
* @return string
|
||||
*/
|
||||
public static function stripQueryString($path)
|
||||
{
|
||||
if (($qpos = strpos($path, '?')) !== false) {
|
||||
return substr($path, 0, $qpos);
|
||||
}
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marshal the host and port from the request header
|
||||
*
|
||||
* @param stdClass $accumulator
|
||||
* @param string|array $host
|
||||
* @return void
|
||||
*/
|
||||
private static function marshalHostAndPortFromHeader(stdClass $accumulator, $host)
|
||||
{
|
||||
if (is_array($host)) {
|
||||
$host = implode(', ', $host);
|
||||
}
|
||||
|
||||
$accumulator->host = $host;
|
||||
$accumulator->port = null;
|
||||
|
||||
// works for regname, IPv4 & IPv6
|
||||
if (preg_match('|\:(\d+)$|', $accumulator->host, $matches)) {
|
||||
$accumulator->host = substr($accumulator->host, 0, -1 * (strlen($matches[1]) + 1));
|
||||
$accumulator->port = (int) $matches[1];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marshal host/port from misinterpreted IPv6 address
|
||||
*
|
||||
* @param stdClass $accumulator
|
||||
* @param array $server
|
||||
*/
|
||||
private static function marshalIpv6HostAndPort(stdClass $accumulator, array $server)
|
||||
{
|
||||
$accumulator->host = '[' . $server['SERVER_ADDR'] . ']';
|
||||
$accumulator->port = $accumulator->port ?: 80;
|
||||
if ($accumulator->port . ']' === substr($accumulator->host, strrpos($accumulator->host, ':') + 1)) {
|
||||
// The last digit of the IPv6-Address has been taken as port
|
||||
// Unset the port so the default port can be used
|
||||
$accumulator->port = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return an UploadedFile instance from a $_FILES specification.
|
||||
*
|
||||
* If the specification represents an array of values, this method will
|
||||
* delegate to normalizeNestedFileSpec() and return that return value.
|
||||
*
|
||||
* @param array $value $_FILES struct
|
||||
* @return array|UploadedFileInterface
|
||||
*/
|
||||
private static function createUploadedFileFromSpec(array $value)
|
||||
{
|
||||
if (is_array($value['tmp_name'])) {
|
||||
return self::normalizeNestedFileSpec($value);
|
||||
}
|
||||
|
||||
return new UploadedFile(
|
||||
$value['tmp_name'],
|
||||
$value['size'],
|
||||
$value['error'],
|
||||
$value['name'],
|
||||
$value['type']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize an array of file specifications.
|
||||
*
|
||||
* Loops through all nested files and returns a normalized array of
|
||||
* UploadedFileInterface instances.
|
||||
*
|
||||
* @param array $files
|
||||
* @return UploadedFileInterface[]
|
||||
*/
|
||||
private static function normalizeNestedFileSpec(array $files = [])
|
||||
{
|
||||
$normalizedFiles = [];
|
||||
foreach (array_keys($files['tmp_name']) as $key) {
|
||||
$spec = [
|
||||
'tmp_name' => $files['tmp_name'][$key],
|
||||
'size' => $files['size'][$key],
|
||||
'error' => $files['error'][$key],
|
||||
'name' => $files['name'][$key],
|
||||
'type' => $files['type'][$key],
|
||||
];
|
||||
$normalizedFiles[$key] = self::createUploadedFileFromSpec($spec);
|
||||
}
|
||||
return $normalizedFiles;
|
||||
}
|
||||
}
|
328
vendor/zendframework/zend-diactoros/src/Stream.php
vendored
Normal file
328
vendor/zendframework/zend-diactoros/src/Stream.php
vendored
Normal file
|
@ -0,0 +1,328 @@
|
|||
<?php
|
||||
/**
|
||||
* Zend Framework (http://framework.zend.com/)
|
||||
*
|
||||
* @see http://github.com/zendframework/zend-diactoros for the canonical source repository
|
||||
* @copyright Copyright (c) 2015 Zend Technologies USA Inc. (http://www.zend.com)
|
||||
* @license https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License
|
||||
*/
|
||||
|
||||
namespace Zend\Diactoros;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
|
||||
/**
|
||||
* Implementation of PSR HTTP streams
|
||||
*/
|
||||
class Stream implements StreamInterface
|
||||
{
|
||||
/**
|
||||
* @var resource
|
||||
*/
|
||||
protected $resource;
|
||||
|
||||
/**
|
||||
* @var string|resource
|
||||
*/
|
||||
protected $stream;
|
||||
|
||||
/**
|
||||
* @param string|resource $stream
|
||||
* @param string $mode Mode with which to open stream
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function __construct($stream, $mode = 'r')
|
||||
{
|
||||
$this->setStream($stream, $mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
if (! $this->isReadable()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
try {
|
||||
$this->rewind();
|
||||
return $this->getContents();
|
||||
} catch (RuntimeException $e) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
if (! $this->resource) {
|
||||
return;
|
||||
}
|
||||
|
||||
$resource = $this->detach();
|
||||
fclose($resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function detach()
|
||||
{
|
||||
$resource = $this->resource;
|
||||
$this->resource = null;
|
||||
return $resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach a new stream/resource to the instance.
|
||||
*
|
||||
* @param string|resource $resource
|
||||
* @param string $mode
|
||||
* @throws InvalidArgumentException for stream identifier that cannot be
|
||||
* cast to a resource
|
||||
* @throws InvalidArgumentException for non-resource stream
|
||||
*/
|
||||
public function attach($resource, $mode = 'r')
|
||||
{
|
||||
$this->setStream($resource, $mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSize()
|
||||
{
|
||||
if (null === $this->resource) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$stats = fstat($this->resource);
|
||||
return $stats['size'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function tell()
|
||||
{
|
||||
if (! $this->resource) {
|
||||
throw new RuntimeException('No resource available; cannot tell position');
|
||||
}
|
||||
|
||||
$result = ftell($this->resource);
|
||||
if (! is_int($result)) {
|
||||
throw new RuntimeException('Error occurred during tell operation');
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function eof()
|
||||
{
|
||||
if (! $this->resource) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return feof($this->resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isSeekable()
|
||||
{
|
||||
if (! $this->resource) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$meta = stream_get_meta_data($this->resource);
|
||||
return $meta['seekable'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function seek($offset, $whence = SEEK_SET)
|
||||
{
|
||||
if (! $this->resource) {
|
||||
throw new RuntimeException('No resource available; cannot seek position');
|
||||
}
|
||||
|
||||
if (! $this->isSeekable()) {
|
||||
throw new RuntimeException('Stream is not seekable');
|
||||
}
|
||||
|
||||
$result = fseek($this->resource, $offset, $whence);
|
||||
|
||||
if (0 !== $result) {
|
||||
throw new RuntimeException('Error seeking within stream');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function rewind()
|
||||
{
|
||||
return $this->seek(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isWritable()
|
||||
{
|
||||
if (! $this->resource) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$meta = stream_get_meta_data($this->resource);
|
||||
$mode = $meta['mode'];
|
||||
|
||||
return (
|
||||
strstr($mode, 'x')
|
||||
|| strstr($mode, 'w')
|
||||
|| strstr($mode, 'c')
|
||||
|| strstr($mode, 'a')
|
||||
|| strstr($mode, '+')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function write($string)
|
||||
{
|
||||
if (! $this->resource) {
|
||||
throw new RuntimeException('No resource available; cannot write');
|
||||
}
|
||||
|
||||
if (! $this->isWritable()) {
|
||||
throw new RuntimeException('Stream is not writable');
|
||||
}
|
||||
|
||||
$result = fwrite($this->resource, $string);
|
||||
|
||||
if (false === $result) {
|
||||
throw new RuntimeException('Error writing to stream');
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isReadable()
|
||||
{
|
||||
if (! $this->resource) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$meta = stream_get_meta_data($this->resource);
|
||||
$mode = $meta['mode'];
|
||||
|
||||
return (strstr($mode, 'r') || strstr($mode, '+'));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function read($length)
|
||||
{
|
||||
if (! $this->resource) {
|
||||
throw new RuntimeException('No resource available; cannot read');
|
||||
}
|
||||
|
||||
if (! $this->isReadable()) {
|
||||
throw new RuntimeException('Stream is not readable');
|
||||
}
|
||||
|
||||
$result = fread($this->resource, $length);
|
||||
|
||||
if (false === $result) {
|
||||
throw new RuntimeException('Error reading stream');
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getContents()
|
||||
{
|
||||
if (! $this->isReadable()) {
|
||||
throw new RuntimeException('Stream is not readable');
|
||||
}
|
||||
|
||||
$result = stream_get_contents($this->resource);
|
||||
if (false === $result) {
|
||||
throw new RuntimeException('Error reading from stream');
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getMetadata($key = null)
|
||||
{
|
||||
if (null === $key) {
|
||||
return stream_get_meta_data($this->resource);
|
||||
}
|
||||
|
||||
$metadata = stream_get_meta_data($this->resource);
|
||||
if (! array_key_exists($key, $metadata)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $metadata[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the internal stream resource.
|
||||
*
|
||||
* @param string|resource $stream String stream target or stream resource.
|
||||
* @param string $mode Resource mode for stream target.
|
||||
* @throws InvalidArgumentException for invalid streams or resources.
|
||||
*/
|
||||
private function setStream($stream, $mode = 'r')
|
||||
{
|
||||
$error = null;
|
||||
$resource = $stream;
|
||||
|
||||
if (is_string($stream)) {
|
||||
set_error_handler(function ($e) use (&$error) {
|
||||
$error = $e;
|
||||
}, E_WARNING);
|
||||
$resource = fopen($stream, $mode);
|
||||
restore_error_handler();
|
||||
}
|
||||
|
||||
if ($error) {
|
||||
throw new InvalidArgumentException('Invalid stream reference provided');
|
||||
}
|
||||
|
||||
if (! is_resource($resource) || 'stream' !== get_resource_type($resource)) {
|
||||
throw new InvalidArgumentException(
|
||||
'Invalid stream provided; must be a string stream identifier or stream resource'
|
||||
);
|
||||
}
|
||||
|
||||
if ($stream !== $resource) {
|
||||
$this->stream = $stream;
|
||||
}
|
||||
|
||||
$this->resource = $resource;
|
||||
}
|
||||
}
|
234
vendor/zendframework/zend-diactoros/src/UploadedFile.php
vendored
Normal file
234
vendor/zendframework/zend-diactoros/src/UploadedFile.php
vendored
Normal file
|
@ -0,0 +1,234 @@
|
|||
<?php
|
||||
/**
|
||||
* Zend Framework (http://framework.zend.com/)
|
||||
*
|
||||
* @see http://github.com/zendframework/zend-diactoros for the canonical source repository
|
||||
* @copyright Copyright (c) 2015 Zend Technologies USA Inc. (http://www.zend.com)
|
||||
* @license https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License
|
||||
*/
|
||||
|
||||
namespace Zend\Diactoros;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
use Psr\Http\Message\UploadedFileInterface;
|
||||
use RuntimeException;
|
||||
|
||||
class UploadedFile implements UploadedFileInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $clientFilename;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $clientMediaType;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $error;
|
||||
|
||||
/**
|
||||
* @var null|string
|
||||
*/
|
||||
private $file;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $moved = false;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $size;
|
||||
|
||||
/**
|
||||
* @var null|StreamInterface
|
||||
*/
|
||||
private $stream;
|
||||
|
||||
public function __construct($streamOrFile, $size, $errorStatus, $clientFilename = null, $clientMediaType = null)
|
||||
{
|
||||
if ($errorStatus === UPLOAD_ERR_OK) {
|
||||
if (is_string($streamOrFile)) {
|
||||
$this->file = $streamOrFile;
|
||||
}
|
||||
if (is_resource($streamOrFile)) {
|
||||
$this->stream = new Stream($streamOrFile);
|
||||
}
|
||||
|
||||
if (! $this->file && ! $this->stream) {
|
||||
if (! $streamOrFile instanceof StreamInterface) {
|
||||
throw new InvalidArgumentException('Invalid stream or file provided for UploadedFile');
|
||||
}
|
||||
$this->stream = $streamOrFile;
|
||||
}
|
||||
}
|
||||
|
||||
if (! is_int($size)) {
|
||||
throw new InvalidArgumentException('Invalid size provided for UploadedFile; must be an int');
|
||||
}
|
||||
$this->size = $size;
|
||||
|
||||
if (! is_int($errorStatus)
|
||||
|| 0 > $errorStatus
|
||||
|| 8 < $errorStatus
|
||||
) {
|
||||
throw new InvalidArgumentException(
|
||||
'Invalid error status for UploadedFile; must be an UPLOAD_ERR_* constant'
|
||||
);
|
||||
}
|
||||
$this->error = $errorStatus;
|
||||
|
||||
if (null !== $clientFilename && ! is_string($clientFilename)) {
|
||||
throw new InvalidArgumentException(
|
||||
'Invalid client filename provided for UploadedFile; must be null or a string'
|
||||
);
|
||||
}
|
||||
$this->clientFilename = $clientFilename;
|
||||
|
||||
if (null !== $clientMediaType && ! is_string($clientMediaType)) {
|
||||
throw new InvalidArgumentException(
|
||||
'Invalid client media type provided for UploadedFile; must be null or a string'
|
||||
);
|
||||
}
|
||||
$this->clientMediaType = $clientMediaType;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @throws \RuntimeException if the upload was not successful.
|
||||
*/
|
||||
public function getStream()
|
||||
{
|
||||
if ($this->error !== UPLOAD_ERR_OK) {
|
||||
throw new RuntimeException('Cannot retrieve stream due to upload error');
|
||||
}
|
||||
|
||||
if ($this->moved) {
|
||||
throw new RuntimeException('Cannot retrieve stream after it has already been moved');
|
||||
}
|
||||
|
||||
if ($this->stream instanceof StreamInterface) {
|
||||
return $this->stream;
|
||||
}
|
||||
|
||||
$this->stream = new Stream($this->file);
|
||||
return $this->stream;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @see http://php.net/is_uploaded_file
|
||||
* @see http://php.net/move_uploaded_file
|
||||
* @param string $targetPath Path to which to move the uploaded file.
|
||||
* @throws \RuntimeException if the upload was not successful.
|
||||
* @throws \InvalidArgumentException if the $path specified is invalid.
|
||||
* @throws \RuntimeException on any error during the move operation, or on
|
||||
* the second or subsequent call to the method.
|
||||
*/
|
||||
public function moveTo($targetPath)
|
||||
{
|
||||
if ($this->error !== UPLOAD_ERR_OK) {
|
||||
throw new RuntimeException('Cannot retrieve stream due to upload error');
|
||||
}
|
||||
|
||||
if (! is_string($targetPath)) {
|
||||
throw new InvalidArgumentException(
|
||||
'Invalid path provided for move operation; must be a string'
|
||||
);
|
||||
}
|
||||
|
||||
if (empty($targetPath)) {
|
||||
throw new InvalidArgumentException(
|
||||
'Invalid path provided for move operation; must be a non-empty string'
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->moved) {
|
||||
throw new RuntimeException('Cannot move file; already moved!');
|
||||
}
|
||||
|
||||
$sapi = PHP_SAPI;
|
||||
switch (true) {
|
||||
case (empty($sapi) || 0 === strpos($sapi, 'cli') || ! $this->file):
|
||||
// Non-SAPI environment, or no filename present
|
||||
$this->writeFile($targetPath);
|
||||
break;
|
||||
default:
|
||||
// SAPI environment, with file present
|
||||
if (false === move_uploaded_file($this->file, $targetPath)) {
|
||||
throw new RuntimeException('Error occurred while moving uploaded file');
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
$this->moved = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return int|null The file size in bytes or null if unknown.
|
||||
*/
|
||||
public function getSize()
|
||||
{
|
||||
return $this->size;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @see http://php.net/manual/en/features.file-upload.errors.php
|
||||
* @return int One of PHP's UPLOAD_ERR_XXX constants.
|
||||
*/
|
||||
public function getError()
|
||||
{
|
||||
return $this->error;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return string|null The filename sent by the client or null if none
|
||||
* was provided.
|
||||
*/
|
||||
public function getClientFilename()
|
||||
{
|
||||
return $this->clientFilename;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getClientMediaType()
|
||||
{
|
||||
return $this->clientMediaType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write internal stream to given path
|
||||
*
|
||||
* @param string $path
|
||||
*/
|
||||
private function writeFile($path)
|
||||
{
|
||||
$handle = fopen($path, 'wb+');
|
||||
if (false === $handle) {
|
||||
throw new RuntimeException('Unable to write to designated path');
|
||||
}
|
||||
|
||||
$stream = $this->getStream();
|
||||
$stream->rewind();
|
||||
while (! $stream->eof()) {
|
||||
fwrite($handle, $stream->read(4096));
|
||||
}
|
||||
|
||||
fclose($handle);
|
||||
}
|
||||
}
|
659
vendor/zendframework/zend-diactoros/src/Uri.php
vendored
Normal file
659
vendor/zendframework/zend-diactoros/src/Uri.php
vendored
Normal file
|
@ -0,0 +1,659 @@
|
|||
<?php
|
||||
/**
|
||||
* Zend Framework (http://framework.zend.com/)
|
||||
*
|
||||
* @see http://github.com/zendframework/zend-diactoros for the canonical source repository
|
||||
* @copyright Copyright (c) 2015 Zend Technologies USA Inc. (http://www.zend.com)
|
||||
* @license https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License
|
||||
*/
|
||||
|
||||
namespace Zend\Diactoros;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
|
||||
/**
|
||||
* Implementation of Psr\Http\UriInterface.
|
||||
*
|
||||
* Provides a value object representing a URI for HTTP requests.
|
||||
*
|
||||
* Instances of this class are considered immutable; all methods that
|
||||
* might change state are implemented such that they retain the internal
|
||||
* state of the current instance and return a new instance that contains the
|
||||
* changed state.
|
||||
*/
|
||||
class Uri implements UriInterface
|
||||
{
|
||||
/**
|
||||
* Sub-delimiters used in query strings and fragments.
|
||||
*
|
||||
* @const string
|
||||
*/
|
||||
const CHAR_SUB_DELIMS = '!\$&\'\(\)\*\+,;=';
|
||||
|
||||
/**
|
||||
* Unreserved characters used in paths, query strings, and fragments.
|
||||
*
|
||||
* @const string
|
||||
*/
|
||||
const CHAR_UNRESERVED = 'a-zA-Z0-9_\-\.~';
|
||||
|
||||
/**
|
||||
* @var int[] Array indexed by valid scheme names to their corresponding ports.
|
||||
*/
|
||||
protected $allowedSchemes = [
|
||||
'http' => 80,
|
||||
'https' => 443,
|
||||
];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $scheme = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $userInfo = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $host = '';
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $port;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $path = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $query = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $fragment = '';
|
||||
|
||||
/**
|
||||
* generated uri string cache
|
||||
* @var string|null
|
||||
*/
|
||||
private $uriString;
|
||||
|
||||
/**
|
||||
* @param string $uri
|
||||
* @throws InvalidArgumentException on non-string $uri argument
|
||||
*/
|
||||
public function __construct($uri = '')
|
||||
{
|
||||
if (! is_string($uri)) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'URI passed to constructor must be a string; received "%s"',
|
||||
(is_object($uri) ? get_class($uri) : gettype($uri))
|
||||
));
|
||||
}
|
||||
|
||||
if (! empty($uri)) {
|
||||
$this->parseUri($uri);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Operations to perform on clone.
|
||||
*
|
||||
* Since cloning usually is for purposes of mutation, we reset the
|
||||
* $uriString property so it will be re-calculated.
|
||||
*/
|
||||
public function __clone()
|
||||
{
|
||||
$this->uriString = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
if (null !== $this->uriString) {
|
||||
return $this->uriString;
|
||||
}
|
||||
|
||||
$this->uriString = static::createUriString(
|
||||
$this->scheme,
|
||||
$this->getAuthority(),
|
||||
$this->getPath(), // Absolute URIs should use a "/" for an empty path
|
||||
$this->query,
|
||||
$this->fragment
|
||||
);
|
||||
|
||||
return $this->uriString;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getScheme()
|
||||
{
|
||||
return $this->scheme;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getAuthority()
|
||||
{
|
||||
if (empty($this->host)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$authority = $this->host;
|
||||
if (! empty($this->userInfo)) {
|
||||
$authority = $this->userInfo . '@' . $authority;
|
||||
}
|
||||
|
||||
if ($this->isNonStandardPort($this->scheme, $this->host, $this->port)) {
|
||||
$authority .= ':' . $this->port;
|
||||
}
|
||||
|
||||
return $authority;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUserInfo()
|
||||
{
|
||||
return $this->userInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getHost()
|
||||
{
|
||||
return $this->host;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getPort()
|
||||
{
|
||||
return $this->isNonStandardPort($this->scheme, $this->host, $this->port)
|
||||
? $this->port
|
||||
: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getPath()
|
||||
{
|
||||
return $this->path;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getQuery()
|
||||
{
|
||||
return $this->query;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFragment()
|
||||
{
|
||||
return $this->fragment;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function withScheme($scheme)
|
||||
{
|
||||
if (! is_string($scheme)) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'%s expects a string argument; received %s',
|
||||
__METHOD__,
|
||||
(is_object($scheme) ? get_class($scheme) : gettype($scheme))
|
||||
));
|
||||
}
|
||||
|
||||
$scheme = $this->filterScheme($scheme);
|
||||
|
||||
if ($scheme === $this->scheme) {
|
||||
// Do nothing if no change was made.
|
||||
return clone $this;
|
||||
}
|
||||
|
||||
$new = clone $this;
|
||||
$new->scheme = $scheme;
|
||||
|
||||
return $new;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function withUserInfo($user, $password = null)
|
||||
{
|
||||
if (! is_string($user)) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'%s expects a string user argument; received %s',
|
||||
__METHOD__,
|
||||
(is_object($user) ? get_class($user) : gettype($user))
|
||||
));
|
||||
}
|
||||
if (null !== $password && ! is_string($password)) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'%s expects a string password argument; received %s',
|
||||
__METHOD__,
|
||||
(is_object($password) ? get_class($password) : gettype($password))
|
||||
));
|
||||
}
|
||||
|
||||
$info = $user;
|
||||
if ($password) {
|
||||
$info .= ':' . $password;
|
||||
}
|
||||
|
||||
if ($info === $this->userInfo) {
|
||||
// Do nothing if no change was made.
|
||||
return clone $this;
|
||||
}
|
||||
|
||||
$new = clone $this;
|
||||
$new->userInfo = $info;
|
||||
|
||||
return $new;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function withHost($host)
|
||||
{
|
||||
if (! is_string($host)) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'%s expects a string argument; received %s',
|
||||
__METHOD__,
|
||||
(is_object($host) ? get_class($host) : gettype($host))
|
||||
));
|
||||
}
|
||||
|
||||
if ($host === $this->host) {
|
||||
// Do nothing if no change was made.
|
||||
return clone $this;
|
||||
}
|
||||
|
||||
$new = clone $this;
|
||||
$new->host = $host;
|
||||
|
||||
return $new;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function withPort($port)
|
||||
{
|
||||
if (! is_numeric($port)) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'Invalid port "%s" specified; must be an integer or integer string',
|
||||
(is_object($port) ? get_class($port) : gettype($port))
|
||||
));
|
||||
}
|
||||
|
||||
$port = (int) $port;
|
||||
|
||||
if ($port === $this->port) {
|
||||
// Do nothing if no change was made.
|
||||
return clone $this;
|
||||
}
|
||||
|
||||
if ($port < 1 || $port > 65535) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'Invalid port "%d" specified; must be a valid TCP/UDP port',
|
||||
$port
|
||||
));
|
||||
}
|
||||
|
||||
$new = clone $this;
|
||||
$new->port = $port;
|
||||
|
||||
return $new;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function withPath($path)
|
||||
{
|
||||
if (! is_string($path)) {
|
||||
throw new InvalidArgumentException(
|
||||
'Invalid path provided; must be a string'
|
||||
);
|
||||
}
|
||||
|
||||
if (strpos($path, '?') !== false) {
|
||||
throw new InvalidArgumentException(
|
||||
'Invalid path provided; must not contain a query string'
|
||||
);
|
||||
}
|
||||
|
||||
if (strpos($path, '#') !== false) {
|
||||
throw new InvalidArgumentException(
|
||||
'Invalid path provided; must not contain a URI fragment'
|
||||
);
|
||||
}
|
||||
|
||||
$path = $this->filterPath($path);
|
||||
|
||||
if ($path === $this->path) {
|
||||
// Do nothing if no change was made.
|
||||
return clone $this;
|
||||
}
|
||||
|
||||
$new = clone $this;
|
||||
$new->path = $path;
|
||||
|
||||
return $new;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function withQuery($query)
|
||||
{
|
||||
if (! is_string($query)) {
|
||||
throw new InvalidArgumentException(
|
||||
'Query string must be a string'
|
||||
);
|
||||
}
|
||||
|
||||
if (strpos($query, '#') !== false) {
|
||||
throw new InvalidArgumentException(
|
||||
'Query string must not include a URI fragment'
|
||||
);
|
||||
}
|
||||
|
||||
$query = $this->filterQuery($query);
|
||||
|
||||
if ($query === $this->query) {
|
||||
// Do nothing if no change was made.
|
||||
return clone $this;
|
||||
}
|
||||
|
||||
$new = clone $this;
|
||||
$new->query = $query;
|
||||
|
||||
return $new;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function withFragment($fragment)
|
||||
{
|
||||
if (! is_string($fragment)) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'%s expects a string argument; received %s',
|
||||
__METHOD__,
|
||||
(is_object($fragment) ? get_class($fragment) : gettype($fragment))
|
||||
));
|
||||
}
|
||||
|
||||
$fragment = $this->filterFragment($fragment);
|
||||
|
||||
if ($fragment === $this->fragment) {
|
||||
// Do nothing if no change was made.
|
||||
return clone $this;
|
||||
}
|
||||
|
||||
$new = clone $this;
|
||||
$new->fragment = $fragment;
|
||||
|
||||
return $new;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a URI into its parts, and set the properties
|
||||
*
|
||||
* @param string $uri
|
||||
*/
|
||||
private function parseUri($uri)
|
||||
{
|
||||
$parts = parse_url($uri);
|
||||
|
||||
if (false === $parts) {
|
||||
throw new \InvalidArgumentException(
|
||||
'The source URI string appears to be malformed'
|
||||
);
|
||||
}
|
||||
|
||||
$this->scheme = isset($parts['scheme']) ? $this->filterScheme($parts['scheme']) : '';
|
||||
$this->userInfo = isset($parts['user']) ? $parts['user'] : '';
|
||||
$this->host = isset($parts['host']) ? $parts['host'] : '';
|
||||
$this->port = isset($parts['port']) ? $parts['port'] : null;
|
||||
$this->path = isset($parts['path']) ? $this->filterPath($parts['path']) : '';
|
||||
$this->query = isset($parts['query']) ? $this->filterQuery($parts['query']) : '';
|
||||
$this->fragment = isset($parts['fragment']) ? $this->filterFragment($parts['fragment']) : '';
|
||||
|
||||
if (isset($parts['pass'])) {
|
||||
$this->userInfo .= ':' . $parts['pass'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a URI string from its various parts
|
||||
*
|
||||
* @param string $scheme
|
||||
* @param string $authority
|
||||
* @param string $path
|
||||
* @param string $query
|
||||
* @param string $fragment
|
||||
* @return string
|
||||
*/
|
||||
private static function createUriString($scheme, $authority, $path, $query, $fragment)
|
||||
{
|
||||
$uri = '';
|
||||
|
||||
if (! empty($scheme)) {
|
||||
$uri .= sprintf('%s://', $scheme);
|
||||
}
|
||||
|
||||
if (! empty($authority)) {
|
||||
$uri .= $authority;
|
||||
}
|
||||
|
||||
if ($path) {
|
||||
if (empty($path) || '/' !== substr($path, 0, 1)) {
|
||||
$path = '/' . $path;
|
||||
}
|
||||
|
||||
$uri .= $path;
|
||||
}
|
||||
|
||||
if ($query) {
|
||||
$uri .= sprintf('?%s', $query);
|
||||
}
|
||||
|
||||
if ($fragment) {
|
||||
$uri .= sprintf('#%s', $fragment);
|
||||
}
|
||||
|
||||
return $uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is a given port non-standard for the current scheme?
|
||||
*
|
||||
* @param string $scheme
|
||||
* @param string $host
|
||||
* @param int $port
|
||||
* @return bool
|
||||
*/
|
||||
private function isNonStandardPort($scheme, $host, $port)
|
||||
{
|
||||
if (! $scheme) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (! $host || ! $port) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ! isset($this->allowedSchemes[$scheme]) || $port !== $this->allowedSchemes[$scheme];
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the scheme to ensure it is a valid scheme.
|
||||
*
|
||||
* @param string $scheme Scheme name.
|
||||
*
|
||||
* @return string Filtered scheme.
|
||||
*/
|
||||
private function filterScheme($scheme)
|
||||
{
|
||||
$scheme = strtolower($scheme);
|
||||
$scheme = preg_replace('#:(//)?$#', '', $scheme);
|
||||
|
||||
if (empty($scheme)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (! array_key_exists($scheme, $this->allowedSchemes)) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'Unsupported scheme "%s"; must be any empty string or in the set (%s)',
|
||||
$scheme,
|
||||
implode(', ', array_keys($this->allowedSchemes))
|
||||
));
|
||||
}
|
||||
|
||||
return $scheme;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the path of a URI to ensure it is properly encoded.
|
||||
*
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
private function filterPath($path)
|
||||
{
|
||||
$path = preg_replace_callback(
|
||||
'/(?:[^' . self::CHAR_UNRESERVED . ':@&=\+\$,\/;%]+|%(?![A-Fa-f0-9]{2}))/',
|
||||
[$this, 'urlEncodeChar'],
|
||||
$path
|
||||
);
|
||||
|
||||
if (empty($path)) {
|
||||
// No path
|
||||
return $path;
|
||||
}
|
||||
|
||||
if ($path[0] !== '/') {
|
||||
// Relative path
|
||||
return $path;
|
||||
}
|
||||
|
||||
// Ensure only one leading slash, to prevent XSS attempts.
|
||||
return '/' . ltrim($path, '/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter a query string to ensure it is propertly encoded.
|
||||
*
|
||||
* Ensures that the values in the query string are properly urlencoded.
|
||||
*
|
||||
* @param string $query
|
||||
* @return string
|
||||
*/
|
||||
private function filterQuery($query)
|
||||
{
|
||||
if (! empty($query) && strpos($query, '?') === 0) {
|
||||
$query = substr($query, 1);
|
||||
}
|
||||
|
||||
$parts = explode('&', $query);
|
||||
foreach ($parts as $index => $part) {
|
||||
list($key, $value) = $this->splitQueryValue($part);
|
||||
if ($value === null) {
|
||||
$parts[$index] = $this->filterQueryOrFragment($key);
|
||||
continue;
|
||||
}
|
||||
$parts[$index] = sprintf(
|
||||
'%s=%s',
|
||||
$this->filterQueryOrFragment($key),
|
||||
$this->filterQueryOrFragment($value)
|
||||
);
|
||||
}
|
||||
|
||||
return implode('&', $parts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Split a query value into a key/value tuple.
|
||||
*
|
||||
* @param string $value
|
||||
* @return array A value with exactly two elements, key and value
|
||||
*/
|
||||
private function splitQueryValue($value)
|
||||
{
|
||||
$data = explode('=', $value, 2);
|
||||
if (1 === count($data)) {
|
||||
$data[] = null;
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter a fragment value to ensure it is properly encoded.
|
||||
*
|
||||
* @param null|string $fragment
|
||||
* @return string
|
||||
*/
|
||||
private function filterFragment($fragment)
|
||||
{
|
||||
if (! empty($fragment) && strpos($fragment, '#') === 0) {
|
||||
$fragment = substr($fragment, 1);
|
||||
}
|
||||
|
||||
return $this->filterQueryOrFragment($fragment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter a query string key or value, or a fragment.
|
||||
*
|
||||
* @param string $value
|
||||
* @return string
|
||||
*/
|
||||
private function filterQueryOrFragment($value)
|
||||
{
|
||||
return preg_replace_callback(
|
||||
'/(?:[^' . self::CHAR_UNRESERVED . self::CHAR_SUB_DELIMS . '%:@\/\?]+|%(?![A-Fa-f0-9]{2}))/',
|
||||
[$this, 'urlEncodeChar'],
|
||||
$value
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* URL encode a character returned by a regex.
|
||||
*
|
||||
* @param array $matches
|
||||
* @return string
|
||||
*/
|
||||
private function urlEncodeChar(array $matches)
|
||||
{
|
||||
return rawurlencode($matches[0]);
|
||||
}
|
||||
}
|
Reference in a new issue