【问题标题】:Detecting a mime type fails in php在 php 中检测 mime 类型失败
【发布时间】:2013-04-17 22:35:46
【问题描述】:

我有以下 PHP 代码显示上传文件的 MIME 类型。

<?php

if ($_POST) {

    var_dump($_FILES);

    $finfo = new finfo(FILEINFO_MIME_TYPE);

    var_dump($finfo->file($_FILES['file']['tmp_name']));

} else{
    ?>
    <form method="POST" enctype="multipart/form-data"><input name="file" type="file"><input name="submit" value="send" type="submit"/></form>
    <?php
}

使用此脚本上传 somefile.csv 的结果如下。

array (size=1)
    'file' =>
    array (size=5)
        'name' => string 'somefile.csv' (length=12)
        'type' => string 'text/csv' (length=8)
        'tmp_name' => string '/tmp/phpKiwqtu' (length=14)
        'error' => int 0
        'size' => int 3561
string 'text/x-fortran' (length=14)

当然,mime 类型应该是 text/csv。但是我使用的框架(Symfony 1.4)使用带有fileinfo的方法。

我还进一步测试了一下,似乎命令(在 Ubuntu 上)file --mime-type somefile.csv 返回 somefile.csv: text/x-fortran,而命令 mimetype somefile.csv 返回 somefile.csv: text/csv。 somefile.csv 是用 MSOffice 创建的(我不知道这是否重要)。 显然 mimetype 使用了一些很棒的 mime 数据库 (http://freedesktop.org/wiki/Software/shared-mime-info),而 file 没有。

  1. PHP 使用filemimetype 还是都不使用?
  2. 此外,我不知道在这里做什么;我上传的文件格式错误吗?我必须使用不同的 mime 数据库吗? PHP被窃听了吗?这是怎么回事?

编辑:

之所以被检测为fortran程序,是因为somefile.csv只包含以下内容:

somecolumn;
C F;

我相信 CSV 文件的上述内容是有效的,对吧?如果一个字段包含空格,则该字段不必放在引号内,对吗?

【问题讨论】:

    标签: php symfony-1.4 mime-types


    【解决方案1】:

    我这里没有 Unix 机器来检查真正的“魔术”文件(用于猜测 mime 类型的签名数据库),但快速的 Google 搜索显示了这一点:

    # $File: fortran,v 1.6 2009/09/19 16:28:09 christos Exp $
    # FORTRAN source
    0       regex/100       \^[Cc][\ \t]    FORTRAN program
    !:mime  text/x-fortran
    

    显然,它会扫描文件的开头以查找以单个 C 字母加空格开头的行,这似乎是 Fortran style comment。因此误报:

    somecolumn;
    C F;
    

    【讨论】:

    • 那么,我应该如何处理误报呢?我知道一个解决方案是在每个单元格周围加上引号,但这并不是我真正想要的,因为我的 web 应用程序的用户上传了这些 CSV 文件。显示的示例是一个有效的 CSV 文件。
    • 取决于您的确切需求,但在这种情况下,最好也使用文件扩展名。您还可以为您的 mime 文件删除 Fortran。 (如果您已经知道它是 CSV,不知道为什么在这里使用启发式算法;猜测 mime 类型不会验证文件)
    • 那么 CSV 文件是由应用程序的用户上传的。如果误报是猜测 mime 类型的结果,那么使用 mime 类型猜测实际上没有意义。我只是确保该文件在公共文件夹中不可执行,并且用户应该知道他们正在下载什么。此外,由于我只使用 CSV 文件并且 CSV 文件的语法必须正确,我还可以使用 BNF 语法检查 CSV 文件的内容。
    【解决方案2】:

    来自PHP Mimetype introduction

    此扩展已被弃用,因为 PECL 扩展 Fileinfo 以更简洁的方式提供了相同的功能(以及更多功能)。

    此模块中的函数尝试通过在文件中的特定位置查找某些魔术字节序列来猜测文件的内容类型和编码。虽然这不是万无一失的方法,但使用的启发式方法做得很好。

    此扩展源自 Apache mod_mime_magic,它本身基于 Ian F. Darwin 维护的文件命令。有关更多历史和版权信息,请参阅源代码。

    来自PHP Fileinfo introduction

    此模块中的函数尝试通过在文件中的特定位置查找某些魔术字节序列来猜测文件的内容类型和编码。 虽然这不是万无一失的方法,但使用的启发式方法做得很好

    这里有一个关于同一主题的一些答案的问题:Detecting MIME type in PHP

    【讨论】:

    • pear.php.net/package/MIME_Type 给出了与 file_info 相同的结果。我不明白为什么 CSV 文件看起来是 fortran 文件。
    • 查看 Fortran 代码示例我无法弄清楚为什么会这样,它们完全不同。如果您在简单的文本编辑器中打开该特定 CSV 文件,它看起来像普通 CSV 文件还是有其他可能导致混淆结果的元素?
    • 另外 5 美分,我在谷歌上搜索了完善的基于 PHP 的 Web 应用程序,这里有另一种方法:Drupal 8 似乎使用 Guzzle PHP 框架来完成这项工作,看看他们的代码github.com/guzzle/guzzle/blob/master/src/Guzzle/Http/…。他们只是对预定义的已知 mime 类型列表进行简单的扩展检查。我会说也不是防弹的。
    • 我编辑了我的初始帖子。我为 CSV 文件找到了最少量的内容,使其看起来像 fortran 代码。我也相信内容对 CSV 文件有效。该怎么办?
    • 从您的文件内容来看,我不会说它是 CSV 文件,因为它不遵循 RFC 4180 definition。这更像是“以分号结尾的空格分隔值”。您可以在Wikipedia 上阅读有关 CSV 文件缺乏标准格式的一些注意事项。
    猜你喜欢
    • 2011-12-14
    • 2010-10-13
    • 1970-01-01
    • 2016-05-20
    • 1970-01-01
    • 2013-11-09
    • 2011-10-18
    • 1970-01-01
    • 2011-06-15
    相关资源
    最近更新 更多