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