如何在PHP 5.5中获取文件的MIME类型?

35

我正在使用PHP 5.5中的mime_content_type()函数获取MIME类型,但它会报错:fatal: error function not found

在PHP 5.5上如何实现这个功能?


3
您介意接受对您的问题的回答吗?我知道这是一段时间之前提出的,但最终知道您的解决方案也很好 :) - Erutan409
1
2017年:这应该是被接受的答案 - rinogo
8个回答

60

利用 finfo() 函数。

一个简单的示例:

<?php
$finfo = finfo_open(FILEINFO_MIME_TYPE);
echo finfo_file($finfo, "path/to/image_dir/image.gif");
finfo_close($finfo);

输出:

image/gif

注意:Windows用户必须在php.ini文件中包含捆绑的php_fileinfo.dll DLL文件才能启用此扩展。


我收到了致命错误:在中未定义函数finfo_open()的调用。 - Jitendra Yadav
@DOZ,这是因为原帖作者可能在使用Windows,他需要手动完成这个操作。 - Shankar Narayana Damodaran
1
@ShankarDamodaran 确切 :) - PASTAGA
我已经激活了php_fileinfo.dll,但它仍然无法工作。if($_SERVER['REQUEST_METHOD']=='POST'){ echo $_FILES['file']['name'].'
'; $finfo = finfo_open(FILEINFO_MIME_TYPE); echo finfo_file($finfo, $_FILES['file']['name']); finfo_close($finfo); }
它显示了文件名,但没有Mime类型。 :)
- Jitendra Yadav
@Jordan在另一个问题中说:“PHP 5.3.0及更高版本内置了Fileinfo,但是在Windows上,您必须在php.ini中手动启用它。您可以在文档中找到更多信息。” - jave.web
显示剩余3条评论

18

我花了太多时间试图让finfo函数正常工作。最终,我只是创建了自己的函数来匹配文件扩展名和任何mime类型数组。这不是一种完全可靠的方法来确保文件确实是它们扩展名所表示的内容,但是您可以通过处理服务器上的文件I/O来缓解该问题。

function mime_type($file) {

    // there's a bug that doesn't properly detect
    // the mime type of css files
    // https://bugs.php.net/bug.php?id=53035
    // so the following is used, instead
    // src: http://www.freeformatter.com/mime-types-list.html#mime-types-list

    $mime_type = array(
        "3dml" => "text/vnd.in3d.3dml",
        "3g2" => "video/3gpp2",
        "3gp" => "video/3gpp",
        "7z" => "application/x-7z-compressed",
        "aab" => "application/x-authorware-bin",
        "aac" => "audio/x-aac",
        "aam" => "application/x-authorware-map",
        "aas" => "application/x-authorware-seg",
        "abw" => "application/x-abiword",
        "ac" => "application/pkix-attr-cert",
        "acc" => "application/vnd.americandynamics.acc",
        "ace" => "application/x-ace-compressed",
        "acu" => "application/vnd.acucobol",
        "adp" => "audio/adpcm",
        "aep" => "application/vnd.audiograph",
        "afp" => "application/vnd.ibm.modcap",
        "ahead" => "application/vnd.ahead.space",
        "ai" => "application/postscript",
        "aif" => "audio/x-aiff",
        "air" => "application/vnd.adobe.air-application-installer-package+zip",
        "ait" => "application/vnd.dvb.ait",
        "ami" => "application/vnd.amiga.ami",
        "apk" => "application/vnd.android.package-archive",
        "application" => "application/x-ms-application",
        // etc...
        // truncated due to Stack Overflow's character limit in posts
    );

    $extension = \strtolower(\pathinfo($file, \PATHINFO_EXTENSION));

    if (isset($mime_type[$extension])) {
        return $mime_type[$extension];
    } else {
        throw new \Exception("Unknown file type");
    }

}

编辑:

我想回应Davuz的评论(因为它一直被点赞),并提醒大家,我在顶部放置了伪免责声明,说明这不是“万无一失”的。因此,在考虑我所提供的方法时,请记住这一点。


如果您分享最终函数的链接,我会给您投票。 - dennis
2
有求必应: https://gist.github.com/Erutan409/8e774dfb2b343fe78b14#file-mimetype-php - Erutan409
3
如果我把文件名“hamster.sh”改为“hamster.jpg”,那么它将无法正常运行。 - Davuz
如果你已经阅读了我的帖子/回答或查看了gist源代码的评论,你会看到关于那个的免责声明。我的建议是在上传时处理扩展名欺骗。无论如何,你只能做这么多。你是控制文件的人。 - Erutan409
2
你应该使用 $extension = strtolower(pathinfo($file, PATHINFO_EXTENSION));,这样它也可以检测到具有大写扩展名的文件的 MIME 类型。 - m132

10

