Paul Klimov
7 years ago
committed by
GitHub
59 changed files with 4372 additions and 1347 deletions
@ -0,0 +1,267 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* @link http://www.yiiframework.com/ |
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC |
||||||
|
* @license http://www.yiiframework.com/license/ |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace yii\http; |
||||||
|
|
||||||
|
use Psr\Http\Message\StreamInterface; |
||||||
|
use Yii; |
||||||
|
use yii\base\BaseObject; |
||||||
|
use yii\base\ErrorHandler; |
||||||
|
use yii\base\InvalidConfigException; |
||||||
|
|
||||||
|
/** |
||||||
|
* FileStream represents file stream. |
||||||
|
* |
||||||
|
* Example: |
||||||
|
* |
||||||
|
* ```php |
||||||
|
* $stream = new FileSteam([ |
||||||
|
* 'filename' => '@app/files/items.txt', |
||||||
|
* 'mode' => 'w+', |
||||||
|
* ]); |
||||||
|
* |
||||||
|
* $stream->write('some content...'); |
||||||
|
* $stream->close(); |
||||||
|
* ``` |
||||||
|
* |
||||||
|
* @author Paul Klimov <klimov.paul@gmail.com> |
||||||
|
* @since 2.1.0 |
||||||
|
*/ |
||||||
|
class FileStream extends BaseObject implements StreamInterface |
||||||
|
{ |
||||||
|
/** |
||||||
|
* @var string file or stream name. |
||||||
|
* Path alias can be used here, for example: '@app/runtime/items.csv'. |
||||||
|
* This field can also be PHP stream name, e.g. anything which can be passed to `fopen()`, for example: 'php://input'. |
||||||
|
*/ |
||||||
|
public $filename; |
||||||
|
/** |
||||||
|
* @var string file open mode. |
||||||
|
*/ |
||||||
|
public $mode = 'r'; |
||||||
|
|
||||||
|
/** |
||||||
|
* @var resource|null stream resource |
||||||
|
*/ |
||||||
|
private $_resource; |
||||||
|
/** |
||||||
|
* @var array a resource metadata. |
||||||
|
*/ |
||||||
|
private $_metadata; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Destructor. |
||||||
|
* Closes the stream resource when destroyed. |
||||||
|
*/ |
||||||
|
public function __destruct() |
||||||
|
{ |
||||||
|
$this->close(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return resource a file pointer resource. |
||||||
|
* @throws InvalidConfigException if unable to open a resource. |
||||||
|
*/ |
||||||
|
public function getResource() |
||||||
|
{ |
||||||
|
if ($this->_resource === null) { |
||||||
|
$resource = fopen(Yii::getAlias($this->filename), $this->mode); |
||||||
|
if ($resource === false) { |
||||||
|
throw new InvalidConfigException("Unable to open file '{$this->filename}' with mode '{$this->mode}'"); |
||||||
|
} |
||||||
|
$this->_resource = $resource; |
||||||
|
} |
||||||
|
return $this->_resource; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function __toString() |
||||||
|
{ |
||||||
|
// __toString cannot throw exception |
||||||
|
// use trigger_error to bypass this limitation |
||||||
|
try { |
||||||
|
$this->seek(0); |
||||||
|
return $this->getContents(); |
||||||
|
} catch (\Exception $e) { |
||||||
|
ErrorHandler::convertExceptionToError($e); |
||||||
|
return ''; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function close() |
||||||
|
{ |
||||||
|
if ($this->_resource !== null) { |
||||||
|
fclose($this->_resource); |
||||||
|
$this->_resource = null; |
||||||
|
$this->_metadata = null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function detach() |
||||||
|
{ |
||||||
|
if ($this->_resource === null) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
$result = $this->_resource; |
||||||
|
$this->_resource = null; |
||||||
|
$this->_metadata = null; |
||||||
|
return $result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function getSize() |
||||||
|
{ |
||||||
|
$uri = $this->getMetadata('uri'); |
||||||
|
if (!empty($uri)) { |
||||||
|
// clear the stat cache in case stream has a URI |
||||||
|
clearstatcache(true, $uri); |
||||||
|
} |
||||||
|
|
||||||
|
$stats = fstat($this->getResource()); |
||||||
|
if (isset($stats['size'])) { |
||||||
|
return $stats['size']; |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function tell() |
||||||
|
{ |
||||||
|
$result = ftell($this->getResource()); |
||||||
|
if ($result === false) { |
||||||
|
throw new \RuntimeException('Unable to determine stream position'); |
||||||
|
} |
||||||
|
return $result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function eof() |
||||||
|
{ |
||||||
|
return feof($this->getResource()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function isSeekable() |
||||||
|
{ |
||||||
|
return (bool)$this->getMetadata('seekable'); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function seek($offset, $whence = SEEK_SET) |
||||||
|
{ |
||||||
|
if (fseek($this->getResource(), $offset, $whence) === -1) { |
||||||
|
throw new \RuntimeException("Unable to seek to stream position '{$offset}' with whence '{$whence}'"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function rewind() |
||||||
|
{ |
||||||
|
$this->seek(0); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function isWritable() |
||||||
|
{ |
||||||
|
$mode = $this->getMetadata('mode'); |
||||||
|
foreach (['w', 'c', 'a', 'x', 'r+'] as $key) { |
||||||
|
if (strpos($mode, $key) !== false) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function write($string) |
||||||
|
{ |
||||||
|
$result = fwrite($this->getResource(), $string); |
||||||
|
if ($result === false) { |
||||||
|
throw new \RuntimeException('Unable to write to stream'); |
||||||
|
} |
||||||
|
return $result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function isReadable() |
||||||
|
{ |
||||||
|
$mode = $this->getMetadata('mode'); |
||||||
|
foreach (['r', 'w+', 'a+', 'c+', 'x+'] as $key) { |
||||||
|
if (strpos($mode, $key) !== false) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function read($length) |
||||||
|
{ |
||||||
|
$string = fread($this->getResource(), $length); |
||||||
|
if ($string === false) { |
||||||
|
throw new \RuntimeException('Unable to read from stream'); |
||||||
|
} |
||||||
|
return $string; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function getContents() |
||||||
|
{ |
||||||
|
$contents = stream_get_contents($this->getResource()); |
||||||
|
if ($contents === false) { |
||||||
|
throw new \RuntimeException('Unable to read stream contents'); |
||||||
|
} |
||||||
|
return $contents; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function getMetadata($key = null) |
||||||
|
{ |
||||||
|
if ($this->_metadata === null) { |
||||||
|
$this->_metadata = stream_get_meta_data($this->getResource()); |
||||||
|
} |
||||||
|
|
||||||
|
if ($key === null) { |
||||||
|
return $this->_metadata; |
||||||
|
} |
||||||
|
|
||||||
|
return isset($this->_metadata[$key]) ? $this->_metadata[$key] : null; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,205 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* @link http://www.yiiframework.com/ |
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC |
||||||
|
* @license http://www.yiiframework.com/license/ |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace yii\http; |
||||||
|
|
||||||
|
use Psr\Http\Message\StreamInterface; |
||||||
|
use yii\base\BaseObject; |
||||||
|
use yii\base\InvalidArgumentException; |
||||||
|
|
||||||
|
/** |
||||||
|
* MemoryStream uses internal field as a stream source. Thus data associated with this stream exists only in |
||||||
|
* memory and will be lost once stream is closed. |
||||||
|
* |
||||||
|
* Example: |
||||||
|
* |
||||||
|
* ```php |
||||||
|
* $stream = new MemoryStream(); |
||||||
|
* |
||||||
|
* $stream->write('some content...'); |
||||||
|
* // ... |
||||||
|
* $stream->rewind(); |
||||||
|
* echo $stream->getContents(); |
||||||
|
* ``` |
||||||
|
* |
||||||
|
* @author Paul Klimov <klimov.paul@gmail.com> |
||||||
|
* @since 2.1.0 |
||||||
|
*/ |
||||||
|
class MemoryStream extends BaseObject implements StreamInterface |
||||||
|
{ |
||||||
|
/** |
||||||
|
* @var string internal content. |
||||||
|
*/ |
||||||
|
private $buffer = ''; |
||||||
|
/** |
||||||
|
* @var int internal stream pointer. |
||||||
|
*/ |
||||||
|
private $pointer = 0; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function __toString() |
||||||
|
{ |
||||||
|
return $this->buffer; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function close() |
||||||
|
{ |
||||||
|
$this->buffer = ''; |
||||||
|
$this->pointer = 0; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function detach() |
||||||
|
{ |
||||||
|
$this->close(); |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function getSize() |
||||||
|
{ |
||||||
|
return strlen($this->buffer); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function tell() |
||||||
|
{ |
||||||
|
return $this->pointer; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function eof() |
||||||
|
{ |
||||||
|
return $this->pointer >= $this->getSize(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function isSeekable() |
||||||
|
{ |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function seek($offset, $whence = SEEK_SET) |
||||||
|
{ |
||||||
|
switch ($whence) { |
||||||
|
case SEEK_SET: |
||||||
|
$this->pointer = $offset; |
||||||
|
break; |
||||||
|
case SEEK_CUR: |
||||||
|
$this->pointer += $offset; |
||||||
|
break; |
||||||
|
case SEEK_END: |
||||||
|
$this->pointer = $this->getSize() + $offset; |
||||||
|
break; |
||||||
|
default: |
||||||
|
throw new InvalidArgumentException("Unknown seek whence: '{$whence}'."); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function rewind() |
||||||
|
{ |
||||||
|
$this->seek(0); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function isWritable() |
||||||
|
{ |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function write($string) |
||||||
|
{ |
||||||
|
$size = $this->getSize(); |
||||||
|
$writeSize = strlen($string); |
||||||
|
|
||||||
|
if ($this->pointer >= $size) { |
||||||
|
$this->buffer .= $string; |
||||||
|
$this->pointer = $size + $writeSize; |
||||||
|
return $writeSize; |
||||||
|
} |
||||||
|
|
||||||
|
$begin = substr($this->buffer, 0, $this->pointer); |
||||||
|
$end = substr($this->buffer, $this->pointer + $writeSize); |
||||||
|
|
||||||
|
$this->buffer = $begin . $string . $end; |
||||||
|
$this->pointer += $writeSize; |
||||||
|
return $writeSize; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function isReadable() |
||||||
|
{ |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function read($length) |
||||||
|
{ |
||||||
|
$data = substr($this->buffer, $this->pointer, $length); |
||||||
|
$this->pointer += $length; |
||||||
|
return $data; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function getContents() |
||||||
|
{ |
||||||
|
if ($this->pointer === 0) { |
||||||
|
return $this->buffer; |
||||||
|
} |
||||||
|
return substr($this->buffer, $this->pointer); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function getMetadata($key = null) |
||||||
|
{ |
||||||
|
$metadata = [ |
||||||
|
'mode' => 'rw', |
||||||
|
'seekable' => $this->isSeekable(), |
||||||
|
]; |
||||||
|
|
||||||
|
if ($key === null) { |
||||||
|
return $metadata; |
||||||
|
} |
||||||
|
|
||||||
|
return (isset($metadata[$key])) ? $metadata[$key] : null; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,370 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* @link http://www.yiiframework.com/ |
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC |
||||||
|
* @license http://www.yiiframework.com/license/ |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace yii\http; |
||||||
|
|
||||||
|
use Psr\Http\Message\StreamInterface; |
||||||
|
use yii\di\Instance; |
||||||
|
|
||||||
|
/** |
||||||
|
* MessageTrait provides set of methods to satisfy [[\Psr\Http\Message\MessageInterface]]. |
||||||
|
* |
||||||
|
* This trait should be applied to descendant of [[\yii\base\BaseObject]] implementing [[\Psr\Http\Message\MessageInterface]]. |
||||||
|
* |
||||||
|
* @property string $protocolVersion HTTP protocol version as a string. |
||||||
|
* @property string[][] $headers the message's headers. |
||||||
|
* @property StreamInterface $body the body of the message. |
||||||
|
* @property HeaderCollection $headerCollection The header collection. This property is read-only. |
||||||
|
* |
||||||
|
* @author Paul Klimov <klimov.paul@gmail.com> |
||||||
|
* @since 2.1.0 |
||||||
|
*/ |
||||||
|
trait MessageTrait |
||||||
|
{ |
||||||
|
/** |
||||||
|
* @var string HTTP protocol version as a string. |
||||||
|
*/ |
||||||
|
private $_protocolVersion; |
||||||
|
/** |
||||||
|
* @var HeaderCollection header collection, which is used for headers storage. |
||||||
|
*/ |
||||||
|
private $_headerCollection; |
||||||
|
/** |
||||||
|
* @var StreamInterface the body of the message. |
||||||
|
*/ |
||||||
|
private $_body; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Retrieves the HTTP protocol version as a string. |
||||||
|
* @return string HTTP protocol version. |
||||||
|
*/ |
||||||
|
public function getProtocolVersion() |
||||||
|
{ |
||||||
|
if ($this->_protocolVersion === null) { |
||||||
|
$this->_protocolVersion = $this->defaultProtocolVersion(); |
||||||
|
} |
||||||
|
return $this->_protocolVersion; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Specifies HTTP protocol version. |
||||||
|
* @param string $version HTTP protocol version |
||||||
|
*/ |
||||||
|
public function setProtocolVersion($version) |
||||||
|
{ |
||||||
|
$this->_protocolVersion = $version; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Return an instance with the specified HTTP protocol version. |
||||||
|
* |
||||||
|
* This method retains the immutability of the message and returns an instance that has the |
||||||
|
* new protocol version. |
||||||
|
* |
||||||
|
* @param string $version HTTP protocol version |
||||||
|
* @return static |
||||||
|
*/ |
||||||
|
public function withProtocolVersion($version) |
||||||
|
{ |
||||||
|
if ($this->getProtocolVersion() === $version) { |
||||||
|
return $this; |
||||||
|
} |
||||||
|
|
||||||
|
$newInstance = clone $this; |
||||||
|
$newInstance->setProtocolVersion($version); |
||||||
|
return $newInstance; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns default HTTP protocol version to be used in case it is not explicitly set. |
||||||
|
* @return string HTTP protocol version. |
||||||
|
*/ |
||||||
|
protected function defaultProtocolVersion() |
||||||
|
{ |
||||||
|
if (!empty($_SERVER['SERVER_PROTOCOL'])) { |
||||||
|
return str_replace('HTTP/', '', $_SERVER['SERVER_PROTOCOL']); |
||||||
|
} |
||||||
|
return '1.0'; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the header collection. |
||||||
|
* The header collection contains the currently registered HTTP headers. |
||||||
|
* @return HeaderCollection the header collection |
||||||
|
*/ |
||||||
|
public function getHeaderCollection() |
||||||
|
{ |
||||||
|
if ($this->_headerCollection === null) { |
||||||
|
$headerCollection = new HeaderCollection(); |
||||||
|
$headerCollection->fromArray($this->defaultHeaders()); |
||||||
|
$this->_headerCollection = $headerCollection; |
||||||
|
} |
||||||
|
return $this->_headerCollection; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns default message's headers, which should be present once [[headerCollection]] is instantiated. |
||||||
|
* @return string[][] an associative array of the message's headers. |
||||||
|
*/ |
||||||
|
protected function defaultHeaders() |
||||||
|
{ |
||||||
|
return []; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets up message's headers at batch, removing any previously existing ones. |
||||||
|
* @param string[][] $headers an associative array of the message's headers. |
||||||
|
*/ |
||||||
|
public function setHeaders($headers) |
||||||
|
{ |
||||||
|
$headerCollection = $this->getHeaderCollection(); |
||||||
|
$headerCollection->removeAll(); |
||||||
|
$headerCollection->fromArray($headers); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets up a particular message's header, removing any its previously existing value. |
||||||
|
* @param string $name Case-insensitive header field name. |
||||||
|
* @param string|string[] $value Header value(s). |
||||||
|
*/ |
||||||
|
public function setHeader($name, $value) |
||||||
|
{ |
||||||
|
$this->getHeaderCollection()->set($name, $value); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Appends the given value to the specified header. |
||||||
|
* Existing values for the specified header will be maintained. The new |
||||||
|
* value(s) will be appended to the existing list. If the header did not |
||||||
|
* exist previously, it will be added. |
||||||
|
* @param string $name Case-insensitive header field name to add. |
||||||
|
* @param string|string[] $value Header value(s). |
||||||
|
*/ |
||||||
|
public function addHeader($name, $value) |
||||||
|
{ |
||||||
|
$this->getHeaderCollection()->add($name, $value); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Retrieves all message header values. |
||||||
|
* |
||||||
|
* The keys represent the header name as it will be sent over the wire, and |
||||||
|
* each value is an array of strings associated with the header. |
||||||
|
* |
||||||
|
* // Represent the headers as a string |
||||||
|
* foreach ($message->getHeaders() as $name => $values) { |
||||||
|
* echo $name . ": " . implode(", ", $values); |
||||||
|
* } |
||||||
|
* |
||||||
|
* // Emit headers iteratively: |
||||||
|
* foreach ($message->getHeaders() as $name => $values) { |
||||||
|
* foreach ($values as $value) { |
||||||
|
* header(sprintf('%s: %s', $name, $value), false); |
||||||
|
* } |
||||||
|
* } |
||||||
|
* |
||||||
|
* While header names are not case-sensitive, getHeaders() will preserve the |
||||||
|
* exact case in which headers were originally specified. |
||||||
|
* |
||||||
|
* @return string[][] Returns an associative array of the message's headers. Each |
||||||
|
* key MUST be a header name, and each value MUST be an array of strings |
||||||
|
* for that header. |
||||||
|
*/ |
||||||
|
public function getHeaders() |
||||||
|
{ |
||||||
|
return $this->getHeaderCollection()->toArray(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Checks if a header exists by the given case-insensitive name. |
||||||
|
* |
||||||
|
* @param string $name Case-insensitive header field name. |
||||||
|
* @return bool Returns true if any header names match the given header |
||||||
|
* name using a case-insensitive string comparison. Returns false if |
||||||
|
* no matching header name is found in the message. |
||||||
|
*/ |
||||||
|
public function hasHeader($name) |
||||||
|
{ |
||||||
|
return $this->getHeaderCollection()->has($name); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Retrieves a message header value by the given case-insensitive name. |
||||||
|
* |
||||||
|
* This method returns an array of all the header values of the given |
||||||
|
* case-insensitive header name. |
||||||
|
* |
||||||
|
* If the header does not appear in the message, this method will return an |
||||||
|
* empty array. |
||||||
|
* |
||||||
|
* @param string $name Case-insensitive header field name. |
||||||
|
* @return string[] An array of string values as provided for the given |
||||||
|
* header. If the header does not appear in the message, this method MUST |
||||||
|
* return an empty array. |
||||||
|
*/ |
||||||
|
public function getHeader($name) |
||||||
|
{ |
||||||
|
return $this->getHeaderCollection()->get($name, [], false); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Retrieves a comma-separated string of the values for a single header. |
||||||
|
* |
||||||
|
* This method returns all of the header values of the given |
||||||
|
* case-insensitive header name as a string concatenated together using |
||||||
|
* a comma. |
||||||
|
* |
||||||
|
* NOTE: Not all header values may be appropriately represented using |
||||||
|
* comma concatenation. For such headers, use getHeader() instead |
||||||
|
* and supply your own delimiter when concatenating. |
||||||
|
* |
||||||
|
* If the header does not appear in the message, this method MUST return |
||||||
|
* an empty string. |
||||||
|
* |
||||||
|
* @param string $name Case-insensitive header field name. |
||||||
|
* @return string A string of values as provided for the given header |
||||||
|
* concatenated together using a comma. If the header does not appear in |
||||||
|
* the message, this method MUST return an empty string. |
||||||
|
*/ |
||||||
|
public function getHeaderLine($name) |
||||||
|
{ |
||||||
|
return implode(',', $this->getHeader($name)); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Return an instance with the provided value replacing the specified header. |
||||||
|
* This method retains the immutability of the message and returns an instance that has the |
||||||
|
* new and/or updated header and value. |
||||||
|
* @param string $name Case-insensitive header field name. |
||||||
|
* @param string|string[] $value Header value(s). |
||||||
|
* @return static |
||||||
|
* @throws \InvalidArgumentException for invalid header names or values. |
||||||
|
*/ |
||||||
|
public function withHeader($name, $value) |
||||||
|
{ |
||||||
|
$newInstance = clone $this; |
||||||
|
$newInstance->setHeader($name, $value); |
||||||
|
return $newInstance; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Return an instance with the specified header appended with the given value. |
||||||
|
* |
||||||
|
* Existing values for the specified header will be maintained. The new |
||||||
|
* value(s) will be appended to the existing list. If the header did not |
||||||
|
* exist previously, it will be added. |
||||||
|
* |
||||||
|
* This method retains the immutability of the message and returns an instance that has the |
||||||
|
* new header and/or value. |
||||||
|
* |
||||||
|
* @param string $name Case-insensitive header field name to add. |
||||||
|
* @param string|string[] $value Header value(s). |
||||||
|
* @return static |
||||||
|
* @throws \InvalidArgumentException for invalid header names or values. |
||||||
|
*/ |
||||||
|
public function withAddedHeader($name, $value) |
||||||
|
{ |
||||||
|
$newInstance = clone $this; |
||||||
|
$newInstance->addHeader($name, $value); |
||||||
|
return $newInstance; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Return an instance without the specified header. |
||||||
|
* Header resolution performed without case-sensitivity. |
||||||
|
* This method retains the immutability of the message and returns an instance that removes |
||||||
|
* the named header. |
||||||
|
* @param string $name Case-insensitive header field name to remove. |
||||||
|
* @return static |
||||||
|
*/ |
||||||
|
public function withoutHeader($name) |
||||||
|
{ |
||||||
|
$newInstance = clone $this; |
||||||
|
$newInstance->getHeaderCollection()->remove($name); |
||||||
|
return $newInstance; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Gets the body of the message. |
||||||
|
* @return StreamInterface Returns the body as a stream. |
||||||
|
*/ |
||||||
|
public function getBody() |
||||||
|
{ |
||||||
|
if (!$this->_body instanceof StreamInterface) { |
||||||
|
if ($this->_body === null) { |
||||||
|
$body = $this->defaultBody(); |
||||||
|
} elseif ($this->_body instanceof \Closure) { |
||||||
|
$body = call_user_func($this->_body, $this); |
||||||
|
} else { |
||||||
|
$body = $this->_body; |
||||||
|
} |
||||||
|
|
||||||
|
$this->_body = Instance::ensure($body, StreamInterface::class); |
||||||
|
} |
||||||
|
return $this->_body; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Specifies message body. |
||||||
|
* @param StreamInterface|\Closure|array $body stream instance or its DI compatible configuration. |
||||||
|
*/ |
||||||
|
public function setBody($body) |
||||||
|
{ |
||||||
|
$this->_body = $body; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Return an instance with the specified message body. |
||||||
|
* This method retains the immutability of the message and returns an instance that has the |
||||||
|
* new body stream. |
||||||
|
* @param StreamInterface $body Body. |
||||||
|
* @return static |
||||||
|
* @throws \InvalidArgumentException When the body is not valid. |
||||||
|
*/ |
||||||
|
public function withBody(StreamInterface $body) |
||||||
|
{ |
||||||
|
if ($this->getBody() === $body) { |
||||||
|
return $this; |
||||||
|
} |
||||||
|
|
||||||
|
$newInstance = clone $this; |
||||||
|
$newInstance->setBody($body); |
||||||
|
return $newInstance; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns default message body to be used in case it is not explicitly set. |
||||||
|
* @return StreamInterface default body instance. |
||||||
|
*/ |
||||||
|
protected function defaultBody() |
||||||
|
{ |
||||||
|
return new MemoryStream(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* This method is called after the object is created by cloning an existing one. |
||||||
|
*/ |
||||||
|
public function __clone() |
||||||
|
{ |
||||||
|
$this->cloneHttpMessageInternals(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Ensures any internal object-type fields related to `MessageTrait` are cloned from their origins. |
||||||
|
* In case actual trait owner implementing method [[__clone()]], it must invoke this method within it. |
||||||
|
*/ |
||||||
|
private function cloneHttpMessageInternals() |
||||||
|
{ |
||||||
|
if (is_object($this->_headerCollection)) { |
||||||
|
$this->_headerCollection = clone $this->_headerCollection; |
||||||
|
} |
||||||
|
if (is_object($this->_body)) { |
||||||
|
$this->_body = clone $this->_body; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,241 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* @link http://www.yiiframework.com/ |
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC |
||||||
|
* @license http://www.yiiframework.com/license/ |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace yii\http; |
||||||
|
|
||||||
|
use Psr\Http\Message\StreamInterface; |
||||||
|
use yii\base\BaseObject; |
||||||
|
use yii\base\ErrorHandler; |
||||||
|
|
||||||
|
/** |
||||||
|
* ResourceStream wraps existing PHP stream resource, e.g. one opened by `fopen()`. |
||||||
|
* |
||||||
|
* Example: |
||||||
|
* |
||||||
|
* ```php |
||||||
|
* $stream = new ResourceStream([ |
||||||
|
* 'resource' => tmpfile(), |
||||||
|
* ]); |
||||||
|
* |
||||||
|
* $stream->write('some content...'); |
||||||
|
* $stream->close(); |
||||||
|
* ``` |
||||||
|
* |
||||||
|
* Usage of this class make sense in case you already have an opened PHP stream from elsewhere and wish to wrap it into `StreamInterface`. |
||||||
|
* |
||||||
|
* > Note: closing this stream will close the resource associated with it, so it becomes invalid for usage elsewhere. |
||||||
|
* |
||||||
|
* @author Paul Klimov <klimov.paul@gmail.com> |
||||||
|
* @since 2.1.0 |
||||||
|
*/ |
||||||
|
class ResourceStream extends BaseObject implements StreamInterface |
||||||
|
{ |
||||||
|
/** |
||||||
|
* @var resource stream resource. |
||||||
|
*/ |
||||||
|
public $resource; |
||||||
|
|
||||||
|
/** |
||||||
|
* @var array a resource metadata. |
||||||
|
*/ |
||||||
|
private $_metadata; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Destructor. |
||||||
|
* Closes the stream resource when destroyed. |
||||||
|
*/ |
||||||
|
public function __destruct() |
||||||
|
{ |
||||||
|
$this->close(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function __toString() |
||||||
|
{ |
||||||
|
// __toString cannot throw exception |
||||||
|
// use trigger_error to bypass this limitation |
||||||
|
try { |
||||||
|
$this->seek(0); |
||||||
|
return $this->getContents(); |
||||||
|
} catch (\Exception $e) { |
||||||
|
ErrorHandler::convertExceptionToError($e); |
||||||
|
return ''; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function close() |
||||||
|
{ |
||||||
|
if ($this->resource !== null && is_resource($this->resource)) { |
||||||
|
fclose($this->resource); |
||||||
|
$this->_metadata = null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function detach() |
||||||
|
{ |
||||||
|
if ($this->resource === null) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
$result = $this->resource; |
||||||
|
$this->resource = null; |
||||||
|
$this->_metadata = null; |
||||||
|
return $result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function getSize() |
||||||
|
{ |
||||||
|
$uri = $this->getMetadata('uri'); |
||||||
|
if (!empty($uri)) { |
||||||
|
// clear the stat cache in case stream has a URI |
||||||
|
clearstatcache(true, $uri); |
||||||
|
} |
||||||
|
|
||||||
|
$stats = fstat($this->resource); |
||||||
|
if (isset($stats['size'])) { |
||||||
|
return $stats['size']; |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function tell() |
||||||
|
{ |
||||||
|
$result = ftell($this->resource); |
||||||
|
if ($result === false) { |
||||||
|
throw new \RuntimeException('Unable to determine stream position'); |
||||||
|
} |
||||||
|
return $result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function eof() |
||||||
|
{ |
||||||
|
return feof($this->resource); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function isSeekable() |
||||||
|
{ |
||||||
|
return (bool)$this->getMetadata('seekable'); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function seek($offset, $whence = SEEK_SET) |
||||||
|
{ |
||||||
|
if (fseek($this->resource, $offset, $whence) === -1) { |
||||||
|
throw new \RuntimeException("Unable to seek to stream position '{$offset}' with whence '{$whence}'"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function rewind() |
||||||
|
{ |
||||||
|
$this->seek(0); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function isWritable() |
||||||
|
{ |
||||||
|
$mode = $this->getMetadata('mode'); |
||||||
|
foreach (['w', 'c', 'a', 'x', 'r+'] as $key) { |
||||||
|
if (strpos($mode, $key) !== false) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function write($string) |
||||||
|
{ |
||||||
|
$result = fwrite($this->resource, $string); |
||||||
|
if ($result === false) { |
||||||
|
throw new \RuntimeException('Unable to write to stream'); |
||||||
|
} |
||||||
|
return $result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function isReadable() |
||||||
|
{ |
||||||
|
$mode = $this->getMetadata('mode'); |
||||||
|
foreach (['r', 'w+', 'a+', 'c+', 'x+'] as $key) { |
||||||
|
if (strpos($mode, $key) !== false) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function read($length) |
||||||
|
{ |
||||||
|
$string = fread($this->resource, $length); |
||||||
|
if ($string === false) { |
||||||
|
throw new \RuntimeException('Unable to read from stream'); |
||||||
|
} |
||||||
|
return $string; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function getContents() |
||||||
|
{ |
||||||
|
$contents = stream_get_contents($this->resource); |
||||||
|
if ($contents === false) { |
||||||
|
throw new \RuntimeException('Unable to read stream contents'); |
||||||
|
} |
||||||
|
return $contents; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function getMetadata($key = null) |
||||||
|
{ |
||||||
|
if ($this->_metadata === null) { |
||||||
|
$this->_metadata = stream_get_meta_data($this->resource); |
||||||
|
} |
||||||
|
|
||||||
|
if ($key === null) { |
||||||
|
return $this->_metadata; |
||||||
|
} |
||||||
|
|
||||||
|
return isset($this->_metadata[$key]) ? $this->_metadata[$key] : null; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,548 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* @link http://www.yiiframework.com/ |
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC |
||||||
|
* @license http://www.yiiframework.com/license/ |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace yii\http; |
||||||
|
|
||||||
|
use Psr\Http\Message\UriInterface; |
||||||
|
use yii\base\BaseObject; |
||||||
|
use yii\base\ErrorHandler; |
||||||
|
use yii\base\InvalidArgumentException; |
||||||
|
|
||||||
|
/** |
||||||
|
* Uri represents a URI. |
||||||
|
* |
||||||
|
* Create from components example: |
||||||
|
* |
||||||
|
* ```php |
||||||
|
* $uri = new Uri([ |
||||||
|
* 'scheme' => 'http', |
||||||
|
* 'user' => 'username', |
||||||
|
* 'password' => 'password', |
||||||
|
* 'host' => 'example.com', |
||||||
|
* 'port' => 9090, |
||||||
|
* 'path' => '/content/path', |
||||||
|
* 'query' => 'foo=some', |
||||||
|
* 'fragment' => 'anchor', |
||||||
|
* ]); |
||||||
|
* ``` |
||||||
|
* |
||||||
|
* Create from string example: |
||||||
|
* |
||||||
|
* ```php |
||||||
|
* $uri = new Uri(['string' => 'http://example.com?foo=some']); |
||||||
|
* ``` |
||||||
|
* |
||||||
|
* Create using PSR-7 syntax: |
||||||
|
* |
||||||
|
* ```php |
||||||
|
* $uri = (new Uri()) |
||||||
|
* ->withScheme('http') |
||||||
|
* ->withUserInfo('username', 'password') |
||||||
|
* ->withHost('example.com') |
||||||
|
* ->withPort(9090) |
||||||
|
* ->withPath('/content/path') |
||||||
|
* ->withQuery('foo=some') |
||||||
|
* ->withFragment('anchor'); |
||||||
|
* ``` |
||||||
|
* |
||||||
|
* @property string $scheme the scheme component of the URI. |
||||||
|
* @property string $user |
||||||
|
* @property string $password |
||||||
|
* @property string $host the hostname to be used. |
||||||
|
* @property int|null $port port number. |
||||||
|
* @property string $path the path component of the URI |
||||||
|
* @property string|array $query the query string or array of query parameters. |
||||||
|
* @property string $fragment URI fragment. |
||||||
|
* @property string $authority the authority component of the URI. This property is read-only. |
||||||
|
* @property string $userInfo the user information component of the URI. This property is read-only. |
||||||
|
* |
||||||
|
* @author Paul Klimov <klimov.paul@gmail.com> |
||||||
|
* @since 2.1.0 |
||||||
|
*/ |
||||||
|
class Uri extends BaseObject implements UriInterface |
||||||
|
{ |
||||||
|
/** |
||||||
|
* @var string URI complete string. |
||||||
|
*/ |
||||||
|
private $_string; |
||||||
|
/** |
||||||
|
* @var array URI components. |
||||||
|
*/ |
||||||
|
private $_components; |
||||||
|
/** |
||||||
|
* @var array scheme default ports in format: `[scheme => port]` |
||||||
|
*/ |
||||||
|
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, |
||||||
|
]; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* @return string URI string representation. |
||||||
|
*/ |
||||||
|
public function getString() |
||||||
|
{ |
||||||
|
if ($this->_string !== null) { |
||||||
|
return $this->_string; |
||||||
|
} |
||||||
|
if ($this->_components === null) { |
||||||
|
return ''; |
||||||
|
} |
||||||
|
return $this->composeUri($this->_components); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @param string $string URI full string. |
||||||
|
*/ |
||||||
|
public function setString($string) |
||||||
|
{ |
||||||
|
$this->_string = $string; |
||||||
|
$this->_components = null; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function getScheme() |
||||||
|
{ |
||||||
|
return $this->getComponent('scheme'); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets up the scheme component of the URI. |
||||||
|
* @param string $scheme the scheme. |
||||||
|
*/ |
||||||
|
public function setScheme($scheme) |
||||||
|
{ |
||||||
|
$this->setComponent('scheme', $scheme); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function withScheme($scheme) |
||||||
|
{ |
||||||
|
if ($this->getScheme() === $scheme) { |
||||||
|
return $this; |
||||||
|
} |
||||||
|
|
||||||
|
$newInstance = clone $this; |
||||||
|
$newInstance->setScheme($scheme); |
||||||
|
return $newInstance; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function getAuthority() |
||||||
|
{ |
||||||
|
return $this->composeAuthority($this->getComponents()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function getUserInfo() |
||||||
|
{ |
||||||
|
return $this->composeUserInfo($this->getComponents()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function getHost() |
||||||
|
{ |
||||||
|
return $this->getComponent('host', ''); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Specifies hostname. |
||||||
|
* @param string $host the hostname to be used. |
||||||
|
*/ |
||||||
|
public function setHost($host) |
||||||
|
{ |
||||||
|
$this->setComponent('host', $host); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function withHost($host) |
||||||
|
{ |
||||||
|
if ($this->getHost() === $host) { |
||||||
|
return $this; |
||||||
|
} |
||||||
|
|
||||||
|
$newInstance = clone $this; |
||||||
|
$newInstance->setHost($host); |
||||||
|
return $newInstance; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function getPort() |
||||||
|
{ |
||||||
|
return $this->getComponent('port'); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Specifies port. |
||||||
|
* @param int|null $port The port to be used; a `null` value removes the port information. |
||||||
|
*/ |
||||||
|
public function setPort($port) |
||||||
|
{ |
||||||
|
if ($port !== null) { |
||||||
|
if (!is_int($port)) { |
||||||
|
throw new InvalidArgumentException('URI port must be an integer.'); |
||||||
|
} |
||||||
|
} |
||||||
|
$this->setComponent('port', $port); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function withPort($port) |
||||||
|
{ |
||||||
|
if ($this->getPort() === $port) { |
||||||
|
return $this; |
||||||
|
} |
||||||
|
|
||||||
|
$newInstance = clone $this; |
||||||
|
$newInstance->setPort($port); |
||||||
|
return $newInstance; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function getPath() |
||||||
|
{ |
||||||
|
return $this->getComponent('path', ''); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Specifies path component of the URI |
||||||
|
* @param string $path the path to be used. |
||||||
|
*/ |
||||||
|
public function setPath($path) |
||||||
|
{ |
||||||
|
$this->setComponent('path', $path); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function withPath($path) |
||||||
|
{ |
||||||
|
if ($this->getPath() === $path) { |
||||||
|
return $this; |
||||||
|
} |
||||||
|
|
||||||
|
$newInstance = clone $this; |
||||||
|
$newInstance->setPath($path); |
||||||
|
return $newInstance; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function getQuery() |
||||||
|
{ |
||||||
|
return $this->getComponent('query', ''); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Specifies query string. |
||||||
|
* @param string|array|object $query the query string or array of query parameters. |
||||||
|
*/ |
||||||
|
public function setQuery($query) |
||||||
|
{ |
||||||
|
if (is_array($query) || is_object($query)) { |
||||||
|
$query = http_build_query($query); |
||||||
|
} |
||||||
|
$this->setComponent('query', $query); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function withQuery($query) |
||||||
|
{ |
||||||
|
if ($this->getQuery() === $query) { |
||||||
|
return $this; |
||||||
|
} |
||||||
|
|
||||||
|
$newInstance = clone $this; |
||||||
|
$newInstance->setQuery($query); |
||||||
|
return $newInstance; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function getFragment() |
||||||
|
{ |
||||||
|
return $this->getComponent('fragment', ''); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Specifies URI fragment. |
||||||
|
* @param string $fragment the fragment to be used. |
||||||
|
*/ |
||||||
|
public function setFragment($fragment) |
||||||
|
{ |
||||||
|
$this->setComponent('fragment', $fragment); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function withFragment($fragment) |
||||||
|
{ |
||||||
|
if ($this->getFragment() === $fragment) { |
||||||
|
return $this; |
||||||
|
} |
||||||
|
|
||||||
|
$newInstance = clone $this; |
||||||
|
$newInstance->setFragment($fragment); |
||||||
|
return $newInstance; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return string the user name to use for authority. |
||||||
|
*/ |
||||||
|
public function getUser() |
||||||
|
{ |
||||||
|
return $this->getComponent('user', ''); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @param string $user the user name to use for authority. |
||||||
|
*/ |
||||||
|
public function setUser($user) |
||||||
|
{ |
||||||
|
$this->setComponent('user', $user); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return string password associated with [[user]]. |
||||||
|
*/ |
||||||
|
public function getPassword() |
||||||
|
{ |
||||||
|
return $this->getComponent('pass', ''); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @param string $password password associated with [[user]]. |
||||||
|
*/ |
||||||
|
public function setPassword($password) |
||||||
|
{ |
||||||
|
$this->setComponent('pass', $password); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function withUserInfo($user, $password = null) |
||||||
|
{ |
||||||
|
$userInfo = $user; |
||||||
|
if ($password != '') { |
||||||
|
$userInfo .= ':' . $password; |
||||||
|
} |
||||||
|
|
||||||
|
if ($userInfo === $this->composeUserInfo($this->getComponents())) { |
||||||
|
return $this; |
||||||
|
} |
||||||
|
|
||||||
|
$newInstance = clone $this; |
||||||
|
$newInstance->setUser($user); |
||||||
|
$newInstance->setPassword($password); |
||||||
|
return $newInstance; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
public function __toString() |
||||||
|
{ |
||||||
|
// __toString cannot throw exception |
||||||
|
// use trigger_error to bypass this limitation |
||||||
|
try { |
||||||
|
return $this->getString(); |
||||||
|
} catch (\Exception $e) { |
||||||
|
ErrorHandler::convertExceptionToError($e); |
||||||
|
return ''; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets up particular URI component. |
||||||
|
* @param string $name URI component name. |
||||||
|
* @param mixed $value URI component value. |
||||||
|
*/ |
||||||
|
protected function setComponent($name, $value) |
||||||
|
{ |
||||||
|
if ($this->_string !== null) { |
||||||
|
$this->_components = $this->parseUri($this->_string); |
||||||
|
} |
||||||
|
$this->_components[$name] = $value; |
||||||
|
$this->_string = null; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @param string $name URI component name. |
||||||
|
* @param mixed $default default value, which should be returned in case component is not exist. |
||||||
|
* @return mixed URI component value. |
||||||
|
*/ |
||||||
|
protected function getComponent($name, $default = null) |
||||||
|
{ |
||||||
|
$components = $this->getComponents(); |
||||||
|
if (isset($components[$name])) { |
||||||
|
return $components[$name]; |
||||||
|
} |
||||||
|
return $default; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns URI components for this instance as an associative array. |
||||||
|
* @return array URI components in format: `[name => value]` |
||||||
|
*/ |
||||||
|
protected function getComponents() |
||||||
|
{ |
||||||
|
if ($this->_components === null) { |
||||||
|
if ($this->_string === null) { |
||||||
|
return []; |
||||||
|
} |
||||||
|
$this->_components = $this->parseUri($this->_string); |
||||||
|
} |
||||||
|
return $this->_components; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Parses a URI and returns an associative array containing any of the various components of the URI |
||||||
|
* that are present. |
||||||
|
* @param string $uri the URI string to parse. |
||||||
|
* @return array URI components. |
||||||
|
*/ |
||||||
|
protected function parseUri($uri) |
||||||
|
{ |
||||||
|
$components = parse_url($uri); |
||||||
|
if ($components === false) { |
||||||
|
throw new InvalidArgumentException("URI string '{$uri}' is not a valid URI."); |
||||||
|
} |
||||||
|
return $components; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Composes URI string from given components. |
||||||
|
* @param array $components URI components. |
||||||
|
* @return string URI full string. |
||||||
|
*/ |
||||||
|
protected function composeUri(array $components) |
||||||
|
{ |
||||||
|
$uri = ''; |
||||||
|
|
||||||
|
$scheme = empty($components['scheme']) ? '' : $components['scheme']; |
||||||
|
if ($scheme !== '') { |
||||||
|
$uri .= $components['scheme'] . ':'; |
||||||
|
} |
||||||
|
|
||||||
|
$authority = $this->composeAuthority($components); |
||||||
|
|
||||||
|
if ($authority !== '' || $scheme === 'file') { |
||||||
|
// authority separator is added even when the authority is missing/empty for the "file" scheme |
||||||
|
// while `file:///myfile` and `file:/myfile` are equivalent according to RFC 3986, `file:///` is more common |
||||||
|
// PHP functions and Chrome, for example, use this format |
||||||
|
$uri .= '//' . $authority; |
||||||
|
} |
||||||
|
|
||||||
|
if (!empty($components['path'])) { |
||||||
|
$uri .= $components['path']; |
||||||
|
} |
||||||
|
|
||||||
|
if (!empty($components['query'])) { |
||||||
|
$uri .= '?' . $components['query']; |
||||||
|
} |
||||||
|
|
||||||
|
if (!empty($components['fragment'])) { |
||||||
|
$uri .= '#' . $components['fragment']; |
||||||
|
} |
||||||
|
|
||||||
|
return $uri; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @param array $components URI components. |
||||||
|
* @return string user info string. |
||||||
|
*/ |
||||||
|
protected function composeUserInfo(array $components) |
||||||
|
{ |
||||||
|
$userInfo = ''; |
||||||
|
if (!empty($components['user'])) { |
||||||
|
$userInfo .= $components['user']; |
||||||
|
} |
||||||
|
if (!empty($components['pass'])) { |
||||||
|
$userInfo .= ':' . $components['pass']; |
||||||
|
} |
||||||
|
return $userInfo; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @param array $components URI components. |
||||||
|
* @return string authority string. |
||||||
|
*/ |
||||||
|
protected function composeAuthority(array $components) |
||||||
|
{ |
||||||
|
$authority = ''; |
||||||
|
|
||||||
|
$scheme = empty($components['scheme']) ? '' : $components['scheme']; |
||||||
|
|
||||||
|
if (empty($components['host'])) { |
||||||
|
if (in_array($scheme, ['http', 'https'], true)) { |
||||||
|
$authority = 'localhost'; |
||||||
|
} |
||||||
|
} else { |
||||||
|
$authority = $components['host']; |
||||||
|
} |
||||||
|
if (!empty($components['port']) && !$this->isDefaultPort($scheme, $components['port'])) { |
||||||
|
$authority .= ':' . $components['port']; |
||||||
|
} |
||||||
|
|
||||||
|
$userInfo = $this->composeUserInfo($components); |
||||||
|
if ($userInfo !== '') { |
||||||
|
$authority = $userInfo . '@' . $authority; |
||||||
|
} |
||||||
|
|
||||||
|
return $authority; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Checks whether specified port is default one for the specified scheme. |
||||||
|
* @param string $scheme scheme. |
||||||
|
* @param int $port port number. |
||||||
|
* @return bool whether specified port is default for specified scheme |
||||||
|
*/ |
||||||
|
protected function isDefaultPort($scheme, $port) |
||||||
|
{ |
||||||
|
if (!isset(self::$defaultPorts[$scheme])) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
return self::$defaultPorts[$scheme] == $port; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,250 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* @link http://www.yiiframework.com/ |
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC |
||||||
|
* @license http://www.yiiframework.com/license/ |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace yiiunit\framework\http; |
||||||
|
|
||||||
|
use Yii; |
||||||
|
use yii\helpers\FileHelper; |
||||||
|
use yii\http\FileStream; |
||||||
|
use yiiunit\TestCase; |
||||||
|
|
||||||
|
class FileStreamTest extends TestCase |
||||||
|
{ |
||||||
|
/** |
||||||
|
* @var string test file path. |
||||||
|
*/ |
||||||
|
protected $testFilePath; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
protected function setUp() |
||||||
|
{ |
||||||
|
parent::setUp(); |
||||||
|
$this->testFilePath = Yii::getAlias('@yiiunit/runtime') . DIRECTORY_SEPARATOR . 'file-stream-test-' . getmypid(); |
||||||
|
FileHelper::createDirectory($this->testFilePath); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
protected function tearDown() |
||||||
|
{ |
||||||
|
FileHelper::removeDirectory($this->testFilePath); |
||||||
|
parent::tearDown(); |
||||||
|
} |
||||||
|
|
||||||
|
public function testRead() |
||||||
|
{ |
||||||
|
$filename = $this->testFilePath . DIRECTORY_SEPARATOR . 'read.txt'; |
||||||
|
file_put_contents($filename, '0123456789'); |
||||||
|
|
||||||
|
$stream = new FileStream(); |
||||||
|
$stream->filename = $filename; |
||||||
|
$stream->mode = 'r'; |
||||||
|
|
||||||
|
$this->assertTrue($stream->isReadable()); |
||||||
|
$this->assertTrue($stream->isSeekable()); |
||||||
|
$this->assertFalse($stream->isWritable()); |
||||||
|
|
||||||
|
$this->assertSame('01234', $stream->read(5)); |
||||||
|
$this->assertFalse($stream->eof()); |
||||||
|
|
||||||
|
$this->assertSame('56789', $stream->read(6)); |
||||||
|
$this->assertTrue($stream->eof()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @depends testRead |
||||||
|
*/ |
||||||
|
public function testSeek() |
||||||
|
{ |
||||||
|
$filename = $this->testFilePath . DIRECTORY_SEPARATOR . 'seek.txt'; |
||||||
|
file_put_contents($filename, '0123456789'); |
||||||
|
|
||||||
|
$stream = new FileStream(); |
||||||
|
$stream->filename = $filename; |
||||||
|
$stream->mode = 'r'; |
||||||
|
|
||||||
|
$stream->seek(5); |
||||||
|
$this->assertSame('56789', $stream->read(5)); |
||||||
|
|
||||||
|
$stream->seek(0); |
||||||
|
$this->assertSame('01234', $stream->read(5)); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @depends testSeek |
||||||
|
*/ |
||||||
|
public function testGetContents() |
||||||
|
{ |
||||||
|
$filename = $this->testFilePath . DIRECTORY_SEPARATOR . 'get-content.txt'; |
||||||
|
file_put_contents($filename, '0123456789'); |
||||||
|
|
||||||
|
$stream = new FileStream(); |
||||||
|
$stream->filename = $filename; |
||||||
|
$stream->mode = 'r'; |
||||||
|
|
||||||
|
$this->assertSame('0123456789', $stream->getContents()); |
||||||
|
|
||||||
|
$stream->seek(5); |
||||||
|
$this->assertSame('56789', $stream->getContents()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @depends testGetContents |
||||||
|
*/ |
||||||
|
public function testToString() |
||||||
|
{ |
||||||
|
$filename = $this->testFilePath . DIRECTORY_SEPARATOR . 'to-string.txt'; |
||||||
|
file_put_contents($filename, '0123456789'); |
||||||
|
|
||||||
|
$stream = new FileStream(); |
||||||
|
$stream->filename = $filename; |
||||||
|
$stream->mode = 'r'; |
||||||
|
|
||||||
|
$this->assertSame('0123456789', (string)$stream); |
||||||
|
|
||||||
|
$stream->seek(5); |
||||||
|
$this->assertSame('0123456789', (string)$stream); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @depends testRead |
||||||
|
*/ |
||||||
|
public function testWrite() |
||||||
|
{ |
||||||
|
$filename = $this->testFilePath . DIRECTORY_SEPARATOR . 'write.txt'; |
||||||
|
|
||||||
|
$stream = new FileStream(); |
||||||
|
$stream->filename = $filename; |
||||||
|
$stream->mode = 'w+'; |
||||||
|
|
||||||
|
$this->assertTrue($stream->isWritable()); |
||||||
|
|
||||||
|
$stream->write('01234'); |
||||||
|
$stream->write('56789'); |
||||||
|
|
||||||
|
$stream->close(); |
||||||
|
|
||||||
|
$this->assertSame('0123456789', file_get_contents($filename)); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @depends testRead |
||||||
|
*/ |
||||||
|
public function testGetSize() |
||||||
|
{ |
||||||
|
$filename = $this->testFilePath . DIRECTORY_SEPARATOR . 'get-size.txt'; |
||||||
|
file_put_contents($filename, '0123456789'); |
||||||
|
|
||||||
|
$stream = new FileStream(); |
||||||
|
$stream->filename = $filename; |
||||||
|
$stream->mode = 'r'; |
||||||
|
|
||||||
|
$this->assertSame(10, $stream->getSize()); |
||||||
|
|
||||||
|
file_put_contents($filename, ''); |
||||||
|
$this->assertSame(0, $stream->getSize()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @depends testRead |
||||||
|
*/ |
||||||
|
public function testGetMetadata() |
||||||
|
{ |
||||||
|
$filename = $this->testFilePath . DIRECTORY_SEPARATOR . 'get-meta-data.txt'; |
||||||
|
file_put_contents($filename, '0123456789'); |
||||||
|
|
||||||
|
$stream = new FileStream(); |
||||||
|
$stream->filename = $filename; |
||||||
|
$stream->mode = 'r'; |
||||||
|
|
||||||
|
$metadata = $stream->getMetadata(); |
||||||
|
|
||||||
|
$this->assertSame('r', $metadata['mode']); |
||||||
|
$this->assertSame('plainfile', $metadata['wrapper_type']); |
||||||
|
|
||||||
|
$this->assertSame('r', $stream->getMetadata('mode')); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return array test data. |
||||||
|
*/ |
||||||
|
public function dataProviderFileMode() |
||||||
|
{ |
||||||
|
return [ |
||||||
|
['r', true, false], |
||||||
|
['r+', true, true], |
||||||
|
['w', false, true], |
||||||
|
['w+', true, true], |
||||||
|
['rw', true, true], |
||||||
|
['x', false, true], |
||||||
|
['x+', true, true], |
||||||
|
['c', false, true], |
||||||
|
['c+', true, true], |
||||||
|
['a', false, true], |
||||||
|
['a+', true, true], |
||||||
|
['wb', false, true], |
||||||
|
['rb', true, false], |
||||||
|
['w+b', true, true], |
||||||
|
['r+b', true, true], |
||||||
|
['rt', true, false], |
||||||
|
['w+t', true, true], |
||||||
|
['r+t', true, true], |
||||||
|
['x+t', true, true], |
||||||
|
['c+t', true, true], |
||||||
|
]; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @depends testGetMetadata |
||||||
|
* @dataProvider dataProviderFileMode |
||||||
|
* |
||||||
|
* @param string $mode |
||||||
|
* @param bool $isReadable |
||||||
|
* @param bool $isWritable |
||||||
|
*/ |
||||||
|
public function testIsReadable($mode, $isReadable, $isWritable) |
||||||
|
{ |
||||||
|
/* @var $stream FileStream|\PHPUnit_Framework_MockObject_MockObject */ |
||||||
|
$stream = $this->getMockBuilder(FileStream::class) |
||||||
|
->setMethods(['getMetadata']) |
||||||
|
->getMock(); |
||||||
|
|
||||||
|
$stream->expects($this->any()) |
||||||
|
->method('getMetadata') |
||||||
|
->with('mode') |
||||||
|
->willReturn($mode); |
||||||
|
|
||||||
|
$this->assertSame($isReadable, $stream->isReadable()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @depends testGetMetadata |
||||||
|
* @dataProvider dataProviderFileMode |
||||||
|
* |
||||||
|
* @param string $mode |
||||||
|
* @param bool $isReadable |
||||||
|
* @param bool $isWritable |
||||||
|
*/ |
||||||
|
public function testIsWritable($mode, $isReadable, $isWritable) |
||||||
|
{ |
||||||
|
/* @var $stream FileStream|\PHPUnit_Framework_MockObject_MockObject */ |
||||||
|
$stream = $this->getMockBuilder(FileStream::class) |
||||||
|
->setMethods(['getMetadata']) |
||||||
|
->getMock(); |
||||||
|
|
||||||
|
$stream->expects($this->any()) |
||||||
|
->method('getMetadata') |
||||||
|
->with('mode') |
||||||
|
->willReturn($mode); |
||||||
|
|
||||||
|
$this->assertSame($isWritable, $stream->isWritable()); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,133 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* @link http://www.yiiframework.com/ |
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC |
||||||
|
* @license http://www.yiiframework.com/license/ |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace yiiunit\framework\http; |
||||||
|
|
||||||
|
use yii\http\MemoryStream; |
||||||
|
use yiiunit\TestCase; |
||||||
|
|
||||||
|
class MemoryStreamTest extends TestCase |
||||||
|
{ |
||||||
|
public function testWrite() |
||||||
|
{ |
||||||
|
$stream = new MemoryStream(); |
||||||
|
|
||||||
|
$this->assertTrue($stream->isWritable()); |
||||||
|
|
||||||
|
$this->assertSame(5, $stream->write('01234')); |
||||||
|
$this->assertSame(5, $stream->write('56789')); |
||||||
|
|
||||||
|
$this->assertSame('0123456789', (string)$stream); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @depends testWrite |
||||||
|
*/ |
||||||
|
public function testRead() |
||||||
|
{ |
||||||
|
$stream = new MemoryStream(); |
||||||
|
$stream->write('0123456789'); |
||||||
|
|
||||||
|
$this->assertTrue($stream->isReadable()); |
||||||
|
|
||||||
|
$stream->rewind(); |
||||||
|
|
||||||
|
$this->assertSame('01234', $stream->read(5)); |
||||||
|
$this->assertFalse($stream->eof()); |
||||||
|
$this->assertSame('56789', $stream->read(6)); |
||||||
|
$this->assertTrue($stream->eof()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @depends testRead |
||||||
|
*/ |
||||||
|
public function testSeek() |
||||||
|
{ |
||||||
|
$stream = new MemoryStream(); |
||||||
|
$stream->write('0123456789'); |
||||||
|
$stream->rewind(); |
||||||
|
|
||||||
|
$this->assertTrue($stream->isSeekable()); |
||||||
|
|
||||||
|
$stream->seek(5); |
||||||
|
$this->assertSame('56789', $stream->read(5)); |
||||||
|
|
||||||
|
$stream->seek(0); |
||||||
|
$this->assertSame('01234', $stream->read(5)); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @depends testSeek |
||||||
|
*/ |
||||||
|
public function testGetContents() |
||||||
|
{ |
||||||
|
$stream = new MemoryStream(); |
||||||
|
$stream->write('0123456789'); |
||||||
|
$stream->rewind(); |
||||||
|
|
||||||
|
$this->assertSame('0123456789', $stream->getContents()); |
||||||
|
|
||||||
|
$stream->seek(5); |
||||||
|
$this->assertSame('56789', $stream->getContents()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @depends testGetContents |
||||||
|
*/ |
||||||
|
public function testToString() |
||||||
|
{ |
||||||
|
$stream = new MemoryStream(); |
||||||
|
$stream->write('0123456789'); |
||||||
|
$stream->rewind(); |
||||||
|
|
||||||
|
$this->assertSame('0123456789', (string)$stream); |
||||||
|
|
||||||
|
$stream->seek(5); |
||||||
|
$this->assertSame('0123456789', (string)$stream); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @depends testRead |
||||||
|
*/ |
||||||
|
public function testGetSize() |
||||||
|
{ |
||||||
|
$stream = new MemoryStream(); |
||||||
|
|
||||||
|
$this->assertSame(0, $stream->getSize()); |
||||||
|
|
||||||
|
$stream->write('0123456789'); |
||||||
|
|
||||||
|
$this->assertSame(10, $stream->getSize()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @depends testRead |
||||||
|
*/ |
||||||
|
public function testGetMetadata() |
||||||
|
{ |
||||||
|
$stream = new MemoryStream(); |
||||||
|
|
||||||
|
$metadata = $stream->getMetadata(); |
||||||
|
|
||||||
|
$this->assertSame('rw', $metadata['mode']); |
||||||
|
$this->assertSame('rw', $stream->getMetadata('mode')); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @depends testSeek |
||||||
|
*/ |
||||||
|
public function testRewrite() |
||||||
|
{ |
||||||
|
$stream = new MemoryStream(); |
||||||
|
$stream->write('0123456789'); |
||||||
|
|
||||||
|
$stream->seek(5); |
||||||
|
$this->assertSame(4, $stream->write('0000')); |
||||||
|
|
||||||
|
$this->assertSame('0123400009', (string)$stream); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,134 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* @link http://www.yiiframework.com/ |
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC |
||||||
|
* @license http://www.yiiframework.com/license/ |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace yiiunit\framework\http; |
||||||
|
|
||||||
|
use Psr\Http\Message\MessageInterface; |
||||||
|
use yii\base\BaseObject; |
||||||
|
use yii\http\FileStream; |
||||||
|
use yii\http\MemoryStream; |
||||||
|
use yii\http\MessageTrait; |
||||||
|
use yiiunit\TestCase; |
||||||
|
|
||||||
|
class MessageTraitTest extends TestCase |
||||||
|
{ |
||||||
|
public function testSetupProtocolVersion() |
||||||
|
{ |
||||||
|
$message = new TestMessage(); |
||||||
|
|
||||||
|
$message->setProtocolVersion('2.0'); |
||||||
|
$this->assertSame('2.0', $message->getProtocolVersion()); |
||||||
|
|
||||||
|
$newMessage = $message->withProtocolVersion('2.1'); |
||||||
|
$this->assertNotSame($newMessage, $message); |
||||||
|
$this->assertSame('2.1', $newMessage->getProtocolVersion()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @depends testSetupProtocolVersion |
||||||
|
*/ |
||||||
|
public function testDefaultProtocolVersion() |
||||||
|
{ |
||||||
|
$_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.2'; |
||||||
|
$message = new TestMessage(); |
||||||
|
$this->assertSame('1.2', $message->getProtocolVersion()); |
||||||
|
|
||||||
|
unset($_SERVER['SERVER_PROTOCOL']); |
||||||
|
$message = new TestMessage(); |
||||||
|
$this->assertSame('1.0', $message->getProtocolVersion()); |
||||||
|
} |
||||||
|
|
||||||
|
public function testSetupBody() |
||||||
|
{ |
||||||
|
$message = new TestMessage(); |
||||||
|
|
||||||
|
$message->setBody([ |
||||||
|
'class' => FileStream::class |
||||||
|
]); |
||||||
|
$this->assertTrue($message->getBody() instanceof FileStream); |
||||||
|
|
||||||
|
$body = new MemoryStream(); |
||||||
|
$newMessage = $message->withBody($body); |
||||||
|
$this->assertNotSame($newMessage, $message); |
||||||
|
$this->assertSame($body, $newMessage->getBody()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @depends testSetupBody |
||||||
|
*/ |
||||||
|
public function testDefaultBody() |
||||||
|
{ |
||||||
|
$message = new TestMessage(); |
||||||
|
$this->assertTrue($message->getBody() instanceof MemoryStream); |
||||||
|
} |
||||||
|
|
||||||
|
public function testSetupHeaders() |
||||||
|
{ |
||||||
|
$message = new TestMessage(); |
||||||
|
|
||||||
|
$this->assertFalse($message->hasHeader('some')); |
||||||
|
$headerMessage = $message->withHeader('some', 'foo'); |
||||||
|
$this->assertNotSame($headerMessage, $message); |
||||||
|
$this->assertTrue($headerMessage->hasHeader('some')); |
||||||
|
$this->assertEquals(['some' => ['foo']], $headerMessage->getHeaders()); |
||||||
|
|
||||||
|
$headerAddedMessage = $headerMessage->withAddedHeader('some', 'another'); |
||||||
|
$this->assertNotSame($headerMessage, $headerAddedMessage); |
||||||
|
$this->assertEquals(['some' => ['foo', 'another']], $headerAddedMessage->getHeaders()); |
||||||
|
$this->assertEquals(['foo', 'another'], $headerAddedMessage->getHeader('some')); |
||||||
|
$this->assertEquals('foo,another', $headerAddedMessage->getHeaderLine('some')); |
||||||
|
|
||||||
|
$overrideMessage = $headerAddedMessage->withHeader('some', 'override'); |
||||||
|
$this->assertNotSame($headerAddedMessage, $overrideMessage); |
||||||
|
$this->assertEquals(['some' => ['override']], $overrideMessage->getHeaders()); |
||||||
|
|
||||||
|
$clearMessage = $headerMessage->withoutHeader('some'); |
||||||
|
$this->assertNotSame($headerMessage, $clearMessage); |
||||||
|
$this->assertFalse($clearMessage->hasHeader('some')); |
||||||
|
$this->assertEquals([], $clearMessage->getHeader('some')); |
||||||
|
$this->assertEquals('', $clearMessage->getHeaderLine('some')); |
||||||
|
|
||||||
|
$message->setHeaders([ |
||||||
|
'some' => ['line1', 'line2'] |
||||||
|
]); |
||||||
|
$this->assertEquals(['some' => ['line1', 'line2']], $message->getHeaders()); |
||||||
|
$message->setHeaders([ |
||||||
|
'another' => ['one'] |
||||||
|
]); |
||||||
|
$this->assertEquals(['another' => ['one']], $message->getHeaders()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @depends testSetupProtocolVersion |
||||||
|
* @depends testSetupBody |
||||||
|
* @depends testSetupHeaders |
||||||
|
*/ |
||||||
|
public function testCreateFromConfig() |
||||||
|
{ |
||||||
|
$message = new TestMessage([ |
||||||
|
'protocolVersion' => '2.1', |
||||||
|
'headers' => [ |
||||||
|
'header' => [ |
||||||
|
'line1', |
||||||
|
'line2', |
||||||
|
], |
||||||
|
], |
||||||
|
'body' => [ |
||||||
|
'class' => FileStream::class |
||||||
|
], |
||||||
|
]); |
||||||
|
|
||||||
|
$this->assertSame('2.1', $message->getProtocolVersion()); |
||||||
|
$this->assertEquals(['header' => ['line1', 'line2']], $message->getHeaders()); |
||||||
|
$this->assertTrue($message->getBody() instanceof FileStream); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class TestMessage extends BaseObject implements MessageInterface |
||||||
|
{ |
||||||
|
use MessageTrait; |
||||||
|
} |
@ -0,0 +1,243 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* @link http://www.yiiframework.com/ |
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC |
||||||
|
* @license http://www.yiiframework.com/license/ |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace yiiunit\framework\http; |
||||||
|
|
||||||
|
use Yii; |
||||||
|
use yii\helpers\FileHelper; |
||||||
|
use yii\http\ResourceStream; |
||||||
|
use yiiunit\TestCase; |
||||||
|
|
||||||
|
class ResourceStreamTest extends TestCase |
||||||
|
{ |
||||||
|
/** |
||||||
|
* @var string test file path. |
||||||
|
*/ |
||||||
|
protected $testFilePath; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
protected function setUp() |
||||||
|
{ |
||||||
|
parent::setUp(); |
||||||
|
$this->testFilePath = Yii::getAlias('@yiiunit/runtime') . DIRECTORY_SEPARATOR . 'resource-stream-test-' . getmypid(); |
||||||
|
FileHelper::createDirectory($this->testFilePath); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritdoc} |
||||||
|
*/ |
||||||
|
protected function tearDown() |
||||||
|
{ |
||||||
|
FileHelper::removeDirectory($this->testFilePath); |
||||||
|
parent::tearDown(); |
||||||
|
} |
||||||
|
|
||||||
|
public function testRead() |
||||||
|
{ |
||||||
|
$filename = $this->testFilePath . DIRECTORY_SEPARATOR . 'read.txt'; |
||||||
|
file_put_contents($filename, '0123456789'); |
||||||
|
|
||||||
|
$stream = new ResourceStream(); |
||||||
|
$stream->resource = fopen($filename, 'r'); |
||||||
|
|
||||||
|
$this->assertTrue($stream->isReadable()); |
||||||
|
$this->assertTrue($stream->isSeekable()); |
||||||
|
$this->assertFalse($stream->isWritable()); |
||||||
|
|
||||||
|
$this->assertSame('01234', $stream->read(5)); |
||||||
|
$this->assertFalse($stream->eof()); |
||||||
|
|
||||||
|
$this->assertSame('56789', $stream->read(6)); |
||||||
|
$this->assertTrue($stream->eof()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @depends testRead |
||||||
|
*/ |
||||||
|
public function testSeek() |
||||||
|
{ |
||||||
|
$filename = $this->testFilePath . DIRECTORY_SEPARATOR . 'seek.txt'; |
||||||
|
file_put_contents($filename, '0123456789'); |
||||||
|
|
||||||
|
$stream = new ResourceStream(); |
||||||
|
$stream->resource = fopen($filename, 'r'); |
||||||
|
|
||||||
|
$stream->seek(5); |
||||||
|
$this->assertSame('56789', $stream->read(5)); |
||||||
|
|
||||||
|
$stream->seek(0); |
||||||
|
$this->assertSame('01234', $stream->read(5)); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @depends testSeek |
||||||
|
*/ |
||||||
|
public function testGetContents() |
||||||
|
{ |
||||||
|
$filename = $this->testFilePath . DIRECTORY_SEPARATOR . 'get-content.txt'; |
||||||
|
file_put_contents($filename, '0123456789'); |
||||||
|
|
||||||
|
$stream = new ResourceStream(); |
||||||
|
$stream->resource = fopen($filename, 'r'); |
||||||
|
|
||||||
|
$this->assertSame('0123456789', $stream->getContents()); |
||||||
|
|
||||||
|
$stream->seek(5); |
||||||
|
$this->assertSame('56789', $stream->getContents()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @depends testGetContents |
||||||
|
*/ |
||||||
|
public function testToString() |
||||||
|
{ |
||||||
|
$filename = $this->testFilePath . DIRECTORY_SEPARATOR . 'to-string.txt'; |
||||||
|
file_put_contents($filename, '0123456789'); |
||||||
|
|
||||||
|
$stream = new ResourceStream(); |
||||||
|
$stream->resource = fopen($filename, 'r'); |
||||||
|
|
||||||
|
$this->assertSame('0123456789', (string)$stream); |
||||||
|
|
||||||
|
$stream->seek(5); |
||||||
|
$this->assertSame('0123456789', (string)$stream); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @depends testRead |
||||||
|
*/ |
||||||
|
public function testWrite() |
||||||
|
{ |
||||||
|
$filename = $this->testFilePath . DIRECTORY_SEPARATOR . 'write.txt'; |
||||||
|
|
||||||
|
$stream = new ResourceStream(); |
||||||
|
$stream->resource = fopen($filename, 'w+'); |
||||||
|
|
||||||
|
$this->assertTrue($stream->isWritable()); |
||||||
|
|
||||||
|
$stream->write('01234'); |
||||||
|
$stream->write('56789'); |
||||||
|
|
||||||
|
$stream->close(); |
||||||
|
|
||||||
|
$this->assertSame('0123456789', file_get_contents($filename)); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @depends testRead |
||||||
|
*/ |
||||||
|
public function testGetSize() |
||||||
|
{ |
||||||
|
$filename = $this->testFilePath . DIRECTORY_SEPARATOR . 'get-size.txt'; |
||||||
|
file_put_contents($filename, '0123456789'); |
||||||
|
|
||||||
|
$stream = new ResourceStream(); |
||||||
|
$stream->resource = fopen($filename, 'r'); |
||||||
|
|
||||||
|
$this->assertSame(10, $stream->getSize()); |
||||||
|
|
||||||
|
file_put_contents($filename, ''); |
||||||
|
$this->assertSame(0, $stream->getSize()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @depends testRead |
||||||
|
*/ |
||||||
|
public function testGetMetadata() |
||||||
|
{ |
||||||
|
$filename = $this->testFilePath . DIRECTORY_SEPARATOR . 'get-meta-data.txt'; |
||||||
|
file_put_contents($filename, '0123456789'); |
||||||
|
|
||||||
|
$stream = new ResourceStream(); |
||||||
|
$stream->resource = fopen($filename, 'r'); |
||||||
|
|
||||||
|
$metadata = $stream->getMetadata(); |
||||||
|
|
||||||
|
$this->assertSame('r', $metadata['mode']); |
||||||
|
$this->assertSame('plainfile', $metadata['wrapper_type']); |
||||||
|
|
||||||
|
$this->assertSame('r', $stream->getMetadata('mode')); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return array test data. |
||||||
|
*/ |
||||||
|
public function dataProviderFileMode() |
||||||
|
{ |
||||||
|
return [ |
||||||
|
['r', true, false], |
||||||
|
['r+', true, true], |
||||||
|
['w', false, true], |
||||||
|
['w+', true, true], |
||||||
|
['rw', true, true], |
||||||
|
['x', false, true], |
||||||
|
['x+', true, true], |
||||||
|
['c', false, true], |
||||||
|
['c+', true, true], |
||||||
|
['a', false, true], |
||||||
|
['a+', true, true], |
||||||
|
['wb', false, true], |
||||||
|
['rb', true, false], |
||||||
|
['w+b', true, true], |
||||||
|
['r+b', true, true], |
||||||
|
['rt', true, false], |
||||||
|
['w+t', true, true], |
||||||
|
['r+t', true, true], |
||||||
|
['x+t', true, true], |
||||||
|
['c+t', true, true], |
||||||
|
]; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @depends testGetMetadata |
||||||
|
* @dataProvider dataProviderFileMode |
||||||
|
* |
||||||
|
* @param string $mode |
||||||
|
* @param bool $isReadable |
||||||
|
* @param bool $isWritable |
||||||
|
*/ |
||||||
|
public function testIsReadable($mode, $isReadable, $isWritable) |
||||||
|
{ |
||||||
|
/* @var $stream ResourceStream|\PHPUnit_Framework_MockObject_MockObject */ |
||||||
|
$stream = $this->getMockBuilder(ResourceStream::class) |
||||||
|
->setMethods(['getMetadata']) |
||||||
|
->getMock(); |
||||||
|
|
||||||
|
$stream->expects($this->any()) |
||||||
|
->method('getMetadata') |
||||||
|
->with('mode') |
||||||
|
->willReturn($mode); |
||||||
|
|
||||||
|
$this->assertSame($isReadable, $stream->isReadable()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @depends testGetMetadata |
||||||
|
* @dataProvider dataProviderFileMode |
||||||
|
* |
||||||
|
* @param string $mode |
||||||
|
* @param bool $isReadable |
||||||
|
* @param bool $isWritable |
||||||
|
*/ |
||||||
|
public function testIsWritable($mode, $isReadable, $isWritable) |
||||||
|
{ |
||||||
|
/* @var $stream ResourceStream|\PHPUnit_Framework_MockObject_MockObject */ |
||||||
|
$stream = $this->getMockBuilder(ResourceStream::class) |
||||||
|
->setMethods(['getMetadata']) |
||||||
|
->getMock(); |
||||||
|
|
||||||
|
$stream->expects($this->any()) |
||||||
|
->method('getMetadata') |
||||||
|
->with('mode') |
||||||
|
->willReturn($mode); |
||||||
|
|
||||||
|
$this->assertSame($isWritable, $stream->isWritable()); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,203 @@ |
|||||||
|
<?php |
||||||
|
/** |
||||||
|
* @link http://www.yiiframework.com/ |
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC |
||||||
|
* @license http://www.yiiframework.com/license/ |
||||||
|
*/ |
||||||
|
|
||||||
|
namespace yiiunit\framework\http; |
||||||
|
|
||||||
|
use yii\http\Uri; |
||||||
|
use yiiunit\TestCase; |
||||||
|
|
||||||
|
class UriTest extends TestCase |
||||||
|
{ |
||||||
|
public function testSetupString() |
||||||
|
{ |
||||||
|
$uri = new Uri(); |
||||||
|
|
||||||
|
$uri->setString('http://example.com?foo=some'); |
||||||
|
$this->assertEquals('http://example.com?foo=some', $uri->getString()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @depends testSetupString |
||||||
|
*/ |
||||||
|
public function testParseString() |
||||||
|
{ |
||||||
|
$uri = new Uri(); |
||||||
|
|
||||||
|
$uri->setString('http://username:password@example.com:9090/content/path?foo=some#anchor'); |
||||||
|
|
||||||
|
$this->assertSame('http', $uri->getScheme()); |
||||||
|
$this->assertSame('username:password', $uri->getUserInfo()); |
||||||
|
$this->assertSame('example.com', $uri->getHost()); |
||||||
|
$this->assertSame(9090, $uri->getPort()); |
||||||
|
$this->assertSame('/content/path', $uri->getPath()); |
||||||
|
$this->assertSame('foo=some', $uri->getQuery()); |
||||||
|
$this->assertSame('anchor', $uri->getFragment()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @depends testSetupString |
||||||
|
*/ |
||||||
|
public function testConstructFromString() |
||||||
|
{ |
||||||
|
$uri = new Uri(['string' => 'http://example.com?foo=some']); |
||||||
|
$this->assertSame('http://example.com?foo=some', $uri->getString()); |
||||||
|
} |
||||||
|
|
||||||
|
public function testConstructFromComponents() |
||||||
|
{ |
||||||
|
$uri = new Uri([ |
||||||
|
'scheme' => 'http', |
||||||
|
'user' => 'username', |
||||||
|
'password' => 'password', |
||||||
|
'host' => 'example.com', |
||||||
|
'port' => 9090, |
||||||
|
'path' => '/content/path', |
||||||
|
'query' => 'foo=some', |
||||||
|
'fragment' => 'anchor', |
||||||
|
]); |
||||||
|
$this->assertSame('http://username:password@example.com:9090/content/path?foo=some#anchor', $uri->getString()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @depends testConstructFromComponents |
||||||
|
*/ |
||||||
|
public function testToString() |
||||||
|
{ |
||||||
|
$uri = new Uri([ |
||||||
|
'scheme' => 'http', |
||||||
|
'host' => 'example.com', |
||||||
|
'path' => '/content/path', |
||||||
|
'query' => 'foo=some', |
||||||
|
]); |
||||||
|
$this->assertSame('http://example.com/content/path?foo=some', (string)$uri); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @depends testParseString |
||||||
|
*/ |
||||||
|
public function testGetUserInfo() |
||||||
|
{ |
||||||
|
$uri = new Uri(); |
||||||
|
|
||||||
|
$uri->setString('http://username:password@example.com/content/path?foo=some'); |
||||||
|
|
||||||
|
$this->assertSame('username:password', $uri->getUserInfo()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @depends testParseString |
||||||
|
*/ |
||||||
|
public function testGetAuthority() |
||||||
|
{ |
||||||
|
$uri = new Uri(); |
||||||
|
|
||||||
|
$uri->setString('http://username:password@example.com/content/path?foo=some'); |
||||||
|
|
||||||
|
$this->assertSame('username:password@example.com', $uri->getAuthority()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @depends testConstructFromComponents |
||||||
|
*/ |
||||||
|
public function testOmitDefaultPort() |
||||||
|
{ |
||||||
|
$uri = new Uri([ |
||||||
|
'scheme' => 'http', |
||||||
|
'host' => 'example.com', |
||||||
|
'port' => 80, |
||||||
|
'path' => '/content/path', |
||||||
|
'query' => 'foo=some', |
||||||
|
]); |
||||||
|
$this->assertSame('http://example.com/content/path?foo=some', $uri->getString()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @depends testConstructFromComponents |
||||||
|
*/ |
||||||
|
public function testSetupQueryByArray() |
||||||
|
{ |
||||||
|
$uri = new Uri([ |
||||||
|
'scheme' => 'http', |
||||||
|
'host' => 'example.com', |
||||||
|
'path' => '/content/path', |
||||||
|
'query' => [ |
||||||
|
'param1' => 'value1', |
||||||
|
'param2' => 'value2', |
||||||
|
], |
||||||
|
]); |
||||||
|
$this->assertSame('http://example.com/content/path?param1=value1¶m2=value2', $uri->getString()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @depends testToString |
||||||
|
*/ |
||||||
|
public function testPsrSyntax() |
||||||
|
{ |
||||||
|
$uri = (new Uri()) |
||||||
|
->withScheme('http') |
||||||
|
->withUserInfo('username', 'password') |
||||||
|
->withHost('example.com') |
||||||
|
->withPort(9090) |
||||||
|
->withPath('/content/path') |
||||||
|
->withQuery('foo=some') |
||||||
|
->withFragment('anchor'); |
||||||
|
|
||||||
|
$this->assertSame('http://username:password@example.com:9090/content/path?foo=some#anchor', $uri->getString()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @depends testConstructFromString |
||||||
|
* @depends testPsrSyntax |
||||||
|
*/ |
||||||
|
public function testModify() |
||||||
|
{ |
||||||
|
$uri = new Uri(['string' => 'http://example.com?foo=some']); |
||||||
|
|
||||||
|
$uri->setHost('another.com'); |
||||||
|
$uri->setPort(9090); |
||||||
|
|
||||||
|
$this->assertSame('http://another.com:9090?foo=some', $uri->getString()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @depends testPsrSyntax |
||||||
|
*/ |
||||||
|
public function testImmutability() |
||||||
|
{ |
||||||
|
$uri = new Uri([ |
||||||
|
'scheme' => 'http', |
||||||
|
'user' => 'username', |
||||||
|
'password' => 'password', |
||||||
|
'host' => 'example.com', |
||||||
|
'port' => 9090, |
||||||
|
'path' => '/content/path', |
||||||
|
'query' => 'foo=some', |
||||||
|
'fragment' => 'anchor', |
||||||
|
]); |
||||||
|
|
||||||
|
$this->assertSame($uri, $uri->withScheme('http')); |
||||||
|
$this->assertNotSame($uri, $uri->withScheme('https')); |
||||||
|
|
||||||
|
$this->assertSame($uri, $uri->withHost('example.com')); |
||||||
|
$this->assertNotSame($uri, $uri->withHost('another.com')); |
||||||
|
|
||||||
|
$this->assertSame($uri, $uri->withPort(9090)); |
||||||
|
$this->assertNotSame($uri, $uri->withPort(33)); |
||||||
|
|
||||||
|
$this->assertSame($uri, $uri->withPath('/content/path')); |
||||||
|
$this->assertNotSame($uri, $uri->withPath('/another/path')); |
||||||
|
|
||||||
|
$this->assertSame($uri, $uri->withQuery('foo=some')); |
||||||
|
$this->assertNotSame($uri, $uri->withQuery('foo=another')); |
||||||
|
|
||||||
|
$this->assertSame($uri, $uri->withFragment('anchor')); |
||||||
|
$this->assertNotSame($uri, $uri->withFragment('another')); |
||||||
|
|
||||||
|
$this->assertSame($uri, $uri->withUserInfo('username', 'password')); |
||||||
|
$this->assertNotSame($uri, $uri->withUserInfo('username', 'another')); |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue