2015-08-27 12:03:05 -07:00
< ? php
/**
* Zend Framework ( http :// framework . zend . com / )
*
* @ see http :// github . com / zendframework / zend - diactoros for the canonical source repository
* @ copyright Copyright ( c ) 2015 Zend Technologies USA Inc . ( http :// www . zend . com )
* @ license https :// github . com / zendframework / zend - diactoros / blob / master / LICENSE . md New BSD License
*/
namespace Zend\Diactoros ;
use InvalidArgumentException ;
use RuntimeException ;
use Psr\Http\Message\StreamInterface ;
/**
* Implementation of PSR HTTP streams
*/
class Stream implements StreamInterface
{
/**
* @ var resource
*/
protected $resource ;
/**
* @ var string | resource
*/
protected $stream ;
/**
* @ param string | resource $stream
* @ param string $mode Mode with which to open stream
* @ throws InvalidArgumentException
*/
public function __construct ( $stream , $mode = 'r' )
{
2015-10-08 11:40:12 -07:00
$this -> setStream ( $stream , $mode );
2015-08-27 12:03:05 -07:00
}
/**
* { @ inheritdoc }
*/
public function __toString ()
{
if ( ! $this -> isReadable ()) {
return '' ;
}
try {
$this -> rewind ();
return $this -> getContents ();
} catch ( RuntimeException $e ) {
return '' ;
}
}
/**
* { @ inheritdoc }
*/
public function close ()
{
if ( ! $this -> resource ) {
return ;
}
$resource = $this -> detach ();
fclose ( $resource );
}
/**
* { @ inheritdoc }
*/
public function detach ()
{
$resource = $this -> resource ;
$this -> resource = null ;
return $resource ;
}
/**
* Attach a new stream / resource to the instance .
*
* @ param string | resource $resource
* @ param string $mode
* @ throws InvalidArgumentException for stream identifier that cannot be
* cast to a resource
* @ throws InvalidArgumentException for non - resource stream
*/
public function attach ( $resource , $mode = 'r' )
{
2015-10-08 11:40:12 -07:00
$this -> setStream ( $resource , $mode );
2015-08-27 12:03:05 -07:00
}
/**
* { @ inheritdoc }
*/
public function getSize ()
{
if ( null === $this -> resource ) {
return null ;
}
$stats = fstat ( $this -> resource );
return $stats [ 'size' ];
}
/**
* { @ inheritdoc }
*/
public function tell ()
{
if ( ! $this -> resource ) {
throw new RuntimeException ( 'No resource available; cannot tell position' );
}
$result = ftell ( $this -> resource );
if ( ! is_int ( $result )) {
throw new RuntimeException ( 'Error occurred during tell operation' );
}
return $result ;
}
/**
* { @ inheritdoc }
*/
public function eof ()
{
if ( ! $this -> resource ) {
return true ;
}
return feof ( $this -> resource );
}
/**
* { @ inheritdoc }
*/
public function isSeekable ()
{
if ( ! $this -> resource ) {
return false ;
}
$meta = stream_get_meta_data ( $this -> resource );
return $meta [ 'seekable' ];
}
/**
* { @ inheritdoc }
*/
public function seek ( $offset , $whence = SEEK_SET )
{
if ( ! $this -> resource ) {
throw new RuntimeException ( 'No resource available; cannot seek position' );
}
if ( ! $this -> isSeekable ()) {
throw new RuntimeException ( 'Stream is not seekable' );
}
$result = fseek ( $this -> resource , $offset , $whence );
if ( 0 !== $result ) {
throw new RuntimeException ( 'Error seeking within stream' );
}
return true ;
}
/**
* { @ inheritdoc }
*/
public function rewind ()
{
return $this -> seek ( 0 );
}
/**
* { @ inheritdoc }
*/
public function isWritable ()
{
if ( ! $this -> resource ) {
return false ;
}
$meta = stream_get_meta_data ( $this -> resource );
$mode = $meta [ 'mode' ];
return (
strstr ( $mode , 'x' )
|| strstr ( $mode , 'w' )
|| strstr ( $mode , 'c' )
|| strstr ( $mode , 'a' )
|| strstr ( $mode , '+' )
);
}
/**
* { @ inheritdoc }
*/
public function write ( $string )
{
if ( ! $this -> resource ) {
throw new RuntimeException ( 'No resource available; cannot write' );
}
if ( ! $this -> isWritable ()) {
throw new RuntimeException ( 'Stream is not writable' );
}
$result = fwrite ( $this -> resource , $string );
if ( false === $result ) {
throw new RuntimeException ( 'Error writing to stream' );
}
return $result ;
}
/**
* { @ inheritdoc }
*/
public function isReadable ()
{
if ( ! $this -> resource ) {
return false ;
}
$meta = stream_get_meta_data ( $this -> resource );
$mode = $meta [ 'mode' ];
return ( strstr ( $mode , 'r' ) || strstr ( $mode , '+' ));
}
/**
* { @ inheritdoc }
*/
public function read ( $length )
{
if ( ! $this -> resource ) {
throw new RuntimeException ( 'No resource available; cannot read' );
}
if ( ! $this -> isReadable ()) {
throw new RuntimeException ( 'Stream is not readable' );
}
$result = fread ( $this -> resource , $length );
if ( false === $result ) {
throw new RuntimeException ( 'Error reading stream' );
}
return $result ;
}
/**
* { @ inheritdoc }
*/
public function getContents ()
{
if ( ! $this -> isReadable ()) {
throw new RuntimeException ( 'Stream is not readable' );
}
$result = stream_get_contents ( $this -> resource );
if ( false === $result ) {
throw new RuntimeException ( 'Error reading from stream' );
}
return $result ;
}
/**
* { @ inheritdoc }
*/
public function getMetadata ( $key = null )
{
if ( null === $key ) {
return stream_get_meta_data ( $this -> resource );
}
$metadata = stream_get_meta_data ( $this -> resource );
if ( ! array_key_exists ( $key , $metadata )) {
return null ;
}
return $metadata [ $key ];
}
2015-10-08 11:40:12 -07:00
/**
* Set the internal stream resource .
*
* @ param string | resource $stream String stream target or stream resource .
* @ param string $mode Resource mode for stream target .
* @ throws InvalidArgumentException for invalid streams or resources .
*/
private function setStream ( $stream , $mode = 'r' )
{
$error = null ;
$resource = $stream ;
if ( is_string ( $stream )) {
set_error_handler ( function ( $e ) use ( & $error ) {
$error = $e ;
}, E_WARNING );
$resource = fopen ( $stream , $mode );
restore_error_handler ();
}
if ( $error ) {
throw new InvalidArgumentException ( 'Invalid stream reference provided' );
}
if ( ! is_resource ( $resource ) || 'stream' !== get_resource_type ( $resource )) {
throw new InvalidArgumentException (
'Invalid stream provided; must be a string stream identifier or stream resource'
);
}
if ( $stream !== $resource ) {
$this -> stream = $stream ;
}
$this -> resource = $resource ;
}
2015-08-27 12:03:05 -07:00
}