1
已点赞,但我还需要编辑一下,如果您不介意的话:说它是“内置的”是误导性的(至少它误导了我):你仍然需要fileinfo扩展才能使其工作!(您所提到的页面只是说您可以重新编译扩展而不需要mime_magic库。) - Sz.
1
它在Linux中是内置的,但在Windows上,您需要在php.ini中包含.dll。 - Anuga

4

我收到了致命错误:在中未定义函数finfo_open()的调用。 - Jitendra Yadav
1
@Jordan在另一个问题中说:“PHP 5.3.0及更高版本内置了Fileinfo,但是在Windows上,您必须在php.ini中手动启用它。您可以在文档中找到更多信息。” - jave.web
具体来说,在您的php.ini文件中取消注释(删除;)以下行:;extension=php_fileinfo.dll - jave.web

2
你需要明白,file_get_contents函数会将整个文件上传到内存中,这不是获取mime类型的好方法。在这种情况下,你不需要使用buffer方法和file_get_contents函数。
为了避免任何错误和警告,最好像这样做。
$filename = 'path to your file';

if (class_exists('finfo')) {
    $finfo = new finfo(FILEINFO_MIME_TYPE);
    if (is_object($finfo)) {
        echo $finfo->file($filename);
    }
} else {
    echo 'fileinfo did not installed';
}

此外,您需要知道如果$finfo->file失败会抛出PHP警告。

如果文件信息未正确安装,并且您使用的是最新版本的PHP,则可以从标头中获取MIME类型。

您可以使用cURL从标头中获取MIME类型。

    $ch = curl_init();
    curl_setopt_array($ch, array(
            CURLOPT_HEADER => true,
            CURLOPT_NOBODY => true,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_SSL_VERIFYHOST => false,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_MAXREDIRS => 1,
            CURLOPT_URL => $link)
    );

    $headers = curl_exec($ch);
    curl_close($ch);

    if (preg_match('/Content-Type:\s(.*)/i', $headers, $matches)) {
        echo trim($matches[1], "\t\n\r");
    }else {
        echo 'There is no content type in the headers!';
    }

您也可以使用get_headers函数,但它比cURL请求更慢。

$url = 'http://www.example.com';

$headers = get_headers($url, 1);

echo $headers['Content-Type'];

Content-Type 返回的值仅取决于扩展名而不是真正的 MIME 类型。因此,将 bad_file.exe 重命名为 good_file.doc 将返回 application/msword - 没有扩展名的文件返回 404。 - yckart
你不能相信互联网上的一切。所以,@yckart,你认为过载服务器并下载所有文件并通过内容检查它是否可以被重写以防止内容类型检测会更好吗?fileinfo:虽然这不是一个百分百可靠的方法,但所使用的启发式方法做得非常出色。- http://php.net/manual/en/intro.fileinfo.php - madlopt

2

使用以下代码获取图片大小:

$infFil=getimagesize($the_file_name);

另外,你也可以使用下面的代码:

echo $infFil["mime"]
getimagesize 返回一个关联数组,其中包含 MIME 键和显然的图像大小。我使用它并且它有效。

0

我使用来自Bat的MimeTypeTool(https://github.com/lingtalfi/Bat

如果可用,它将使用fileinfo,并在否则默认返回“扩展名 => mime类型”映射。


0

这是我通过结合两篇非常好的文章找到的最佳解决方案

// 感谢http://php.net/manual/en/function.mime-content-type.php#87856

function getMimeContentType($filename, $ext)
{
    if(!function_exists('mime_content_type'))
    {
        if($mime_types = getMimeTypes())
        {
            if (array_key_exists($ext, $mime_types))
            {
                return $mime_types[$ext];
            }
            elseif (function_exists('finfo_open'))
            {
                $finfo  = finfo_open(FILEINFO_MIME);
                $mimetype = finfo_file($finfo, $filename);
                finfo_close($finfo);
                return $mimetype;
            }
        }
        return 'application/octet-stream';
    }
    return mime_content_type($filename);
}

// 感谢 http://php.net/manual/zh/function.mime-content-type.php#107798

function getMimeTypes()
{
    $url = 'http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types';

    $mimes = array();
    foreach(@explode("\n",@file_get_contents($url)) as $x)
    {
        if(isset($x[0]) && $x[0]!=='#' && preg_match_all('#([^\s]+)#', $x, $out) && isset($out[1]) && ($c = count($out[1])) > 1)
        {
                for($i=1; $i < $c; $i++)
            {
                    $mimes[$out[1][$i]] = $out[1][0];
            }
        }
    }
    return (@sort($mimes)) ? $mimes : false;
}

使用方法如下:

$filename = '/path/to/the/file.pdf';
$ext = strtolower(array_pop(explode('.',$filename)));
$content_type = getMimeContentType($filename, $ext);

即使在 PHP 不再支持 mime_content_type 函数,它仍将继续工作。


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