Ne-Lexa /
php-zip
| 1 | <?php |
||||||||
| 2 | |||||||||
| 3 | namespace PhpZip\IO\Stream; |
||||||||
| 4 | |||||||||
| 5 | use PhpZip\Exception\ZipException; |
||||||||
| 6 | use PhpZip\Model\ZipEntry; |
||||||||
| 7 | |||||||||
| 8 | /** |
||||||||
| 9 | * The class provides stream reuse functionality. |
||||||||
| 10 | * |
||||||||
| 11 | * Stream will not be closed at {@see fclose}. |
||||||||
| 12 | * |
||||||||
| 13 | * @see https://www.php.net/streamwrapper |
||||||||
| 14 | */ |
||||||||
| 15 | final class ZipEntryStreamWrapper |
||||||||
| 16 | { |
||||||||
| 17 | /** @var string the registered protocol */ |
||||||||
| 18 | const PROTOCOL = 'zipentry'; |
||||||||
| 19 | |||||||||
| 20 | /** @var resource */ |
||||||||
| 21 | public $context; |
||||||||
| 22 | |||||||||
| 23 | /** @var resource */ |
||||||||
| 24 | private $fp; |
||||||||
| 25 | |||||||||
| 26 | /** |
||||||||
| 27 | * @return bool |
||||||||
| 28 | */ |
||||||||
| 29 | 8 | public static function register() |
|||||||
| 30 | { |
||||||||
| 31 | 8 | $protocol = self::PROTOCOL; |
|||||||
| 32 | |||||||||
| 33 | 8 | if (!\in_array($protocol, stream_get_wrappers(), true)) { |
|||||||
| 34 | 1 | if (!stream_wrapper_register($protocol, self::class)) { |
|||||||
| 35 | throw new \RuntimeException("Failed to register '{$protocol}://' protocol"); |
||||||||
| 36 | } |
||||||||
| 37 | |||||||||
| 38 | 1 | return true; |
|||||||
| 39 | } |
||||||||
| 40 | |||||||||
| 41 | 8 | return false; |
|||||||
| 42 | } |
||||||||
| 43 | |||||||||
| 44 | public static function unregister() |
||||||||
| 45 | { |
||||||||
| 46 | stream_wrapper_unregister(self::PROTOCOL); |
||||||||
| 47 | } |
||||||||
| 48 | |||||||||
| 49 | /** |
||||||||
| 50 | * @param ZipEntry $entry |
||||||||
| 51 | * |
||||||||
| 52 | * @return resource |
||||||||
| 53 | */ |
||||||||
| 54 | 8 | public static function wrap(ZipEntry $entry) |
|||||||
| 55 | { |
||||||||
| 56 | 8 | self::register(); |
|||||||
| 57 | |||||||||
| 58 | 8 | $context = stream_context_create( |
|||||||
| 59 | [ |
||||||||
| 60 | 8 | self::PROTOCOL => [ |
|||||||
| 61 | 8 | 'entry' => $entry, |
|||||||
| 62 | ], |
||||||||
| 63 | ] |
||||||||
| 64 | ); |
||||||||
| 65 | |||||||||
| 66 | 8 | $uri = self::PROTOCOL . '://' . $entry->getName(); |
|||||||
| 67 | 8 | $fp = fopen($uri, 'r+b', false, $context); |
|||||||
| 68 | |||||||||
| 69 | 8 | if ($fp === false) { |
|||||||
| 70 | throw new \RuntimeException('Error open ' . $uri); |
||||||||
| 71 | } |
||||||||
| 72 | |||||||||
| 73 | 8 | return $fp; |
|||||||
| 74 | } |
||||||||
| 75 | |||||||||
| 76 | /** |
||||||||
| 77 | * Opens file or URL. |
||||||||
| 78 | * |
||||||||
| 79 | * This method is called immediately after the wrapper is |
||||||||
| 80 | * initialized (f.e. by {@see fopen()} and {@see file_get_contents()}). |
||||||||
| 81 | * |
||||||||
| 82 | * @param string $path specifies the URL that was passed to |
||||||||
| 83 | * the original function |
||||||||
| 84 | * @param string $mode the mode used to open the file, as detailed |
||||||||
| 85 | * for {@see fopen()} |
||||||||
| 86 | * @param int $options Holds additional flags set by the streams |
||||||||
| 87 | * API. It can hold one or more of the |
||||||||
| 88 | * following values OR'd together. |
||||||||
| 89 | * @param string $opened_path if the path is opened successfully, and |
||||||||
| 90 | * STREAM_USE_PATH is set in options, |
||||||||
| 91 | * opened_path should be set to the |
||||||||
| 92 | * full path of the file/resource that |
||||||||
| 93 | * was actually opened |
||||||||
| 94 | * |
||||||||
| 95 | * @throws ZipException |
||||||||
| 96 | * |
||||||||
| 97 | * @return bool |
||||||||
| 98 | * |
||||||||
| 99 | * @see https://www.php.net/streamwrapper.stream-open |
||||||||
| 100 | */ |
||||||||
| 101 | 8 | public function stream_open($path, $mode, $options, &$opened_path) |
|||||||
|
0 ignored issues
–
show
The parameter
$opened_path is not used and could be removed.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for parameters that have been defined for a function or method, but which are not used in the method body. Loading history...
The parameter
$options is not used and could be removed.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for parameters that have been defined for a function or method, but which are not used in the method body. Loading history...
The parameter
$path is not used and could be removed.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for parameters that have been defined for a function or method, but which are not used in the method body. Loading history...
|
|||||||||
| 102 | { |
||||||||
| 103 | 8 | if ($this->context === null) { |
|||||||
| 104 | throw new \RuntimeException('stream context is null'); |
||||||||
| 105 | } |
||||||||
| 106 | 8 | $streamOptions = stream_context_get_options($this->context); |
|||||||
| 107 | |||||||||
| 108 | 8 | if (!isset($streamOptions[self::PROTOCOL]['entry'])) { |
|||||||
| 109 | throw new \RuntimeException('no stream option ["' . self::PROTOCOL . '"]["entry"]'); |
||||||||
| 110 | } |
||||||||
| 111 | 8 | $zipEntry = $streamOptions[self::PROTOCOL]['entry']; |
|||||||
| 112 | |||||||||
| 113 | 8 | if (!$zipEntry instanceof ZipEntry) { |
|||||||
| 114 | throw new \RuntimeException('invalid stream context'); |
||||||||
| 115 | } |
||||||||
| 116 | |||||||||
| 117 | 8 | $zipData = $zipEntry->getData(); |
|||||||
| 118 | |||||||||
| 119 | 8 | if ($zipData === null) { |
|||||||
| 120 | throw new ZipException(sprintf('No data for zip entry "%s"', $zipEntry->getName())); |
||||||||
| 121 | } |
||||||||
| 122 | 8 | $this->fp = $zipData->getDataAsStream(); |
|||||||
| 123 | |||||||||
| 124 | 8 | return $this->fp !== false; |
|||||||
| 125 | } |
||||||||
| 126 | |||||||||
| 127 | /** |
||||||||
| 128 | * Read from stream. |
||||||||
| 129 | * |
||||||||
| 130 | * This method is called in response to {@see fread()} and {@see fgets()}. |
||||||||
| 131 | * |
||||||||
| 132 | * Note: Remember to update the read/write position of the stream |
||||||||
| 133 | * (by the number of bytes that were successfully read). |
||||||||
| 134 | * |
||||||||
| 135 | * @param int $count how many bytes of data from the current |
||||||||
| 136 | * position should be returned |
||||||||
| 137 | * |
||||||||
| 138 | * @return false|string If there are less than count bytes available, |
||||||||
| 139 | * return as many as are available. If no more data |
||||||||
| 140 | * is available, return either FALSE or |
||||||||
| 141 | * an empty string. |
||||||||
| 142 | * |
||||||||
| 143 | * @see https://www.php.net/streamwrapper.stream-read |
||||||||
| 144 | */ |
||||||||
| 145 | 8 | public function stream_read($count) |
|||||||
| 146 | { |
||||||||
| 147 | 8 | return fread($this->fp, $count); |
|||||||
| 148 | } |
||||||||
| 149 | |||||||||
| 150 | /** |
||||||||
| 151 | * Seeks to specific location in a stream. |
||||||||
| 152 | * |
||||||||
| 153 | * This method is called in response to {@see fseek()}. |
||||||||
| 154 | * The read/write position of the stream should be updated according |
||||||||
| 155 | * to the offset and whence. |
||||||||
| 156 | * |
||||||||
| 157 | * @param int $offset the stream offset to seek to |
||||||||
| 158 | * @param int $whence Possible values: |
||||||||
| 159 | * {@see \SEEK_SET} - Set position equal to offset bytes. |
||||||||
| 160 | * {@see \SEEK_CUR} - Set position to current location plus offset. |
||||||||
| 161 | * {@see \SEEK_END} - Set position to end-of-file plus offset. |
||||||||
| 162 | * |
||||||||
| 163 | * @return bool return TRUE if the position was updated, FALSE otherwise |
||||||||
| 164 | * |
||||||||
| 165 | * @see https://www.php.net/streamwrapper.stream-seek |
||||||||
| 166 | */ |
||||||||
| 167 | 8 | public function stream_seek($offset, $whence = \SEEK_SET) |
|||||||
| 168 | { |
||||||||
| 169 | 8 | return fseek($this->fp, $offset, $whence) === 0; |
|||||||
| 170 | } |
||||||||
| 171 | |||||||||
| 172 | /** |
||||||||
| 173 | * Retrieve the current position of a stream. |
||||||||
| 174 | * |
||||||||
| 175 | * This method is called in response to {@see fseek()} to determine |
||||||||
| 176 | * the current position. |
||||||||
| 177 | * |
||||||||
| 178 | * @return int should return the current position of the stream |
||||||||
| 179 | * |
||||||||
| 180 | * @see https://www.php.net/streamwrapper.stream-tell |
||||||||
| 181 | */ |
||||||||
| 182 | 8 | public function stream_tell() |
|||||||
| 183 | { |
||||||||
| 184 | 8 | $pos = ftell($this->fp); |
|||||||
| 185 | |||||||||
| 186 | 8 | if ($pos === false) { |
|||||||
| 187 | throw new \RuntimeException('Cannot get stream position.'); |
||||||||
| 188 | } |
||||||||
| 189 | |||||||||
| 190 | 8 | return $pos; |
|||||||
| 191 | } |
||||||||
| 192 | |||||||||
| 193 | /** |
||||||||
| 194 | * Tests for end-of-file on a file pointer. |
||||||||
| 195 | * |
||||||||
| 196 | * This method is called in response to {@see feof()}. |
||||||||
| 197 | * |
||||||||
| 198 | * @return bool should return TRUE if the read/write position is at |
||||||||
| 199 | * the end of the stream and if no more data is available |
||||||||
| 200 | * to be read, or FALSE otherwise |
||||||||
| 201 | * |
||||||||
| 202 | * @see https://www.php.net/streamwrapper.stream-eof |
||||||||
| 203 | */ |
||||||||
| 204 | 8 | public function stream_eof() |
|||||||
| 205 | { |
||||||||
| 206 | 8 | return feof($this->fp); |
|||||||
| 207 | } |
||||||||
| 208 | |||||||||
| 209 | /** |
||||||||
| 210 | * Retrieve information about a file resource. |
||||||||
| 211 | * |
||||||||
| 212 | * This method is called in response to {@see fstat()}. |
||||||||
| 213 | * |
||||||||
| 214 | * @return array |
||||||||
| 215 | * |
||||||||
| 216 | * @see https://www.php.net/streamwrapper.stream-stat |
||||||||
| 217 | * @see https://www.php.net/stat |
||||||||
| 218 | * @see https://www.php.net/fstat |
||||||||
| 219 | */ |
||||||||
| 220 | 8 | public function stream_stat() |
|||||||
| 221 | { |
||||||||
| 222 | 8 | return fstat($this->fp); |
|||||||
| 223 | } |
||||||||
| 224 | |||||||||
| 225 | /** |
||||||||
| 226 | * Flushes the output. |
||||||||
| 227 | * |
||||||||
| 228 | * This method is called in response to {@see fflush()} and when the |
||||||||
| 229 | * stream is being closed while any unflushed data has been written to |
||||||||
| 230 | * it before. |
||||||||
| 231 | * If you have cached data in your stream but not yet stored it into |
||||||||
| 232 | * the underlying storage, you should do so now. |
||||||||
| 233 | * |
||||||||
| 234 | * @return bool should return TRUE if the cached data was successfully |
||||||||
| 235 | * stored (or if there was no data to store), or FALSE |
||||||||
| 236 | * if the data could not be stored |
||||||||
| 237 | * |
||||||||
| 238 | * @see https://www.php.net/streamwrapper.stream-flush |
||||||||
| 239 | */ |
||||||||
| 240 | public function stream_flush() |
||||||||
| 241 | { |
||||||||
| 242 | return fflush($this->fp); |
||||||||
| 243 | } |
||||||||
| 244 | |||||||||
| 245 | /** |
||||||||
| 246 | * Truncate stream. |
||||||||
| 247 | * |
||||||||
| 248 | * Will respond to truncation, e.g., through {@see ftruncate()}. |
||||||||
| 249 | * |
||||||||
| 250 | * @param int $new_size the new size |
||||||||
| 251 | * |
||||||||
| 252 | * @return bool returns TRUE on success or FALSE on failure |
||||||||
| 253 | * |
||||||||
| 254 | * @see https://www.php.net/streamwrapper.stream-truncate |
||||||||
| 255 | */ |
||||||||
| 256 | public function stream_truncate($new_size) |
||||||||
| 257 | { |
||||||||
| 258 | return ftruncate($this->fp, (int) $new_size); |
||||||||
| 259 | } |
||||||||
| 260 | |||||||||
| 261 | /** |
||||||||
| 262 | * Write to stream. |
||||||||
| 263 | * |
||||||||
| 264 | * This method is called in response to {@see fwrite().} |
||||||||
| 265 | * |
||||||||
| 266 | * Note: Remember to update the current position of the stream by |
||||||||
| 267 | * number of bytes that were successfully written. |
||||||||
| 268 | * |
||||||||
| 269 | * @param string $data should be stored into the underlying stream |
||||||||
| 270 | * |
||||||||
| 271 | * @return int should return the number of bytes that were successfully stored, or 0 if none could be stored |
||||||||
| 272 | * |
||||||||
| 273 | * @see https://www.php.net/streamwrapper.stream-write |
||||||||
| 274 | */ |
||||||||
| 275 | public function stream_write($data) |
||||||||
| 276 | { |
||||||||
| 277 | $bytes = fwrite($this->fp, $data); |
||||||||
| 278 | |||||||||
| 279 | return $bytes === false ? 0 : $bytes; |
||||||||
| 280 | } |
||||||||
| 281 | |||||||||
| 282 | /** |
||||||||
| 283 | * Retrieve the underlaying resource. |
||||||||
| 284 | * |
||||||||
| 285 | * This method is called in response to {@see stream_select()}. |
||||||||
| 286 | * |
||||||||
| 287 | * @param int $cast_as can be {@see STREAM_CAST_FOR_SELECT} when {@see stream_select()} |
||||||||
| 288 | * is callingstream_cast() or {@see STREAM_CAST_AS_STREAM} when |
||||||||
| 289 | * stream_cast() is called for other uses |
||||||||
| 290 | * |
||||||||
| 291 | * @return resource |
||||||||
| 292 | */ |
||||||||
| 293 | public function stream_cast($cast_as) |
||||||||
|
0 ignored issues
–
show
The parameter
$cast_as is not used and could be removed.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for parameters that have been defined for a function or method, but which are not used in the method body. Loading history...
|
|||||||||
| 294 | { |
||||||||
| 295 | return $this->fp; |
||||||||
| 296 | } |
||||||||
| 297 | |||||||||
| 298 | /** |
||||||||
| 299 | * Close a resource. |
||||||||
| 300 | * |
||||||||
| 301 | * This method is called in response to {@see fclose()}. |
||||||||
| 302 | * All resources that were locked, or allocated, by the wrapper should be released. |
||||||||
| 303 | * |
||||||||
| 304 | * @see https://www.php.net/streamwrapper.stream-close |
||||||||
| 305 | */ |
||||||||
| 306 | 8 | public function stream_close() |
|||||||
| 307 | { |
||||||||
| 308 | 8 | } |
|||||||
| 309 | } |
||||||||
| 310 |
This check looks for parameters that have been defined for a function or method, but which are not used in the method body.