如何使用PHP查找文件的MIME类型?

49

我有一个index.php文件,它必须处理许多不同的文件类型。如何根据REQUEST_URI猜测文件类型?

如果我请求http://site/image.jpg,并且所有请求都通过看起来像这样的index.php重定向:

<?php
   include('/www/site'.$_SERVER['REQUEST_URI']);
?>

如何使它正确工作?

我应该基于所请求的文件扩展名进行测试,还是有一种获取文件类型的方法?


3
你能否重新表述你的问题?我希望你的网站上并没有真的运行那样的代码。 - Till
1
不,当然这不是实际工作的方式。那只是我认为最好的传达观点的方式。 - Issac Kelly
13个回答

51
如果你确定你只会处理图像,你可以查看exif_imagetype() PHP函数,它尝试返回图像的MIME类型。
如果你不介意使用外部依赖,你还可以查看优秀的getID3库,它可以确定许多不同文件类型的MIME类型。
最后,你可以查看mime_content_type()函数 - 但它已经被Fileinfo PECL扩展弃用。

17
不要使用getimagesize()函数,而是改用exif_imagetype()函数:http://us3.php.net/manual/en/function.exif-imagetype.php 。它可以提供相同的信息,而且不会有执行其他操作时的性能惩罚。 - Xiong Chiamiov
返回值与getimagesize()在索引2中返回的值相同,但exif_imagetype()速度更快。 - Loonb
@leek:如何获取任何内容的MIME类型.... http://stackoverflow.com/questions/21847663/changing-video-content-type-mime-type-in-cdn-in-drupal-7 - Hitesh

23

mime_content_type()已经被弃用,所以将来可能无法正常工作。虽然有一个名为“fileinfo”的PECL扩展,但我没有听到好的消息。

如果您正在运行类Unix服务器,可以尝试以下方法,这对我来说效果很好:

$file = escapeshellarg($filename);
$mime = shell_exec("file -bi " . $file);
$filename should probably include the absolute path.

由于安全原因,共享主机上的“file”命令可能已被禁用。 - SAMPro
3
我没有听到关于它的好消息。- 如果我们能读到你所听到的,那会很不错 ;) - yckart
1
你说 mime_content_type 已经被弃用了,依据是什么?根据 https://www.php.net/manual/en/function.mime-content-type.php 看起来并没有被弃用啊。 - Jānis Elmeris

18
function get_mime($file) {
  if (function_exists("finfo_file")) {
    $finfo = finfo_open(FILEINFO_MIME_TYPE); // Return MIME type a la the 'mimetype' extension
    $mime = finfo_file($finfo, $file);
    finfo_close($finfo);
    return $mime;
  } else if (function_exists("mime_content_type")) {
    return mime_content_type($file);
  } else if (!stristr(ini_get("disable_functions"), "shell_exec")) {
    // https://dev59.com/ZHVC5IYBdhLWcg3w9GLM#134930
    $file = escapeshellarg($file);
    $mime = shell_exec("file -bi " . $file);
    return $mime;
  } else {
    return false;
  }
}

对于我来说,这些都不起作用——mime_content_type已被弃用,finfo未安装,而且不允许使用shell_exec


10

我实际上对PHP中缺乏标准 MIME 嗅探方法感到厌烦了。安装 fileinfo......使用弃用的函数......这些东西可以工作,但仅适用于图像!我受够了,所以我进行了一些研究,并找到了WHATWG MIME 嗅探规范 - 尽管我相信这仍然是一份草案。

无论如何,使用此规范,我能够在 PHP 中实现一个 MIME 嗅探器。性能不是问题。事实上,在我的平凡机器上,我能够在 PHP 超时之前打开和嗅探数千个文件。

这里是MimeReader 类

require_once("MimeReader.php");

$mime = new MimeReader(<YOUR FILE PATH>);
$mime_type_string = $mime->getType();     // "image/jpeg", etc.

