diff options
author | Anton Luka Šijanec <anton@sijanec.eu> | 2022-01-11 12:35:47 +0100 |
---|---|---|
committer | Anton Luka Šijanec <anton@sijanec.eu> | 2022-01-11 12:35:47 +0100 |
commit | 19985dbb8c0aa66dc4bf7905abc1148de909097d (patch) | |
tree | 2cd5a5d20d7e80fc2a51adf60d838d8a2c40999e /vendor/guzzlehttp/psr7/src | |
download | 1ka-19985dbb8c0aa66dc4bf7905abc1148de909097d.tar 1ka-19985dbb8c0aa66dc4bf7905abc1148de909097d.tar.gz 1ka-19985dbb8c0aa66dc4bf7905abc1148de909097d.tar.bz2 1ka-19985dbb8c0aa66dc4bf7905abc1148de909097d.tar.lz 1ka-19985dbb8c0aa66dc4bf7905abc1148de909097d.tar.xz 1ka-19985dbb8c0aa66dc4bf7905abc1148de909097d.tar.zst 1ka-19985dbb8c0aa66dc4bf7905abc1148de909097d.zip |
Diffstat (limited to 'vendor/guzzlehttp/psr7/src')
30 files changed, 5862 insertions, 0 deletions
diff --git a/vendor/guzzlehttp/psr7/src/AppendStream.php b/vendor/guzzlehttp/psr7/src/AppendStream.php new file mode 100644 index 0000000..d4e9e87 --- /dev/null +++ b/vendor/guzzlehttp/psr7/src/AppendStream.php @@ -0,0 +1,246 @@ +<?php
+
+namespace GuzzleHttp\Psr7;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Reads from multiple streams, one after the other.
+ *
+ * This is a read-only stream decorator.
+ *
+ * @final
+ */
+class AppendStream implements StreamInterface
+{
+ /** @var StreamInterface[] Streams being decorated */
+ private $streams = [];
+
+ private $seekable = true;
+ private $current = 0;
+ private $pos = 0;
+
+ /**
+ * @param StreamInterface[] $streams Streams to decorate. Each stream must
+ * be readable.
+ */
+ public function __construct(array $streams = [])
+ {
+ foreach ($streams as $stream) {
+ $this->addStream($stream);
+ }
+ }
+
+ public function __toString()
+ {
+ try {
+ $this->rewind();
+ return $this->getContents();
+ } catch (\Exception $e) {
+ return '';
+ }
+ }
+
+ /**
+ * Add a stream to the AppendStream
+ *
+ * @param StreamInterface $stream Stream to append. Must be readable.
+ *
+ * @throws \InvalidArgumentException if the stream is not readable
+ */
+ public function addStream(StreamInterface $stream)
+ {
+ if (!$stream->isReadable()) {
+ throw new \InvalidArgumentException('Each stream must be readable');
+ }
+
+ // The stream is only seekable if all streams are seekable
+ if (!$stream->isSeekable()) {
+ $this->seekable = false;
+ }
+
+ $this->streams[] = $stream;
+ }
+
+ public function getContents()
+ {
+ return Utils::copyToString($this);
+ }
+
+ /**
+ * Closes each attached stream.
+ *
+ * {@inheritdoc}
+ */
+ public function close()
+ {
+ $this->pos = $this->current = 0;
+ $this->seekable = true;
+
+ foreach ($this->streams as $stream) {
+ $stream->close();
+ }
+
+ $this->streams = [];
+ }
+
+ /**
+ * Detaches each attached stream.
+ *
+ * Returns null as it's not clear which underlying stream resource to return.
+ *
+ * {@inheritdoc}
+ */
+ public function detach()
+ {
+ $this->pos = $this->current = 0;
+ $this->seekable = true;
+
+ foreach ($this->streams as $stream) {
+ $stream->detach();
+ }
+
+ $this->streams = [];
+
+ return null;
+ }
+
+ public function tell()
+ {
+ return $this->pos;
+ }
+
+ /**
+ * Tries to calculate the size by adding the size of each stream.
+ *
+ * If any of the streams do not return a valid number, then the size of the
+ * append stream cannot be determined and null is returned.
+ *
+ * {@inheritdoc}
+ */
+ public function getSize()
+ {
+ $size = 0;
+
+ foreach ($this->streams as $stream) {
+ $s = $stream->getSize();
+ if ($s === null) {
+ return null;
+ }
+ $size += $s;
+ }
+
+ return $size;
+ }
+
+ public function eof()
+ {
+ return !$this->streams ||
+ ($this->current >= count($this->streams) - 1 &&
+ $this->streams[$this->current]->eof());
+ }
+
+ public function rewind()
+ {
+ $this->seek(0);
+ }
+
+ /**
+ * Attempts to seek to the given position. Only supports SEEK_SET.
+ *
+ * {@inheritdoc}
+ */
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ if (!$this->seekable) {
+ throw new \RuntimeException('This AppendStream is not seekable');
+ } elseif ($whence !== SEEK_SET) {
+ throw new \RuntimeException('The AppendStream can only seek with SEEK_SET');
+ }
+
+ $this->pos = $this->current = 0;
+
+ // Rewind each stream
+ foreach ($this->streams as $i => $stream) {
+ try {
+ $stream->rewind();
+ } catch (\Exception $e) {
+ throw new \RuntimeException('Unable to seek stream '
+ . $i . ' of the AppendStream', 0, $e);
+ }
+ }
+
+ // Seek to the actual position by reading from each stream
+ while ($this->pos < $offset && !$this->eof()) {
+ $result = $this->read(min(8096, $offset - $this->pos));
+ if ($result === '') {
+ break;
+ }
+ }
+ }
+
+ /**
+ * Reads from all of the appended streams until the length is met or EOF.
+ *
+ * {@inheritdoc}
+ */
+ public function read($length)
+ {
+ $buffer = '';
+ $total = count($this->streams) - 1;
+ $remaining = $length;
+ $progressToNext = false;
+
+ while ($remaining > 0) {
+
+ // Progress to the next stream if needed.
+ if ($progressToNext || $this->streams[$this->current]->eof()) {
+ $progressToNext = false;
+ if ($this->current === $total) {
+ break;
+ }
+ $this->current++;
+ }
+
+ $result = $this->streams[$this->current]->read($remaining);
+
+ // Using a loose comparison here to match on '', false, and null
+ if ($result == null) {
+ $progressToNext = true;
+ continue;
+ }
+
+ $buffer .= $result;
+ $remaining = $length - strlen($buffer);
+ }
+
+ $this->pos += strlen($buffer);
+
+ return $buffer;
+ }
+
+ public function isReadable()
+ {
+ return true;
+ }
+
+ public function isWritable()
+ {
+ return false;
+ }
+
+ public function isSeekable()
+ {
+ return $this->seekable;
+ }
+
+ public function write($string)
+ {
+ throw new \RuntimeException('Cannot write to an AppendStream');
+ }
+
+ public function getMetadata($key = null)
+ {
+ return $key ? null : [];
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/BufferStream.php b/vendor/guzzlehttp/psr7/src/BufferStream.php new file mode 100644 index 0000000..21e8a99 --- /dev/null +++ b/vendor/guzzlehttp/psr7/src/BufferStream.php @@ -0,0 +1,142 @@ +<?php
+
+namespace GuzzleHttp\Psr7;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Provides a buffer stream that can be written to to fill a buffer, and read
+ * from to remove bytes from the buffer.
+ *
+ * This stream returns a "hwm" metadata value that tells upstream consumers
+ * what the configured high water mark of the stream is, or the maximum
+ * preferred size of the buffer.
+ *
+ * @final
+ */
+class BufferStream implements StreamInterface
+{
+ private $hwm;
+ private $buffer = '';
+
+ /**
+ * @param int $hwm High water mark, representing the preferred maximum
+ * buffer size. If the size of the buffer exceeds the high
+ * water mark, then calls to write will continue to succeed
+ * but will return false to inform writers to slow down
+ * until the buffer has been drained by reading from it.
+ */
+ public function __construct($hwm = 16384)
+ {
+ $this->hwm = $hwm;
+ }
+
+ public function __toString()
+ {
+ return $this->getContents();
+ }
+
+ public function getContents()
+ {
+ $buffer = $this->buffer;
+ $this->buffer = '';
+
+ return $buffer;
+ }
+
+ public function close()
+ {
+ $this->buffer = '';
+ }
+
+ public function detach()
+ {
+ $this->close();
+
+ return null;
+ }
+
+ public function getSize()
+ {
+ return strlen($this->buffer);
+ }
+
+ public function isReadable()
+ {
+ return true;
+ }
+
+ public function isWritable()
+ {
+ return true;
+ }
+
+ public function isSeekable()
+ {
+ return false;
+ }
+
+ public function rewind()
+ {
+ $this->seek(0);
+ }
+
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ throw new \RuntimeException('Cannot seek a BufferStream');
+ }
+
+ public function eof()
+ {
+ return strlen($this->buffer) === 0;
+ }
+
+ public function tell()
+ {
+ throw new \RuntimeException('Cannot determine the position of a BufferStream');
+ }
+
+ /**
+ * Reads data from the buffer.
+ */
+ public function read($length)
+ {
+ $currentLength = strlen($this->buffer);
+
+ if ($length >= $currentLength) {
+ // No need to slice the buffer because we don't have enough data.
+ $result = $this->buffer;
+ $this->buffer = '';
+ } else {
+ // Slice up the result to provide a subset of the buffer.
+ $result = substr($this->buffer, 0, $length);
+ $this->buffer = substr($this->buffer, $length);
+ }
+
+ return $result;
+ }
+
+ /**
+ * Writes data to the buffer.
+ */
+ public function write($string)
+ {
+ $this->buffer .= $string;
+
+ // TODO: What should happen here?
+ if (strlen($this->buffer) >= $this->hwm) {
+ return false;
+ }
+
+ return strlen($string);
+ }
+
+ public function getMetadata($key = null)
+ {
+ if ($key == 'hwm') {
+ return $this->hwm;
+ }
+
+ return $key ? null : [];
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/CachingStream.php b/vendor/guzzlehttp/psr7/src/CachingStream.php new file mode 100644 index 0000000..7000593 --- /dev/null +++ b/vendor/guzzlehttp/psr7/src/CachingStream.php @@ -0,0 +1,141 @@ +<?php
+
+namespace GuzzleHttp\Psr7;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Stream decorator that can cache previously read bytes from a sequentially
+ * read stream.
+ *
+ * @final
+ */
+class CachingStream implements StreamInterface
+{
+ use StreamDecoratorTrait;
+
+ /** @var StreamInterface Stream being wrapped */
+ private $remoteStream;
+
+ /** @var int Number of bytes to skip reading due to a write on the buffer */
+ private $skipReadBytes = 0;
+
+ /**
+ * We will treat the buffer object as the body of the stream
+ *
+ * @param StreamInterface $stream Stream to cache. The cursor is assumed to be at the beginning of the stream.
+ * @param StreamInterface $target Optionally specify where data is cached
+ */
+ public function __construct(
+ StreamInterface $stream,
+ StreamInterface $target = null
+ ) {
+ $this->remoteStream = $stream;
+ $this->stream = $target ?: new Stream(Utils::tryFopen('php://temp', 'r+'));
+ }
+
+ public function getSize()
+ {
+ return max($this->stream->getSize(), $this->remoteStream->getSize());
+ }
+
+ public function rewind()
+ {
+ $this->seek(0);
+ }
+
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ if ($whence == SEEK_SET) {
+ $byte = $offset;
+ } elseif ($whence == SEEK_CUR) {
+ $byte = $offset + $this->tell();
+ } elseif ($whence == SEEK_END) {
+ $size = $this->remoteStream->getSize();
+ if ($size === null) {
+ $size = $this->cacheEntireStream();
+ }
+ $byte = $size + $offset;
+ } else {
+ throw new \InvalidArgumentException('Invalid whence');
+ }
+
+ $diff = $byte - $this->stream->getSize();
+
+ if ($diff > 0) {
+ // Read the remoteStream until we have read in at least the amount
+ // of bytes requested, or we reach the end of the file.
+ while ($diff > 0 && !$this->remoteStream->eof()) {
+ $this->read($diff);
+ $diff = $byte - $this->stream->getSize();
+ }
+ } else {
+ // We can just do a normal seek since we've already seen this byte.
+ $this->stream->seek($byte);
+ }
+ }
+
+ public function read($length)
+ {
+ // Perform a regular read on any previously read data from the buffer
+ $data = $this->stream->read($length);
+ $remaining = $length - strlen($data);
+
+ // More data was requested so read from the remote stream
+ if ($remaining) {
+ // If data was written to the buffer in a position that would have
+ // been filled from the remote stream, then we must skip bytes on
+ // the remote stream to emulate overwriting bytes from that
+ // position. This mimics the behavior of other PHP stream wrappers.
+ $remoteData = $this->remoteStream->read(
+ $remaining + $this->skipReadBytes
+ );
+
+ if ($this->skipReadBytes) {
+ $len = strlen($remoteData);
+ $remoteData = substr($remoteData, $this->skipReadBytes);
+ $this->skipReadBytes = max(0, $this->skipReadBytes - $len);
+ }
+
+ $data .= $remoteData;
+ $this->stream->write($remoteData);
+ }
+
+ return $data;
+ }
+
+ public function write($string)
+ {
+ // When appending to the end of the currently read stream, you'll want
+ // to skip bytes from being read from the remote stream to emulate
+ // other stream wrappers. Basically replacing bytes of data of a fixed
+ // length.
+ $overflow = (strlen($string) + $this->tell()) - $this->remoteStream->tell();
+ if ($overflow > 0) {
+ $this->skipReadBytes += $overflow;
+ }
+
+ return $this->stream->write($string);
+ }
+
+ public function eof()
+ {
+ return $this->stream->eof() && $this->remoteStream->eof();
+ }
+
+ /**
+ * Close both the remote stream and buffer stream
+ */
+ public function close()
+ {
+ $this->remoteStream->close() && $this->stream->close();
+ }
+
+ private function cacheEntireStream()
+ {
+ $target = new FnStream(['write' => 'strlen']);
+ Utils::copyToStream($this, $target);
+
+ return $this->tell();
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/DroppingStream.php b/vendor/guzzlehttp/psr7/src/DroppingStream.php new file mode 100644 index 0000000..680a697 --- /dev/null +++ b/vendor/guzzlehttp/psr7/src/DroppingStream.php @@ -0,0 +1,45 @@ +<?php
+
+namespace GuzzleHttp\Psr7;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Stream decorator that begins dropping data once the size of the underlying
+ * stream becomes too full.
+ *
+ * @final
+ */
+class DroppingStream implements StreamInterface
+{
+ use StreamDecoratorTrait;
+
+ private $maxLength;
+
+ /**
+ * @param StreamInterface $stream Underlying stream to decorate.
+ * @param int $maxLength Maximum size before dropping data.
+ */
+ public function __construct(StreamInterface $stream, $maxLength)
+ {
+ $this->stream = $stream;
+ $this->maxLength = $maxLength;
+ }
+
+ public function write($string)
+ {
+ $diff = $this->maxLength - $this->stream->getSize();
+
+ // Begin returning 0 when the underlying stream is too large.
+ if ($diff <= 0) {
+ return 0;
+ }
+
+ // Write the stream or a subset of the stream if needed.
+ if (strlen($string) < $diff) {
+ return $this->stream->write($string);
+ }
+
+ return $this->stream->write(substr($string, 0, $diff));
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/FnStream.php b/vendor/guzzlehttp/psr7/src/FnStream.php new file mode 100644 index 0000000..6c93a50 --- /dev/null +++ b/vendor/guzzlehttp/psr7/src/FnStream.php @@ -0,0 +1,163 @@ +<?php
+
+namespace GuzzleHttp\Psr7;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Compose stream implementations based on a hash of functions.
+ *
+ * Allows for easy testing and extension of a provided stream without needing
+ * to create a concrete class for a simple extension point.
+ *
+ * @final
+ */
+class FnStream implements StreamInterface
+{
+ /** @var array */
+ private $methods;
+
+ /** @var array Methods that must be implemented in the given array */
+ private static $slots = ['__toString', 'close', 'detach', 'rewind',
+ 'getSize', 'tell', 'eof', 'isSeekable', 'seek', 'isWritable', 'write',
+ 'isReadable', 'read', 'getContents', 'getMetadata'];
+
+ /**
+ * @param array $methods Hash of method name to a callable.
+ */
+ public function __construct(array $methods)
+ {
+ $this->methods = $methods;
+
+ // Create the functions on the class
+ foreach ($methods as $name => $fn) {
+ $this->{'_fn_' . $name} = $fn;
+ }
+ }
+
+ /**
+ * Lazily determine which methods are not implemented.
+ *
+ * @throws \BadMethodCallException
+ */
+ public function __get($name)
+ {
+ throw new \BadMethodCallException(str_replace('_fn_', '', $name)
+ . '() is not implemented in the FnStream');
+ }
+
+ /**
+ * The close method is called on the underlying stream only if possible.
+ */
+ public function __destruct()
+ {
+ if (isset($this->_fn_close)) {
+ call_user_func($this->_fn_close);
+ }
+ }
+
+ /**
+ * An unserialize would allow the __destruct to run when the unserialized value goes out of scope.
+ *
+ * @throws \LogicException
+ */
+ public function __wakeup()
+ {
+ throw new \LogicException('FnStream should never be unserialized');
+ }
+
+ /**
+ * Adds custom functionality to an underlying stream by intercepting
+ * specific method calls.
+ *
+ * @param StreamInterface $stream Stream to decorate
+ * @param array $methods Hash of method name to a closure
+ *
+ * @return FnStream
+ */
+ public static function decorate(StreamInterface $stream, array $methods)
+ {
+ // If any of the required methods were not provided, then simply
+ // proxy to the decorated stream.
+ foreach (array_diff(self::$slots, array_keys($methods)) as $diff) {
+ $methods[$diff] = [$stream, $diff];
+ }
+
+ return new self($methods);
+ }
+
+ public function __toString()
+ {
+ return call_user_func($this->_fn___toString);
+ }
+
+ public function close()
+ {
+ return call_user_func($this->_fn_close);
+ }
+
+ public function detach()
+ {
+ return call_user_func($this->_fn_detach);
+ }
+
+ public function getSize()
+ {
+ return call_user_func($this->_fn_getSize);
+ }
+
+ public function tell()
+ {
+ return call_user_func($this->_fn_tell);
+ }
+
+ public function eof()
+ {
+ return call_user_func($this->_fn_eof);
+ }
+
+ public function isSeekable()
+ {
+ return call_user_func($this->_fn_isSeekable);
+ }
+
+ public function rewind()
+ {
+ call_user_func($this->_fn_rewind);
+ }
+
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ call_user_func($this->_fn_seek, $offset, $whence);
+ }
+
+ public function isWritable()
+ {
+ return call_user_func($this->_fn_isWritable);
+ }
+
+ public function write($string)
+ {
+ return call_user_func($this->_fn_write, $string);
+ }
+
+ public function isReadable()
+ {
+ return call_user_func($this->_fn_isReadable);
+ }
+
+ public function read($length)
+ {
+ return call_user_func($this->_fn_read, $length);
+ }
+
+ public function getContents()
+ {
+ return call_user_func($this->_fn_getContents);
+ }
+
+ public function getMetadata($key = null)
+ {
+ return call_user_func($this->_fn_getMetadata, $key);
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/Header.php b/vendor/guzzlehttp/psr7/src/Header.php new file mode 100644 index 0000000..865d742 --- /dev/null +++ b/vendor/guzzlehttp/psr7/src/Header.php @@ -0,0 +1,71 @@ +<?php + +namespace GuzzleHttp\Psr7; + +final class Header +{ + /** + * Parse an array of header values containing ";" separated data into an + * array of associative arrays representing the header key value pair data + * of the header. When a parameter does not contain a value, but just + * contains a key, this function will inject a key with a '' string value. + * + * @param string|array $header Header to parse into components. + * + * @return array Returns the parsed header values. + */ + public static function parse($header) + { + static $trimmed = "\"' \n\t\r"; + $params = $matches = []; + + foreach (self::normalize($header) as $val) { + $part = []; + foreach (preg_split('/;(?=([^"]*"[^"]*")*[^"]*$)/', $val) as $kvp) { + if (preg_match_all('/<[^>]+>|[^=]+/', $kvp, $matches)) { + $m = $matches[0]; + if (isset($m[1])) { + $part[trim($m[0], $trimmed)] = trim($m[1], $trimmed); + } else { + $part[] = trim($m[0], $trimmed); + } + } + } + if ($part) { + $params[] = $part; + } + } + + return $params; + } + + /** + * Converts an array of header values that may contain comma separated + * headers into an array of headers with no comma separated values. + * + * @param string|array $header Header to normalize. + * + * @return array Returns the normalized header field values. + */ + public static function normalize($header) + { + if (!is_array($header)) { + return array_map('trim', explode(',', $header)); + } + + $result = []; + foreach ($header as $value) { + foreach ((array) $value as $v) { + if (strpos($v, ',') === false) { + $result[] = $v; + continue; + } + foreach (preg_split('/,(?=([^"]*"[^"]*")*[^"]*$)/', $v) as $vv) { + $result[] = trim($vv); + } + } + } + + return $result; + } +} diff --git a/vendor/guzzlehttp/psr7/src/InflateStream.php b/vendor/guzzlehttp/psr7/src/InflateStream.php new file mode 100644 index 0000000..2066f9d --- /dev/null +++ b/vendor/guzzlehttp/psr7/src/InflateStream.php @@ -0,0 +1,56 @@ +<?php
+
+namespace GuzzleHttp\Psr7;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Uses PHP's zlib.inflate filter to inflate deflate or gzipped content.
+ *
+ * This stream decorator skips the first 10 bytes of the given stream to remove
+ * the gzip header, converts the provided stream to a PHP stream resource,
+ * then appends the zlib.inflate filter. The stream is then converted back
+ * to a Guzzle stream resource to be used as a Guzzle stream.
+ *
+ * @link http://tools.ietf.org/html/rfc1952
+ * @link http://php.net/manual/en/filters.compression.php
+ *
+ * @final
+ */
+class InflateStream implements StreamInterface
+{
+ use StreamDecoratorTrait;
+
+ public function __construct(StreamInterface $stream)
+ {
+ // read the first 10 bytes, ie. gzip header
+ $header = $stream->read(10);
+ $filenameHeaderLength = $this->getLengthOfPossibleFilenameHeader($stream, $header);
+ // Skip the header, that is 10 + length of filename + 1 (nil) bytes
+ $stream = new LimitStream($stream, -1, 10 + $filenameHeaderLength);
+ $resource = StreamWrapper::getResource($stream);
+ stream_filter_append($resource, 'zlib.inflate', STREAM_FILTER_READ);
+ $this->stream = $stream->isSeekable() ? new Stream($resource) : new NoSeekStream(new Stream($resource));
+ }
+
+ /**
+ * @param StreamInterface $stream
+ * @param $header
+ *
+ * @return int
+ */
+ private function getLengthOfPossibleFilenameHeader(StreamInterface $stream, $header)
+ {
+ $filename_header_length = 0;
+
+ if (substr(bin2hex($header), 6, 2) === '08') {
+ // we have a filename, read until nil
+ $filename_header_length = 1;
+ while ($stream->read(1) !== chr(0)) {
+ $filename_header_length++;
+ }
+ }
+
+ return $filename_header_length;
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/LazyOpenStream.php b/vendor/guzzlehttp/psr7/src/LazyOpenStream.php new file mode 100644 index 0000000..72ef6ff --- /dev/null +++ b/vendor/guzzlehttp/psr7/src/LazyOpenStream.php @@ -0,0 +1,42 @@ +<?php
+
+namespace GuzzleHttp\Psr7;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Lazily reads or writes to a file that is opened only after an IO operation
+ * take place on the stream.
+ *
+ * @final
+ */
+class LazyOpenStream implements StreamInterface
+{
+ use StreamDecoratorTrait;
+
+ /** @var string File to open */
+ private $filename;
+
+ /** @var string */
+ private $mode;
+
+ /**
+ * @param string $filename File to lazily open
+ * @param string $mode fopen mode to use when opening the stream
+ */
+ public function __construct($filename, $mode)
+ {
+ $this->filename = $filename;
+ $this->mode = $mode;
+ }
+
+ /**
+ * Creates the underlying stream lazily when required.
+ *
+ * @return StreamInterface
+ */
+ protected function createStream()
+ {
+ return Utils::streamFor(Utils::tryFopen($this->filename, $this->mode));
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/LimitStream.php b/vendor/guzzlehttp/psr7/src/LimitStream.php new file mode 100644 index 0000000..26ef188 --- /dev/null +++ b/vendor/guzzlehttp/psr7/src/LimitStream.php @@ -0,0 +1,157 @@ +<?php
+
+namespace GuzzleHttp\Psr7;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Decorator used to return only a subset of a stream.
+ *
+ * @final
+ */
+class LimitStream implements StreamInterface
+{
+ use StreamDecoratorTrait;
+
+ /** @var int Offset to start reading from */
+ private $offset;
+
+ /** @var int Limit the number of bytes that can be read */
+ private $limit;
+
+ /**
+ * @param StreamInterface $stream Stream to wrap
+ * @param int $limit Total number of bytes to allow to be read
+ * from the stream. Pass -1 for no limit.
+ * @param int $offset Position to seek to before reading (only
+ * works on seekable streams).
+ */
+ public function __construct(
+ StreamInterface $stream,
+ $limit = -1,
+ $offset = 0
+ ) {
+ $this->stream = $stream;
+ $this->setLimit($limit);
+ $this->setOffset($offset);
+ }
+
+ public function eof()
+ {
+ // Always return true if the underlying stream is EOF
+ if ($this->stream->eof()) {
+ return true;
+ }
+
+ // No limit and the underlying stream is not at EOF
+ if ($this->limit == -1) {
+ return false;
+ }
+
+ return $this->stream->tell() >= $this->offset + $this->limit;
+ }
+
+ /**
+ * Returns the size of the limited subset of data
+ * {@inheritdoc}
+ */
+ public function getSize()
+ {
+ if (null === ($length = $this->stream->getSize())) {
+ return null;
+ } elseif ($this->limit == -1) {
+ return $length - $this->offset;
+ } else {
+ return min($this->limit, $length - $this->offset);
+ }
+ }
+
+ /**
+ * Allow for a bounded seek on the read limited stream
+ * {@inheritdoc}
+ */
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ if ($whence !== SEEK_SET || $offset < 0) {
+ throw new \RuntimeException(sprintf(
+ 'Cannot seek to offset %s with whence %s',
+ $offset,
+ $whence
+ ));
+ }
+
+ $offset += $this->offset;
+
+ if ($this->limit !== -1) {
+ if ($offset > $this->offset + $this->limit) {
+ $offset = $this->offset + $this->limit;
+ }
+ }
+
+ $this->stream->seek($offset);
+ }
+
+ /**
+ * Give a relative tell()
+ * {@inheritdoc}
+ */
+ public function tell()
+ {
+ return $this->stream->tell() - $this->offset;
+ }
+
+ /**
+ * Set the offset to start limiting from
+ *
+ * @param int $offset Offset to seek to and begin byte limiting from
+ *
+ * @throws \RuntimeException if the stream cannot be seeked.
+ */
+ public function setOffset($offset)
+ {
+ $current = $this->stream->tell();
+
+ if ($current !== $offset) {
+ // If the stream cannot seek to the offset position, then read to it
+ if ($this->stream->isSeekable()) {
+ $this->stream->seek($offset);
+ } elseif ($current > $offset) {
+ throw new \RuntimeException("Could not seek to stream offset $offset");
+ } else {
+ $this->stream->read($offset - $current);
+ }
+ }
+
+ $this->offset = $offset;
+ }
+
+ /**
+ * Set the limit of bytes that the decorator allows to be read from the
+ * stream.
+ *
+ * @param int $limit Number of bytes to allow to be read from the stream.
+ * Use -1 for no limit.
+ */
+ public function setLimit($limit)
+ {
+ $this->limit = $limit;
+ }
+
+ public function read($length)
+ {
+ if ($this->limit == -1) {
+ return $this->stream->read($length);
+ }
+
+ // Check if the current position is less than the total allowed
+ // bytes + original offset
+ $remaining = ($this->offset + $this->limit) - $this->stream->tell();
+ if ($remaining > 0) {
+ // Only return the amount of requested data, ensuring that the byte
+ // limit is not exceeded
+ return $this->stream->read(min($remaining, $length));
+ }
+
+ return '';
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/Message.php b/vendor/guzzlehttp/psr7/src/Message.php new file mode 100644 index 0000000..516d1cb --- /dev/null +++ b/vendor/guzzlehttp/psr7/src/Message.php @@ -0,0 +1,252 @@ +<?php + +namespace GuzzleHttp\Psr7; + +use Psr\Http\Message\MessageInterface; +use Psr\Http\Message\RequestInterface; +use Psr\Http\Message\ResponseInterface; + +final class Message +{ + /** + * Returns the string representation of an HTTP message. + * + * @param MessageInterface $message Message to convert to a string. + * + * @return string + */ + public static function toString(MessageInterface $message) + { + if ($message instanceof RequestInterface) { + $msg = trim($message->getMethod() . ' ' + . $message->getRequestTarget()) + . ' HTTP/' . $message->getProtocolVersion(); + if (!$message->hasHeader('host')) { + $msg .= "\r\nHost: " . $message->getUri()->getHost(); + } + } elseif ($message instanceof ResponseInterface) { + $msg = 'HTTP/' . $message->getProtocolVersion() . ' ' + . $message->getStatusCode() . ' ' + . $message->getReasonPhrase(); + } else { + throw new \InvalidArgumentException('Unknown message type'); + } + + foreach ($message->getHeaders() as $name => $values) { + if (strtolower($name) === 'set-cookie') { + foreach ($values as $value) { + $msg .= "\r\n{$name}: " . $value; + } + } else { + $msg .= "\r\n{$name}: " . implode(', ', $values); + } + } + + return "{$msg}\r\n\r\n" . $message->getBody(); + } + + /** + * Get a short summary of the message body. + * + * Will return `null` if the response is not printable. + * + * @param MessageInterface $message The message to get the body summary + * @param int $truncateAt The maximum allowed size of the summary + * + * @return string|null + */ + public static function bodySummary(MessageInterface $message, $truncateAt = 120) + { + $body = $message->getBody(); + + if (!$body->isSeekable() || !$body->isReadable()) { + return null; + } + + $size = $body->getSize(); + + if ($size === 0) { + return null; + } + + $summary = $body->read($truncateAt); + $body->rewind(); + + if ($size > $truncateAt) { + $summary .= ' (truncated...)'; + } + + // Matches any printable character, including unicode characters: + // letters, marks, numbers, punctuation, spacing, and separators. + if (preg_match('/[^\pL\pM\pN\pP\pS\pZ\n\r\t]/u', $summary)) { + return null; + } + + return $summary; + } + + /** + * Attempts to rewind a message body and throws an exception on failure. + * + * The body of the message will only be rewound if a call to `tell()` + * returns a value other than `0`. + * + * @param MessageInterface $message Message to rewind + * + * @throws \RuntimeException + */ + public static function rewindBody(MessageInterface $message) + { + $body = $message->getBody(); + + if ($body->tell()) { + $body->rewind(); + } + } + + /** + * Parses an HTTP message into an associative array. + * + * The array contains the "start-line" key containing the start line of + * the message, "headers" key containing an associative array of header + * array values, and a "body" key containing the body of the message. + * + * @param string $message HTTP request or response to parse. + * + * @return array + */ + public static function parseMessage($message) + { + if (!$message) { + throw new \InvalidArgumentException('Invalid message'); + } + + $message = ltrim($message, "\r\n"); + + $messageParts = preg_split("/\r?\n\r?\n/", $message, 2); + + if ($messageParts === false || count($messageParts) !== 2) { + throw new \InvalidArgumentException('Invalid message: Missing header delimiter'); + } + + list($rawHeaders, $body) = $messageParts; + $rawHeaders .= "\r\n"; // Put back the delimiter we split previously + $headerParts = preg_split("/\r?\n/", $rawHeaders, 2); + + if ($headerParts === false || count($headerParts) !== 2) { + throw new \InvalidArgumentException('Invalid message: Missing status line'); + } + + list($startLine, $rawHeaders) = $headerParts; + + if (preg_match("/(?:^HTTP\/|^[A-Z]+ \S+ HTTP\/)(\d+(?:\.\d+)?)/i", $startLine, $matches) && $matches[1] === '1.0') { + // Header folding is deprecated for HTTP/1.1, but allowed in HTTP/1.0 + $rawHeaders = preg_replace(Rfc7230::HEADER_FOLD_REGEX, ' ', $rawHeaders); + } + + /** @var array[] $headerLines */ + $count = preg_match_all(Rfc7230::HEADER_REGEX, $rawHeaders, $headerLines, PREG_SET_ORDER); + + // If these aren't the same, then one line didn't match and there's an invalid header. + if ($count !== substr_count($rawHeaders, "\n")) { + // Folding is deprecated, see https://tools.ietf.org/html/rfc7230#section-3.2.4 + if (preg_match(Rfc7230::HEADER_FOLD_REGEX, $rawHeaders)) { + throw new \InvalidArgumentException('Invalid header syntax: Obsolete line folding'); + } + + throw new \InvalidArgumentException('Invalid header syntax'); + } + + $headers = []; + + foreach ($headerLines as $headerLine) { + $headers[$headerLine[1]][] = $headerLine[2]; + } + + return [ + 'start-line' => $startLine, + 'headers' => $headers, + 'body' => $body, + ]; + } + + /** + * Constructs a URI for an HTTP request message. + * + * @param string $path Path from the start-line + * @param array $headers Array of headers (each value an array). + * + * @return string + */ + public static function parseRequestUri($path, array $headers) + { + $hostKey = array_filter(array_keys($headers), function ($k) { + return strtolower($k) === 'host'; + }); + + // If no host is found, then a full URI cannot be constructed. + if (!$hostKey) { + return $path; + } + + $host = $headers[reset($hostKey)][0]; + $scheme = substr($host, -4) === ':443' ? 'https' : 'http'; + + return $scheme . '://' . $host . '/' . ltrim($path, '/'); + } + + /** + * Parses a request message string into a request object. + * + * @param string $message Request message string. + * + * @return Request + */ + public static function parseRequest($message) + { + $data = self::parseMessage($message); + $matches = []; + if (!preg_match('/^[\S]+\s+([a-zA-Z]+:\/\/|\/).*/', $data['start-line'], $matches)) { + throw new \InvalidArgumentException('Invalid request string'); + } + $parts = explode(' ', $data['start-line'], 3); + $version = isset($parts[2]) ? explode('/', $parts[2])[1] : '1.1'; + + $request = new Request( + $parts[0], + $matches[1] === '/' ? self::parseRequestUri($parts[1], $data['headers']) : $parts[1], + $data['headers'], + $data['body'], + $version + ); + + return $matches[1] === '/' ? $request : $request->withRequestTarget($parts[1]); + } + + /** + * Parses a response message string into a response object. + * + * @param string $message Response message string. + * + * @return Response + */ + public static function parseResponse($message) + { + $data = self::parseMessage($message); + // According to https://tools.ietf.org/html/rfc7230#section-3.1.2 the space + // between status-code and reason-phrase is required. But browsers accept + // responses without space and reason as well. + if (!preg_match('/^HTTP\/.* [0-9]{3}( .*|$)/', $data['start-line'])) { + throw new \InvalidArgumentException('Invalid response string: ' . $data['start-line']); + } + $parts = explode(' ', $data['start-line'], 3); + + return new Response( + (int) $parts[1], + $data['headers'], + $data['body'], + explode('/', $parts[0])[1], + isset($parts[2]) ? $parts[2] : null + ); + } +} diff --git a/vendor/guzzlehttp/psr7/src/MessageTrait.php b/vendor/guzzlehttp/psr7/src/MessageTrait.php new file mode 100644 index 0000000..99203bb --- /dev/null +++ b/vendor/guzzlehttp/psr7/src/MessageTrait.php @@ -0,0 +1,214 @@ +<?php + +namespace GuzzleHttp\Psr7; + +use Psr\Http\Message\StreamInterface; + +/** + * Trait implementing functionality common to requests and responses. + */ +trait MessageTrait +{ + /** @var array Map of all registered headers, as original name => array of values */ + private $headers = []; + + /** @var array Map of lowercase header name => original name at registration */ + private $headerNames = []; + + /** @var string */ + private $protocol = '1.1'; + + /** @var StreamInterface|null */ + private $stream; + + public function getProtocolVersion() + { + return $this->protocol; + } + + public function withProtocolVersion($version) + { + if ($this->protocol === $version) { + return $this; + } + + $new = clone $this; + $new->protocol = $version; + return $new; + } + + public function getHeaders() + { + return $this->headers; + } + + public function hasHeader($header) + { + return isset($this->headerNames[strtolower($header)]); + } + + public function getHeader($header) + { + $header = strtolower($header); + + if (!isset($this->headerNames[$header])) { + return []; + } + + $header = $this->headerNames[$header]; + + return $this->headers[$header]; + } + + public function getHeaderLine($header) + { + return implode(', ', $this->getHeader($header)); + } + + public function withHeader($header, $value) + { + $this->assertHeader($header); + $value = $this->normalizeHeaderValue($value); + $normalized = strtolower($header); + + $new = clone $this; + if (isset($new->headerNames[$normalized])) { + unset($new->headers[$new->headerNames[$normalized]]); + } + $new->headerNames[$normalized] = $header; + $new->headers[$header] = $value; + + return $new; + } + + public function withAddedHeader($header, $value) + { + $this->assertHeader($header); + $value = $this->normalizeHeaderValue($value); + $normalized = strtolower($header); + + $new = clone $this; + if (isset($new->headerNames[$normalized])) { + $header = $this->headerNames[$normalized]; + $new->headers[$header] = array_merge($this->headers[$header], $value); + } else { + $new->headerNames[$normalized] = $header; + $new->headers[$header] = $value; + } + + return $new; + } + + public function withoutHeader($header) + { + $normalized = strtolower($header); + + if (!isset($this->headerNames[$normalized])) { + return $this; + } + + $header = $this->headerNames[$normalized]; + + $new = clone $this; + unset($new->headers[$header], $new->headerNames[$normalized]); + + return $new; + } + + public function getBody() + { + if (!$this->stream) { + $this->stream = Utils::streamFor(''); + } + + return $this->stream; + } + + public function withBody(StreamInterface $body) + { + if ($body === $this->stream) { + return $this; + } + + $new = clone $this; + $new->stream = $body; + return $new; + } + + private function setHeaders(array $headers) + { + $this->headerNames = $this->headers = []; + foreach ($headers as $header => $value) { + if (is_int($header)) { + // Numeric array keys are converted to int by PHP but having a header name '123' is not forbidden by the spec + // and also allowed in withHeader(). So we need to cast it to string again for the following assertion to pass. + $header = (string) $header; + } + $this->assertHeader($header); + $value = $this->normalizeHeaderValue($value); + $normalized = strtolower($header); + if (isset($this->headerNames[$normalized])) { + $header = $this->headerNames[$normalized]; + $this->headers[$header] = array_merge($this->headers[$header], $value); + } else { + $this->headerNames[$normalized] = $header; + $this->headers[$header] = $value; + } + } + } + + private function normalizeHeaderValue($value) + { + if (!is_array($value)) { + return $this->trimHeaderValues([$value]); + } + + if (count($value) === 0) { + throw new \InvalidArgumentException('Header value can not be an empty array.'); + } + + return $this->trimHeaderValues($value); + } + + /** + * Trims whitespace from the header values. + * + * Spaces and tabs ought to be excluded by parsers when extracting the field value from a header field. + * + * header-field = field-name ":" OWS field-value OWS + * OWS = *( SP / HTAB ) + * + * @param string[] $values Header values + * + * @return string[] Trimmed header values + * + * @see https://tools.ietf.org/html/rfc7230#section-3.2.4 + */ + private function trimHeaderValues(array $values) + { + return array_map(function ($value) { + if (!is_scalar($value) && null !== $value) { + throw new \InvalidArgumentException(sprintf( + 'Header value must be scalar or null but %s provided.', + is_object($value) ? get_class($value) : gettype($value) + )); + } + + return trim((string) $value, " \t"); + }, array_values($values)); + } + + private function assertHeader($header) + { + if (!is_string($header)) { + throw new \InvalidArgumentException(sprintf( + 'Header name must be a string but %s provided.', + is_object($header) ? get_class($header) : gettype($header) + )); + } + + if ($header === '') { + throw new \InvalidArgumentException('Header name can not be empty.'); + } + } +} diff --git a/vendor/guzzlehttp/psr7/src/MimeType.php b/vendor/guzzlehttp/psr7/src/MimeType.php new file mode 100644 index 0000000..205c7b1 --- /dev/null +++ b/vendor/guzzlehttp/psr7/src/MimeType.php @@ -0,0 +1,140 @@ +<?php + +namespace GuzzleHttp\Psr7; + +final class MimeType +{ + /** + * Determines the mimetype of a file by looking at its extension. + * + * @param string $filename + * + * @return string|null + */ + public static function fromFilename($filename) + { + return self::fromExtension(pathinfo($filename, PATHINFO_EXTENSION)); + } + + /** + * Maps a file extensions to a mimetype. + * + * @param string $extension string The file extension. + * + * @return string|null + * + * @link http://svn.apache.org/repos/asf/httpd/httpd/branches/1.3.x/conf/mime.types + */ + public static function fromExtension($extension) + { + static $mimetypes = [ + '3gp' => 'video/3gpp', + '7z' => 'application/x-7z-compressed', + 'aac' => 'audio/x-aac', + 'ai' => 'application/postscript', + 'aif' => 'audio/x-aiff', + 'asc' => 'text/plain', + 'asf' => 'video/x-ms-asf', + 'atom' => 'application/atom+xml', + 'avi' => 'video/x-msvideo', + 'bmp' => 'image/bmp', + 'bz2' => 'application/x-bzip2', + 'cer' => 'application/pkix-cert', + 'crl' => 'application/pkix-crl', + 'crt' => 'application/x-x509-ca-cert', + 'css' => 'text/css', + 'csv' => 'text/csv', + 'cu' => 'application/cu-seeme', + 'deb' => 'application/x-debian-package', + 'doc' => 'application/msword', + 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'dvi' => 'application/x-dvi', + 'eot' => 'application/vnd.ms-fontobject', + 'eps' => 'application/postscript', + 'epub' => 'application/epub+zip', + 'etx' => 'text/x-setext', + 'flac' => 'audio/flac', + 'flv' => 'video/x-flv', + 'gif' => 'image/gif', + 'gz' => 'application/gzip', + 'htm' => 'text/html', + 'html' => 'text/html', + 'ico' => 'image/x-icon', + 'ics' => 'text/calendar', + 'ini' => 'text/plain', + 'iso' => 'application/x-iso9660-image', + 'jar' => 'application/java-archive', + 'jpe' => 'image/jpeg', + 'jpeg' => 'image/jpeg', + 'jpg' => 'image/jpeg', + 'js' => 'text/javascript', + 'json' => 'application/json', + 'latex' => 'application/x-latex', + 'log' => 'text/plain', + 'm4a' => 'audio/mp4', + 'm4v' => 'video/mp4', + 'mid' => 'audio/midi', + 'midi' => 'audio/midi', + 'mov' => 'video/quicktime', + 'mkv' => 'video/x-matroska', + 'mp3' => 'audio/mpeg', + 'mp4' => 'video/mp4', + 'mp4a' => 'audio/mp4', + 'mp4v' => 'video/mp4', + 'mpe' => 'video/mpeg', + 'mpeg' => 'video/mpeg', + 'mpg' => 'video/mpeg', + 'mpg4' => 'video/mp4', + 'oga' => 'audio/ogg', + 'ogg' => 'audio/ogg', + 'ogv' => 'video/ogg', + 'ogx' => 'application/ogg', + 'pbm' => 'image/x-portable-bitmap', + 'pdf' => 'application/pdf', + 'pgm' => 'image/x-portable-graymap', + 'png' => 'image/png', + 'pnm' => 'image/x-portable-anymap', + 'ppm' => 'image/x-portable-pixmap', + 'ppt' => 'application/vnd.ms-powerpoint', + 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + 'ps' => 'application/postscript', + 'qt' => 'video/quicktime', + 'rar' => 'application/x-rar-compressed', + 'ras' => 'image/x-cmu-raster', + 'rss' => 'application/rss+xml', + 'rtf' => 'application/rtf', + 'sgm' => 'text/sgml', + 'sgml' => 'text/sgml', + 'svg' => 'image/svg+xml', + 'swf' => 'application/x-shockwave-flash', + 'tar' => 'application/x-tar', + 'tif' => 'image/tiff', + 'tiff' => 'image/tiff', + 'torrent' => 'application/x-bittorrent', + 'ttf' => 'application/x-font-ttf', + 'txt' => 'text/plain', + 'wav' => 'audio/x-wav', + 'webm' => 'video/webm', + 'webp' => 'image/webp', + 'wma' => 'audio/x-ms-wma', + 'wmv' => 'video/x-ms-wmv', + 'woff' => 'application/x-font-woff', + 'wsdl' => 'application/wsdl+xml', + 'xbm' => 'image/x-xbitmap', + 'xls' => 'application/vnd.ms-excel', + 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'xml' => 'application/xml', + 'xpm' => 'image/x-xpixmap', + 'xwd' => 'image/x-xwindowdump', + 'yaml' => 'text/yaml', + 'yml' => 'text/yaml', + 'zip' => 'application/zip', + ]; + + $extension = strtolower($extension); + + return isset($mimetypes[$extension]) + ? $mimetypes[$extension] + : null; + } +} diff --git a/vendor/guzzlehttp/psr7/src/MultipartStream.php b/vendor/guzzlehttp/psr7/src/MultipartStream.php new file mode 100644 index 0000000..eeba99c --- /dev/null +++ b/vendor/guzzlehttp/psr7/src/MultipartStream.php @@ -0,0 +1,158 @@ +<?php
+
+namespace GuzzleHttp\Psr7;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Stream that when read returns bytes for a streaming multipart or
+ * multipart/form-data stream.
+ *
+ * @final
+ */
+class MultipartStream implements StreamInterface
+{
+ use StreamDecoratorTrait;
+
+ private $boundary;
+
+ /**
+ * @param array $elements Array of associative arrays, each containing a
+ * required "name" key mapping to the form field,
+ * name, a required "contents" key mapping to a
+ * StreamInterface/resource/string, an optional
+ * "headers" associative array of custom headers,
+ * and an optional "filename" key mapping to a
+ * string to send as the filename in the part.
+ * @param string $boundary You can optionally provide a specific boundary
+ *
+ * @throws \InvalidArgumentException
+ */
+ public function __construct(array $elements = [], $boundary = null)
+ {
+ $this->boundary = $boundary ?: sha1(uniqid('', true));
+ $this->stream = $this->createStream($elements);
+ }
+
+ /**
+ * Get the boundary
+ *
+ * @return string
+ */
+ public function getBoundary()
+ {
+ return $this->boundary;
+ }
+
+ public function isWritable()
+ {
+ return false;
+ }
+
+ /**
+ * Get the headers needed before transferring the content of a POST file
+ */
+ private function getHeaders(array $headers)
+ {
+ $str = '';
+ foreach ($headers as $key => $value) {
+ $str .= "{$key}: {$value}\r\n";
+ }
+
+ return "--{$this->boundary}\r\n" . trim($str) . "\r\n\r\n";
+ }
+
+ /**
+ * Create the aggregate stream that will be used to upload the POST data
+ */
+ protected function createStream(array $elements)
+ {
+ $stream = new AppendStream();
+
+ foreach ($elements as $element) {
+ $this->addElement($stream, $element);
+ }
+
+ // Add the trailing boundary with CRLF
+ $stream->addStream(Utils::streamFor("--{$this->boundary}--\r\n"));
+
+ return $stream;
+ }
+
+ private function addElement(AppendStream $stream, array $element)
+ {
+ foreach (['contents', 'name'] as $key) {
+ if (!array_key_exists($key, $element)) {
+ throw new \InvalidArgumentException("A '{$key}' key is required");
+ }
+ }
+
+ $element['contents'] = Utils::streamFor($element['contents']);
+
+ if (empty($element['filename'])) {
+ $uri = $element['contents']->getMetadata('uri');
+ if (substr($uri, 0, 6) !== 'php://') {
+ $element['filename'] = $uri;
+ }
+ }
+
+ list($body, $headers) = $this->createElement(
+ $element['name'],
+ $element['contents'],
+ isset($element['filename']) ? $element['filename'] : null,
+ isset($element['headers']) ? $element['headers'] : []
+ );
+
+ $stream->addStream(Utils::streamFor($this->getHeaders($headers)));
+ $stream->addStream($body);
+ $stream->addStream(Utils::streamFor("\r\n"));
+ }
+
+ /**
+ * @return array
+ */
+ private function createElement($name, StreamInterface $stream, $filename, array $headers)
+ {
+ // Set a default content-disposition header if one was no provided
+ $disposition = $this->getHeader($headers, 'content-disposition');
+ if (!$disposition) {
+ $headers['Content-Disposition'] = ($filename === '0' || $filename)
+ ? sprintf(
+ 'form-data; name="%s"; filename="%s"',
+ $name,
+ basename($filename)
+ )
+ : "form-data; name=\"{$name}\"";
+ }
+
+ // Set a default content-length header if one was no provided
+ $length = $this->getHeader($headers, 'content-length');
+ if (!$length) {
+ if ($length = $stream->getSize()) {
+ $headers['Content-Length'] = (string) $length;
+ }
+ }
+
+ // Set a default Content-Type if one was not supplied
+ $type = $this->getHeader($headers, 'content-type');
+ if (!$type && ($filename === '0' || $filename)) {
+ if ($type = MimeType::fromFilename($filename)) {
+ $headers['Content-Type'] = $type;
+ }
+ }
+
+ return [$stream, $headers];
+ }
+
+ private function getHeader(array $headers, $key)
+ {
+ $lowercaseHeader = strtolower($key);
+ foreach ($headers as $k => $v) {
+ if (strtolower($k) === $lowercaseHeader) {
+ return $v;
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/NoSeekStream.php b/vendor/guzzlehttp/psr7/src/NoSeekStream.php new file mode 100644 index 0000000..caf7131 --- /dev/null +++ b/vendor/guzzlehttp/psr7/src/NoSeekStream.php @@ -0,0 +1,25 @@ +<?php
+
+namespace GuzzleHttp\Psr7;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Stream decorator that prevents a stream from being seeked.
+ *
+ * @final
+ */
+class NoSeekStream implements StreamInterface
+{
+ use StreamDecoratorTrait;
+
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ throw new \RuntimeException('Cannot seek a NoSeekStream');
+ }
+
+ public function isSeekable()
+ {
+ return false;
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/PumpStream.php b/vendor/guzzlehttp/psr7/src/PumpStream.php new file mode 100644 index 0000000..154782a --- /dev/null +++ b/vendor/guzzlehttp/psr7/src/PumpStream.php @@ -0,0 +1,170 @@ +<?php
+
+namespace GuzzleHttp\Psr7;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Provides a read only stream that pumps data from a PHP callable.
+ *
+ * When invoking the provided callable, the PumpStream will pass the amount of
+ * data requested to read to the callable. The callable can choose to ignore
+ * this value and return fewer or more bytes than requested. Any extra data
+ * returned by the provided callable is buffered internally until drained using
+ * the read() function of the PumpStream. The provided callable MUST return
+ * false when there is no more data to read.
+ *
+ * @final
+ */
+class PumpStream implements StreamInterface
+{
+ /** @var callable */
+ private $source;
+
+ /** @var int */
+ private $size;
+
+ /** @var int */
+ private $tellPos = 0;
+
+ /** @var array */
+ private $metadata;
+
+ /** @var BufferStream */
+ private $buffer;
+
+ /**
+ * @param callable $source Source of the stream data. The callable MAY
+ * accept an integer argument used to control the
+ * amount of data to return. The callable MUST
+ * return a string when called, or false on error
+ * or EOF.
+ * @param array $options Stream options:
+ * - metadata: Hash of metadata to use with stream.
+ * - size: Size of the stream, if known.
+ */
+ public function __construct(callable $source, array $options = [])
+ {
+ $this->source = $source;
+ $this->size = isset($options['size']) ? $options['size'] : null;
+ $this->metadata = isset($options['metadata']) ? $options['metadata'] : [];
+ $this->buffer = new BufferStream();
+ }
+
+ public function __toString()
+ {
+ try {
+ return Utils::copyToString($this);
+ } catch (\Exception $e) {
+ return '';
+ }
+ }
+
+ public function close()
+ {
+ $this->detach();
+ }
+
+ public function detach()
+ {
+ $this->tellPos = false;
+ $this->source = null;
+
+ return null;
+ }
+
+ public function getSize()
+ {
+ return $this->size;
+ }
+
+ public function tell()
+ {
+ return $this->tellPos;
+ }
+
+ public function eof()
+ {
+ return !$this->source;
+ }
+
+ public function isSeekable()
+ {
+ return false;
+ }
+
+ public function rewind()
+ {
+ $this->seek(0);
+ }
+
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ throw new \RuntimeException('Cannot seek a PumpStream');
+ }
+
+ public function isWritable()
+ {
+ return false;
+ }
+
+ public function write($string)
+ {
+ throw new \RuntimeException('Cannot write to a PumpStream');
+ }
+
+ public function isReadable()
+ {
+ return true;
+ }
+
+ public function read($length)
+ {
+ $data = $this->buffer->read($length);
+ $readLen = strlen($data);
+ $this->tellPos += $readLen;
+ $remaining = $length - $readLen;
+
+ if ($remaining) {
+ $this->pump($remaining);
+ $data .= $this->buffer->read($remaining);
+ $this->tellPos += strlen($data) - $readLen;
+ }
+
+ return $data;
+ }
+
+ public function getContents()
+ {
+ $result = '';
+ while (!$this->eof()) {
+ $result .= $this->read(1000000);
+ }
+
+ return $result;
+ }
+
+ public function getMetadata($key = null)
+ {
+ if (!$key) {
+ return $this->metadata;
+ }
+
+ return isset($this->metadata[$key]) ? $this->metadata[$key] : null;
+ }
+
+ private function pump($length)
+ {
+ if ($this->source) {
+ do {
+ $data = call_user_func($this->source, $length);
+ if ($data === false || $data === null) {
+ $this->source = null;
+ return;
+ }
+ $this->buffer->write($data);
+ $length -= strlen($data);
+ } while ($length > 0);
+ }
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/Query.php b/vendor/guzzlehttp/psr7/src/Query.php new file mode 100644 index 0000000..34eb273 --- /dev/null +++ b/vendor/guzzlehttp/psr7/src/Query.php @@ -0,0 +1,113 @@ +<?php
+
+namespace GuzzleHttp\Psr7;
+
+final class Query
+{
+ /**
+ * Parse a query string into an associative array.
+ *
+ * If multiple values are found for the same key, the value of that key
+ * value pair will become an array. This function does not parse nested
+ * PHP style arrays into an associative array (e.g., `foo[a]=1&foo[b]=2`
+ * will be parsed into `['foo[a]' => '1', 'foo[b]' => '2'])`.
+ *
+ * @param string $str Query string to parse
+ * @param int|bool $urlEncoding How the query string is encoded
+ *
+ * @return array
+ */
+ public static function parse($str, $urlEncoding = true)
+ {
+ $result = [];
+
+ if ($str === '') {
+ return $result;
+ }
+
+ if ($urlEncoding === true) {
+ $decoder = function ($value) {
+ return rawurldecode(str_replace('+', ' ', $value));
+ };
+ } elseif ($urlEncoding === PHP_QUERY_RFC3986) {
+ $decoder = 'rawurldecode';
+ } elseif ($urlEncoding === PHP_QUERY_RFC1738) {
+ $decoder = 'urldecode';
+ } else {
+ $decoder = function ($str) {
+ return $str;
+ };
+ }
+
+ foreach (explode('&', $str) as $kvp) {
+ $parts = explode('=', $kvp, 2);
+ $key = $decoder($parts[0]);
+ $value = isset($parts[1]) ? $decoder($parts[1]) : null;
+ if (!isset($result[$key])) {
+ $result[$key] = $value;
+ } else {
+ if (!is_array($result[$key])) {
+ $result[$key] = [$result[$key]];
+ }
+ $result[$key][] = $value;
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * Build a query string from an array of key value pairs.
+ *
+ * This function can use the return value of `parse()` to build a query
+ * string. This function does not modify the provided keys when an array is
+ * encountered (like `http_build_query()` would).
+ *
+ * @param array $params Query string parameters.
+ * @param int|false $encoding Set to false to not encode, PHP_QUERY_RFC3986
+ * to encode using RFC3986, or PHP_QUERY_RFC1738
+ * to encode using RFC1738.
+ *
+ * @return string
+ */
+ public static function build(array $params, $encoding = PHP_QUERY_RFC3986)
+ {
+ if (!$params) {
+ return '';
+ }
+
+ if ($encoding === false) {
+ $encoder = function ($str) {
+ return $str;
+ };
+ } elseif ($encoding === PHP_QUERY_RFC3986) {
+ $encoder = 'rawurlencode';
+ } elseif ($encoding === PHP_QUERY_RFC1738) {
+ $encoder = 'urlencode';
+ } else {
+ throw new \InvalidArgumentException('Invalid type');
+ }
+
+ $qs = '';
+ foreach ($params as $k => $v) {
+ $k = $encoder($k);
+ if (!is_array($v)) {
+ $qs .= $k;
+ if ($v !== null) {
+ $qs .= '=' . $encoder($v);
+ }
+ $qs .= '&';
+ } else {
+ foreach ($v as $vv) {
+ $qs .= $k;
+ if ($vv !== null) {
+ $qs .= '=' . $encoder($vv);
+ }
+ $qs .= '&';
+ }
+ }
+ }
+
+ return $qs ? (string) substr($qs, 0, -1) : '';
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/Request.php b/vendor/guzzlehttp/psr7/src/Request.php new file mode 100644 index 0000000..682585e --- /dev/null +++ b/vendor/guzzlehttp/psr7/src/Request.php @@ -0,0 +1,152 @@ +<?php
+
+namespace GuzzleHttp\Psr7;
+
+use InvalidArgumentException;
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\StreamInterface;
+use Psr\Http\Message\UriInterface;
+
+/**
+ * PSR-7 request implementation.
+ */
+class Request implements RequestInterface
+{
+ use MessageTrait;
+
+ /** @var string */
+ private $method;
+
+ /** @var string|null */
+ private $requestTarget;
+
+ /** @var UriInterface */
+ private $uri;
+
+ /**
+ * @param string $method HTTP method
+ * @param string|UriInterface $uri URI
+ * @param array $headers Request headers
+ * @param string|resource|StreamInterface|null $body Request body
+ * @param string $version Protocol version
+ */
+ public function __construct(
+ $method,
+ $uri,
+ array $headers = [],
+ $body = null,
+ $version = '1.1'
+ ) {
+ $this->assertMethod($method);
+ if (!($uri instanceof UriInterface)) {
+ $uri = new Uri($uri);
+ }
+
+ $this->method = strtoupper($method);
+ $this->uri = $uri;
+ $this->setHeaders($headers);
+ $this->protocol = $version;
+
+ if (!isset($this->headerNames['host'])) {
+ $this->updateHostFromUri();
+ }
+
+ if ($body !== '' && $body !== null) {
+ $this->stream = Utils::streamFor($body);
+ }
+ }
+
+ public function getRequestTarget()
+ {
+ if ($this->requestTarget !== null) {
+ return $this->requestTarget;
+ }
+
+ $target = $this->uri->getPath();
+ if ($target == '') {
+ $target = '/';
+ }
+ if ($this->uri->getQuery() != '') {
+ $target .= '?' . $this->uri->getQuery();
+ }
+
+ return $target;
+ }
+
+ 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;
+ }
+
+ public function getMethod()
+ {
+ return $this->method;
+ }
+
+ public function withMethod($method)
+ {
+ $this->assertMethod($method);
+ $new = clone $this;
+ $new->method = strtoupper($method);
+ return $new;
+ }
+
+ public function getUri()
+ {
+ return $this->uri;
+ }
+
+ public function withUri(UriInterface $uri, $preserveHost = false)
+ {
+ if ($uri === $this->uri) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->uri = $uri;
+
+ if (!$preserveHost || !isset($this->headerNames['host'])) {
+ $new->updateHostFromUri();
+ }
+
+ return $new;
+ }
+
+ private function updateHostFromUri()
+ {
+ $host = $this->uri->getHost();
+
+ if ($host == '') {
+ return;
+ }
+
+ if (($port = $this->uri->getPort()) !== null) {
+ $host .= ':' . $port;
+ }
+
+ if (isset($this->headerNames['host'])) {
+ $header = $this->headerNames['host'];
+ } else {
+ $header = 'Host';
+ $this->headerNames['host'] = 'Host';
+ }
+ // Ensure Host is the first header.
+ // See: http://tools.ietf.org/html/rfc7230#section-5.4
+ $this->headers = [$header => [$host]] + $this->headers;
+ }
+
+ private function assertMethod($method)
+ {
+ if (!is_string($method) || $method === '') {
+ throw new \InvalidArgumentException('Method must be a non-empty string.');
+ }
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/Response.php b/vendor/guzzlehttp/psr7/src/Response.php new file mode 100644 index 0000000..4d36826 --- /dev/null +++ b/vendor/guzzlehttp/psr7/src/Response.php @@ -0,0 +1,155 @@ +<?php
+
+namespace GuzzleHttp\Psr7;
+
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * PSR-7 response implementation.
+ */
+class Response implements ResponseInterface
+{
+ use MessageTrait;
+
+ /** @var array Map of standard HTTP status code/reason phrases */
+ private static $phrases = [
+ 100 => 'Continue',
+ 101 => 'Switching Protocols',
+ 102 => 'Processing',
+ 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',
+ 300 => 'Multiple Choices',
+ 301 => 'Moved Permanently',
+ 302 => 'Found',
+ 303 => 'See Other',
+ 304 => 'Not Modified',
+ 305 => 'Use Proxy',
+ 306 => 'Switch Proxy',
+ 307 => 'Temporary Redirect',
+ 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',
+ 451 => 'Unavailable For Legal Reasons',
+ 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 int $status Status code
+ * @param array $headers Response headers
+ * @param string|resource|StreamInterface|null $body Response body
+ * @param string $version Protocol version
+ * @param string|null $reason Reason phrase (when empty a default will be used based on the status code)
+ */
+ public function __construct(
+ $status = 200,
+ array $headers = [],
+ $body = null,
+ $version = '1.1',
+ $reason = null
+ ) {
+ $this->assertStatusCodeIsInteger($status);
+ $status = (int) $status;
+ $this->assertStatusCodeRange($status);
+
+ $this->statusCode = $status;
+
+ if ($body !== '' && $body !== null) {
+ $this->stream = Utils::streamFor($body);
+ }
+
+ $this->setHeaders($headers);
+ if ($reason == '' && isset(self::$phrases[$this->statusCode])) {
+ $this->reasonPhrase = self::$phrases[$this->statusCode];
+ } else {
+ $this->reasonPhrase = (string) $reason;
+ }
+
+ $this->protocol = $version;
+ }
+
+ public function getStatusCode()
+ {
+ return $this->statusCode;
+ }
+
+ public function getReasonPhrase()
+ {
+ return $this->reasonPhrase;
+ }
+
+ public function withStatus($code, $reasonPhrase = '')
+ {
+ $this->assertStatusCodeIsInteger($code);
+ $code = (int) $code;
+ $this->assertStatusCodeRange($code);
+
+ $new = clone $this;
+ $new->statusCode = $code;
+ if ($reasonPhrase == '' && isset(self::$phrases[$new->statusCode])) {
+ $reasonPhrase = self::$phrases[$new->statusCode];
+ }
+ $new->reasonPhrase = (string) $reasonPhrase;
+ return $new;
+ }
+
+ private function assertStatusCodeIsInteger($statusCode)
+ {
+ if (filter_var($statusCode, FILTER_VALIDATE_INT) === false) {
+ throw new \InvalidArgumentException('Status code must be an integer value.');
+ }
+ }
+
+ private function assertStatusCodeRange($statusCode)
+ {
+ if ($statusCode < 100 || $statusCode >= 600) {
+ throw new \InvalidArgumentException('Status code must be an integer value between 1xx and 5xx.');
+ }
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/Rfc7230.php b/vendor/guzzlehttp/psr7/src/Rfc7230.php new file mode 100644 index 0000000..33417c7 --- /dev/null +++ b/vendor/guzzlehttp/psr7/src/Rfc7230.php @@ -0,0 +1,19 @@ +<?php
+
+namespace GuzzleHttp\Psr7;
+
+final class Rfc7230
+{
+ /**
+ * Header related regular expressions (copied from amphp/http package)
+ * (Note: once we require PHP 7.x we could just depend on the upstream package)
+ *
+ * Note: header delimiter (\r\n) is modified to \r?\n to accept line feed only delimiters for BC reasons.
+ *
+ * @link https://github.com/amphp/http/blob/v1.0.1/src/Rfc7230.php#L12-L15
+ *
+ * @license https://github.com/amphp/http/blob/v1.0.1/LICENSE
+ */
+ const HEADER_REGEX = "(^([^()<>@,;:\\\"/[\]?={}\x01-\x20\x7F]++):[ \t]*+((?:[ \t]*+[\x21-\x7E\x80-\xFF]++)*+)[ \t]*+\r?\n)m";
+ const HEADER_FOLD_REGEX = "(\r?\n[ \t]++)";
+}
diff --git a/vendor/guzzlehttp/psr7/src/ServerRequest.php b/vendor/guzzlehttp/psr7/src/ServerRequest.php new file mode 100644 index 0000000..0873e11 --- /dev/null +++ b/vendor/guzzlehttp/psr7/src/ServerRequest.php @@ -0,0 +1,379 @@ +<?php
+
+namespace GuzzleHttp\Psr7;
+
+use InvalidArgumentException;
+use Psr\Http\Message\ServerRequestInterface;
+use Psr\Http\Message\StreamInterface;
+use Psr\Http\Message\UploadedFileInterface;
+use Psr\Http\Message\UriInterface;
+
+/**
+ * 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 extends Request implements ServerRequestInterface
+{
+ /**
+ * @var array
+ */
+ private $attributes = [];
+
+ /**
+ * @var array
+ */
+ private $cookieParams = [];
+
+ /**
+ * @var array|object|null
+ */
+ private $parsedBody;
+
+ /**
+ * @var array
+ */
+ private $queryParams = [];
+
+ /**
+ * @var array
+ */
+ private $serverParams;
+
+ /**
+ * @var array
+ */
+ private $uploadedFiles = [];
+
+ /**
+ * @param string $method HTTP method
+ * @param string|UriInterface $uri URI
+ * @param array $headers Request headers
+ * @param string|resource|StreamInterface|null $body Request body
+ * @param string $version Protocol version
+ * @param array $serverParams Typically the $_SERVER superglobal
+ */
+ public function __construct(
+ $method,
+ $uri,
+ array $headers = [],
+ $body = null,
+ $version = '1.1',
+ array $serverParams = []
+ ) {
+ $this->serverParams = $serverParams;
+
+ parent::__construct($method, $uri, $headers, $body, $version);
+ }
+
+ /**
+ * Return an UploadedFile instance array.
+ *
+ * @param array $files A array which respect $_FILES structure
+ *
+ * @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;
+ } elseif (is_array($value) && isset($value['tmp_name'])) {
+ $normalized[$key] = self::createUploadedFileFromSpec($value);
+ } elseif (is_array($value)) {
+ $normalized[$key] = self::normalizeFiles($value);
+ continue;
+ } else {
+ throw new InvalidArgumentException('Invalid value in files specification');
+ }
+ }
+
+ return $normalized;
+ }
+
+ /**
+ * 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'],
+ (int) $value['size'],
+ (int) $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;
+ }
+
+ /**
+ * Return a ServerRequest populated with superglobals:
+ * $_GET
+ * $_POST
+ * $_COOKIE
+ * $_FILES
+ * $_SERVER
+ *
+ * @return ServerRequestInterface
+ */
+ public static function fromGlobals()
+ {
+ $method = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : 'GET';
+ $headers = getallheaders();
+ $uri = self::getUriFromGlobals();
+ $body = new CachingStream(new LazyOpenStream('php://input', 'r+'));
+ $protocol = isset($_SERVER['SERVER_PROTOCOL']) ? str_replace('HTTP/', '', $_SERVER['SERVER_PROTOCOL']) : '1.1';
+
+ $serverRequest = new ServerRequest($method, $uri, $headers, $body, $protocol, $_SERVER);
+
+ return $serverRequest
+ ->withCookieParams($_COOKIE)
+ ->withQueryParams($_GET)
+ ->withParsedBody($_POST)
+ ->withUploadedFiles(self::normalizeFiles($_FILES));
+ }
+
+ private static function extractHostAndPortFromAuthority($authority)
+ {
+ $uri = 'http://' . $authority;
+ $parts = parse_url($uri);
+ if (false === $parts) {
+ return [null, null];
+ }
+
+ $host = isset($parts['host']) ? $parts['host'] : null;
+ $port = isset($parts['port']) ? $parts['port'] : null;
+
+ return [$host, $port];
+ }
+
+ /**
+ * Get a Uri populated with values from $_SERVER.
+ *
+ * @return UriInterface
+ */
+ public static function getUriFromGlobals()
+ {
+ $uri = new Uri('');
+
+ $uri = $uri->withScheme(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' ? 'https' : 'http');
+
+ $hasPort = false;
+ if (isset($_SERVER['HTTP_HOST'])) {
+ list($host, $port) = self::extractHostAndPortFromAuthority($_SERVER['HTTP_HOST']);
+ if ($host !== null) {
+ $uri = $uri->withHost($host);
+ }
+
+ if ($port !== null) {
+ $hasPort = true;
+ $uri = $uri->withPort($port);
+ }
+ } elseif (isset($_SERVER['SERVER_NAME'])) {
+ $uri = $uri->withHost($_SERVER['SERVER_NAME']);
+ } elseif (isset($_SERVER['SERVER_ADDR'])) {
+ $uri = $uri->withHost($_SERVER['SERVER_ADDR']);
+ }
+
+ if (!$hasPort && isset($_SERVER['SERVER_PORT'])) {
+ $uri = $uri->withPort($_SERVER['SERVER_PORT']);
+ }
+
+ $hasQuery = false;
+ if (isset($_SERVER['REQUEST_URI'])) {
+ $requestUriParts = explode('?', $_SERVER['REQUEST_URI'], 2);
+ $uri = $uri->withPath($requestUriParts[0]);
+ if (isset($requestUriParts[1])) {
+ $hasQuery = true;
+ $uri = $uri->withQuery($requestUriParts[1]);
+ }
+ }
+
+ if (!$hasQuery && isset($_SERVER['QUERY_STRING'])) {
+ $uri = $uri->withQuery($_SERVER['QUERY_STRING']);
+ }
+
+ return $uri;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getServerParams()
+ {
+ return $this->serverParams;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getUploadedFiles()
+ {
+ return $this->uploadedFiles;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function withUploadedFiles(array $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 (false === 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 (false === array_key_exists($attribute, $this->attributes)) {
+ return $this;
+ }
+
+ $new = clone $this;
+ unset($new->attributes[$attribute]);
+
+ return $new;
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/Stream.php b/vendor/guzzlehttp/psr7/src/Stream.php new file mode 100644 index 0000000..3865d6d --- /dev/null +++ b/vendor/guzzlehttp/psr7/src/Stream.php @@ -0,0 +1,270 @@ +<?php + +namespace GuzzleHttp\Psr7; + +use Psr\Http\Message\StreamInterface; + +/** + * PHP stream implementation. + * + * @var $stream + */ +class Stream implements StreamInterface +{ + /** + * Resource modes. + * + * @var string + * + * @see http://php.net/manual/function.fopen.php + * @see http://php.net/manual/en/function.gzopen.php + */ + const READABLE_MODES = '/r|a\+|ab\+|w\+|wb\+|x\+|xb\+|c\+|cb\+/'; + const WRITABLE_MODES = '/a|w|r\+|rb\+|rw|x|c/'; + + private $stream; + private $size; + private $seekable; + private $readable; + private $writable; + private $uri; + private $customMetadata; + + /** + * This constructor accepts an associative array of options. + * + * - size: (int) If a read stream would otherwise have an indeterminate + * size, but the size is known due to foreknowledge, then you can + * provide that size, in bytes. + * - metadata: (array) Any additional metadata to return when the metadata + * of the stream is accessed. + * + * @param resource $stream Stream resource to wrap. + * @param array $options Associative array of options. + * + * @throws \InvalidArgumentException if the stream is not a stream resource + */ + public function __construct($stream, $options = []) + { + if (!is_resource($stream)) { + throw new \InvalidArgumentException('Stream must be a resource'); + } + + if (isset($options['size'])) { + $this->size = $options['size']; + } + + $this->customMetadata = isset($options['metadata']) + ? $options['metadata'] + : []; + + $this->stream = $stream; + $meta = stream_get_meta_data($this->stream); + $this->seekable = $meta['seekable']; + $this->readable = (bool)preg_match(self::READABLE_MODES, $meta['mode']); + $this->writable = (bool)preg_match(self::WRITABLE_MODES, $meta['mode']); + $this->uri = $this->getMetadata('uri'); + } + + /** + * Closes the stream when the destructed + */ + public function __destruct() + { + $this->close(); + } + + public function __toString() + { + try { + if ($this->isSeekable()) { + $this->seek(0); + } + return $this->getContents(); + } catch (\Exception $e) { + return ''; + } + } + + public function getContents() + { + if (!isset($this->stream)) { + throw new \RuntimeException('Stream is detached'); + } + + $contents = stream_get_contents($this->stream); + + if ($contents === false) { + throw new \RuntimeException('Unable to read stream contents'); + } + + return $contents; + } + + public function close() + { + if (isset($this->stream)) { + if (is_resource($this->stream)) { + fclose($this->stream); + } + $this->detach(); + } + } + + public function detach() + { + if (!isset($this->stream)) { + return null; + } + + $result = $this->stream; + unset($this->stream); + $this->size = $this->uri = null; + $this->readable = $this->writable = $this->seekable = false; + + return $result; + } + + public function getSize() + { + if ($this->size !== null) { + return $this->size; + } + + if (!isset($this->stream)) { + return null; + } + + // Clear the stat cache if the stream has a URI + if ($this->uri) { + clearstatcache(true, $this->uri); + } + + $stats = fstat($this->stream); + if (isset($stats['size'])) { + $this->size = $stats['size']; + return $this->size; + } + + return null; + } + + public function isReadable() + { + return $this->readable; + } + + public function isWritable() + { + return $this->writable; + } + + public function isSeekable() + { + return $this->seekable; + } + + public function eof() + { + if (!isset($this->stream)) { + throw new \RuntimeException('Stream is detached'); + } + + return feof($this->stream); + } + + public function tell() + { + if (!isset($this->stream)) { + throw new \RuntimeException('Stream is detached'); + } + + $result = ftell($this->stream); + + if ($result === false) { + throw new \RuntimeException('Unable to determine stream position'); + } + + return $result; + } + + public function rewind() + { + $this->seek(0); + } + + public function seek($offset, $whence = SEEK_SET) + { + $whence = (int) $whence; + + if (!isset($this->stream)) { + throw new \RuntimeException('Stream is detached'); + } + if (!$this->seekable) { + throw new \RuntimeException('Stream is not seekable'); + } + if (fseek($this->stream, $offset, $whence) === -1) { + throw new \RuntimeException('Unable to seek to stream position ' + . $offset . ' with whence ' . var_export($whence, true)); + } + } + + public function read($length) + { + if (!isset($this->stream)) { + throw new \RuntimeException('Stream is detached'); + } + if (!$this->readable) { + throw new \RuntimeException('Cannot read from non-readable stream'); + } + if ($length < 0) { + throw new \RuntimeException('Length parameter cannot be negative'); + } + + if (0 === $length) { + return ''; + } + + $string = fread($this->stream, $length); + if (false === $string) { + throw new \RuntimeException('Unable to read from stream'); + } + + return $string; + } + + public function write($string) + { + if (!isset($this->stream)) { + throw new \RuntimeException('Stream is detached'); + } + if (!$this->writable) { + throw new \RuntimeException('Cannot write to a non-writable stream'); + } + + // We can't know the size after writing anything + $this->size = null; + $result = fwrite($this->stream, $string); + + if ($result === false) { + throw new \RuntimeException('Unable to write to stream'); + } + + return $result; + } + + public function getMetadata($key = null) + { + if (!isset($this->stream)) { + return $key ? null : []; + } elseif (!$key) { + return $this->customMetadata + stream_get_meta_data($this->stream); + } elseif (isset($this->customMetadata[$key])) { + return $this->customMetadata[$key]; + } + + $meta = stream_get_meta_data($this->stream); + + return isset($meta[$key]) ? $meta[$key] : null; + } +} diff --git a/vendor/guzzlehttp/psr7/src/StreamDecoratorTrait.php b/vendor/guzzlehttp/psr7/src/StreamDecoratorTrait.php new file mode 100644 index 0000000..98925e1 --- /dev/null +++ b/vendor/guzzlehttp/psr7/src/StreamDecoratorTrait.php @@ -0,0 +1,152 @@ +<?php
+
+namespace GuzzleHttp\Psr7;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Stream decorator trait
+ *
+ * @property StreamInterface stream
+ */
+trait StreamDecoratorTrait
+{
+ /**
+ * @param StreamInterface $stream Stream to decorate
+ */
+ public function __construct(StreamInterface $stream)
+ {
+ $this->stream = $stream;
+ }
+
+ /**
+ * Magic method used to create a new stream if streams are not added in
+ * the constructor of a decorator (e.g., LazyOpenStream).
+ *
+ * @param string $name Name of the property (allows "stream" only).
+ *
+ * @return StreamInterface
+ */
+ public function __get($name)
+ {
+ if ($name == 'stream') {
+ $this->stream = $this->createStream();
+ return $this->stream;
+ }
+
+ throw new \UnexpectedValueException("$name not found on class");
+ }
+
+ public function __toString()
+ {
+ try {
+ if ($this->isSeekable()) {
+ $this->seek(0);
+ }
+ return $this->getContents();
+ } catch (\Exception $e) {
+ // Really, PHP? https://bugs.php.net/bug.php?id=53648
+ trigger_error('StreamDecorator::__toString exception: '
+ . (string) $e, E_USER_ERROR);
+ return '';
+ }
+ }
+
+ public function getContents()
+ {
+ return Utils::copyToString($this);
+ }
+
+ /**
+ * Allow decorators to implement custom methods
+ *
+ * @param string $method Missing method name
+ * @param array $args Method arguments
+ *
+ * @return mixed
+ */
+ public function __call($method, array $args)
+ {
+ $result = call_user_func_array([$this->stream, $method], $args);
+
+ // Always return the wrapped object if the result is a return $this
+ return $result === $this->stream ? $this : $result;
+ }
+
+ public function close()
+ {
+ $this->stream->close();
+ }
+
+ public function getMetadata($key = null)
+ {
+ return $this->stream->getMetadata($key);
+ }
+
+ public function detach()
+ {
+ return $this->stream->detach();
+ }
+
+ public function getSize()
+ {
+ return $this->stream->getSize();
+ }
+
+ public function eof()
+ {
+ return $this->stream->eof();
+ }
+
+ public function tell()
+ {
+ return $this->stream->tell();
+ }
+
+ public function isReadable()
+ {
+ return $this->stream->isReadable();
+ }
+
+ public function isWritable()
+ {
+ return $this->stream->isWritable();
+ }
+
+ public function isSeekable()
+ {
+ return $this->stream->isSeekable();
+ }
+
+ public function rewind()
+ {
+ $this->seek(0);
+ }
+
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ $this->stream->seek($offset, $whence);
+ }
+
+ public function read($length)
+ {
+ return $this->stream->read($length);
+ }
+
+ public function write($string)
+ {
+ return $this->stream->write($string);
+ }
+
+ /**
+ * Implement in subclasses to dynamically create streams when requested.
+ *
+ * @return StreamInterface
+ *
+ * @throws \BadMethodCallException
+ */
+ protected function createStream()
+ {
+ throw new \BadMethodCallException('Not implemented');
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/StreamWrapper.php b/vendor/guzzlehttp/psr7/src/StreamWrapper.php new file mode 100644 index 0000000..c36f2a9 --- /dev/null +++ b/vendor/guzzlehttp/psr7/src/StreamWrapper.php @@ -0,0 +1,165 @@ +<?php
+
+namespace GuzzleHttp\Psr7;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Converts Guzzle streams into PHP stream resources.
+ *
+ * @final
+ */
+class StreamWrapper
+{
+ /** @var resource */
+ public $context;
+
+ /** @var StreamInterface */
+ private $stream;
+
+ /** @var string r, r+, or w */
+ private $mode;
+
+ /**
+ * Returns a resource representing the stream.
+ *
+ * @param StreamInterface $stream The stream to get a resource for
+ *
+ * @return resource
+ *
+ * @throws \InvalidArgumentException if stream is not readable or writable
+ */
+ public static function getResource(StreamInterface $stream)
+ {
+ self::register();
+
+ if ($stream->isReadable()) {
+ $mode = $stream->isWritable() ? 'r+' : 'r';
+ } elseif ($stream->isWritable()) {
+ $mode = 'w';
+ } else {
+ throw new \InvalidArgumentException('The stream must be readable, '
+ . 'writable, or both.');
+ }
+
+ return fopen('guzzle://stream', $mode, null, self::createStreamContext($stream));
+ }
+
+ /**
+ * Creates a stream context that can be used to open a stream as a php stream resource.
+ *
+ * @param StreamInterface $stream
+ *
+ * @return resource
+ */
+ public static function createStreamContext(StreamInterface $stream)
+ {
+ return stream_context_create([
+ 'guzzle' => ['stream' => $stream]
+ ]);
+ }
+
+ /**
+ * Registers the stream wrapper if needed
+ */
+ public static function register()
+ {
+ if (!in_array('guzzle', stream_get_wrappers())) {
+ stream_wrapper_register('guzzle', __CLASS__);
+ }
+ }
+
+ public function stream_open($path, $mode, $options, &$opened_path)
+ {
+ $options = stream_context_get_options($this->context);
+
+ if (!isset($options['guzzle']['stream'])) {
+ return false;
+ }
+
+ $this->mode = $mode;
+ $this->stream = $options['guzzle']['stream'];
+
+ return true;
+ }
+
+ public function stream_read($count)
+ {
+ return $this->stream->read($count);
+ }
+
+ public function stream_write($data)
+ {
+ return (int) $this->stream->write($data);
+ }
+
+ public function stream_tell()
+ {
+ return $this->stream->tell();
+ }
+
+ public function stream_eof()
+ {
+ return $this->stream->eof();
+ }
+
+ public function stream_seek($offset, $whence)
+ {
+ $this->stream->seek($offset, $whence);
+
+ return true;
+ }
+
+ public function stream_cast($cast_as)
+ {
+ $stream = clone($this->stream);
+
+ return $stream->detach();
+ }
+
+ public function stream_stat()
+ {
+ static $modeMap = [
+ 'r' => 33060,
+ 'rb' => 33060,
+ 'r+' => 33206,
+ 'w' => 33188,
+ 'wb' => 33188
+ ];
+
+ return [
+ 'dev' => 0,
+ 'ino' => 0,
+ 'mode' => $modeMap[$this->mode],
+ 'nlink' => 0,
+ 'uid' => 0,
+ 'gid' => 0,
+ 'rdev' => 0,
+ 'size' => $this->stream->getSize() ?: 0,
+ 'atime' => 0,
+ 'mtime' => 0,
+ 'ctime' => 0,
+ 'blksize' => 0,
+ 'blocks' => 0
+ ];
+ }
+
+ public function url_stat($path, $flags)
+ {
+ return [
+ 'dev' => 0,
+ 'ino' => 0,
+ 'mode' => 0,
+ 'nlink' => 0,
+ 'uid' => 0,
+ 'gid' => 0,
+ 'rdev' => 0,
+ 'size' => 0,
+ 'atime' => 0,
+ 'mtime' => 0,
+ 'ctime' => 0,
+ 'blksize' => 0,
+ 'blocks' => 0
+ ];
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/UploadedFile.php b/vendor/guzzlehttp/psr7/src/UploadedFile.php new file mode 100644 index 0000000..b6ffead --- /dev/null +++ b/vendor/guzzlehttp/psr7/src/UploadedFile.php @@ -0,0 +1,328 @@ +<?php
+
+namespace GuzzleHttp\Psr7;
+
+use InvalidArgumentException;
+use Psr\Http\Message\StreamInterface;
+use Psr\Http\Message\UploadedFileInterface;
+use RuntimeException;
+
+class UploadedFile implements UploadedFileInterface
+{
+ /**
+ * @var int[]
+ */
+ private static $errors = [
+ UPLOAD_ERR_OK,
+ UPLOAD_ERR_INI_SIZE,
+ UPLOAD_ERR_FORM_SIZE,
+ UPLOAD_ERR_PARTIAL,
+ UPLOAD_ERR_NO_FILE,
+ UPLOAD_ERR_NO_TMP_DIR,
+ UPLOAD_ERR_CANT_WRITE,
+ UPLOAD_ERR_EXTENSION,
+ ];
+
+ /**
+ * @var string
+ */
+ private $clientFilename;
+
+ /**
+ * @var string
+ */
+ private $clientMediaType;
+
+ /**
+ * @var int
+ */
+ private $error;
+
+ /**
+ * @var string|null
+ */
+ private $file;
+
+ /**
+ * @var bool
+ */
+ private $moved = false;
+
+ /**
+ * @var int
+ */
+ private $size;
+
+ /**
+ * @var StreamInterface|null
+ */
+ private $stream;
+
+ /**
+ * @param StreamInterface|string|resource $streamOrFile
+ * @param int $size
+ * @param int $errorStatus
+ * @param string|null $clientFilename
+ * @param string|null $clientMediaType
+ */
+ public function __construct(
+ $streamOrFile,
+ $size,
+ $errorStatus,
+ $clientFilename = null,
+ $clientMediaType = null
+ ) {
+ $this->setError($errorStatus);
+ $this->setSize($size);
+ $this->setClientFilename($clientFilename);
+ $this->setClientMediaType($clientMediaType);
+
+ if ($this->isOk()) {
+ $this->setStreamOrFile($streamOrFile);
+ }
+ }
+
+ /**
+ * Depending on the value set file or stream variable
+ *
+ * @param mixed $streamOrFile
+ *
+ * @throws InvalidArgumentException
+ */
+ private function setStreamOrFile($streamOrFile)
+ {
+ if (is_string($streamOrFile)) {
+ $this->file = $streamOrFile;
+ } elseif (is_resource($streamOrFile)) {
+ $this->stream = new Stream($streamOrFile);
+ } elseif ($streamOrFile instanceof StreamInterface) {
+ $this->stream = $streamOrFile;
+ } else {
+ throw new InvalidArgumentException(
+ 'Invalid stream or file provided for UploadedFile'
+ );
+ }
+ }
+
+ /**
+ * @param int $error
+ *
+ * @throws InvalidArgumentException
+ */
+ private function setError($error)
+ {
+ if (false === is_int($error)) {
+ throw new InvalidArgumentException(
+ 'Upload file error status must be an integer'
+ );
+ }
+
+ if (false === in_array($error, UploadedFile::$errors)) {
+ throw new InvalidArgumentException(
+ 'Invalid error status for UploadedFile'
+ );
+ }
+
+ $this->error = $error;
+ }
+
+ /**
+ * @param int $size
+ *
+ * @throws InvalidArgumentException
+ */
+ private function setSize($size)
+ {
+ if (false === is_int($size)) {
+ throw new InvalidArgumentException(
+ 'Upload file size must be an integer'
+ );
+ }
+
+ $this->size = $size;
+ }
+
+ /**
+ * @param mixed $param
+ *
+ * @return bool
+ */
+ private function isStringOrNull($param)
+ {
+ return in_array(gettype($param), ['string', 'NULL']);
+ }
+
+ /**
+ * @param mixed $param
+ *
+ * @return bool
+ */
+ private function isStringNotEmpty($param)
+ {
+ return is_string($param) && false === empty($param);
+ }
+
+ /**
+ * @param string|null $clientFilename
+ *
+ * @throws InvalidArgumentException
+ */
+ private function setClientFilename($clientFilename)
+ {
+ if (false === $this->isStringOrNull($clientFilename)) {
+ throw new InvalidArgumentException(
+ 'Upload file client filename must be a string or null'
+ );
+ }
+
+ $this->clientFilename = $clientFilename;
+ }
+
+ /**
+ * @param string|null $clientMediaType
+ *
+ * @throws InvalidArgumentException
+ */
+ private function setClientMediaType($clientMediaType)
+ {
+ if (false === $this->isStringOrNull($clientMediaType)) {
+ throw new InvalidArgumentException(
+ 'Upload file client media type must be a string or null'
+ );
+ }
+
+ $this->clientMediaType = $clientMediaType;
+ }
+
+ /**
+ * Return true if there is no upload error
+ *
+ * @return bool
+ */
+ private function isOk()
+ {
+ return $this->error === UPLOAD_ERR_OK;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isMoved()
+ {
+ return $this->moved;
+ }
+
+ /**
+ * @throws RuntimeException if is moved or not ok
+ */
+ private function validateActive()
+ {
+ if (false === $this->isOk()) {
+ throw new RuntimeException('Cannot retrieve stream due to upload error');
+ }
+
+ if ($this->isMoved()) {
+ throw new RuntimeException('Cannot retrieve stream after it has already been moved');
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @throws RuntimeException if the upload was not successful.
+ */
+ public function getStream()
+ {
+ $this->validateActive();
+
+ if ($this->stream instanceof StreamInterface) {
+ return $this->stream;
+ }
+
+ return new LazyOpenStream($this->file, 'r+');
+ }
+
+ /**
+ * {@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)
+ {
+ $this->validateActive();
+
+ if (false === $this->isStringNotEmpty($targetPath)) {
+ throw new InvalidArgumentException(
+ 'Invalid path provided for move operation; must be a non-empty string'
+ );
+ }
+
+ if ($this->file) {
+ $this->moved = php_sapi_name() == 'cli'
+ ? rename($this->file, $targetPath)
+ : move_uploaded_file($this->file, $targetPath);
+ } else {
+ Utils::copyToStream(
+ $this->getStream(),
+ new LazyOpenStream($targetPath, 'w')
+ );
+
+ $this->moved = true;
+ }
+
+ if (false === $this->moved) {
+ throw new RuntimeException(
+ sprintf('Uploaded file could not be moved to %s', $targetPath)
+ );
+ }
+ }
+
+ /**
+ * {@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;
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/Uri.php b/vendor/guzzlehttp/psr7/src/Uri.php new file mode 100644 index 0000000..75ee06b --- /dev/null +++ b/vendor/guzzlehttp/psr7/src/Uri.php @@ -0,0 +1,810 @@ +<?php
+
+namespace GuzzleHttp\Psr7;
+
+use Psr\Http\Message\UriInterface;
+
+/**
+ * PSR-7 URI implementation.
+ *
+ * @author Michael Dowling
+ * @author Tobias Schultze
+ * @author Matthew Weier O'Phinney
+ */
+class Uri implements UriInterface
+{
+ /**
+ * Absolute http and https URIs require a host per RFC 7230 Section 2.7
+ * but in generic URIs the host can be empty. So for http(s) URIs
+ * we apply this default host when no host is given yet to form a
+ * valid URI.
+ */
+ const HTTP_DEFAULT_HOST = 'localhost';
+
+ private static $defaultPorts = [
+ 'http' => 80,
+ 'https' => 443,
+ 'ftp' => 21,
+ 'gopher' => 70,
+ 'nntp' => 119,
+ 'news' => 119,
+ 'telnet' => 23,
+ 'tn3270' => 23,
+ 'imap' => 143,
+ 'pop' => 110,
+ 'ldap' => 389,
+ ];
+
+ private static $charUnreserved = 'a-zA-Z0-9_\-\.~';
+ private static $charSubDelims = '!\$&\'\(\)\*\+,;=';
+ private static $replaceQuery = ['=' => '%3D', '&' => '%26'];
+
+ /** @var string Uri scheme. */
+ private $scheme = '';
+
+ /** @var string Uri user info. */
+ private $userInfo = '';
+
+ /** @var string Uri host. */
+ private $host = '';
+
+ /** @var int|null Uri port. */
+ private $port;
+
+ /** @var string Uri path. */
+ private $path = '';
+
+ /** @var string Uri query string. */
+ private $query = '';
+
+ /** @var string Uri fragment. */
+ private $fragment = '';
+
+ /**
+ * @param string $uri URI to parse
+ */
+ public function __construct($uri = '')
+ {
+ // weak type check to also accept null until we can add scalar type hints
+ if ($uri != '') {
+ $parts = self::parse($uri);
+ if ($parts === false) {
+ throw new \InvalidArgumentException("Unable to parse URI: $uri");
+ }
+ $this->applyParts($parts);
+ }
+ }
+
+ /**
+ * UTF-8 aware \parse_url() replacement.
+ *
+ * The internal function produces broken output for non ASCII domain names
+ * (IDN) when used with locales other than "C".
+ *
+ * On the other hand, cURL understands IDN correctly only when UTF-8 locale
+ * is configured ("C.UTF-8", "en_US.UTF-8", etc.).
+ *
+ * @see https://bugs.php.net/bug.php?id=52923
+ * @see https://www.php.net/manual/en/function.parse-url.php#114817
+ * @see https://curl.haxx.se/libcurl/c/CURLOPT_URL.html#ENCODING
+ *
+ * @param string $url
+ *
+ * @return array|false
+ */
+ private static function parse($url)
+ {
+ // If IPv6
+ $prefix = '';
+ if (preg_match('%^(.*://\[[0-9:a-f]+\])(.*?)$%', $url, $matches)) {
+ $prefix = $matches[1];
+ $url = $matches[2];
+ }
+
+ $encodedUrl = preg_replace_callback(
+ '%[^:/@?&=#]+%usD',
+ static function ($matches) {
+ return urlencode($matches[0]);
+ },
+ $url
+ );
+
+ $result = parse_url($prefix . $encodedUrl);
+
+ if ($result === false) {
+ return false;
+ }
+
+ return array_map('urldecode', $result);
+ }
+
+ public function __toString()
+ {
+ return self::composeComponents(
+ $this->scheme,
+ $this->getAuthority(),
+ $this->path,
+ $this->query,
+ $this->fragment
+ );
+ }
+
+ /**
+ * Composes a URI reference string from its various components.
+ *
+ * Usually this method does not need to be called manually but instead is used indirectly via
+ * `Psr\Http\Message\UriInterface::__toString`.
+ *
+ * PSR-7 UriInterface treats an empty component the same as a missing component as
+ * getQuery(), getFragment() etc. always return a string. This explains the slight
+ * difference to RFC 3986 Section 5.3.
+ *
+ * Another adjustment is that the authority separator is added even when the authority is missing/empty
+ * for the "file" scheme. This is because PHP stream functions like `file_get_contents` only work with
+ * `file:///myfile` but not with `file:/myfile` although they are equivalent according to RFC 3986. But
+ * `file:///` is the more common syntax for the file scheme anyway (Chrome for example redirects to
+ * that format).
+ *
+ * @param string $scheme
+ * @param string $authority
+ * @param string $path
+ * @param string $query
+ * @param string $fragment
+ *
+ * @return string
+ *
+ * @link https://tools.ietf.org/html/rfc3986#section-5.3
+ */
+ public static function composeComponents($scheme, $authority, $path, $query, $fragment)
+ {
+ $uri = '';
+
+ // weak type checks to also accept null until we can add scalar type hints
+ if ($scheme != '') {
+ $uri .= $scheme . ':';
+ }
+
+ if ($authority != ''|| $scheme === 'file') {
+ $uri .= '//' . $authority;
+ }
+
+ $uri .= $path;
+
+ if ($query != '') {
+ $uri .= '?' . $query;
+ }
+
+ if ($fragment != '') {
+ $uri .= '#' . $fragment;
+ }
+
+ return $uri;
+ }
+
+ /**
+ * Whether the URI has the default port of the current scheme.
+ *
+ * `Psr\Http\Message\UriInterface::getPort` may return null or the standard port. This method can be used
+ * independently of the implementation.
+ *
+ * @param UriInterface $uri
+ *
+ * @return bool
+ */
+ public static function isDefaultPort(UriInterface $uri)
+ {
+ return $uri->getPort() === null
+ || (isset(self::$defaultPorts[$uri->getScheme()]) && $uri->getPort() === self::$defaultPorts[$uri->getScheme()]);
+ }
+
+ /**
+ * Whether the URI is absolute, i.e. it has a scheme.
+ *
+ * An instance of UriInterface can either be an absolute URI or a relative reference. This method returns true
+ * if it is the former. An absolute URI has a scheme. A relative reference is used to express a URI relative
+ * to another URI, the base URI. Relative references can be divided into several forms:
+ * - network-path references, e.g. '//example.com/path'
+ * - absolute-path references, e.g. '/path'
+ * - relative-path references, e.g. 'subpath'
+ *
+ * @param UriInterface $uri
+ *
+ * @return bool
+ *
+ * @see Uri::isNetworkPathReference
+ * @see Uri::isAbsolutePathReference
+ * @see Uri::isRelativePathReference
+ * @link https://tools.ietf.org/html/rfc3986#section-4
+ */
+ public static function isAbsolute(UriInterface $uri)
+ {
+ return $uri->getScheme() !== '';
+ }
+
+ /**
+ * Whether the URI is a network-path reference.
+ *
+ * A relative reference that begins with two slash characters is termed an network-path reference.
+ *
+ * @param UriInterface $uri
+ *
+ * @return bool
+ *
+ * @link https://tools.ietf.org/html/rfc3986#section-4.2
+ */
+ public static function isNetworkPathReference(UriInterface $uri)
+ {
+ return $uri->getScheme() === '' && $uri->getAuthority() !== '';
+ }
+
+ /**
+ * Whether the URI is a absolute-path reference.
+ *
+ * A relative reference that begins with a single slash character is termed an absolute-path reference.
+ *
+ * @param UriInterface $uri
+ *
+ * @return bool
+ *
+ * @link https://tools.ietf.org/html/rfc3986#section-4.2
+ */
+ public static function isAbsolutePathReference(UriInterface $uri)
+ {
+ return $uri->getScheme() === ''
+ && $uri->getAuthority() === ''
+ && isset($uri->getPath()[0])
+ && $uri->getPath()[0] === '/';
+ }
+
+ /**
+ * Whether the URI is a relative-path reference.
+ *
+ * A relative reference that does not begin with a slash character is termed a relative-path reference.
+ *
+ * @param UriInterface $uri
+ *
+ * @return bool
+ *
+ * @link https://tools.ietf.org/html/rfc3986#section-4.2
+ */
+ public static function isRelativePathReference(UriInterface $uri)
+ {
+ return $uri->getScheme() === ''
+ && $uri->getAuthority() === ''
+ && (!isset($uri->getPath()[0]) || $uri->getPath()[0] !== '/');
+ }
+
+ /**
+ * Whether the URI is a same-document reference.
+ *
+ * A same-document reference refers to a URI that is, aside from its fragment
+ * component, identical to the base URI. When no base URI is given, only an empty
+ * URI reference (apart from its fragment) is considered a same-document reference.
+ *
+ * @param UriInterface $uri The URI to check
+ * @param UriInterface|null $base An optional base URI to compare against
+ *
+ * @return bool
+ *
+ * @link https://tools.ietf.org/html/rfc3986#section-4.4
+ */
+ public static function isSameDocumentReference(UriInterface $uri, UriInterface $base = null)
+ {
+ if ($base !== null) {
+ $uri = UriResolver::resolve($base, $uri);
+
+ return ($uri->getScheme() === $base->getScheme())
+ && ($uri->getAuthority() === $base->getAuthority())
+ && ($uri->getPath() === $base->getPath())
+ && ($uri->getQuery() === $base->getQuery());
+ }
+
+ return $uri->getScheme() === '' && $uri->getAuthority() === '' && $uri->getPath() === '' && $uri->getQuery() === '';
+ }
+
+ /**
+ * Removes dot segments from a path and returns the new path.
+ *
+ * @param string $path
+ *
+ * @return string
+ *
+ * @deprecated since version 1.4. Use UriResolver::removeDotSegments instead.
+ * @see UriResolver::removeDotSegments
+ */
+ public static function removeDotSegments($path)
+ {
+ return UriResolver::removeDotSegments($path);
+ }
+
+ /**
+ * Converts the relative URI into a new URI that is resolved against the base URI.
+ *
+ * @param UriInterface $base Base URI
+ * @param string|UriInterface $rel Relative URI
+ *
+ * @return UriInterface
+ *
+ * @deprecated since version 1.4. Use UriResolver::resolve instead.
+ * @see UriResolver::resolve
+ */
+ public static function resolve(UriInterface $base, $rel)
+ {
+ if (!($rel instanceof UriInterface)) {
+ $rel = new self($rel);
+ }
+
+ return UriResolver::resolve($base, $rel);
+ }
+
+ /**
+ * Creates a new URI with a specific query string value removed.
+ *
+ * Any existing query string values that exactly match the provided key are
+ * removed.
+ *
+ * @param UriInterface $uri URI to use as a base.
+ * @param string $key Query string key to remove.
+ *
+ * @return UriInterface
+ */
+ public static function withoutQueryValue(UriInterface $uri, $key)
+ {
+ $result = self::getFilteredQueryString($uri, [$key]);
+
+ return $uri->withQuery(implode('&', $result));
+ }
+
+ /**
+ * Creates a new URI with a specific query string value.
+ *
+ * Any existing query string values that exactly match the provided key are
+ * removed and replaced with the given key value pair.
+ *
+ * A value of null will set the query string key without a value, e.g. "key"
+ * instead of "key=value".
+ *
+ * @param UriInterface $uri URI to use as a base.
+ * @param string $key Key to set.
+ * @param string|null $value Value to set
+ *
+ * @return UriInterface
+ */
+ public static function withQueryValue(UriInterface $uri, $key, $value)
+ {
+ $result = self::getFilteredQueryString($uri, [$key]);
+
+ $result[] = self::generateQueryString($key, $value);
+
+ return $uri->withQuery(implode('&', $result));
+ }
+
+ /**
+ * Creates a new URI with multiple specific query string values.
+ *
+ * It has the same behavior as withQueryValue() but for an associative array of key => value.
+ *
+ * @param UriInterface $uri URI to use as a base.
+ * @param array $keyValueArray Associative array of key and values
+ *
+ * @return UriInterface
+ */
+ public static function withQueryValues(UriInterface $uri, array $keyValueArray)
+ {
+ $result = self::getFilteredQueryString($uri, array_keys($keyValueArray));
+
+ foreach ($keyValueArray as $key => $value) {
+ $result[] = self::generateQueryString($key, $value);
+ }
+
+ return $uri->withQuery(implode('&', $result));
+ }
+
+ /**
+ * Creates a URI from a hash of `parse_url` components.
+ *
+ * @param array $parts
+ *
+ * @return UriInterface
+ *
+ * @link http://php.net/manual/en/function.parse-url.php
+ *
+ * @throws \InvalidArgumentException If the components do not form a valid URI.
+ */
+ public static function fromParts(array $parts)
+ {
+ $uri = new self();
+ $uri->applyParts($parts);
+ $uri->validateState();
+
+ return $uri;
+ }
+
+ public function getScheme()
+ {
+ return $this->scheme;
+ }
+
+ public function getAuthority()
+ {
+ $authority = $this->host;
+ if ($this->userInfo !== '') {
+ $authority = $this->userInfo . '@' . $authority;
+ }
+
+ if ($this->port !== null) {
+ $authority .= ':' . $this->port;
+ }
+
+ return $authority;
+ }
+
+ public function getUserInfo()
+ {
+ return $this->userInfo;
+ }
+
+ public function getHost()
+ {
+ return $this->host;
+ }
+
+ public function getPort()
+ {
+ return $this->port;
+ }
+
+ public function getPath()
+ {
+ return $this->path;
+ }
+
+ public function getQuery()
+ {
+ return $this->query;
+ }
+
+ public function getFragment()
+ {
+ return $this->fragment;
+ }
+
+ public function withScheme($scheme)
+ {
+ $scheme = $this->filterScheme($scheme);
+
+ if ($this->scheme === $scheme) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->scheme = $scheme;
+ $new->removeDefaultPort();
+ $new->validateState();
+
+ return $new;
+ }
+
+ public function withUserInfo($user, $password = null)
+ {
+ $info = $this->filterUserInfoComponent($user);
+ if ($password !== null) {
+ $info .= ':' . $this->filterUserInfoComponent($password);
+ }
+
+ if ($this->userInfo === $info) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->userInfo = $info;
+ $new->validateState();
+
+ return $new;
+ }
+
+ public function withHost($host)
+ {
+ $host = $this->filterHost($host);
+
+ if ($this->host === $host) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->host = $host;
+ $new->validateState();
+
+ return $new;
+ }
+
+ public function withPort($port)
+ {
+ $port = $this->filterPort($port);
+
+ if ($this->port === $port) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->port = $port;
+ $new->removeDefaultPort();
+ $new->validateState();
+
+ return $new;
+ }
+
+ public function withPath($path)
+ {
+ $path = $this->filterPath($path);
+
+ if ($this->path === $path) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->path = $path;
+ $new->validateState();
+
+ return $new;
+ }
+
+ public function withQuery($query)
+ {
+ $query = $this->filterQueryAndFragment($query);
+
+ if ($this->query === $query) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->query = $query;
+
+ return $new;
+ }
+
+ public function withFragment($fragment)
+ {
+ $fragment = $this->filterQueryAndFragment($fragment);
+
+ if ($this->fragment === $fragment) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->fragment = $fragment;
+
+ return $new;
+ }
+
+ /**
+ * Apply parse_url parts to a URI.
+ *
+ * @param array $parts Array of parse_url parts to apply.
+ */
+ private function applyParts(array $parts)
+ {
+ $this->scheme = isset($parts['scheme'])
+ ? $this->filterScheme($parts['scheme'])
+ : '';
+ $this->userInfo = isset($parts['user'])
+ ? $this->filterUserInfoComponent($parts['user'])
+ : '';
+ $this->host = isset($parts['host'])
+ ? $this->filterHost($parts['host'])
+ : '';
+ $this->port = isset($parts['port'])
+ ? $this->filterPort($parts['port'])
+ : null;
+ $this->path = isset($parts['path'])
+ ? $this->filterPath($parts['path'])
+ : '';
+ $this->query = isset($parts['query'])
+ ? $this->filterQueryAndFragment($parts['query'])
+ : '';
+ $this->fragment = isset($parts['fragment'])
+ ? $this->filterQueryAndFragment($parts['fragment'])
+ : '';
+ if (isset($parts['pass'])) {
+ $this->userInfo .= ':' . $this->filterUserInfoComponent($parts['pass']);
+ }
+
+ $this->removeDefaultPort();
+ }
+
+ /**
+ * @param string $scheme
+ *
+ * @return string
+ *
+ * @throws \InvalidArgumentException If the scheme is invalid.
+ */
+ private function filterScheme($scheme)
+ {
+ if (!is_string($scheme)) {
+ throw new \InvalidArgumentException('Scheme must be a string');
+ }
+
+ return \strtr($scheme, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz');
+ }
+
+ /**
+ * @param string $component
+ *
+ * @return string
+ *
+ * @throws \InvalidArgumentException If the user info is invalid.
+ */
+ private function filterUserInfoComponent($component)
+ {
+ if (!is_string($component)) {
+ throw new \InvalidArgumentException('User info must be a string');
+ }
+
+ return preg_replace_callback(
+ '/(?:[^%' . self::$charUnreserved . self::$charSubDelims . ']+|%(?![A-Fa-f0-9]{2}))/',
+ [$this, 'rawurlencodeMatchZero'],
+ $component
+ );
+ }
+
+ /**
+ * @param string $host
+ *
+ * @return string
+ *
+ * @throws \InvalidArgumentException If the host is invalid.
+ */
+ private function filterHost($host)
+ {
+ if (!is_string($host)) {
+ throw new \InvalidArgumentException('Host must be a string');
+ }
+
+ return \strtr($host, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz');
+ }
+
+ /**
+ * @param int|null $port
+ *
+ * @return int|null
+ *
+ * @throws \InvalidArgumentException If the port is invalid.
+ */
+ private function filterPort($port)
+ {
+ if ($port === null) {
+ return null;
+ }
+
+ $port = (int) $port;
+ if (0 > $port || 0xffff < $port) {
+ throw new \InvalidArgumentException(
+ sprintf('Invalid port: %d. Must be between 0 and 65535', $port)
+ );
+ }
+
+ return $port;
+ }
+
+ /**
+ * @param UriInterface $uri
+ * @param array $keys
+ *
+ * @return array
+ */
+ private static function getFilteredQueryString(UriInterface $uri, array $keys)
+ {
+ $current = $uri->getQuery();
+
+ if ($current === '') {
+ return [];
+ }
+
+ $decodedKeys = array_map('rawurldecode', $keys);
+
+ return array_filter(explode('&', $current), function ($part) use ($decodedKeys) {
+ return !in_array(rawurldecode(explode('=', $part)[0]), $decodedKeys, true);
+ });
+ }
+
+ /**
+ * @param string $key
+ * @param string|null $value
+ *
+ * @return string
+ */
+ private static function generateQueryString($key, $value)
+ {
+ // Query string separators ("=", "&") within the key or value need to be encoded
+ // (while preventing double-encoding) before setting the query string. All other
+ // chars that need percent-encoding will be encoded by withQuery().
+ $queryString = strtr($key, self::$replaceQuery);
+
+ if ($value !== null) {
+ $queryString .= '=' . strtr($value, self::$replaceQuery);
+ }
+
+ return $queryString;
+ }
+
+ private function removeDefaultPort()
+ {
+ if ($this->port !== null && self::isDefaultPort($this)) {
+ $this->port = null;
+ }
+ }
+
+ /**
+ * Filters the path of a URI
+ *
+ * @param string $path
+ *
+ * @return string
+ *
+ * @throws \InvalidArgumentException If the path is invalid.
+ */
+ private function filterPath($path)
+ {
+ if (!is_string($path)) {
+ throw new \InvalidArgumentException('Path must be a string');
+ }
+
+ return preg_replace_callback(
+ '/(?:[^' . self::$charUnreserved . self::$charSubDelims . '%:@\/]++|%(?![A-Fa-f0-9]{2}))/',
+ [$this, 'rawurlencodeMatchZero'],
+ $path
+ );
+ }
+
+ /**
+ * Filters the query string or fragment of a URI.
+ *
+ * @param string $str
+ *
+ * @return string
+ *
+ * @throws \InvalidArgumentException If the query or fragment is invalid.
+ */
+ private function filterQueryAndFragment($str)
+ {
+ if (!is_string($str)) {
+ throw new \InvalidArgumentException('Query and fragment must be a string');
+ }
+
+ return preg_replace_callback(
+ '/(?:[^' . self::$charUnreserved . self::$charSubDelims . '%:@\/\?]++|%(?![A-Fa-f0-9]{2}))/',
+ [$this, 'rawurlencodeMatchZero'],
+ $str
+ );
+ }
+
+ private function rawurlencodeMatchZero(array $match)
+ {
+ return rawurlencode($match[0]);
+ }
+
+ private function validateState()
+ {
+ if ($this->host === '' && ($this->scheme === 'http' || $this->scheme === 'https')) {
+ $this->host = self::HTTP_DEFAULT_HOST;
+ }
+
+ if ($this->getAuthority() === '') {
+ if (0 === strpos($this->path, '//')) {
+ throw new \InvalidArgumentException('The path of a URI without an authority must not start with two slashes "//"');
+ }
+ if ($this->scheme === '' && false !== strpos(explode('/', $this->path, 2)[0], ':')) {
+ throw new \InvalidArgumentException('A relative URI must not have a path beginning with a segment containing a colon');
+ }
+ } elseif (isset($this->path[0]) && $this->path[0] !== '/') {
+ @trigger_error(
+ 'The path of a URI with an authority must start with a slash "/" or be empty. Automagically fixing the URI ' .
+ 'by adding a leading slash to the path is deprecated since version 1.4 and will throw an exception instead.',
+ E_USER_DEPRECATED
+ );
+ $this->path = '/' . $this->path;
+ //throw new \InvalidArgumentException('The path of a URI with an authority must start with a slash "/" or be empty');
+ }
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/UriNormalizer.php b/vendor/guzzlehttp/psr7/src/UriNormalizer.php new file mode 100644 index 0000000..f5c093c --- /dev/null +++ b/vendor/guzzlehttp/psr7/src/UriNormalizer.php @@ -0,0 +1,219 @@ +<?php
+
+namespace GuzzleHttp\Psr7;
+
+use Psr\Http\Message\UriInterface;
+
+/**
+ * Provides methods to normalize and compare URIs.
+ *
+ * @author Tobias Schultze
+ *
+ * @link https://tools.ietf.org/html/rfc3986#section-6
+ */
+final class UriNormalizer
+{
+ /**
+ * Default normalizations which only include the ones that preserve semantics.
+ *
+ * self::CAPITALIZE_PERCENT_ENCODING | self::DECODE_UNRESERVED_CHARACTERS | self::CONVERT_EMPTY_PATH |
+ * self::REMOVE_DEFAULT_HOST | self::REMOVE_DEFAULT_PORT | self::REMOVE_DOT_SEGMENTS
+ */
+ const PRESERVING_NORMALIZATIONS = 63;
+
+ /**
+ * All letters within a percent-encoding triplet (e.g., "%3A") are case-insensitive, and should be capitalized.
+ *
+ * Example: http://example.org/a%c2%b1b → http://example.org/a%C2%B1b
+ */
+ const CAPITALIZE_PERCENT_ENCODING = 1;
+
+ /**
+ * Decodes percent-encoded octets of unreserved characters.
+ *
+ * For consistency, percent-encoded octets in the ranges of ALPHA (%41–%5A and %61–%7A), DIGIT (%30–%39),
+ * hyphen (%2D), period (%2E), underscore (%5F), or tilde (%7E) should not be created by URI producers and,
+ * when found in a URI, should be decoded to their corresponding unreserved characters by URI normalizers.
+ *
+ * Example: http://example.org/%7Eusern%61me/ → http://example.org/~username/
+ */
+ const DECODE_UNRESERVED_CHARACTERS = 2;
+
+ /**
+ * Converts the empty path to "/" for http and https URIs.
+ *
+ * Example: http://example.org → http://example.org/
+ */
+ const CONVERT_EMPTY_PATH = 4;
+
+ /**
+ * Removes the default host of the given URI scheme from the URI.
+ *
+ * Only the "file" scheme defines the default host "localhost".
+ * All of `file:/myfile`, `file:///myfile`, and `file://localhost/myfile`
+ * are equivalent according to RFC 3986. The first format is not accepted
+ * by PHPs stream functions and thus already normalized implicitly to the
+ * second format in the Uri class. See `GuzzleHttp\Psr7\Uri::composeComponents`.
+ *
+ * Example: file://localhost/myfile → file:///myfile
+ */
+ const REMOVE_DEFAULT_HOST = 8;
+
+ /**
+ * Removes the default port of the given URI scheme from the URI.
+ *
+ * Example: http://example.org:80/ → http://example.org/
+ */
+ const REMOVE_DEFAULT_PORT = 16;
+
+ /**
+ * Removes unnecessary dot-segments.
+ *
+ * Dot-segments in relative-path references are not removed as it would
+ * change the semantics of the URI reference.
+ *
+ * Example: http://example.org/../a/b/../c/./d.html → http://example.org/a/c/d.html
+ */
+ const REMOVE_DOT_SEGMENTS = 32;
+
+ /**
+ * Paths which include two or more adjacent slashes are converted to one.
+ *
+ * Webservers usually ignore duplicate slashes and treat those URIs equivalent.
+ * But in theory those URIs do not need to be equivalent. So this normalization
+ * may change the semantics. Encoded slashes (%2F) are not removed.
+ *
+ * Example: http://example.org//foo///bar.html → http://example.org/foo/bar.html
+ */
+ const REMOVE_DUPLICATE_SLASHES = 64;
+
+ /**
+ * Sort query parameters with their values in alphabetical order.
+ *
+ * However, the order of parameters in a URI may be significant (this is not defined by the standard).
+ * So this normalization is not safe and may change the semantics of the URI.
+ *
+ * Example: ?lang=en&article=fred → ?article=fred&lang=en
+ *
+ * Note: The sorting is neither locale nor Unicode aware (the URI query does not get decoded at all) as the
+ * purpose is to be able to compare URIs in a reproducible way, not to have the params sorted perfectly.
+ */
+ const SORT_QUERY_PARAMETERS = 128;
+
+ /**
+ * Returns a normalized URI.
+ *
+ * The scheme and host component are already normalized to lowercase per PSR-7 UriInterface.
+ * This methods adds additional normalizations that can be configured with the $flags parameter.
+ *
+ * PSR-7 UriInterface cannot distinguish between an empty component and a missing component as
+ * getQuery(), getFragment() etc. always return a string. This means the URIs "/?#" and "/" are
+ * treated equivalent which is not necessarily true according to RFC 3986. But that difference
+ * is highly uncommon in reality. So this potential normalization is implied in PSR-7 as well.
+ *
+ * @param UriInterface $uri The URI to normalize
+ * @param int $flags A bitmask of normalizations to apply, see constants
+ *
+ * @return UriInterface The normalized URI
+ *
+ * @link https://tools.ietf.org/html/rfc3986#section-6.2
+ */
+ public static function normalize(UriInterface $uri, $flags = self::PRESERVING_NORMALIZATIONS)
+ {
+ if ($flags & self::CAPITALIZE_PERCENT_ENCODING) {
+ $uri = self::capitalizePercentEncoding($uri);
+ }
+
+ if ($flags & self::DECODE_UNRESERVED_CHARACTERS) {
+ $uri = self::decodeUnreservedCharacters($uri);
+ }
+
+ if ($flags & self::CONVERT_EMPTY_PATH && $uri->getPath() === '' &&
+ ($uri->getScheme() === 'http' || $uri->getScheme() === 'https')
+ ) {
+ $uri = $uri->withPath('/');
+ }
+
+ if ($flags & self::REMOVE_DEFAULT_HOST && $uri->getScheme() === 'file' && $uri->getHost() === 'localhost') {
+ $uri = $uri->withHost('');
+ }
+
+ if ($flags & self::REMOVE_DEFAULT_PORT && $uri->getPort() !== null && Uri::isDefaultPort($uri)) {
+ $uri = $uri->withPort(null);
+ }
+
+ if ($flags & self::REMOVE_DOT_SEGMENTS && !Uri::isRelativePathReference($uri)) {
+ $uri = $uri->withPath(UriResolver::removeDotSegments($uri->getPath()));
+ }
+
+ if ($flags & self::REMOVE_DUPLICATE_SLASHES) {
+ $uri = $uri->withPath(preg_replace('#//++#', '/', $uri->getPath()));
+ }
+
+ if ($flags & self::SORT_QUERY_PARAMETERS && $uri->getQuery() !== '') {
+ $queryKeyValues = explode('&', $uri->getQuery());
+ sort($queryKeyValues);
+ $uri = $uri->withQuery(implode('&', $queryKeyValues));
+ }
+
+ return $uri;
+ }
+
+ /**
+ * Whether two URIs can be considered equivalent.
+ *
+ * Both URIs are normalized automatically before comparison with the given $normalizations bitmask. The method also
+ * accepts relative URI references and returns true when they are equivalent. This of course assumes they will be
+ * resolved against the same base URI. If this is not the case, determination of equivalence or difference of
+ * relative references does not mean anything.
+ *
+ * @param UriInterface $uri1 An URI to compare
+ * @param UriInterface $uri2 An URI to compare
+ * @param int $normalizations A bitmask of normalizations to apply, see constants
+ *
+ * @return bool
+ *
+ * @link https://tools.ietf.org/html/rfc3986#section-6.1
+ */
+ public static function isEquivalent(UriInterface $uri1, UriInterface $uri2, $normalizations = self::PRESERVING_NORMALIZATIONS)
+ {
+ return (string) self::normalize($uri1, $normalizations) === (string) self::normalize($uri2, $normalizations);
+ }
+
+ private static function capitalizePercentEncoding(UriInterface $uri)
+ {
+ $regex = '/(?:%[A-Fa-f0-9]{2})++/';
+
+ $callback = function (array $match) {
+ return strtoupper($match[0]);
+ };
+
+ return
+ $uri->withPath(
+ preg_replace_callback($regex, $callback, $uri->getPath())
+ )->withQuery(
+ preg_replace_callback($regex, $callback, $uri->getQuery())
+ );
+ }
+
+ private static function decodeUnreservedCharacters(UriInterface $uri)
+ {
+ $regex = '/%(?:2D|2E|5F|7E|3[0-9]|[46][1-9A-F]|[57][0-9A])/i';
+
+ $callback = function (array $match) {
+ return rawurldecode($match[0]);
+ };
+
+ return
+ $uri->withPath(
+ preg_replace_callback($regex, $callback, $uri->getPath())
+ )->withQuery(
+ preg_replace_callback($regex, $callback, $uri->getQuery())
+ );
+ }
+
+ private function __construct()
+ {
+ // cannot be instantiated
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/UriResolver.php b/vendor/guzzlehttp/psr7/src/UriResolver.php new file mode 100644 index 0000000..540db52 --- /dev/null +++ b/vendor/guzzlehttp/psr7/src/UriResolver.php @@ -0,0 +1,222 @@ +<?php
+
+namespace GuzzleHttp\Psr7;
+
+use Psr\Http\Message\UriInterface;
+
+/**
+ * Resolves a URI reference in the context of a base URI and the opposite way.
+ *
+ * @author Tobias Schultze
+ *
+ * @link https://tools.ietf.org/html/rfc3986#section-5
+ */
+final class UriResolver
+{
+ /**
+ * Removes dot segments from a path and returns the new path.
+ *
+ * @param string $path
+ *
+ * @return string
+ *
+ * @link http://tools.ietf.org/html/rfc3986#section-5.2.4
+ */
+ public static function removeDotSegments($path)
+ {
+ if ($path === '' || $path === '/') {
+ return $path;
+ }
+
+ $results = [];
+ $segments = explode('/', $path);
+ foreach ($segments as $segment) {
+ if ($segment === '..') {
+ array_pop($results);
+ } elseif ($segment !== '.') {
+ $results[] = $segment;
+ }
+ }
+
+ $newPath = implode('/', $results);
+
+ if ($path[0] === '/' && (!isset($newPath[0]) || $newPath[0] !== '/')) {
+ // Re-add the leading slash if necessary for cases like "/.."
+ $newPath = '/' . $newPath;
+ } elseif ($newPath !== '' && ($segment === '.' || $segment === '..')) {
+ // Add the trailing slash if necessary
+ // If newPath is not empty, then $segment must be set and is the last segment from the foreach
+ $newPath .= '/';
+ }
+
+ return $newPath;
+ }
+
+ /**
+ * Converts the relative URI into a new URI that is resolved against the base URI.
+ *
+ * @param UriInterface $base Base URI
+ * @param UriInterface $rel Relative URI
+ *
+ * @return UriInterface
+ *
+ * @link http://tools.ietf.org/html/rfc3986#section-5.2
+ */
+ public static function resolve(UriInterface $base, UriInterface $rel)
+ {
+ if ((string) $rel === '') {
+ // we can simply return the same base URI instance for this same-document reference
+ return $base;
+ }
+
+ if ($rel->getScheme() != '') {
+ return $rel->withPath(self::removeDotSegments($rel->getPath()));
+ }
+
+ if ($rel->getAuthority() != '') {
+ $targetAuthority = $rel->getAuthority();
+ $targetPath = self::removeDotSegments($rel->getPath());
+ $targetQuery = $rel->getQuery();
+ } else {
+ $targetAuthority = $base->getAuthority();
+ if ($rel->getPath() === '') {
+ $targetPath = $base->getPath();
+ $targetQuery = $rel->getQuery() != '' ? $rel->getQuery() : $base->getQuery();
+ } else {
+ if ($rel->getPath()[0] === '/') {
+ $targetPath = $rel->getPath();
+ } else {
+ if ($targetAuthority != '' && $base->getPath() === '') {
+ $targetPath = '/' . $rel->getPath();
+ } else {
+ $lastSlashPos = strrpos($base->getPath(), '/');
+ if ($lastSlashPos === false) {
+ $targetPath = $rel->getPath();
+ } else {
+ $targetPath = substr($base->getPath(), 0, $lastSlashPos + 1) . $rel->getPath();
+ }
+ }
+ }
+ $targetPath = self::removeDotSegments($targetPath);
+ $targetQuery = $rel->getQuery();
+ }
+ }
+
+ return new Uri(Uri::composeComponents(
+ $base->getScheme(),
+ $targetAuthority,
+ $targetPath,
+ $targetQuery,
+ $rel->getFragment()
+ ));
+ }
+
+ /**
+ * Returns the target URI as a relative reference from the base URI.
+ *
+ * This method is the counterpart to resolve():
+ *
+ * (string) $target === (string) UriResolver::resolve($base, UriResolver::relativize($base, $target))
+ *
+ * One use-case is to use the current request URI as base URI and then generate relative links in your documents
+ * to reduce the document size or offer self-contained downloadable document archives.
+ *
+ * $base = new Uri('http://example.com/a/b/');
+ * echo UriResolver::relativize($base, new Uri('http://example.com/a/b/c')); // prints 'c'.
+ * echo UriResolver::relativize($base, new Uri('http://example.com/a/x/y')); // prints '../x/y'.
+ * echo UriResolver::relativize($base, new Uri('http://example.com/a/b/?q')); // prints '?q'.
+ * echo UriResolver::relativize($base, new Uri('http://example.org/a/b/')); // prints '//example.org/a/b/'.
+ *
+ * This method also accepts a target that is already relative and will try to relativize it further. Only a
+ * relative-path reference will be returned as-is.
+ *
+ * echo UriResolver::relativize($base, new Uri('/a/b/c')); // prints 'c' as well
+ *
+ * @param UriInterface $base Base URI
+ * @param UriInterface $target Target URI
+ *
+ * @return UriInterface The relative URI reference
+ */
+ public static function relativize(UriInterface $base, UriInterface $target)
+ {
+ if ($target->getScheme() !== '' &&
+ ($base->getScheme() !== $target->getScheme() || $target->getAuthority() === '' && $base->getAuthority() !== '')
+ ) {
+ return $target;
+ }
+
+ if (Uri::isRelativePathReference($target)) {
+ // As the target is already highly relative we return it as-is. It would be possible to resolve
+ // the target with `$target = self::resolve($base, $target);` and then try make it more relative
+ // by removing a duplicate query. But let's not do that automatically.
+ return $target;
+ }
+
+ if ($target->getAuthority() !== '' && $base->getAuthority() !== $target->getAuthority()) {
+ return $target->withScheme('');
+ }
+
+ // We must remove the path before removing the authority because if the path starts with two slashes, the URI
+ // would turn invalid. And we also cannot set a relative path before removing the authority, as that is also
+ // invalid.
+ $emptyPathUri = $target->withScheme('')->withPath('')->withUserInfo('')->withPort(null)->withHost('');
+
+ if ($base->getPath() !== $target->getPath()) {
+ return $emptyPathUri->withPath(self::getRelativePath($base, $target));
+ }
+
+ if ($base->getQuery() === $target->getQuery()) {
+ // Only the target fragment is left. And it must be returned even if base and target fragment are the same.
+ return $emptyPathUri->withQuery('');
+ }
+
+ // If the base URI has a query but the target has none, we cannot return an empty path reference as it would
+ // inherit the base query component when resolving.
+ if ($target->getQuery() === '') {
+ $segments = explode('/', $target->getPath());
+ $lastSegment = end($segments);
+
+ return $emptyPathUri->withPath($lastSegment === '' ? './' : $lastSegment);
+ }
+
+ return $emptyPathUri;
+ }
+
+ private static function getRelativePath(UriInterface $base, UriInterface $target)
+ {
+ $sourceSegments = explode('/', $base->getPath());
+ $targetSegments = explode('/', $target->getPath());
+ array_pop($sourceSegments);
+ $targetLastSegment = array_pop($targetSegments);
+ foreach ($sourceSegments as $i => $segment) {
+ if (isset($targetSegments[$i]) && $segment === $targetSegments[$i]) {
+ unset($sourceSegments[$i], $targetSegments[$i]);
+ } else {
+ break;
+ }
+ }
+ $targetSegments[] = $targetLastSegment;
+ $relativePath = str_repeat('../', count($sourceSegments)) . implode('/', $targetSegments);
+
+ // A reference to am empty last segment or an empty first sub-segment must be prefixed with "./".
+ // This also applies to a segment with a colon character (e.g., "file:colon") that cannot be used
+ // as the first segment of a relative-path reference, as it would be mistaken for a scheme name.
+ if ('' === $relativePath || false !== strpos(explode('/', $relativePath, 2)[0], ':')) {
+ $relativePath = "./$relativePath";
+ } elseif ('/' === $relativePath[0]) {
+ if ($base->getAuthority() != '' && $base->getPath() === '') {
+ // In this case an extra slash is added by resolve() automatically. So we must not add one here.
+ $relativePath = ".$relativePath";
+ } else {
+ $relativePath = "./$relativePath";
+ }
+ }
+
+ return $relativePath;
+ }
+
+ private function __construct()
+ {
+ // cannot be instantiated
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/Utils.php b/vendor/guzzlehttp/psr7/src/Utils.php new file mode 100644 index 0000000..60ce6b9 --- /dev/null +++ b/vendor/guzzlehttp/psr7/src/Utils.php @@ -0,0 +1,428 @@ +<?php
+
+namespace GuzzleHttp\Psr7;
+
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use Psr\Http\Message\StreamInterface;
+use Psr\Http\Message\UriInterface;
+
+final class Utils
+{
+ /**
+ * Remove the items given by the keys, case insensitively from the data.
+ *
+ * @param iterable<string> $keys
+ *
+ * @return array
+ */
+ public static function caselessRemove($keys, array $data)
+ {
+ $result = [];
+
+ foreach ($keys as &$key) {
+ $key = strtolower($key);
+ }
+
+ foreach ($data as $k => $v) {
+ if (!in_array(strtolower($k), $keys)) {
+ $result[$k] = $v;
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * Copy the contents of a stream into another stream until the given number
+ * of bytes have been read.
+ *
+ * @param StreamInterface $source Stream to read from
+ * @param StreamInterface $dest Stream to write to
+ * @param int $maxLen Maximum number of bytes to read. Pass -1
+ * to read the entire stream.
+ *
+ * @throws \RuntimeException on error.
+ */
+ public static function copyToStream(StreamInterface $source, StreamInterface $dest, $maxLen = -1)
+ {
+ $bufferSize = 8192;
+
+ if ($maxLen === -1) {
+ while (!$source->eof()) {
+ if (!$dest->write($source->read($bufferSize))) {
+ break;
+ }
+ }
+ } else {
+ $remaining = $maxLen;
+ while ($remaining > 0 && !$source->eof()) {
+ $buf = $source->read(min($bufferSize, $remaining));
+ $len = strlen($buf);
+ if (!$len) {
+ break;
+ }
+ $remaining -= $len;
+ $dest->write($buf);
+ }
+ }
+ }
+
+ /**
+ * Copy the contents of a stream into a string until the given number of
+ * bytes have been read.
+ *
+ * @param StreamInterface $stream Stream to read
+ * @param int $maxLen Maximum number of bytes to read. Pass -1
+ * to read the entire stream.
+ *
+ * @return string
+ *
+ * @throws \RuntimeException on error.
+ */
+ public static function copyToString(StreamInterface $stream, $maxLen = -1)
+ {
+ $buffer = '';
+
+ if ($maxLen === -1) {
+ while (!$stream->eof()) {
+ $buf = $stream->read(1048576);
+ // Using a loose equality here to match on '' and false.
+ if ($buf == null) {
+ break;
+ }
+ $buffer .= $buf;
+ }
+ return $buffer;
+ }
+
+ $len = 0;
+ while (!$stream->eof() && $len < $maxLen) {
+ $buf = $stream->read($maxLen - $len);
+ // Using a loose equality here to match on '' and false.
+ if ($buf == null) {
+ break;
+ }
+ $buffer .= $buf;
+ $len = strlen($buffer);
+ }
+
+ return $buffer;
+ }
+
+ /**
+ * Calculate a hash of a stream.
+ *
+ * This method reads the entire stream to calculate a rolling hash, based
+ * on PHP's `hash_init` functions.
+ *
+ * @param StreamInterface $stream Stream to calculate the hash for
+ * @param string $algo Hash algorithm (e.g. md5, crc32, etc)
+ * @param bool $rawOutput Whether or not to use raw output
+ *
+ * @return string Returns the hash of the stream
+ *
+ * @throws \RuntimeException on error.
+ */
+ public static function hash(StreamInterface $stream, $algo, $rawOutput = false)
+ {
+ $pos = $stream->tell();
+
+ if ($pos > 0) {
+ $stream->rewind();
+ }
+
+ $ctx = hash_init($algo);
+ while (!$stream->eof()) {
+ hash_update($ctx, $stream->read(1048576));
+ }
+
+ $out = hash_final($ctx, (bool) $rawOutput);
+ $stream->seek($pos);
+
+ return $out;
+ }
+
+ /**
+ * Clone and modify a request with the given changes.
+ *
+ * This method is useful for reducing the number of clones needed to mutate
+ * a message.
+ *
+ * The changes can be one of:
+ * - method: (string) Changes the HTTP method.
+ * - set_headers: (array) Sets the given headers.
+ * - remove_headers: (array) Remove the given headers.
+ * - body: (mixed) Sets the given body.
+ * - uri: (UriInterface) Set the URI.
+ * - query: (string) Set the query string value of the URI.
+ * - version: (string) Set the protocol version.
+ *
+ * @param RequestInterface $request Request to clone and modify.
+ * @param array $changes Changes to apply.
+ *
+ * @return RequestInterface
+ */
+ public static function modifyRequest(RequestInterface $request, array $changes)
+ {
+ if (!$changes) {
+ return $request;
+ }
+
+ $headers = $request->getHeaders();
+
+ if (!isset($changes['uri'])) {
+ $uri = $request->getUri();
+ } else {
+ // Remove the host header if one is on the URI
+ if ($host = $changes['uri']->getHost()) {
+ $changes['set_headers']['Host'] = $host;
+
+ if ($port = $changes['uri']->getPort()) {
+ $standardPorts = ['http' => 80, 'https' => 443];
+ $scheme = $changes['uri']->getScheme();
+ if (isset($standardPorts[$scheme]) && $port != $standardPorts[$scheme]) {
+ $changes['set_headers']['Host'] .= ':' . $port;
+ }
+ }
+ }
+ $uri = $changes['uri'];
+ }
+
+ if (!empty($changes['remove_headers'])) {
+ $headers = self::caselessRemove($changes['remove_headers'], $headers);
+ }
+
+ if (!empty($changes['set_headers'])) {
+ $headers = self::caselessRemove(array_keys($changes['set_headers']), $headers);
+ $headers = $changes['set_headers'] + $headers;
+ }
+
+ if (isset($changes['query'])) {
+ $uri = $uri->withQuery($changes['query']);
+ }
+
+ if ($request instanceof ServerRequestInterface) {
+ $new = (new ServerRequest(
+ isset($changes['method']) ? $changes['method'] : $request->getMethod(),
+ $uri,
+ $headers,
+ isset($changes['body']) ? $changes['body'] : $request->getBody(),
+ isset($changes['version'])
+ ? $changes['version']
+ : $request->getProtocolVersion(),
+ $request->getServerParams()
+ ))
+ ->withParsedBody($request->getParsedBody())
+ ->withQueryParams($request->getQueryParams())
+ ->withCookieParams($request->getCookieParams())
+ ->withUploadedFiles($request->getUploadedFiles());
+
+ foreach ($request->getAttributes() as $key => $value) {
+ $new = $new->withAttribute($key, $value);
+ }
+
+ return $new;
+ }
+
+ return new Request(
+ isset($changes['method']) ? $changes['method'] : $request->getMethod(),
+ $uri,
+ $headers,
+ isset($changes['body']) ? $changes['body'] : $request->getBody(),
+ isset($changes['version'])
+ ? $changes['version']
+ : $request->getProtocolVersion()
+ );
+ }
+
+ /**
+ * Read a line from the stream up to the maximum allowed buffer length.
+ *
+ * @param StreamInterface $stream Stream to read from
+ * @param int|null $maxLength Maximum buffer length
+ *
+ * @return string
+ */
+ public static function readLine(StreamInterface $stream, $maxLength = null)
+ {
+ $buffer = '';
+ $size = 0;
+
+ while (!$stream->eof()) {
+ // Using a loose equality here to match on '' and false.
+ if (null == ($byte = $stream->read(1))) {
+ return $buffer;
+ }
+ $buffer .= $byte;
+ // Break when a new line is found or the max length - 1 is reached
+ if ($byte === "\n" || ++$size === $maxLength - 1) {
+ break;
+ }
+ }
+
+ return $buffer;
+ }
+
+ /**
+ * Create a new stream based on the input type.
+ *
+ * Options is an associative array that can contain the following keys:
+ * - metadata: Array of custom metadata.
+ * - size: Size of the stream.
+ *
+ * This method accepts the following `$resource` types:
+ * - `Psr\Http\Message\StreamInterface`: Returns the value as-is.
+ * - `string`: Creates a stream object that uses the given string as the contents.
+ * - `resource`: Creates a stream object that wraps the given PHP stream resource.
+ * - `Iterator`: If the provided value implements `Iterator`, then a read-only
+ * stream object will be created that wraps the given iterable. Each time the
+ * stream is read from, data from the iterator will fill a buffer and will be
+ * continuously called until the buffer is equal to the requested read size.
+ * Subsequent read calls will first read from the buffer and then call `next`
+ * on the underlying iterator until it is exhausted.
+ * - `object` with `__toString()`: If the object has the `__toString()` method,
+ * the object will be cast to a string and then a stream will be returned that
+ * uses the string value.
+ * - `NULL`: When `null` is passed, an empty stream object is returned.
+ * - `callable` When a callable is passed, a read-only stream object will be
+ * created that invokes the given callable. The callable is invoked with the
+ * number of suggested bytes to read. The callable can return any number of
+ * bytes, but MUST return `false` when there is no more data to return. The
+ * stream object that wraps the callable will invoke the callable until the
+ * number of requested bytes are available. Any additional bytes will be
+ * buffered and used in subsequent reads.
+ *
+ * @param resource|string|int|float|bool|StreamInterface|callable|\Iterator|null $resource Entity body data
+ * @param array $options Additional options
+ *
+ * @return StreamInterface
+ *
+ * @throws \InvalidArgumentException if the $resource arg is not valid.
+ */
+ public static function streamFor($resource = '', array $options = [])
+ {
+ if (is_scalar($resource)) {
+ $stream = self::tryFopen('php://temp', 'r+');
+ if ($resource !== '') {
+ fwrite($stream, $resource);
+ fseek($stream, 0);
+ }
+ return new Stream($stream, $options);
+ }
+
+ switch (gettype($resource)) {
+ case 'resource':
+ /*
+ * The 'php://input' is a special stream with quirks and inconsistencies.
+ * We avoid using that stream by reading it into php://temp
+ */
+ $metaData = \stream_get_meta_data($resource);
+ if (isset($metaData['uri']) && $metaData['uri'] === 'php://input') {
+ $stream = self::tryFopen('php://temp', 'w+');
+ fwrite($stream, stream_get_contents($resource));
+ fseek($stream, 0);
+ $resource = $stream;
+ }
+ return new Stream($resource, $options);
+ case 'object':
+ if ($resource instanceof StreamInterface) {
+ return $resource;
+ } elseif ($resource instanceof \Iterator) {
+ return new PumpStream(function () use ($resource) {
+ if (!$resource->valid()) {
+ return false;
+ }
+ $result = $resource->current();
+ $resource->next();
+ return $result;
+ }, $options);
+ } elseif (method_exists($resource, '__toString')) {
+ return Utils::streamFor((string) $resource, $options);
+ }
+ break;
+ case 'NULL':
+ return new Stream(self::tryFopen('php://temp', 'r+'), $options);
+ }
+
+ if (is_callable($resource)) {
+ return new PumpStream($resource, $options);
+ }
+
+ throw new \InvalidArgumentException('Invalid resource type: ' . gettype($resource));
+ }
+
+ /**
+ * Safely opens a PHP stream resource using a filename.
+ *
+ * When fopen fails, PHP normally raises a warning. This function adds an
+ * error handler that checks for errors and throws an exception instead.
+ *
+ * @param string $filename File to open
+ * @param string $mode Mode used to open the file
+ *
+ * @return resource
+ *
+ * @throws \RuntimeException if the file cannot be opened
+ */
+ public static function tryFopen($filename, $mode)
+ {
+ $ex = null;
+ set_error_handler(function () use ($filename, $mode, &$ex) {
+ $ex = new \RuntimeException(sprintf(
+ 'Unable to open "%s" using mode "%s": %s',
+ $filename,
+ $mode,
+ func_get_args()[1]
+ ));
+
+ return true;
+ });
+
+ try {
+ $handle = fopen($filename, $mode);
+ } catch (\Throwable $e) {
+ $ex = new \RuntimeException(sprintf(
+ 'Unable to open "%s" using mode "%s": %s',
+ $filename,
+ $mode,
+ $e->getMessage()
+ ), 0, $e);
+ }
+
+ restore_error_handler();
+
+ if ($ex) {
+ /** @var $ex \RuntimeException */
+ throw $ex;
+ }
+
+ return $handle;
+ }
+
+ /**
+ * Returns a UriInterface for the given value.
+ *
+ * This function accepts a string or UriInterface and returns a
+ * UriInterface for the given value. If the value is already a
+ * UriInterface, it is returned as-is.
+ *
+ * @param string|UriInterface $uri
+ *
+ * @return UriInterface
+ *
+ * @throws \InvalidArgumentException
+ */
+ public static function uriFor($uri)
+ {
+ if ($uri instanceof UriInterface) {
+ return $uri;
+ }
+
+ if (is_string($uri)) {
+ return new Uri($uri);
+ }
+
+ throw new \InvalidArgumentException('URI must be a string or UriInterface');
+ }
+}
diff --git a/vendor/guzzlehttp/psr7/src/functions.php b/vendor/guzzlehttp/psr7/src/functions.php new file mode 100644 index 0000000..266e659 --- /dev/null +++ b/vendor/guzzlehttp/psr7/src/functions.php @@ -0,0 +1,422 @@ +<?php
+
+namespace GuzzleHttp\Psr7;
+
+use Psr\Http\Message\MessageInterface;
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\StreamInterface;
+use Psr\Http\Message\UriInterface;
+
+/**
+ * Returns the string representation of an HTTP message.
+ *
+ * @param MessageInterface $message Message to convert to a string.
+ *
+ * @return string
+ *
+ * @deprecated str will be removed in guzzlehttp/psr7:2.0. Use Message::toString instead.
+ */
+function str(MessageInterface $message)
+{
+ return Message::toString($message);
+}
+
+/**
+ * Returns a UriInterface for the given value.
+ *
+ * This function accepts a string or UriInterface and returns a
+ * UriInterface for the given value. If the value is already a
+ * UriInterface, it is returned as-is.
+ *
+ * @param string|UriInterface $uri
+ *
+ * @return UriInterface
+ *
+ * @throws \InvalidArgumentException
+ *
+ * @deprecated uri_for will be removed in guzzlehttp/psr7:2.0. Use Utils::uriFor instead.
+ */
+function uri_for($uri)
+{
+ return Utils::uriFor($uri);
+}
+
+/**
+ * Create a new stream based on the input type.
+ *
+ * Options is an associative array that can contain the following keys:
+ * - metadata: Array of custom metadata.
+ * - size: Size of the stream.
+ *
+ * This method accepts the following `$resource` types:
+ * - `Psr\Http\Message\StreamInterface`: Returns the value as-is.
+ * - `string`: Creates a stream object that uses the given string as the contents.
+ * - `resource`: Creates a stream object that wraps the given PHP stream resource.
+ * - `Iterator`: If the provided value implements `Iterator`, then a read-only
+ * stream object will be created that wraps the given iterable. Each time the
+ * stream is read from, data from the iterator will fill a buffer and will be
+ * continuously called until the buffer is equal to the requested read size.
+ * Subsequent read calls will first read from the buffer and then call `next`
+ * on the underlying iterator until it is exhausted.
+ * - `object` with `__toString()`: If the object has the `__toString()` method,
+ * the object will be cast to a string and then a stream will be returned that
+ * uses the string value.
+ * - `NULL`: When `null` is passed, an empty stream object is returned.
+ * - `callable` When a callable is passed, a read-only stream object will be
+ * created that invokes the given callable. The callable is invoked with the
+ * number of suggested bytes to read. The callable can return any number of
+ * bytes, but MUST return `false` when there is no more data to return. The
+ * stream object that wraps the callable will invoke the callable until the
+ * number of requested bytes are available. Any additional bytes will be
+ * buffered and used in subsequent reads.
+ *
+ * @param resource|string|int|float|bool|StreamInterface|callable|\Iterator|null $resource Entity body data
+ * @param array $options Additional options
+ *
+ * @return StreamInterface
+ *
+ * @throws \InvalidArgumentException if the $resource arg is not valid.
+ *
+ * @deprecated stream_for will be removed in guzzlehttp/psr7:2.0. Use Utils::streamFor instead.
+ */
+function stream_for($resource = '', array $options = [])
+{
+ return Utils::streamFor($resource, $options);
+}
+
+/**
+ * Parse an array of header values containing ";" separated data into an
+ * array of associative arrays representing the header key value pair data
+ * of the header. When a parameter does not contain a value, but just
+ * contains a key, this function will inject a key with a '' string value.
+ *
+ * @param string|array $header Header to parse into components.
+ *
+ * @return array Returns the parsed header values.
+ *
+ * @deprecated parse_header will be removed in guzzlehttp/psr7:2.0. Use Header::parse instead.
+ */
+function parse_header($header)
+{
+ return Header::parse($header);
+}
+
+/**
+ * Converts an array of header values that may contain comma separated
+ * headers into an array of headers with no comma separated values.
+ *
+ * @param string|array $header Header to normalize.
+ *
+ * @return array Returns the normalized header field values.
+ *
+ * @deprecated normalize_header will be removed in guzzlehttp/psr7:2.0. Use Header::normalize instead.
+ */
+function normalize_header($header)
+{
+ return Header::normalize($header);
+}
+
+/**
+ * Clone and modify a request with the given changes.
+ *
+ * This method is useful for reducing the number of clones needed to mutate a
+ * message.
+ *
+ * The changes can be one of:
+ * - method: (string) Changes the HTTP method.
+ * - set_headers: (array) Sets the given headers.
+ * - remove_headers: (array) Remove the given headers.
+ * - body: (mixed) Sets the given body.
+ * - uri: (UriInterface) Set the URI.
+ * - query: (string) Set the query string value of the URI.
+ * - version: (string) Set the protocol version.
+ *
+ * @param RequestInterface $request Request to clone and modify.
+ * @param array $changes Changes to apply.
+ *
+ * @return RequestInterface
+ *
+ * @deprecated modify_request will be removed in guzzlehttp/psr7:2.0. Use Utils::modifyRequest instead.
+ */
+function modify_request(RequestInterface $request, array $changes)
+{
+ return Utils::modifyRequest($request, $changes);
+}
+
+/**
+ * Attempts to rewind a message body and throws an exception on failure.
+ *
+ * The body of the message will only be rewound if a call to `tell()` returns a
+ * value other than `0`.
+ *
+ * @param MessageInterface $message Message to rewind
+ *
+ * @throws \RuntimeException
+ *
+ * @deprecated rewind_body will be removed in guzzlehttp/psr7:2.0. Use Message::rewindBody instead.
+ */
+function rewind_body(MessageInterface $message)
+{
+ Message::rewindBody($message);
+}
+
+/**
+ * Safely opens a PHP stream resource using a filename.
+ *
+ * When fopen fails, PHP normally raises a warning. This function adds an
+ * error handler that checks for errors and throws an exception instead.
+ *
+ * @param string $filename File to open
+ * @param string $mode Mode used to open the file
+ *
+ * @return resource
+ *
+ * @throws \RuntimeException if the file cannot be opened
+ *
+ * @deprecated try_fopen will be removed in guzzlehttp/psr7:2.0. Use Utils::tryFopen instead.
+ */
+function try_fopen($filename, $mode)
+{
+ return Utils::tryFopen($filename, $mode);
+}
+
+/**
+ * Copy the contents of a stream into a string until the given number of
+ * bytes have been read.
+ *
+ * @param StreamInterface $stream Stream to read
+ * @param int $maxLen Maximum number of bytes to read. Pass -1
+ * to read the entire stream.
+ *
+ * @return string
+ *
+ * @throws \RuntimeException on error.
+ *
+ * @deprecated copy_to_string will be removed in guzzlehttp/psr7:2.0. Use Utils::copyToString instead.
+ */
+function copy_to_string(StreamInterface $stream, $maxLen = -1)
+{
+ return Utils::copyToString($stream, $maxLen);
+}
+
+/**
+ * Copy the contents of a stream into another stream until the given number
+ * of bytes have been read.
+ *
+ * @param StreamInterface $source Stream to read from
+ * @param StreamInterface $dest Stream to write to
+ * @param int $maxLen Maximum number of bytes to read. Pass -1
+ * to read the entire stream.
+ *
+ * @throws \RuntimeException on error.
+ *
+ * @deprecated copy_to_stream will be removed in guzzlehttp/psr7:2.0. Use Utils::copyToStream instead.
+ */
+function copy_to_stream(StreamInterface $source, StreamInterface $dest, $maxLen = -1)
+{
+ return Utils::copyToStream($source, $dest, $maxLen);
+}
+
+/**
+ * Calculate a hash of a stream.
+ *
+ * This method reads the entire stream to calculate a rolling hash, based on
+ * PHP's `hash_init` functions.
+ *
+ * @param StreamInterface $stream Stream to calculate the hash for
+ * @param string $algo Hash algorithm (e.g. md5, crc32, etc)
+ * @param bool $rawOutput Whether or not to use raw output
+ *
+ * @return string Returns the hash of the stream
+ *
+ * @throws \RuntimeException on error.
+ *
+ * @deprecated hash will be removed in guzzlehttp/psr7:2.0. Use Utils::hash instead.
+ */
+function hash(StreamInterface $stream, $algo, $rawOutput = false)
+{
+ return Utils::hash($stream, $algo, $rawOutput);
+}
+
+/**
+ * Read a line from the stream up to the maximum allowed buffer length.
+ *
+ * @param StreamInterface $stream Stream to read from
+ * @param int|null $maxLength Maximum buffer length
+ *
+ * @return string
+ *
+ * @deprecated readline will be removed in guzzlehttp/psr7:2.0. Use Utils::readLine instead.
+ */
+function readline(StreamInterface $stream, $maxLength = null)
+{
+ return Utils::readLine($stream, $maxLength);
+}
+
+/**
+ * Parses a request message string into a request object.
+ *
+ * @param string $message Request message string.
+ *
+ * @return Request
+ *
+ * @deprecated parse_request will be removed in guzzlehttp/psr7:2.0. Use Message::parseRequest instead.
+ */
+function parse_request($message)
+{
+ return Message::parseRequest($message);
+}
+
+/**
+ * Parses a response message string into a response object.
+ *
+ * @param string $message Response message string.
+ *
+ * @return Response
+ *
+ * @deprecated parse_response will be removed in guzzlehttp/psr7:2.0. Use Message::parseResponse instead.
+ */
+function parse_response($message)
+{
+ return Message::parseResponse($message);
+}
+
+/**
+ * Parse a query string into an associative array.
+ *
+ * If multiple values are found for the same key, the value of that key value
+ * pair will become an array. This function does not parse nested PHP style
+ * arrays into an associative array (e.g., `foo[a]=1&foo[b]=2` will be parsed
+ * into `['foo[a]' => '1', 'foo[b]' => '2'])`.
+ *
+ * @param string $str Query string to parse
+ * @param int|bool $urlEncoding How the query string is encoded
+ *
+ * @return array
+ *
+ * @deprecated parse_query will be removed in guzzlehttp/psr7:2.0. Use Query::parse instead.
+ */
+function parse_query($str, $urlEncoding = true)
+{
+ return Query::parse($str, $urlEncoding);
+}
+
+/**
+ * Build a query string from an array of key value pairs.
+ *
+ * This function can use the return value of `parse_query()` to build a query
+ * string. This function does not modify the provided keys when an array is
+ * encountered (like `http_build_query()` would).
+ *
+ * @param array $params Query string parameters.
+ * @param int|false $encoding Set to false to not encode, PHP_QUERY_RFC3986
+ * to encode using RFC3986, or PHP_QUERY_RFC1738
+ * to encode using RFC1738.
+ *
+ * @return string
+ *
+ * @deprecated build_query will be removed in guzzlehttp/psr7:2.0. Use Query::build instead.
+ */
+function build_query(array $params, $encoding = PHP_QUERY_RFC3986)
+{
+ return Query::build($params, $encoding);
+}
+
+/**
+ * Determines the mimetype of a file by looking at its extension.
+ *
+ * @param string $filename
+ *
+ * @return string|null
+ *
+ * @deprecated mimetype_from_filename will be removed in guzzlehttp/psr7:2.0. Use MimeType::fromFilename instead.
+ */
+function mimetype_from_filename($filename)
+{
+ return MimeType::fromFilename($filename);
+}
+
+/**
+ * Maps a file extensions to a mimetype.
+ *
+ * @param $extension string The file extension.
+ *
+ * @return string|null
+ *
+ * @link http://svn.apache.org/repos/asf/httpd/httpd/branches/1.3.x/conf/mime.types
+ * @deprecated mimetype_from_extension will be removed in guzzlehttp/psr7:2.0. Use MimeType::fromExtension instead.
+ */
+function mimetype_from_extension($extension)
+{
+ return MimeType::fromExtension($extension);
+}
+
+/**
+ * Parses an HTTP message into an associative array.
+ *
+ * The array contains the "start-line" key containing the start line of
+ * the message, "headers" key containing an associative array of header
+ * array values, and a "body" key containing the body of the message.
+ *
+ * @param string $message HTTP request or response to parse.
+ *
+ * @return array
+ *
+ * @internal
+ *
+ * @deprecated _parse_message will be removed in guzzlehttp/psr7:2.0. Use Message::parseMessage instead.
+ */
+function _parse_message($message)
+{
+ return Message::parseMessage($message);
+}
+
+/**
+ * Constructs a URI for an HTTP request message.
+ *
+ * @param string $path Path from the start-line
+ * @param array $headers Array of headers (each value an array).
+ *
+ * @return string
+ *
+ * @internal
+ *
+ * @deprecated _parse_request_uri will be removed in guzzlehttp/psr7:2.0. Use Message::parseRequestUri instead.
+ */
+function _parse_request_uri($path, array $headers)
+{
+ return Message::parseRequestUri($path, $headers);
+}
+
+/**
+ * Get a short summary of the message body.
+ *
+ * Will return `null` if the response is not printable.
+ *
+ * @param MessageInterface $message The message to get the body summary
+ * @param int $truncateAt The maximum allowed size of the summary
+ *
+ * @return string|null
+ *
+ * @deprecated get_message_body_summary will be removed in guzzlehttp/psr7:2.0. Use Message::bodySummary instead.
+ */
+function get_message_body_summary(MessageInterface $message, $truncateAt = 120)
+{
+ return Message::bodySummary($message, $truncateAt);
+}
+
+/**
+ * Remove the items given by the keys, case insensitively from the data.
+ *
+ * @param iterable<string> $keys
+ *
+ * @return array
+ *
+ * @internal
+ *
+ * @deprecated _caseless_remove will be removed in guzzlehttp/psr7:2.0. Use Utils::caselessRemove instead.
+ */
+function _caseless_remove($keys, array $data)
+{
+ return Utils::caselessRemove($keys, $data);
+}
diff --git a/vendor/guzzlehttp/psr7/src/functions_include.php b/vendor/guzzlehttp/psr7/src/functions_include.php new file mode 100644 index 0000000..96a4a83 --- /dev/null +++ b/vendor/guzzlehttp/psr7/src/functions_include.php @@ -0,0 +1,6 @@ +<?php + +// Don't redefine the functions if included multiple times. +if (!function_exists('GuzzleHttp\Psr7\str')) { + require __DIR__ . '/functions.php'; +} |