MediaWiki  master
UploadedFileStream.php
Go to the documentation of this file.
1 <?php
2 
4 
5 use Psr\Http\Message\StreamInterface;
6 use RuntimeException;
7 use Throwable;
8 use Wikimedia\AtEase\AtEase;
9 
20 class UploadedFileStream implements StreamInterface {
21 
23  private $fp;
24 
26  private $size = false;
27 
37  private static function quietCall( callable $func, array $args, $fail, $msg ) {
38  error_clear_last();
39  $ret = AtEase::quietCall( $func, ...$args );
40  if ( $ret === $fail ) {
41  $err = error_get_last();
42  throw new RuntimeException( "$msg: " . ( $err['message'] ?? 'Unknown error' ) );
43  }
44  return $ret;
45  }
46 
50  public function __construct( $filename ) {
51  $this->fp = self::quietCall( 'fopen', [ $filename, 'r' ], false, 'Failed to open file' );
52  }
53 
58  private function checkOpen() {
59  if ( !$this->fp ) {
60  throw new RuntimeException( 'Stream is not open' );
61  }
62  }
63 
64  public function __destruct() {
65  $this->close();
66  }
67 
68  public function __toString() {
69  try {
70  $this->seek( 0 );
71  return $this->getContents();
72  } catch ( Throwable $ex ) {
73  // Not allowed to throw
74  return '';
75  }
76  }
77 
78  public function close() {
79  if ( $this->fp ) {
80  // Spec doesn't care about close errors.
81  try {
82  // PHP 7 emits warnings, suppress
83  AtEase::quietCall( 'fclose', $this->fp );
84  } catch ( \TypeError $unused ) {
85  // While PHP 8 throws exceptions, ignore
86  }
87  $this->fp = null;
88  }
89  }
90 
91  public function detach() {
92  $ret = $this->fp;
93  $this->fp = null;
94  return $ret;
95  }
96 
97  public function getSize() {
98  if ( $this->size === false ) {
99  $this->size = null;
100 
101  if ( $this->fp ) {
102  // Spec doesn't care about errors here.
103  try {
104  $stat = AtEase::quietCall( 'fstat', $this->fp );
105  } catch ( \TypeError $unused ) {
106  }
107  $this->size = $stat['size'] ?? null;
108  }
109  }
110 
111  return $this->size;
112  }
113 
114  public function tell() {
115  $this->checkOpen();
116  return self::quietCall( 'ftell', [ $this->fp ], -1, 'Cannot determine stream position' );
117  }
118 
119  public function eof() {
120  // Spec doesn't care about errors here.
121  try {
122  return !$this->fp || AtEase::quietCall( 'feof', $this->fp );
123  } catch ( \TypeError $unused ) {
124  return true;
125  }
126  }
127 
128  public function isSeekable() {
129  return (bool)$this->fp;
130  }
131 
132  public function seek( $offset, $whence = SEEK_SET ) {
133  $this->checkOpen();
134  self::quietCall( 'fseek', [ $this->fp, $offset, $whence ], -1, 'Seek failed' );
135  }
136 
137  public function rewind() {
138  $this->seek( 0 );
139  }
140 
141  public function isWritable() {
142  return false;
143  }
144 
145  public function write( $string ) {
146  // @phan-suppress-previous-line PhanPluginNeverReturnMethod
147  $this->checkOpen();
148  throw new RuntimeException( 'Stream is read-only' );
149  }
150 
151  public function isReadable() {
152  return (bool)$this->fp;
153  }
154 
155  public function read( $length ) {
156  $this->checkOpen();
157  return self::quietCall( 'fread', [ $this->fp, $length ], false, 'Read failed' );
158  }
159 
160  public function getContents() {
161  $this->checkOpen();
162  return self::quietCall( 'stream_get_contents', [ $this->fp ], false, 'Read failed' );
163  }
164 
165  public function getMetadata( $key = null ) {
166  $this->checkOpen();
167  $ret = self::quietCall( 'stream_get_meta_data', [ $this->fp ], false, 'Metadata fetch failed' );
168  if ( $key !== null ) {
169  $ret = $ret[$key] ?? null;
170  }
171  return $ret;
172  }
173 
174 }
Wikimedia\ParamValidator\Util\UploadedFileStream\quietCall
static quietCall(callable $func, array $args, $fail, $msg)
Call, throwing on error.
Definition: UploadedFileStream.php:37
Wikimedia\ParamValidator\Util\UploadedFileStream\rewind
rewind()
Definition: UploadedFileStream.php:137
Wikimedia\ParamValidator\Util\UploadedFileStream\read
read( $length)
Definition: UploadedFileStream.php:155
Wikimedia\ParamValidator\Util\UploadedFileStream\$fp
resource null $fp
File handle.
Definition: UploadedFileStream.php:23
Wikimedia\ParamValidator\Util\UploadedFileStream
Implementation of StreamInterface for a file in $_FILES.
Definition: UploadedFileStream.php:20
Wikimedia\ParamValidator\Util\UploadedFileStream\isWritable
isWritable()
Definition: UploadedFileStream.php:141
Wikimedia\ParamValidator\Util\UploadedFileStream\detach
detach()
Definition: UploadedFileStream.php:91
Wikimedia\ParamValidator\Util\UploadedFileStream\checkOpen
checkOpen()
Check if the stream is open.
Definition: UploadedFileStream.php:58
Wikimedia\ParamValidator\Util\UploadedFileStream\getMetadata
getMetadata( $key=null)
Definition: UploadedFileStream.php:165
Wikimedia\ParamValidator\Util\UploadedFileStream\$size
int false null $size
File size.
Definition: UploadedFileStream.php:26
Wikimedia\ParamValidator\Util\UploadedFileStream\seek
seek( $offset, $whence=SEEK_SET)
Definition: UploadedFileStream.php:132
Wikimedia\ParamValidator\Util\UploadedFileStream\getSize
getSize()
Definition: UploadedFileStream.php:97
Wikimedia\ParamValidator\Util\UploadedFileStream\isSeekable
isSeekable()
Definition: UploadedFileStream.php:128
$args
if( $line===false) $args
Definition: mcc.php:124
Wikimedia\ParamValidator\Util\UploadedFileStream\eof
eof()
Definition: UploadedFileStream.php:119
Wikimedia\ParamValidator\Util\UploadedFileStream\__toString
__toString()
Definition: UploadedFileStream.php:68
Wikimedia\ParamValidator\Util\UploadedFileStream\__construct
__construct( $filename)
Definition: UploadedFileStream.php:50
Wikimedia\ParamValidator\Util\UploadedFileStream\tell
tell()
Definition: UploadedFileStream.php:114
Wikimedia\ParamValidator\Util
Definition: UploadedFile.php:3
Wikimedia\ParamValidator\Util\UploadedFileStream\close
close()
Definition: UploadedFileStream.php:78
Wikimedia\ParamValidator\Util\UploadedFileStream\getContents
getContents()
Definition: UploadedFileStream.php:160
Wikimedia\ParamValidator\Util\UploadedFileStream\write
write( $string)
Definition: UploadedFileStream.php:145
Wikimedia\ParamValidator\Util\UploadedFileStream\__destruct
__destruct()
Definition: UploadedFileStream.php:64
Wikimedia\ParamValidator\Util\UploadedFileStream\isReadable
isReadable()
Definition: UploadedFileStream.php:151