太好了!现在它是“Living Standard - 最后更新于2013年6月11日”,所以不再是草稿。你是否成功上传/分享了你的PHP代码? - trejder
2
嗨trejder。谢谢你的更新,很抱歉回复晚了。你可以在我的迷你网站上找到我所有的项目(这不算多,我知道)。如果它变得流行,我可能会将其放在Github上。所有内容都在项目下面。它已经发布到公共领域中,所以你可以自由清理代码(需要这样做!)或按照你认为合适的方式进行修改。http://shane.social-library.org/ - Shane
嗨,Syed Qarib,感谢您让我知道。如您所建议,我已更新了Github的链接。 - Shane
这个类没有CSV类型。 - Jarosław Osmólski
正确 - 这是因为CSV文件是纯文本,这个类完全基于魔数工作,所以就该类而言,它是纯文本。如果您想区分这些纯文本文件,您应该能够对这些文件进行一些检查,或者请随意创建一个分支。谢谢。 - Shane
显示剩余3条评论

8

如果您只使用图像并需要MIME类型(例如用于标头),那么这是最快且最直接的答案:

$file = 'path/to/image.jpg';
$image_mime = image_type_to_mime_type(exif_imagetype($file));

即使您重命名图像文件,它也会输出真实的图像MIME类型。

1
您可以在PHP 5.3中使用finfo来完成此操作:
<?php
$info = new finfo(FILEINFO_MIME_TYPE);
echo $info->file('myImage.jpg');
// prints "image/jpeg"

FILEINFO_MIME_TYPE标记是可选的;如果没有使用该标记,则对于某些文件,您将获得更详细的字符串(显然,一些图像类型会返回大小和颜色深度信息)。使用FILEINFO_MIME标记将返回mime类型和编码(例如,image/png; charset=binary或text/x-php; charset=us-ascii),如果有的话。有关更多信息,请参见this site

1

mime_content_type() 看起来是一个不错的选择,尽管之前的评论说它已经被弃用了。实际上,至少这个版本的 mime_content_type() 没有被弃用,根据 http://php.net/manual/en/function.mime-content-type.php 的说明。它是 FileInfo 扩展的一部分,但 PHP 文档现在告诉我们,自 PHP 5.3.0 起默认启用。


1
根据PHP手册,finfo-file函数是最好的方法。但是,您需要安装FileInfo PECL扩展。
如果无法使用该扩展,您可以使用过时的mime_content_type函数。

2
另外,自 PHP 5.3 版本起,默认启用了 Fileinfo 扩展。 - Stann
@Stann 不,不是这样的!PHP 版本 5.4.7 + 致命错误:在 C:\XAMPP\htdocs\... 中调用未定义的函数 finfo_open() - trejder

0

可以使用以下代码获取服务器上任何文件的 MIME 类型:

<?php
  function get_mime($file_path){
    $finfo = new finfo(FILEINFO_MIME_TYPE);
    $type  = $finfo->file(file_path);
  }

  $mime = get_mime('path/to/file.ext');

0

如果你在运行Linux并且安装了相关扩展,你可以通过创建哈希数组从/etc/mime.types中读取MIME类型。然后你可以将其存储到内存中,通过数组键来简单地调用MIME类型 :)

/**
 * Helper function to extract all mime types from the default Linux /etc/mime.types
 */
function get_mime_types() {
    $mime_types = array();
    if (
        file_exists('/etc/mime.types') &&
        ($fh = fopen('/etc/mime.types', 'r')) !== false
    ) {
        while (($line = fgets($fh)) !== false) {
            if (!trim($line) || substr($line, 0, 1) === '#') continue;
            $mime_type = preg_split('/\t+/', rtrim($line));
            if (
                is_array($mime_type) &&
                isset($mime_type[0]) && $mime_type[0] &&
                isset($mime_type[1]) && $mime_type[1]
            ) {
                foreach (explode(' ', $mime_type[1]) as $ext) {
                    $mime_types[$ext] = $mime_type[0];
                }
            }
        }
        fclose($fh);
    }
    return $mime_types;
}

什么扩展名?文件扩展名? - Peter Mortensen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接