See Release Notes
Long Term Support Release
Differences Between: [Versions 39 and 311] [Versions 39 and 400] [Versions 39 and 401]
1 <?php 2 /* 3 * Copyright 2016-2017 MongoDB, Inc. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 namespace MongoDB\GridFS; 19 20 use Exception; 21 use MongoDB\BSON\UTCDateTime; 22 use stdClass; 23 use function explode; 24 use function get_class; 25 use function in_array; 26 use function is_integer; 27 use function sprintf; 28 use function stream_context_get_options; 29 use function stream_get_wrappers; 30 use function stream_wrapper_register; 31 use function stream_wrapper_unregister; 32 use function trigger_error; 33 use const E_USER_WARNING; 34 use const SEEK_CUR; 35 use const SEEK_END; 36 use const SEEK_SET; 37 use const STREAM_IS_URL; 38 39 /** 40 * Stream wrapper for reading and writing a GridFS file. 41 * 42 * @internal 43 * @see Bucket::openUploadStream() 44 * @see Bucket::openDownloadStream() 45 */ 46 class StreamWrapper 47 { 48 /** @var resource|null Stream context (set by PHP) */ 49 public $context; 50 51 /** @var string|null */ 52 private $mode; 53 54 /** @var string|null */ 55 private $protocol; 56 57 /** @var ReadableStream|WritableStream|null */ 58 private $stream; 59 60 /** 61 * Return the stream's file document. 62 * 63 * @return stdClass 64 */ 65 public function getFile() 66 { 67 return $this->stream->getFile(); 68 } 69 70 /** 71 * Register the GridFS stream wrapper. 72 * 73 * @param string $protocol Protocol to use for stream_wrapper_register() 74 */ 75 public static function register($protocol = 'gridfs') 76 { 77 if (in_array($protocol, stream_get_wrappers())) { 78 stream_wrapper_unregister($protocol); 79 } 80 81 stream_wrapper_register($protocol, static::class, STREAM_IS_URL); 82 } 83 84 /** 85 * Closes the stream. 86 * 87 * @see http://php.net/manual/en/streamwrapper.stream-close.php 88 */ 89 public function stream_close() 90 { 91 $this->stream->close(); 92 } 93 94 /** 95 * Returns whether the file pointer is at the end of the stream. 96 * 97 * @see http://php.net/manual/en/streamwrapper.stream-eof.php 98 * @return boolean 99 */ 100 public function stream_eof() 101 { 102 if (! $this->stream instanceof ReadableStream) { 103 return false; 104 } 105 106 return $this->stream->isEOF(); 107 } 108 109 /** 110 * Opens the stream. 111 * 112 * @see http://php.net/manual/en/streamwrapper.stream-open.php 113 * @param string $path Path to the file resource 114 * @param string $mode Mode used to open the file (only "r" and "w" are supported) 115 * @param integer $options Additional flags set by the streams API 116 * @param string $openedPath Not used 117 * @return boolean 118 */ 119 public function stream_open($path, $mode, $options, &$openedPath) 120 { 121 $this->initProtocol($path); 122 $this->mode = $mode; 123 124 if ($mode === 'r') { 125 return $this->initReadableStream(); 126 } 127 128 if ($mode === 'w') { 129 return $this->initWritableStream(); 130 } 131 132 return false; 133 } 134 135 /** 136 * Read bytes from the stream. 137 * 138 * Note: this method may return a string smaller than the requested length 139 * if data is not available to be read. 140 * 141 * @see http://php.net/manual/en/streamwrapper.stream-read.php 142 * @param integer $length Number of bytes to read 143 * @return string 144 */ 145 public function stream_read($length) 146 { 147 if (! $this->stream instanceof ReadableStream) { 148 return ''; 149 } 150 151 try { 152 return $this->stream->readBytes($length); 153 } catch (Exception $e) { 154 trigger_error(sprintf('%s: %s', get_class($e), $e->getMessage()), E_USER_WARNING); 155 156 return false; 157 } 158 } 159 160 /** 161 * Return the current position of the stream. 162 * 163 * @see http://php.net/manual/en/streamwrapper.stream-seek.php 164 * @param integer $offset Stream offset to seek to 165 * @param integer $whence One of SEEK_SET, SEEK_CUR, or SEEK_END 166 * @return boolean True if the position was updated and false otherwise 167 */ 168 public function stream_seek($offset, $whence = SEEK_SET) 169 { 170 $size = $this->stream->getSize(); 171 172 if ($whence === SEEK_CUR) { 173 $offset += $this->stream->tell(); 174 } 175 176 if ($whence === SEEK_END) { 177 $offset += $size; 178 } 179 180 // WritableStreams are always positioned at the end of the stream 181 if ($this->stream instanceof WritableStream) { 182 return $offset === $size; 183 } 184 185 if ($offset < 0 || $offset > $size) { 186 return false; 187 } 188 189 $this->stream->seek($offset); 190 191 return true; 192 } 193 194 /** 195 * Return information about the stream. 196 * 197 * @see http://php.net/manual/en/streamwrapper.stream-stat.php 198 * @return array 199 */ 200 public function stream_stat() 201 { 202 $stat = $this->getStatTemplate(); 203 204 $stat[2] = $stat['mode'] = $this->stream instanceof ReadableStream 205 ? 0100444 // S_IFREG & S_IRUSR & S_IRGRP & S_IROTH 206 : 0100222; // S_IFREG & S_IWUSR & S_IWGRP & S_IWOTH 207 $stat[7] = $stat['size'] = $this->stream->getSize(); 208 209 $file = $this->stream->getFile(); 210 211 if (isset($file->uploadDate) && $file->uploadDate instanceof UTCDateTime) { 212 $timestamp = $file->uploadDate->toDateTime()->getTimestamp(); 213 $stat[9] = $stat['mtime'] = $timestamp; 214 $stat[10] = $stat['ctime'] = $timestamp; 215 } 216 217 if (isset($file->chunkSize) && is_integer($file->chunkSize)) { 218 $stat[11] = $stat['blksize'] = $file->chunkSize; 219 } 220 221 return $stat; 222 } 223 224 /** 225 * Return the current position of the stream. 226 * 227 * @see http://php.net/manual/en/streamwrapper.stream-tell.php 228 * @return integer The current position of the stream 229 */ 230 public function stream_tell() 231 { 232 return $this->stream->tell(); 233 } 234 235 /** 236 * Write bytes to the stream. 237 * 238 * @see http://php.net/manual/en/streamwrapper.stream-write.php 239 * @param string $data Data to write 240 * @return integer The number of bytes written 241 */ 242 public function stream_write($data) 243 { 244 if (! $this->stream instanceof WritableStream) { 245 return 0; 246 } 247 248 try { 249 return $this->stream->writeBytes($data); 250 } catch (Exception $e) { 251 trigger_error(sprintf('%s: %s', get_class($e), $e->getMessage()), E_USER_WARNING); 252 253 return false; 254 } 255 } 256 257 /** 258 * Returns a stat template with default values. 259 * 260 * @return array 261 */ 262 private function getStatTemplate() 263 { 264 return [ 265 // phpcs:disable Squiz.Arrays.ArrayDeclaration.IndexNoNewline 266 0 => 0, 'dev' => 0, 267 1 => 0, 'ino' => 0, 268 2 => 0, 'mode' => 0, 269 3 => 0, 'nlink' => 0, 270 4 => 0, 'uid' => 0, 271 5 => 0, 'gid' => 0, 272 6 => -1, 'rdev' => -1, 273 7 => 0, 'size' => 0, 274 8 => 0, 'atime' => 0, 275 9 => 0, 'mtime' => 0, 276 10 => 0, 'ctime' => 0, 277 11 => -1, 'blksize' => -1, 278 12 => -1, 'blocks' => -1, 279 // phpcs:enable 280 ]; 281 } 282 283 /** 284 * Initialize the protocol from the given path. 285 * 286 * @see StreamWrapper::stream_open() 287 * @param string $path 288 */ 289 private function initProtocol($path) 290 { 291 $parts = explode('://', $path, 2); 292 $this->protocol = $parts[0] ?: 'gridfs'; 293 } 294 295 /** 296 * Initialize the internal stream for reading. 297 * 298 * @see StreamWrapper::stream_open() 299 * @return boolean 300 */ 301 private function initReadableStream() 302 { 303 $context = stream_context_get_options($this->context); 304 305 $this->stream = new ReadableStream( 306 $context[$this->protocol]['collectionWrapper'], 307 $context[$this->protocol]['file'] 308 ); 309 310 return true; 311 } 312 313 /** 314 * Initialize the internal stream for writing. 315 * 316 * @see StreamWrapper::stream_open() 317 * @return boolean 318 */ 319 private function initWritableStream() 320 { 321 $context = stream_context_get_options($this->context); 322 323 $this->stream = new WritableStream( 324 $context[$this->protocol]['collectionWrapper'], 325 $context[$this->protocol]['filename'], 326 $context[$this->protocol]['options'] 327 ); 328 329 return true; 330 } 331 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body