PluginProbe
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration / 1.91.6
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration v1.91.6
2.1.0 2.0.15 2.0.12 2.0.10 2.0.4 2.0.1 2.0.0 1.95.3 1.95.2 1.95 1.91.6 trunk 1.11 1.12 1.13 1.20 1.21 1.22 1.23 1.30 1.31 1.32 1.35 1.40 1.41 All 42 releases
fluent-boards / vendor / wpfluent / framework / src / WPFluent / Http / Request / File.php

File.php in FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration 1.91.6, at vendor/wpfluent/framework/src/WPFluent/Http/Request/File.php

558 lines 13.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentBoards\Framework\Http\Request;
4
5 use ArrayAccess;
6 use SplFileInfo;
7 use JsonSerializable;
8 use RuntimeException;
9 use FluentBoards\Framework\Support\Util;
10 use FluentBoards\Framework\Foundation\App;
11 use FluentBoards\Framework\Validator\Contracts\File as Contract;
12
13 class File extends SplFileInfo implements Contract, JsonSerializable, ArrayAccess
14 {
15 /**
16 * Original file name.
17 *
18 * @var string $originalName
19 */
20 private $originalName;
21
22 /**
23 * Mime type of the file.
24 *
25 * @var string $mimeType
26 */
27 private $mimeType;
28
29 /**
30 * File size in bytes.
31 *
32 * @var int|null $size
33 */
34 private $size;
35
36 /**
37 * File upload error.
38 *
39 * @var int $error
40 */
41 private $error;
42
43 /**
44 * HTTP File instantiator.
45 *
46 * @param $path
47 * @param $originalName
48 * @param null $mimeType
49 * @param null $size
50 * @param null $error
51 */
52 public function __construct(
53 $path,
54 $originalName,
55 $mimeType = null,
56 $size = null,
57 $error = null
58 ) {
59 $this->init($path, $size, $error);
60 $this->originalName = $this->getName($originalName);
61 $this->mimeType = $this->getFileMimeType($mimeType);
62 }
63
64 /**
65 * Init the file object with size and error.
66 *
67 * @param string $path
68 * @param int|null $size
69 * @param string|nill $error
70 * @return void
71 */
72 protected function init($path, $size, $error)
73 {
74 $this->size = $size ?: @filesize($path);
75 $this->error = $error ?: UPLOAD_ERR_OK;
76 parent::__construct($path);
77 }
78
79 /**
80 * @taken from \Symfony\Component\HttpFoundation\File\File
81 *
82 * Returns locale independent base name of the given path.
83 *
84 * @param string $name The new file name
85 *
86 * @return string containing
87 */
88 public function getName($name)
89 {
90 $originalName = str_replace('\\', '/', $name);
91
92 $pos = strrpos($originalName, '/');
93
94 $originalName = false === $pos ? $originalName : substr(
95 $originalName, $pos + 1
96 );
97
98 return sanitize_file_name($originalName);
99 }
100
101 public function getFileMimeType($mimeType)
102 {
103 $mimeType = $mimeType ?: $this->getMimeType();
104
105 if (!$mimeType) {
106 $path = $this->getPathname() ?: $this->getRealPath();
107
108 if (!file_exists($path)) {
109 throw new RuntimeException(
110 "File does not exist at path: $path"
111 );
112 }
113
114 if ($handle = @fopen($path, 'rb')) {
115 $data = fread($handle, 8192);
116 $finfo = new \finfo(FILEINFO_MIME_TYPE);
117 $mimeType = $finfo->buffer($data);
118 fclose($handle);
119 } else {
120 throw new RuntimeException(
121 "Failed to open file at path: $path"
122 );
123 }
124 }
125
126 return $mimeType ?: 'application/octet-stream';
127 }
128
129 /**
130 * Get the file upload error.
131 *
132 * @return int
133 */
134 public function getError()
135 {
136 return $this->error;
137 }
138
139 /**
140 * Returns whether the file was uploaded successfully.
141 *
142 * @return bool True if the file has been uploaded with HTTP and no error occurred
143 */
144 public function isValid()
145 {
146 $isOk = UPLOAD_ERR_OK === $this->getError();
147
148 return $isOk && is_uploaded_file($this->getPathname());
149 }
150
151 /**
152 * Returns the original file name.
153 *
154 * @return string The Name Of the file
155 */
156 public function getClientOriginalName()
157 {
158 return $this->originalName;
159 }
160
161 /**
162 * Returns the original file extension.
163 *
164 * It is extracted from the original file name that was uploaded.
165 * Then it should not be considered as a safe value.
166 *
167 * @return string The extension
168 */
169 public function getClientOriginalExtension()
170 {
171 return pathinfo($this->originalName, PATHINFO_EXTENSION);
172 }
173
174 /**
175 * Take an educated guess of the file's extension.
176 *
177 * @return mixed|null
178 */
179 public function guessExtension()
180 {
181 return $this->getMimeTypeAndExtension()['ext'];
182 }
183
184 /**
185 * Take an educated guess of the file's mime type.
186 *
187 * @return string
188 */
189 public function getMimeType()
190 {
191 return $this->getMimeTypeAndExtension()['type'];
192 }
193
194 /**
195 * Take an educated guess of the file's mime type and ext
196 * based on the WordsPress' get_allowed_mime_types.
197 *
198 * @return array
199 * @see https://developer.wordpress.org/reference/functions/get_allowed_mime_types
200 * @see https://developer.wordpress.org/reference/functions/wp_get_mime_types
201 */
202 public function getMimeTypeAndExtension()
203 {
204 $path = $this->getPathname();
205
206 if(!function_exists('wp_check_filetype_and_ext')) {
207 require_once ABSPATH .'wp-admin/includes/file.php';
208 }
209
210 return wp_check_filetype_and_ext($path, $this->originalName);
211 }
212
213 /**
214 * Get the file name.
215 *
216 * @return string
217 */
218 public function getSavedFileName()
219 {
220 if ($name = $this->originalName) {
221 return $name;
222 }
223
224 return basename($this->getPathname());
225 }
226
227 /**
228 * Get the url from path.
229 *
230 * @return string
231 */
232 public function getUrl()
233 {
234 return $this->url($this->getPathname());
235 }
236
237 /**
238 * Returns the contents of the file.
239 *
240 * @return string the contents of the file
241 *
242 * @throws RuntimeException
243 */
244 public function getContents()
245 {
246 $level = error_reporting(0);
247 $content = file_get_contents($this->getPathname());
248 error_reporting($level);
249 if (false === $content) {
250 $error = error_get_last();
251 throw new RuntimeException($error['message']);
252 }
253
254 return $content;
255 }
256
257 /**
258 * Move the file to a new location.
259 *
260 * @param string $directory Target Path
261 * @param string $name Target file name (optional)
262 * @return self
263 * @throws RuntimeException
264 */
265 public function move($directory, $name = null)
266 {
267 $err = '';
268
269 $target = $this->getTargetFile($directory, $name);
270
271 set_error_handler(function ($_, $msg) use (&$err) { $err = $msg; });
272
273 try {
274 $renamed = rename($this->getPathname(), $target);
275 } finally {
276 restore_error_handler();
277 }
278
279 if (!$renamed) {
280 throw new RuntimeException(
281 sprintf(
282 'Could not move the file "%s" to "%s" (%s).',
283 $this->getPathname(), $target, strip_tags($err)
284 )
285 );
286 }
287
288 @chmod($target, 0666 & ~umask());
289
290 return new static($target, basename($target));
291 }
292
293 /**
294 * Save the uploaded file.
295 *
296 * @param string $path
297 * @return self (File Object)
298 * @throws RuntimeException
299 */
300 public function save($path = null)
301 {
302 $path = $this->resolveTargetPath($path);
303
304 return $this->move($path);
305 }
306
307 /**
308 * Save the uploaded file with a given name.
309 *
310 * @param string $name
311 * @param string $path
312 * @return self (File Object)
313 * @throws RuntimeException
314 */
315 public function saveAs($name, $path = null)
316 {
317 $path = $this->resolveTargetPath($path);
318
319 return $this->move($path, $name);
320 }
321
322 /**
323 * Check that the given path exists.
324 *
325 * @param string $path
326 * @return string
327 * @throws RuntimeException
328 */
329 protected function resolveTargetPath($path)
330 {
331 if ($this->isAbsolutePath($path)) {
332
333 $pieces = array_values(
334 array_filter(
335 explode(DIRECTORY_SEPARATOR, $path)
336 )
337 );
338
339 // Sometimes developers can pass a relative directory like an
340 // absolute directory so in that case, If the root is not a
341 // real directory then make it relative and resolve it:
342 // i.e: 'a/relative/path/looks/like/an/absolute/path'
343
344 if (!is_dir(DIRECTORY_SEPARATOR.$pieces[0])) {
345 return $this->resolveTargetPath(trim($path, DIRECTORY_SEPARATOR));
346 }
347
348 $path = dirname($this->getTargetFile($path));
349
350 if (!is_dir($path)) {
351 throw new RuntimeException("Invalid file upload path: {$path}");
352 }
353
354 return $path;
355 }
356
357 $config = App::make('config');
358
359 $default = $config->get(
360 'app.file_upload_path', function() use ($config) {
361 $slug = $config->get('app.slug');
362 $uploadDir = wp_upload_dir()['basedir'];
363 $uploadDir .= DIRECTORY_SEPARATOR . $slug;
364 return $uploadDir;
365 }
366 );
367
368 $path = trim(
369 ($default . DIRECTORY_SEPARATOR . $path), DIRECTORY_SEPARATOR
370 );
371
372 $baseDir = trim(wp_upload_dir()['basedir'], DIRECTORY_SEPARATOR);
373
374 if (strpos($path, $baseDir) !== 0) {
375 $path = $baseDir . DIRECTORY_SEPARATOR . $path;
376 }
377
378 if (is_file($path)) {
379 throw new RuntimeException("Invalid file upload path: {$path}");
380 }
381
382 return DIRECTORY_SEPARATOR.$path;
383 }
384
385 /**
386 * Check if given path is absolute.
387 *
388 * @param string $path
389 * @return boolean
390 */
391 function isAbsolutePath($path)
392 {
393 if (!$path) return false;
394
395 // For Unix-like systems
396 if (DIRECTORY_SEPARATOR === '/') {
397 return $path[0] === '/';
398 }
399
400 // For Windows
401 if (DIRECTORY_SEPARATOR === '\\') {
402 return preg_match(
403 '/^[a-zA-Z]:\\\\/', $path
404 ) || substr($path, 0, 2) === '\\\\';
405 }
406
407 return false;
408 }
409
410 /**
411 * Get the URL from the file path.
412 *
413 * @param string $path
414 * @return string
415 */
416 public function url($path = '')
417 {
418 return Util::pathToUrl($path ?: $this->getPathname());
419 }
420
421 /**
422 * Get the target file name to move (full path).
423 *
424 * @param string $directory Target Path
425 * @param string $name Target file name (optional)
426 * @return self
427 * @throws RuntimeException
428 */
429 protected function getTargetFile($directory, $name = null)
430 {
431 if (!is_dir($directory)) {
432 if (false === @mkdir($directory, 0777, true) && !is_dir($directory)) {
433 throw new RuntimeException(
434 sprintf('Unable to create the "%s" directory.', $directory)
435 );
436 }
437 } elseif (!is_writable($directory)) {
438 throw new RuntimeException(
439 sprintf('Unable to write in the "%s" directory.', $directory)
440 );
441 }
442
443 return $this->makeTargetPath($directory, $name);
444 }
445
446 /**
447 * Resolves the absolute path for saving.
448 *
449 * @param string $dir
450 * @param string $name
451 * @return string
452 */
453 protected function makeTargetPath($dir, $name)
454 {
455 return $dir . DIRECTORY_SEPARATOR . $this->resolveFileName($name);
456 }
457
458 /**
459 * Resolves the file name for saving.
460 *
461 * @param string|null $name
462 * @return string
463 */
464 protected function resolveFileName($name = null)
465 {
466 if ($name) {
467 $name = $this->getName($name);
468 if (!$this->hasExtension($name)) {
469 $name .= '.' . $this->guessExtension();
470 }
471 } else {
472 $name = $this->originalName;
473 }
474
475 return $name;
476 }
477
478 /**
479 * Check if the given filename has an extension.
480 *
481 * @param string $filename
482 * @return boolean
483 */
484 protected function hasExtension($filename)
485 {
486 $info = pathinfo($filename);
487 return isset($info['extension']) && $info['extension'] !== '';
488 }
489
490 /**
491 * Get original HTTP file array
492 *
493 * @return array
494 */
495 public function toArray()
496 {
497 return [
498 'type' => $this->mimeType,
499 'size_in_bytes' => $this->size,
500 'size' => size_format($this->size),
501 'name' => $this->getSavedFileName(),
502 'path' => $this->getPathname(),
503 'url' => $this->getUrl(),
504 'tmp_name' => $this->getPathname(),
505 'error' => $this->getError(),
506 ];
507 }
508
509 /**
510 * JsonSerialize implementation
511 * @return array
512 */
513 #[\ReturnTypeWillChange]
514 public function jsonSerialize()
515 {
516 return $this->toArray();
517 }
518
519 /* ArrayAccess methods */
520
521 /**
522 * Check if the property exists.
523 * @param string $offset
524 * @return bool
525 */
526 #[\ReturnTypeWillChange]
527 public function offsetExists($offset)
528 {
529 return array_key_exists($offset, $this->toArray());
530 }
531
532 /**
533 * Get the property.
534 *
535 * @param string $offset
536 * @return string
537 */
538 #[\ReturnTypeWillChange]
539 public function offsetGet($offset)
540 {
541 $array = $this->toArray();
542
543 return $array[$offset] ?? null;
544 }
545
546 #[\ReturnTypeWillChange]
547 public function offsetSet($offset, $value)
548 {
549 //...
550 }
551
552 #[\ReturnTypeWillChange]
553 public function offsetUnset($offset)
554 {
555 //...
556 }
557 }
558