123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290 |
- <?php
- namespace Symfony\Component\HttpFoundation\File;
- use Symfony\Component\HttpFoundation\File\Exception\CannotWriteFileException;
- use Symfony\Component\HttpFoundation\File\Exception\ExtensionFileException;
- use Symfony\Component\HttpFoundation\File\Exception\FileException;
- use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
- use Symfony\Component\HttpFoundation\File\Exception\FormSizeFileException;
- use Symfony\Component\HttpFoundation\File\Exception\IniSizeFileException;
- use Symfony\Component\HttpFoundation\File\Exception\NoFileException;
- use Symfony\Component\HttpFoundation\File\Exception\NoTmpDirFileException;
- use Symfony\Component\HttpFoundation\File\Exception\PartialFileException;
- use Symfony\Component\Mime\MimeTypes;
- class UploadedFile extends File
- {
- private $test;
- private $originalName;
- private $mimeType;
- private $error;
-
- public function __construct(string $path, string $originalName, string $mimeType = null, int $error = null, bool $test = false)
- {
- $this->originalName = $this->getName($originalName);
- $this->mimeType = $mimeType ?: 'application/octet-stream';
- $this->error = $error ?: \UPLOAD_ERR_OK;
- $this->test = $test;
- parent::__construct($path, \UPLOAD_ERR_OK === $this->error);
- }
-
- public function getClientOriginalName()
- {
- return $this->originalName;
- }
-
- public function getClientOriginalExtension()
- {
- return pathinfo($this->originalName, \PATHINFO_EXTENSION);
- }
-
- public function getClientMimeType()
- {
- return $this->mimeType;
- }
-
- public function guessClientExtension()
- {
- if (!class_exists(MimeTypes::class)) {
- throw new \LogicException('You cannot guess the extension as the Mime component is not installed. Try running "composer require symfony/mime".');
- }
- return MimeTypes::getDefault()->getExtensions($this->getClientMimeType())[0] ?? null;
- }
-
- public function getError()
- {
- return $this->error;
- }
-
- public function isValid()
- {
- $isOk = \UPLOAD_ERR_OK === $this->error;
- return $this->test ? $isOk : $isOk && is_uploaded_file($this->getPathname());
- }
-
- public function move(string $directory, string $name = null)
- {
- if ($this->isValid()) {
- if ($this->test) {
- return parent::move($directory, $name);
- }
- $target = $this->getTargetFile($directory, $name);
- set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; });
- try {
- $moved = move_uploaded_file($this->getPathname(), $target);
- } finally {
- restore_error_handler();
- }
- if (!$moved) {
- throw new FileException(sprintf('Could not move the file "%s" to "%s" (%s).', $this->getPathname(), $target, strip_tags($error)));
- }
- @chmod($target, 0666 & ~umask());
- return $target;
- }
- switch ($this->error) {
- case \UPLOAD_ERR_INI_SIZE:
- throw new IniSizeFileException($this->getErrorMessage());
- case \UPLOAD_ERR_FORM_SIZE:
- throw new FormSizeFileException($this->getErrorMessage());
- case \UPLOAD_ERR_PARTIAL:
- throw new PartialFileException($this->getErrorMessage());
- case \UPLOAD_ERR_NO_FILE:
- throw new NoFileException($this->getErrorMessage());
- case \UPLOAD_ERR_CANT_WRITE:
- throw new CannotWriteFileException($this->getErrorMessage());
- case \UPLOAD_ERR_NO_TMP_DIR:
- throw new NoTmpDirFileException($this->getErrorMessage());
- case \UPLOAD_ERR_EXTENSION:
- throw new ExtensionFileException($this->getErrorMessage());
- }
- throw new FileException($this->getErrorMessage());
- }
-
- public static function getMaxFilesize()
- {
- $sizePostMax = self::parseFilesize(\ini_get('post_max_size'));
- $sizeUploadMax = self::parseFilesize(\ini_get('upload_max_filesize'));
- return min($sizePostMax ?: \PHP_INT_MAX, $sizeUploadMax ?: \PHP_INT_MAX);
- }
-
- private static function parseFilesize(string $size)
- {
- if ('' === $size) {
- return 0;
- }
- $size = strtolower($size);
- $max = ltrim($size, '+');
- if (str_starts_with($max, '0x')) {
- $max = \intval($max, 16);
- } elseif (str_starts_with($max, '0')) {
- $max = \intval($max, 8);
- } else {
- $max = (int) $max;
- }
- switch (substr($size, -1)) {
- case 't': $max *= 1024;
-
- case 'g': $max *= 1024;
-
- case 'm': $max *= 1024;
-
- case 'k': $max *= 1024;
- }
- return $max;
- }
-
- public function getErrorMessage()
- {
- static $errors = [
- \UPLOAD_ERR_INI_SIZE => 'The file "%s" exceeds your upload_max_filesize ini directive (limit is %d KiB).',
- \UPLOAD_ERR_FORM_SIZE => 'The file "%s" exceeds the upload limit defined in your form.',
- \UPLOAD_ERR_PARTIAL => 'The file "%s" was only partially uploaded.',
- \UPLOAD_ERR_NO_FILE => 'No file was uploaded.',
- \UPLOAD_ERR_CANT_WRITE => 'The file "%s" could not be written on disk.',
- \UPLOAD_ERR_NO_TMP_DIR => 'File could not be uploaded: missing temporary directory.',
- \UPLOAD_ERR_EXTENSION => 'File upload was stopped by a PHP extension.',
- ];
- $errorCode = $this->error;
- $maxFilesize = \UPLOAD_ERR_INI_SIZE === $errorCode ? self::getMaxFilesize() / 1024 : 0;
- $message = $errors[$errorCode] ?? 'The file "%s" was not uploaded due to an unknown error.';
- return sprintf($message, $this->getClientOriginalName(), $maxFilesize);
- }
- }
|