1<?php 2 3namespace GuzzleHttp\Psr7; 4 5use Psr\Http\Message\StreamInterface; 6 7/** 8 * Converts Guzzle streams into PHP stream resources. 9 * 10 * @final 11 */ 12class StreamWrapper 13{ 14 /** @var resource */ 15 public $context; 16 17 /** @var StreamInterface */ 18 private $stream; 19 20 /** @var string r, r+, or w */ 21 private $mode; 22 23 /** 24 * Returns a resource representing the stream. 25 * 26 * @param StreamInterface $stream The stream to get a resource for 27 * 28 * @return resource 29 * 30 * @throws \InvalidArgumentException if stream is not readable or writable 31 */ 32 public static function getResource(StreamInterface $stream) 33 { 34 self::register(); 35 36 if ($stream->isReadable()) { 37 $mode = $stream->isWritable() ? 'r+' : 'r'; 38 } elseif ($stream->isWritable()) { 39 $mode = 'w'; 40 } else { 41 throw new \InvalidArgumentException('The stream must be readable, ' 42 . 'writable, or both.'); 43 } 44 45 return fopen('guzzle://stream', $mode, null, self::createStreamContext($stream)); 46 } 47 48 /** 49 * Creates a stream context that can be used to open a stream as a php stream resource. 50 * 51 * @param StreamInterface $stream 52 * 53 * @return resource 54 */ 55 public static function createStreamContext(StreamInterface $stream) 56 { 57 return stream_context_create([ 58 'guzzle' => ['stream' => $stream] 59 ]); 60 } 61 62 /** 63 * Registers the stream wrapper if needed 64 */ 65 public static function register() 66 { 67 if (!in_array('guzzle', stream_get_wrappers())) { 68 stream_wrapper_register('guzzle', __CLASS__); 69 } 70 } 71 72 public function stream_open($path, $mode, $options, &$opened_path) 73 { 74 $options = stream_context_get_options($this->context); 75 76 if (!isset($options['guzzle']['stream'])) { 77 return false; 78 } 79 80 $this->mode = $mode; 81 $this->stream = $options['guzzle']['stream']; 82 83 return true; 84 } 85 86 public function stream_read($count) 87 { 88 return $this->stream->read($count); 89 } 90 91 public function stream_write($data) 92 { 93 return (int) $this->stream->write($data); 94 } 95 96 public function stream_tell() 97 { 98 return $this->stream->tell(); 99 } 100 101 public function stream_eof() 102 { 103 return $this->stream->eof(); 104 } 105 106 public function stream_seek($offset, $whence) 107 { 108 $this->stream->seek($offset, $whence); 109 110 return true; 111 } 112 113 public function stream_cast($cast_as) 114 { 115 $stream = clone($this->stream); 116 117 return $stream->detach(); 118 } 119 120 public function stream_stat() 121 { 122 static $modeMap = [ 123 'r' => 33060, 124 'rb' => 33060, 125 'r+' => 33206, 126 'w' => 33188, 127 'wb' => 33188 128 ]; 129 130 return [ 131 'dev' => 0, 132 'ino' => 0, 133 'mode' => $modeMap[$this->mode], 134 'nlink' => 0, 135 'uid' => 0, 136 'gid' => 0, 137 'rdev' => 0, 138 'size' => $this->stream->getSize() ?: 0, 139 'atime' => 0, 140 'mtime' => 0, 141 'ctime' => 0, 142 'blksize' => 0, 143 'blocks' => 0 144 ]; 145 } 146 147 public function url_stat($path, $flags) 148 { 149 return [ 150 'dev' => 0, 151 'ino' => 0, 152 'mode' => 0, 153 'nlink' => 0, 154 'uid' => 0, 155 'gid' => 0, 156 'rdev' => 0, 157 'size' => 0, 158 'atime' => 0, 159 'mtime' => 0, 160 'ctime' => 0, 161 'blksize' => 0, 162 'blocks' => 0 163 ]; 164 } 165} 166