1<?php 2 3/* 4 * This file is part of the Symfony package. 5 * 6 * (c) Fabien Potencier <fabien@symfony.com> 7 * 8 * For the full copyright and license information, please view the LICENSE 9 * file that was distributed with this source code. 10 */ 11 12namespace Symfony\Component\HttpFoundation\File; 13 14use Symfony\Component\HttpFoundation\File\Exception\FileException; 15use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException; 16use Symfony\Component\Mime\MimeTypes; 17 18/** 19 * A file in the file system. 20 * 21 * @author Bernhard Schussek <bschussek@gmail.com> 22 */ 23class File extends \SplFileInfo 24{ 25 /** 26 * Constructs a new file from the given path. 27 * 28 * @param string $path The path to the file 29 * @param bool $checkPath Whether to check the path or not 30 * 31 * @throws FileNotFoundException If the given path is not a file 32 */ 33 public function __construct(string $path, bool $checkPath = true) 34 { 35 if ($checkPath && !is_file($path)) { 36 throw new FileNotFoundException($path); 37 } 38 39 parent::__construct($path); 40 } 41 42 /** 43 * Returns the extension based on the mime type. 44 * 45 * If the mime type is unknown, returns null. 46 * 47 * This method uses the mime type as guessed by getMimeType() 48 * to guess the file extension. 49 * 50 * @return string|null The guessed extension or null if it cannot be guessed 51 * 52 * @see MimeTypes 53 * @see getMimeType() 54 */ 55 public function guessExtension() 56 { 57 return MimeTypes::getDefault()->getExtensions($this->getMimeType())[0] ?? null; 58 } 59 60 /** 61 * Returns the mime type of the file. 62 * 63 * The mime type is guessed using a MimeTypeGuesserInterface instance, 64 * which uses finfo_file() then the "file" system binary, 65 * depending on which of those are available. 66 * 67 * @return string|null The guessed mime type (e.g. "application/pdf") 68 * 69 * @see MimeTypes 70 */ 71 public function getMimeType() 72 { 73 return MimeTypes::getDefault()->guessMimeType($this->getPathname()); 74 } 75 76 /** 77 * Moves the file to a new location. 78 * 79 * @return self A File object representing the new file 80 * 81 * @throws FileException if the target file could not be created 82 */ 83 public function move(string $directory, string $name = null) 84 { 85 $target = $this->getTargetFile($directory, $name); 86 87 set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; }); 88 $renamed = rename($this->getPathname(), $target); 89 restore_error_handler(); 90 if (!$renamed) { 91 throw new FileException(sprintf('Could not move the file "%s" to "%s" (%s).', $this->getPathname(), $target, strip_tags($error))); 92 } 93 94 @chmod($target, 0666 & ~umask()); 95 96 return $target; 97 } 98 99 /** 100 * @return self 101 */ 102 protected function getTargetFile(string $directory, string $name = null) 103 { 104 if (!is_dir($directory)) { 105 if (false === @mkdir($directory, 0777, true) && !is_dir($directory)) { 106 throw new FileException(sprintf('Unable to create the "%s" directory.', $directory)); 107 } 108 } elseif (!is_writable($directory)) { 109 throw new FileException(sprintf('Unable to write in the "%s" directory.', $directory)); 110 } 111 112 $target = rtrim($directory, '/\\').\DIRECTORY_SEPARATOR.(null === $name ? $this->getBasename() : $this->getName($name)); 113 114 return new self($target, false); 115 } 116 117 /** 118 * Returns locale independent base name of the given path. 119 * 120 * @return string 121 */ 122 protected function getName(string $name) 123 { 124 $originalName = str_replace('\\', '/', $name); 125 $pos = strrpos($originalName, '/'); 126 $originalName = false === $pos ? $originalName : substr($originalName, $pos + 1); 127 128 return $originalName; 129 } 130} 131