diff --git a/src/Symfony/Component/HttpFoundation/File/File.php b/src/Symfony/Component/HttpFoundation/File/File.php index 729d870cfc..9002b51085 100644 --- a/src/Symfony/Component/HttpFoundation/File/File.php +++ b/src/Symfony/Component/HttpFoundation/File/File.php @@ -49,9 +49,15 @@ class File extends \SplFileInfo * * If the mime type is unknown, returns null. * + * This method uses the mime type as guessed by getMimeType() + * to guess the file extension. + * * @return string|null The guessed extension or null if it cannot be guessed * * @api + * + * @see ExtensionGuesser + * @see getMimeType() */ public function guessExtension() { @@ -64,12 +70,14 @@ class File extends \SplFileInfo /** * Returns the mime type of the file. * - * The mime type is guessed using the functions finfo(), mime_content_type() - * and the system binary "file" (in this order), depending on which of those - * is available on the current operating system. + * The mime type is guessed using a MimeTypeGuesser instance, which uses finfo(), + * mime_content_type() and the system binary "file" (in this order), depending on + * which of those are available. * * @return string|null The guessed mime type (i.e. "application/pdf") * + * @see MimeTypeGuesser + * * @api */ public function getMimeType() diff --git a/src/Symfony/Component/HttpFoundation/File/MimeType/ExtensionGuesser.php b/src/Symfony/Component/HttpFoundation/File/MimeType/ExtensionGuesser.php index d5715f6f55..cc646180c8 100644 --- a/src/Symfony/Component/HttpFoundation/File/MimeType/ExtensionGuesser.php +++ b/src/Symfony/Component/HttpFoundation/File/MimeType/ExtensionGuesser.php @@ -16,15 +16,12 @@ namespace Symfony\Component\HttpFoundation\File\MimeType; * * A default guesser is provided. * You can register custom guessers by calling the register() - * method on the singleton instance. + * method on the singleton instance: * - * - * $guesser = ExtensionGuesser::getInstance(); - * $guesser->register(new MyCustomExtensionGuesser()); - * + * $guesser = ExtensionGuesser::getInstance(); + * $guesser->register(new MyCustomExtensionGuesser()); * * The last registered guesser is preferred over previously registered ones. - * */ class ExtensionGuesser implements ExtensionGuesserInterface { diff --git a/src/Symfony/Component/HttpFoundation/File/MimeType/FileinfoMimeTypeGuesser.php b/src/Symfony/Component/HttpFoundation/File/MimeType/FileinfoMimeTypeGuesser.php index 09a0d7ed19..a6950df2cd 100644 --- a/src/Symfony/Component/HttpFoundation/File/MimeType/FileinfoMimeTypeGuesser.php +++ b/src/Symfony/Component/HttpFoundation/File/MimeType/FileinfoMimeTypeGuesser.php @@ -15,12 +15,26 @@ use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException; use Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException; /** - * Guesses the mime type using the PECL extension FileInfo + * Guesses the mime type using the PECL extension FileInfo. * * @author Bernhard Schussek */ class FileinfoMimeTypeGuesser implements MimeTypeGuesserInterface { + private $magicFile; + + /** + * Constructor. + * + * @param string $magicFile A magic file to use with the finfo instance + * + * @link http://www.php.net/manual/en/function.finfo-open.php + */ + public function __construct($magicFile = null) + { + $this->magicFile = $magicFile; + } + /** * Returns whether this guesser is supported on the current OS/PHP setup * @@ -48,7 +62,7 @@ class FileinfoMimeTypeGuesser implements MimeTypeGuesserInterface return null; } - if (!$finfo = new \finfo(FILEINFO_MIME_TYPE)) { + if (!$finfo = new \finfo(FILEINFO_MIME_TYPE, $this->magicFile)) { return null; } diff --git a/src/Symfony/Component/HttpFoundation/File/MimeType/MimeTypeExtensionGuesser.php b/src/Symfony/Component/HttpFoundation/File/MimeType/MimeTypeExtensionGuesser.php index 13fe4a2fdc..42e7b77af0 100644 --- a/src/Symfony/Component/HttpFoundation/File/MimeType/MimeTypeExtensionGuesser.php +++ b/src/Symfony/Component/HttpFoundation/File/MimeType/MimeTypeExtensionGuesser.php @@ -20,6 +20,7 @@ class MimeTypeExtensionGuesser implements ExtensionGuesserInterface * A map of mime types and their default extensions. * * This list has been placed under the public domain by the Apache HTTPD project. + * This list has been updated from upstream on 2013-04-23. * * @see http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types * @@ -39,6 +40,7 @@ class MimeTypeExtensionGuesser implements ExtensionGuesserInterface 'application/cdmi-queue' => 'cdmiq', 'application/cu-seeme' => 'cu', 'application/davmount+xml' => 'davmount', + 'application/docbook+xml' => 'dbk', 'application/dssc+der' => 'dssc', 'application/dssc+xml' => 'xdssc', 'application/ecmascript' => 'ecma', @@ -46,6 +48,9 @@ class MimeTypeExtensionGuesser implements ExtensionGuesserInterface 'application/epub+zip' => 'epub', 'application/exi' => 'exi', 'application/font-tdpfr' => 'pfr', + 'application/gml+xml' => 'gml', + 'application/gpx+xml' => 'gpx', + 'application/gxf' => 'gxf', 'application/hyperstudio' => 'stk', 'application/inkml+xml' => 'ink', 'application/ipfix' => 'ipfix', @@ -54,6 +59,7 @@ class MimeTypeExtensionGuesser implements ExtensionGuesserInterface 'application/java-vm' => 'class', 'application/javascript' => 'js', 'application/json' => 'json', + 'application/jsonml+json' => 'jsonml', 'application/lost+xml' => 'lostxml', 'application/mac-binhex40' => 'hqx', 'application/mac-compactpro' => 'cpt', @@ -64,6 +70,7 @@ class MimeTypeExtensionGuesser implements ExtensionGuesserInterface 'application/mathml+xml' => 'mathml', 'application/mbox' => 'mbox', 'application/mediaservercontrol+xml' => 'mscml', + 'application/metalink+xml' => 'metalink', 'application/metalink4+xml' => 'meta4', 'application/mets+xml' => 'mets', 'application/mods+xml' => 'mods', @@ -75,6 +82,7 @@ class MimeTypeExtensionGuesser implements ExtensionGuesserInterface 'application/oda' => 'oda', 'application/oebps-package+xml' => 'opf', 'application/ogg' => 'ogx', + 'application/omdoc+xml' => 'omdoc', 'application/onenote' => 'onetoc', 'application/oxps' => 'oxps', 'application/patch-ops-error+xml' => 'xer', @@ -122,6 +130,7 @@ class MimeTypeExtensionGuesser implements ExtensionGuesserInterface 'application/srgs' => 'gram', 'application/srgs+xml' => 'grxml', 'application/sru+xml' => 'sru', + 'application/ssdl+xml' => 'ssdl', 'application/ssml+xml' => 'ssml', 'application/tei+xml' => 'tei', 'application/thraud+xml' => 'tfi', @@ -136,6 +145,7 @@ class MimeTypeExtensionGuesser implements ExtensionGuesserInterface 'application/vnd.acucobol' => 'acu', 'application/vnd.acucorp' => 'atc', 'application/vnd.adobe.air-application-installer-package+zip' => 'air', + 'application/vnd.adobe.formscentral.fcdt' => 'fcdt', 'application/vnd.adobe.fxp' => 'fxp', 'application/vnd.adobe.xdp+xml' => 'xdp', 'application/vnd.adobe.xfdf' => 'xfdf', @@ -178,6 +188,7 @@ class MimeTypeExtensionGuesser implements ExtensionGuesserInterface 'application/vnd.cups-ppd' => 'ppd', 'application/vnd.curl.car' => 'car', 'application/vnd.curl.pcurl' => 'pcurl', + 'application/vnd.dart' => 'dart', 'application/vnd.data-vision.rdz' => 'rdz', 'application/vnd.dece.data' => 'uvf', 'application/vnd.dece.ttml+xml' => 'uvt', @@ -188,6 +199,7 @@ class MimeTypeExtensionGuesser implements ExtensionGuesserInterface 'application/vnd.dolby.mlp' => 'mlp', 'application/vnd.dpgraph' => 'dpg', 'application/vnd.dreamfactory' => 'dfac', + 'application/vnd.ds-keypoint' => 'kpxx', 'application/vnd.dvb.ait' => 'ait', 'application/vnd.dvb.service' => 'svc', 'application/vnd.dynageo' => 'geo', @@ -248,7 +260,6 @@ class MimeTypeExtensionGuesser implements ExtensionGuesserInterface 'application/vnd.hp-pcl' => 'pcl', 'application/vnd.hp-pclxl' => 'pclxl', 'application/vnd.hydrostatix.sof-data' => 'sfd-hdstx', - 'application/vnd.hzn-3d-crossword' => 'x3d', 'application/vnd.ibm.minipay' => 'mpy', 'application/vnd.ibm.modcap' => 'afp', 'application/vnd.ibm.rights-management' => 'irm', @@ -344,6 +355,7 @@ class MimeTypeExtensionGuesser implements ExtensionGuesserInterface 'application/vnd.muvee.style' => 'msty', 'application/vnd.mynfc' => 'taglet', 'application/vnd.neurolanguage.nlu' => 'nlu', + 'application/vnd.nitf' => 'ntf', 'application/vnd.noblenet-directory' => 'nnd', 'application/vnd.noblenet-sealer' => 'nns', 'application/vnd.noblenet-web' => 'nnw', @@ -384,6 +396,7 @@ class MimeTypeExtensionGuesser implements ExtensionGuesserInterface 'application/vnd.openxmlformats-officedocument.wordprocessingml.template' => 'dotx', 'application/vnd.osgeo.mapguide.package' => 'mgp', 'application/vnd.osgi.dp' => 'dp', + 'application/vnd.osgi.subsystem' => 'esa', 'application/vnd.palm' => 'pdb', 'application/vnd.pawaafile' => 'paw', 'application/vnd.pg.format' => 'str', @@ -403,6 +416,7 @@ class MimeTypeExtensionGuesser implements ExtensionGuesserInterface 'application/vnd.rig.cryptonote' => 'cryptonote', 'application/vnd.rim.cod' => 'cod', 'application/vnd.rn-realmedia' => 'rm', + 'application/vnd.rn-realmedia-vbr' => 'rmvb', 'application/vnd.route66.link66+xml' => 'link66', 'application/vnd.sailingtracker.track' => 'st', 'application/vnd.seemail' => 'see', @@ -486,25 +500,33 @@ class MimeTypeExtensionGuesser implements ExtensionGuesserInterface 'application/x-7z-compressed' => '7z', 'application/x-abiword' => 'abw', 'application/x-ace-compressed' => 'ace', + 'application/x-apple-diskimage' => 'dmg', 'application/x-authorware-bin' => 'aab', 'application/x-authorware-map' => 'aam', 'application/x-authorware-seg' => 'aas', 'application/x-bcpio' => 'bcpio', 'application/x-bittorrent' => 'torrent', + 'application/x-blorb' => 'blb', 'application/x-bzip' => 'bz', 'application/x-bzip2' => 'bz2', + 'application/x-cbr' => 'cbr', 'application/x-cdlink' => 'vcd', + 'application/x-cfs-compressed' => 'cfs', 'application/x-chat' => 'chat', 'application/x-chess-pgn' => 'pgn', + 'application/x-conference' => 'nsc', 'application/x-cpio' => 'cpio', 'application/x-csh' => 'csh', 'application/x-debian-package' => 'deb', + 'application/x-dgc-compressed' => 'dgc', 'application/x-director' => 'dir', 'application/x-doom' => 'wad', 'application/x-dtbncx+xml' => 'ncx', 'application/x-dtbook+xml' => 'dtb', 'application/x-dtbresource+xml' => 'res', 'application/x-dvi' => 'dvi', + 'application/x-envoy' => 'evy', + 'application/x-eva' => 'eva', 'application/x-font-bdf' => 'bdf', 'application/x-font-ghostscript' => 'gsf', 'application/x-font-linux-psf' => 'psf', @@ -514,14 +536,23 @@ class MimeTypeExtensionGuesser implements ExtensionGuesserInterface 'application/x-font-ttf' => 'ttf', 'application/x-font-type1' => 'pfa', 'application/x-font-woff' => 'woff', + 'application/x-freearc' => 'arc', 'application/x-futuresplash' => 'spl', + 'application/x-gca-compressed' => 'gca', + 'application/x-glulx' => 'ulx', 'application/x-gnumeric' => 'gnumeric', + 'application/x-gramps-xml' => 'gramps', 'application/x-gtar' => 'gtar', 'application/x-hdf' => 'hdf', + 'application/x-install-instructions' => 'install', + 'application/x-iso9660-image' => 'iso', 'application/x-java-jnlp-file' => 'jnlp', 'application/x-latex' => 'latex', + 'application/x-lzh-compressed' => 'lzh', + 'application/x-mie' => 'mie', 'application/x-mobipocket-ebook' => 'prc', 'application/x-ms-application' => 'application', + 'application/x-ms-shortcut' => 'lnk', 'application/x-ms-wmd' => 'wmd', 'application/x-ms-wmz' => 'wmz', 'application/x-ms-xbap' => 'xbap', @@ -538,35 +569,47 @@ class MimeTypeExtensionGuesser implements ExtensionGuesserInterface 'application/x-msterminal' => 'trm', 'application/x-mswrite' => 'wri', 'application/x-netcdf' => 'nc', + 'application/x-nzb' => 'nzb', 'application/x-pkcs12' => 'p12', 'application/x-pkcs7-certificates' => 'p7b', 'application/x-pkcs7-certreqresp' => 'p7r', 'application/x-rar-compressed' => 'rar', 'application/x-rar' => 'rar', + 'application/x-research-info-systems' => 'ris', 'application/x-sh' => 'sh', 'application/x-shar' => 'shar', 'application/x-shockwave-flash' => 'swf', 'application/x-silverlight-app' => 'xap', + 'application/x-sql' => 'sql', 'application/x-stuffit' => 'sit', 'application/x-stuffitx' => 'sitx', + 'application/x-subrip' => 'srt', 'application/x-sv4cpio' => 'sv4cpio', 'application/x-sv4crc' => 'sv4crc', + 'application/x-t3vm-image' => 't3', + 'application/x-tads' => 'gam', 'application/x-tar' => 'tar', 'application/x-tcl' => 'tcl', 'application/x-tex' => 'tex', 'application/x-tex-tfm' => 'tfm', 'application/x-texinfo' => 'texinfo', + 'application/x-tgif' => 'obj', 'application/x-ustar' => 'ustar', 'application/x-wais-source' => 'src', 'application/x-x509-ca-cert' => 'der', 'application/x-xfig' => 'fig', + 'application/x-xliff+xml' => 'xlf', 'application/x-xpinstall' => 'xpi', + 'application/x-xz' => 'xz', + 'application/x-zmachine' => 'z1', + 'application/xaml+xml' => 'xaml', 'application/xcap-diff+xml' => 'xdf', 'application/xenc+xml' => 'xenc', 'application/xhtml+xml' => 'xhtml', 'application/xml' => 'xml', 'application/xml-dtd' => 'dtd', 'application/xop+xml' => 'xop', + 'application/xproc+xml' => 'xpl', 'application/xslt+xml' => 'xslt', 'application/xspf+xml' => 'xspf', 'application/xv+xml' => 'mxml', @@ -579,6 +622,8 @@ class MimeTypeExtensionGuesser implements ExtensionGuesserInterface 'audio/mp4' => 'mp4a', 'audio/mpeg' => 'mpga', 'audio/ogg' => 'oga', + 'audio/s3m' => 's3m', + 'audio/silk' => 'sil', 'audio/vnd.dece.audio' => 'uva', 'audio/vnd.digital-winds' => 'eol', 'audio/vnd.dra' => 'dra', @@ -593,12 +638,16 @@ class MimeTypeExtensionGuesser implements ExtensionGuesserInterface 'audio/webm' => 'weba', 'audio/x-aac' => 'aac', 'audio/x-aiff' => 'aif', + 'audio/x-caf' => 'caf', + 'audio/x-flac' => 'flac', + 'audio/x-matroska' => 'mka', 'audio/x-mpegurl' => 'm3u', 'audio/x-ms-wax' => 'wax', 'audio/x-ms-wma' => 'wma', 'audio/x-pn-realaudio' => 'ram', 'audio/x-pn-realaudio-plugin' => 'rmp', 'audio/x-wav' => 'wav', + 'audio/xm' => 'xm', 'chemical/x-cdx' => 'cdx', 'chemical/x-cif' => 'cif', 'chemical/x-cmdf' => 'cmdf', @@ -614,6 +663,7 @@ class MimeTypeExtensionGuesser implements ExtensionGuesserInterface 'image/ktx' => 'ktx', 'image/png' => 'png', 'image/prs.btif' => 'btif', + 'image/sgi' => 'sgi', 'image/svg+xml' => 'svg', 'image/tiff' => 'tiff', 'image/vnd.adobe.photoshop' => 'psd', @@ -628,14 +678,17 @@ class MimeTypeExtensionGuesser implements ExtensionGuesserInterface 'image/vnd.fujixerox.edmics-mmr' => 'mmr', 'image/vnd.fujixerox.edmics-rlc' => 'rlc', 'image/vnd.ms-modi' => 'mdi', + 'image/vnd.ms-photo' => 'wdp', 'image/vnd.net-fpx' => 'npx', 'image/vnd.wap.wbmp' => 'wbmp', 'image/vnd.xiff' => 'xif', 'image/webp' => 'webp', + 'image/x-3ds' => '3ds', 'image/x-cmu-raster' => 'ras', 'image/x-cmx' => 'cmx', 'image/x-freehand' => 'fh', 'image/x-icon' => 'ico', + 'image/x-mrsid-image' => 'sid', 'image/x-pcx' => 'pcx', 'image/x-pict' => 'pic', 'image/x-portable-anymap' => 'pnm', @@ -643,6 +696,7 @@ class MimeTypeExtensionGuesser implements ExtensionGuesserInterface 'image/x-portable-graymap' => 'pgm', 'image/x-portable-pixmap' => 'ppm', 'image/x-rgb' => 'rgb', + 'image/x-tga' => 'tga', 'image/x-xbitmap' => 'xbm', 'image/x-xpixmap' => 'xpm', 'image/x-xwindowdump' => 'xwd', @@ -656,6 +710,10 @@ class MimeTypeExtensionGuesser implements ExtensionGuesserInterface 'model/vnd.mts' => 'mts', 'model/vnd.vtu' => 'vtu', 'model/vrml' => 'wrl', + 'model/x3d+binary' => 'x3db', + 'model/x3d+vrml' => 'x3dv', + 'model/x3d+xml' => 'x3d', + 'text/cache-manifest' => 'appcache', 'text/calendar' => 'ics', 'text/css' => 'css', 'text/csv' => 'csv', @@ -688,7 +746,10 @@ class MimeTypeExtensionGuesser implements ExtensionGuesserInterface 'text/x-fortran' => 'f', 'text/x-pascal' => 'p', 'text/x-java-source' => 'java', + 'text/x-opml' => 'opml', + 'text/x-nfo' => 'nfo', 'text/x-setext' => 'etx', + 'text/x-sfv' => 'sfv', 'text/x-uuencode' => 'uu', 'text/x-vcalendar' => 'vcs', 'text/x-vcard' => 'vcf', @@ -720,13 +781,17 @@ class MimeTypeExtensionGuesser implements ExtensionGuesserInterface 'video/x-fli' => 'fli', 'video/x-flv' => 'flv', 'video/x-m4v' => 'm4v', + 'video/x-matroska' => 'mkv', + 'video/x-mng' => 'mng', 'video/x-ms-asf' => 'asf', + 'video/x-ms-vob' => 'vob', 'video/x-ms-wm' => 'wm', 'video/x-ms-wmv' => 'wmv', 'video/x-ms-wmx' => 'wmx', 'video/x-ms-wvx' => 'wvx', 'video/x-msvideo' => 'avi', 'video/x-sgi-movie' => 'movie', + 'video/x-smv' => 'smv', 'x-conference/x-cooltalk' => 'ice', ); diff --git a/src/Symfony/Component/HttpFoundation/File/MimeType/MimeTypeGuesser.php b/src/Symfony/Component/HttpFoundation/File/MimeType/MimeTypeGuesser.php index 59ddc077be..f6bf2cd39d 100644 --- a/src/Symfony/Component/HttpFoundation/File/MimeType/MimeTypeGuesser.php +++ b/src/Symfony/Component/HttpFoundation/File/MimeType/MimeTypeGuesser.php @@ -18,15 +18,22 @@ use Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException; * A singleton mime type guesser. * * By default, all mime type guessers provided by the framework are installed - * (if available on the current OS/PHP setup). You can register custom - * guessers by calling the register() method on the singleton instance. + * (if available on the current OS/PHP setup). * - * - * $guesser = MimeTypeGuesser::getInstance(); - * $guesser->register(new MyCustomMimeTypeGuesser()); - * + * You can register custom guessers by calling the register() method on the + * singleton instance. Custom guessers are always called before any default ones. * - * The last registered guesser is preferred over previously registered ones. + * $guesser = MimeTypeGuesser::getInstance(); + * $guesser->register(new MyCustomMimeTypeGuesser()); + * + * If you want to change the order of the default guessers, just re-register your + * preferred one as a custom one. The last registered guesser is preferred over + * previously registered ones. + * + * Re-registering a built-in guesser also allows you to configure it: + * + * $guesser = MimeTypeGuesser::getInstance(); + * $guesser->register(new FileinfoMimeTypeGuesser('/path/to/magic/file')); * * @author Bernhard Schussek */ diff --git a/src/Symfony/Component/HttpFoundation/File/UploadedFile.php b/src/Symfony/Component/HttpFoundation/File/UploadedFile.php index f08bccd4dd..bd7ebec52e 100644 --- a/src/Symfony/Component/HttpFoundation/File/UploadedFile.php +++ b/src/Symfony/Component/HttpFoundation/File/UploadedFile.php @@ -134,11 +134,16 @@ class UploadedFile extends File /** * Returns the file mime type. * - * It is extracted from the request from which the file has been uploaded. - * Then is should not be considered as a safe value. + * The client mime type is extracted from the request from which the file + * was uploaded, so it should not be considered as a safe value. + * + * For a trusted mime type, use getMimeType() instead (which guesses the mime + * type based on the file content). * * @return string|null The mime type * + * @see getMimeType + * * @api */ public function getClientMimeType() @@ -146,6 +151,31 @@ class UploadedFile extends File return $this->mimeType; } + /** + * Returns the extension based on the client mime type. + * + * If the mime type is unknown, returns null. + * + * This method uses the mime type as guessed by getClientMimeType() + * to guess the file extension. As such, the extension returned + * by this method cannot be trusted. + * + * For a trusted extension, use guessExtension() instead (which guesses + * the extension based on the guessed mime type for the file). + * + * @return string|null The guessed extension or null if it cannot be guessed + * + * @see guessExtension() + * @see getClientMimeType() + */ + public function guessClientExtension() + { + $type = $this->getMimeType(); + $guesser = ExtensionGuesser::getInstance(); + + return $guesser->guess($type); + } + /** * Returns the file size. *