1 | <?php |
||
2 | /** |
||
3 | * This file is part of the O2System Framework package. |
||
4 | * |
||
5 | * For the full copyright and license information, please view the LICENSE |
||
6 | * file that was distributed with this source code. |
||
7 | * |
||
8 | * @author Steeve Andrian Salim |
||
9 | * @copyright Copyright (c) Steeve Andrian Salim |
||
10 | */ |
||
11 | |||
12 | // ------------------------------------------------------------------------ |
||
13 | |||
14 | namespace O2System\Kernel\Http\Message; |
||
15 | |||
16 | |||
17 | use O2System\Psr\Http\Message\StreamInterface; |
||
18 | use O2System\Psr\Http\Message\UploadedFileInterface; |
||
19 | use O2System\Spl\Exceptions\Logic\BadFunctionCall\BadPhpExtensionCallException; |
||
20 | |||
21 | class UploadFile implements UploadedFileInterface |
||
22 | { |
||
23 | /** |
||
24 | * UploadFile::$name |
||
25 | * |
||
26 | * @var string |
||
27 | */ |
||
28 | protected $name; |
||
29 | |||
30 | /** |
||
31 | * UploadFile::$type |
||
32 | * |
||
33 | * @var string |
||
34 | */ |
||
35 | protected $type; |
||
36 | |||
37 | /** |
||
38 | * UploadFile::$tmpName |
||
39 | * |
||
40 | * @var string |
||
41 | */ |
||
42 | protected $tmpName; |
||
43 | |||
44 | /** |
||
45 | * UploadFile::$size |
||
46 | * |
||
47 | * @var int |
||
48 | */ |
||
49 | protected $size; |
||
50 | |||
51 | /** |
||
52 | * UploadFile::$error |
||
53 | * |
||
54 | * @var mixed |
||
55 | */ |
||
56 | protected $error; |
||
57 | |||
58 | /** |
||
59 | * UploadFIle::$isMoved |
||
60 | * |
||
61 | * @var bool |
||
62 | */ |
||
63 | protected $isMoved = false; |
||
64 | |||
65 | /** |
||
66 | * Uploader File Stream |
||
67 | * |
||
68 | * @var Stream |
||
69 | */ |
||
70 | protected $stream; |
||
71 | |||
72 | // ------------------------------------------------------------------------ |
||
73 | |||
74 | /** |
||
75 | * UploadFile::__construct |
||
76 | * |
||
77 | * @param array $uploadedFile |
||
78 | * |
||
79 | * @throws \O2System\Spl\Exceptions\Logic\BadFunctionCall\BadPhpExtensionCallException |
||
80 | */ |
||
81 | public function __construct(array $uploadedFile) |
||
82 | { |
||
83 | if ( ! class_exists('finfo')) { |
||
84 | throw new BadPhpExtensionCallException('E_HEADER_BADPHPEXTENSIONCALLEXCEPTION', 1); |
||
85 | } |
||
86 | |||
87 | $this->name = $uploadedFile[ 'name' ]; |
||
88 | $this->type = $uploadedFile[ 'type' ]; |
||
89 | $this->tmpName = $uploadedFile[ 'tmp_name' ]; |
||
90 | $this->size = $uploadedFile[ 'size' ]; |
||
91 | $this->error = $uploadedFile[ 'error' ]; |
||
92 | } |
||
93 | |||
94 | // ------------------------------------------------------------------------ |
||
95 | |||
96 | /** |
||
97 | * UploadedFileInterface::getStream |
||
98 | * |
||
99 | * Retrieve a stream representing the uploaded file. |
||
100 | * |
||
101 | * This method MUST return a StreamInterface instance, representing the |
||
102 | * uploaded file. The purpose of this method is to allow utilizing native PHP |
||
103 | * stream functionality to manipulate the file upload, such as |
||
104 | * stream_copy_to_stream() (though the result will need to be decorated in a |
||
105 | * native PHP stream wrapper to work with such functions). |
||
106 | * |
||
107 | * If the moveTo() method has been called previously, this method MUST raise |
||
108 | * an exception. |
||
109 | * |
||
110 | * @return StreamInterface Stream representation of the uploaded file. |
||
111 | * @throws \RuntimeException in cases when no stream is available. |
||
112 | * @throws \RuntimeException in cases when no stream can be created. |
||
113 | */ |
||
114 | public function getStream() |
||
115 | { |
||
116 | if ($this->isMoved) { |
||
117 | throw new \RuntimeException('File Has Been Already Moved'); |
||
118 | } |
||
119 | |||
120 | if ($this->stream === null) { |
||
121 | $context = fopen($this->tmpName, 'r'); |
||
122 | |||
123 | if (is_resource($context)) { |
||
124 | $this->stream = new Stream(); |
||
125 | } else { |
||
126 | throw new \RuntimeException('Cannot create stream context'); |
||
127 | } |
||
128 | } |
||
129 | |||
130 | return $this->stream; |
||
131 | } |
||
132 | |||
133 | // ------------------------------------------------------------------------ |
||
134 | |||
135 | /** |
||
136 | * UploadedFileInterface::moveTo |
||
137 | * |
||
138 | * Move the uploaded file to a new location. |
||
139 | * |
||
140 | * Use this method as an alternative to move_uploaded_file(). This method is |
||
141 | * guaranteed to work in both SAPI and non-SAPI environments. |
||
142 | * Implementations must determine which environment they are in, and use the |
||
143 | * appropriate method (move_uploaded_file(), rename(), or a stream |
||
144 | * operation) to perform the operation. |
||
145 | * |
||
146 | * $targetPath may be an absolute path, or a relative path. If it is a |
||
147 | * relative path, resolution should be the same as used by PHP's rename() |
||
148 | * function. |
||
149 | * |
||
150 | * The original file or stream MUST be removed on completion. |
||
151 | * |
||
152 | * If this method is called more than once, any subsequent calls MUST raise |
||
153 | * an exception. |
||
154 | * |
||
155 | * When used in an SAPI environment where $_FILES is populated, when writing |
||
156 | * files via moveTo(), is_uploaded_file() and move_uploaded_file() SHOULD be |
||
157 | * used to ensure permissions and upload status are verified correctly. |
||
158 | * |
||
159 | * If you wish to move to a stream, use getStream(), as SAPI operations |
||
160 | * cannot guarantee writing to stream destinations. |
||
161 | * |
||
162 | * @see http://php.net/is_uploaded_file |
||
163 | * @see http://php.net/move_uploaded_file |
||
164 | * |
||
165 | * @param string $targetPath Path to which to move the uploaded file. |
||
166 | * |
||
167 | * @throws \InvalidArgumentException if the $targetPath specified is invalid. |
||
168 | * @throws \RuntimeException on any errors during the move operation. |
||
169 | * @throws \RuntimeException on the second or subsequent call to the method. |
||
170 | */ |
||
171 | public function moveTo($targetPath) |
||
172 | { |
||
173 | if ($this->isMoved) { |
||
174 | throw new \RuntimeException('Uploaded File Has Been Moved'); |
||
175 | } |
||
176 | |||
177 | if ( ! is_writable(dirname($targetPath))) { |
||
178 | @mkdir(dirname($targetPath), 0777, true); |
||
0 ignored issues
–
show
|
|||
179 | } |
||
180 | |||
181 | if (strpos($targetPath, '://') !== false) { |
||
182 | if ( ! copy($this->tmpName, $targetPath)) { |
||
183 | throw new \RuntimeException(sprintf('Cant Move Uploaded File %1 to %2', $this->tmpName, $targetPath)); |
||
184 | } |
||
185 | |||
186 | if ( ! unlink($this->tmpName)) { |
||
187 | throw new \RuntimeException('Failed To Remove Uploaded Temp File'); |
||
188 | } |
||
189 | } else { |
||
190 | if ( ! is_uploaded_file($this->tmpName)) { |
||
191 | throw new \RuntimeException('File Is Not Valid Uploaded File'); |
||
192 | } |
||
193 | |||
194 | if ( ! move_uploaded_file($this->tmpName, $targetPath)) { |
||
195 | throw new \RuntimeException(sprintf('Cant Move Uploaded File %1 to %2', $this->tmpName, $targetPath)); |
||
196 | } |
||
197 | } |
||
198 | |||
199 | $this->isMoved = true; |
||
200 | } |
||
201 | |||
202 | // ------------------------------------------------------------------------ |
||
203 | |||
204 | /** |
||
205 | * UploadedFileInterface::getSize |
||
206 | * |
||
207 | * Retrieve the file size. |
||
208 | * |
||
209 | * Implementations SHOULD return the value stored in the "size" key of |
||
210 | * the file in the $_FILES array if available, as PHP calculates this based |
||
211 | * on the actual size transmitted. |
||
212 | * |
||
213 | * @return int|null The file size in bytes or null if unknown. |
||
214 | */ |
||
215 | public function getSize() |
||
216 | { |
||
217 | return $this->size; |
||
218 | } |
||
219 | |||
220 | // ------------------------------------------------------------------------ |
||
221 | |||
222 | /** |
||
223 | * UploadedFileInterface::getError |
||
224 | * |
||
225 | * Retrieve the error associated with the uploaded file. |
||
226 | * |
||
227 | * The return value MUST be one of PHP's UPLOAD_ERR_XXX constants. |
||
228 | * |
||
229 | * If the file was uploaded successfully, this method MUST return |
||
230 | * UPLOAD_ERR_OK. |
||
231 | * |
||
232 | * Implementations SHOULD return the value stored in the "error" key of |
||
233 | * the file in the $_FILES array. |
||
234 | * |
||
235 | * @see http://php.net/manual/en/features.file-upload.error.php |
||
236 | * @return int One of PHP's UPLOAD_ERR_XXX constants. |
||
237 | */ |
||
238 | public function getError() |
||
239 | { |
||
240 | return $this->error; |
||
241 | } |
||
242 | |||
243 | // ------------------------------------------------------------------------ |
||
244 | |||
245 | /** |
||
246 | * UploadedFileInterface::getClientFilename |
||
247 | * |
||
248 | * Retrieve the filename sent by the client. |
||
249 | * |
||
250 | * Do not trust the value returned by this method. A client could send |
||
251 | * a malicious filename with the intention to corrupt or hack your |
||
252 | * application. |
||
253 | * |
||
254 | * Implementations SHOULD return the value stored in the "name" key of |
||
255 | * the file in the $_FILES array. |
||
256 | * |
||
257 | * @return string|null The filename sent by the client or null if none |
||
258 | * was provided. |
||
259 | */ |
||
260 | public function getClientFilename() |
||
261 | { |
||
262 | return $this->name; |
||
263 | } |
||
264 | |||
265 | // ------------------------------------------------------------------------ |
||
266 | |||
267 | /** |
||
268 | * UploadedFileInterface::getClientMediaType |
||
269 | * |
||
270 | * Retrieve the media type sent by the client. |
||
271 | * |
||
272 | * Do not trust the value returned by this method. A client could send |
||
273 | * a malicious media type with the intention to corrupt or hack your |
||
274 | * application. |
||
275 | * |
||
276 | * Implementations SHOULD return the value stored in the "type" key of |
||
277 | * the file in the $_FILES array. |
||
278 | * |
||
279 | * @return string|null The media type sent by the client or null if none |
||
280 | * was provided. |
||
281 | */ |
||
282 | public function getClientMediaType() |
||
283 | { |
||
284 | return $this->type; |
||
285 | } |
||
286 | |||
287 | // -------------------------------------------------------------------------------------- |
||
288 | |||
289 | /** |
||
290 | * UploadFile::getFileMime |
||
291 | * |
||
292 | * Get file mime type |
||
293 | * |
||
294 | * @return string |
||
295 | */ |
||
296 | public function getFileMime() |
||
297 | { |
||
298 | $mime = finfo_file(finfo_open(FILEINFO_MIME_TYPE), $this->tmpName); |
||
299 | |||
300 | return $mime; |
||
301 | } |
||
302 | |||
303 | // -------------------------------------------------------------------------------------- |
||
304 | |||
305 | /** |
||
306 | * UploadFile::getExtension |
||
307 | * |
||
308 | * Get uploaded file extension |
||
309 | * |
||
310 | * @return string |
||
311 | */ |
||
312 | public function getExtension() |
||
313 | { |
||
314 | return pathinfo($this->name, PATHINFO_EXTENSION); |
||
315 | } |
||
316 | |||
317 | // ------------------------------------------------------------------------ |
||
318 | |||
319 | /** |
||
320 | * UploadFile::getFileTemp |
||
321 | * |
||
322 | * @return mixed|string |
||
323 | */ |
||
324 | public function getFileTemp() |
||
325 | { |
||
326 | return $this->tmpName; |
||
327 | } |
||
328 | |||
329 | } |
If you suppress an error, we recommend checking for the error condition explicitly: