Differences Between: [Versions 311 and 401] [Versions 311 and 402] [Versions 311 and 403]
1 <?php 2 declare(strict_types=1); 3 4 namespace ZipStream; 5 6 use Psr\Http\Message\StreamInterface; 7 use RuntimeException; 8 9 /** 10 * Describes a data stream. 11 * 12 * Typically, an instance will wrap a PHP stream; this interface provides 13 * a wrapper around the most common operations, including serialization of 14 * the entire stream to a string. 15 */ 16 class Stream implements StreamInterface 17 { 18 protected $stream; 19 20 public function __construct($stream) 21 { 22 $this->stream = $stream; 23 } 24 25 /** 26 * Closes the stream and any underlying resources. 27 * 28 * @return void 29 */ 30 public function close(): void 31 { 32 if (is_resource($this->stream)) { 33 fclose($this->stream); 34 } 35 $this->detach(); 36 } 37 38 /** 39 * Separates any underlying resources from the stream. 40 * 41 * After the stream has been detached, the stream is in an unusable state. 42 * 43 * @return resource|null Underlying PHP stream, if any 44 */ 45 public function detach() 46 { 47 $result = $this->stream; 48 $this->stream = null; 49 return $result; 50 } 51 52 /** 53 * Reads all data from the stream into a string, from the beginning to end. 54 * 55 * This method MUST attempt to seek to the beginning of the stream before 56 * reading data and read the stream until the end is reached. 57 * 58 * Warning: This could attempt to load a large amount of data into memory. 59 * 60 * This method MUST NOT raise an exception in order to conform with PHP's 61 * string casting operations. 62 * 63 * @see http://php.net/manual/en/language.oop5.magic.php#object.tostring 64 * @return string 65 */ 66 public function __toString(): string 67 { 68 try { 69 $this->seek(0); 70 } catch (\RuntimeException $e) {} 71 return (string) stream_get_contents($this->stream); 72 } 73 74 /** 75 * Seek to a position in the stream. 76 * 77 * @link http://www.php.net/manual/en/function.fseek.php 78 * @param int $offset Stream offset 79 * @param int $whence Specifies how the cursor position will be calculated 80 * based on the seek offset. Valid values are identical to the built-in 81 * PHP $whence values for `fseek()`. SEEK_SET: Set position equal to 82 * offset bytes SEEK_CUR: Set position to current location plus offset 83 * SEEK_END: Set position to end-of-stream plus offset. 84 * @throws \RuntimeException on failure. 85 */ 86 public function seek($offset, $whence = SEEK_SET): void 87 { 88 if (!$this->isSeekable()) { 89 throw new RuntimeException; 90 } 91 if (fseek($this->stream, $offset, $whence) !== 0) { 92 throw new RuntimeException; 93 } 94 } 95 96 /** 97 * Returns whether or not the stream is seekable. 98 * 99 * @return bool 100 */ 101 public function isSeekable(): bool 102 { 103 return (bool)$this->getMetadata('seekable'); 104 } 105 106 /** 107 * Get stream metadata as an associative array or retrieve a specific key. 108 * 109 * The keys returned are identical to the keys returned from PHP's 110 * stream_get_meta_data() function. 111 * 112 * @link http://php.net/manual/en/function.stream-get-meta-data.php 113 * @param string $key Specific metadata to retrieve. 114 * @return array|mixed|null Returns an associative array if no key is 115 * provided. Returns a specific key value if a key is provided and the 116 * value is found, or null if the key is not found. 117 */ 118 public function getMetadata($key = null) 119 { 120 $metadata = stream_get_meta_data($this->stream); 121 return $key !== null ? @$metadata[$key] : $metadata; 122 } 123 124 /** 125 * Get the size of the stream if known. 126 * 127 * @return int|null Returns the size in bytes if known, or null if unknown. 128 */ 129 public function getSize(): ?int 130 { 131 $stats = fstat($this->stream); 132 return $stats['size']; 133 } 134 135 /** 136 * Returns the current position of the file read/write pointer 137 * 138 * @return int Position of the file pointer 139 * @throws \RuntimeException on error. 140 */ 141 public function tell(): int 142 { 143 $position = ftell($this->stream); 144 if ($position === false) { 145 throw new RuntimeException; 146 } 147 return $position; 148 } 149 150 /** 151 * Returns true if the stream is at the end of the stream. 152 * 153 * @return bool 154 */ 155 public function eof(): bool 156 { 157 return feof($this->stream); 158 } 159 160 /** 161 * Seek to the beginning of the stream. 162 * 163 * If the stream is not seekable, this method will raise an exception; 164 * otherwise, it will perform a seek(0). 165 * 166 * @see seek() 167 * @link http://www.php.net/manual/en/function.fseek.php 168 * @throws \RuntimeException on failure. 169 */ 170 public function rewind(): void 171 { 172 $this->seek(0); 173 } 174 175 /** 176 * Write data to the stream. 177 * 178 * @param string $string The string that is to be written. 179 * @return int Returns the number of bytes written to the stream. 180 * @throws \RuntimeException on failure. 181 */ 182 public function write($string): int 183 { 184 if (!$this->isWritable()) { 185 throw new RuntimeException; 186 } 187 if (fwrite($this->stream, $string) === false) { 188 throw new RuntimeException; 189 } 190 return \mb_strlen($string); 191 } 192 193 /** 194 * Returns whether or not the stream is writable. 195 * 196 * @return bool 197 */ 198 public function isWritable(): bool 199 { 200 return preg_match('/[waxc+]/', $this->getMetadata('mode')) === 1; 201 } 202 203 /** 204 * Read data from the stream. 205 * 206 * @param int $length Read up to $length bytes from the object and return 207 * them. Fewer than $length bytes may be returned if underlying stream 208 * call returns fewer bytes. 209 * @return string Returns the data read from the stream, or an empty string 210 * if no bytes are available. 211 * @throws \RuntimeException if an error occurs. 212 */ 213 public function read($length): string 214 { 215 if (!$this->isReadable()) { 216 throw new RuntimeException; 217 } 218 $result = fread($this->stream, $length); 219 if ($result === false) { 220 throw new RuntimeException; 221 } 222 return $result; 223 } 224 225 /** 226 * Returns whether or not the stream is readable. 227 * 228 * @return bool 229 */ 230 public function isReadable(): bool 231 { 232 return preg_match('/[r+]/', $this->getMetadata('mode')) === 1; 233 } 234 235 /** 236 * Returns the remaining contents in a string 237 * 238 * @return string 239 * @throws \RuntimeException if unable to read or an error occurs while 240 * reading. 241 */ 242 public function getContents(): string 243 { 244 if (!$this->isReadable()) { 245 throw new RuntimeException; 246 } 247 $result = stream_get_contents($this->stream); 248 if ($result === false) { 249 throw new RuntimeException; 250 } 251 return $result; 252 } 253 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body