【问题标题】:PHP allowed zip mimetypesPHP 允许的 zip mimetypes
【发布时间】:2012-05-20 10:58:08
【问题描述】:

我知道(从这个问题的答案:.rar, .zip files MIME Type)大多数人检查 PHP 中的 zip 文件为 application/zipapplication/octet-stream,但我对此有几个问题:

  • 只检查application/octet-stream 是否安全(鉴于application/octet-stream 可用于描述更多的文件类型而不仅仅是zip!)。我知道我也可以通过其他方式检查文件,但我认为我应该尽量保持一切简单
  • 我尝试尽可能多地检查不同的实际拉链类型;但是,有些会产生一些意想不到的结果。我发现 1 的 mime 类型为 application/x-external-editor,但 PHP 处理它时遇到问题(尽管我得到的唯一错误是 Warning: ZipArchive::close() [ziparchive.close]: Invalid or unitialized Zip object) - 这在任何地方都有记录吗?是否有 PHP 可以处理的实际 x- mimetypes 列表?

编辑

回答以下问题:

  • 我正在使用$_FILES['fileatt']['type'] 检查mime 类型,但使用mime_content_type() 会得到相同的结果。不同的 zip 文件似乎是以下任何一种:'application/zip''application/x-compressed''application/x-zip-compressed''application/x-compressed''multipart/x-zip'。我不明白为什么在检测到 MIME 类型为 application/x-external-editor 时出现错误。
  • 我已经安装了 zip 扩展,并且在上传 zip 文件时,我会从这些文件中提取所有文件。我没想过要检查错误。

我还发现了另一件事我不太明白:当我将以下代码与 PHP 读取为 application/x-external-editor 的文件一起使用时:

if($zip->open($_FILES[fileatt]['tmp_name'])===TRUE)
{
    echo "success";
} else {
    echo "error";
} 

打印“错误”,但检查文件类型为

$res = $zip->open($_FILES[fileatt]['tmp_name']);
if($res)
{
    echo "success";
} else {
    echo "error";
} 

打印“成功”;在这段代码中,我假设布尔值有效地使用了==,而不是===,但这为什么会有所作为?

错误:

$res = $zip->open($_FILES[fileatt]['tmp_name']);
if($res===TRUE)
{
    echo "success";
} else {
    echo $res;
} 

打印19 - 19 指的是哪个错误 (http://uk3.php.net/manual/en/ziparchive.open.php)?!

【问题讨论】:

  • 回答您的第一个问题:不,它不安全,它不会告诉您有关该文件的任何信息。你如何检查这个,不同的 zip 文件不应该给你不同的结果,除非它们真的是 zip 文件。只要有正确的库,PHP 就可以处理任何事情。显示您如何检测 mime 类型的代码。

标签: php mime-types


【解决方案1】:

永远不要相信 mime 类型,这很容易被客户端欺骗。如果他们愿意,他们可以提交一个 exe 并给它一个 mime 类型 text/plain

所有 zip 文件都以标准本地文件头签名 (0x04034b50) 开头,因此您可以检查文件的前 4 个字节是否与 zip 签名字节匹配。有关详细信息,请参阅PKZIP Appnote

如果您启用了zip extension,您可以更进一步,尝试打开并读取 zip 以确保它是完全有效的 zip 文件。

这样的东西效果很好:

$zip = zip_open('/path/to/file.zip');
if (is_int($zip)) {
    echo "Error $zip encountered reading the file, is it a valid zip?";
} else {
    echo "Thanks for uploading a valid zip file!";
}

zip_open 如果打开成功则返回一个资源,否则返回一个整数,表示读取文件时发生的错误。

编辑:详细说明您的一些问题:

关于application/octet-stream:这就是你说的,很通用的类型。这只是意味着任何包含 8 位数据的文件,基本上是所有内容。 application/zip 是事实上的标准 mime 类型,但某些客户端会使用您发现的其他值。此外,考虑到客户端可以轻松欺骗任何文件类型以使用application/zip,我不会依赖$_FILES['fileatt']['type'],因为它可以是任何东西。

AFIK,mime_content_type() 只是查看文件扩展名并将其映射到系统上的 mime.types 文件或 PHP 中内置的 mime 类型。如果有人将.zip 扩展名放在exe 文件上,它仍会注册为application/zip。我相信某些扩展可能会检查文件头。

Zip::open() 如果文件打开成功,则返回TRUE,或者返回整数错误代码。因此,== 会给您一个错误的误报,因为任何非零整数都将使用== 评估为真,因为它将非零整数转换为TRUE。如果您要检查来自Zip::open 的返回,则应始终使用$res === true 以检查是否成功。您可以在页面底部的评论中找到错误代码here的含义。

底线:由于您说您已经在提取 zip,因此根据 mime 类型进行验证可能不会那么麻烦,但是尝试打开文件并根据返回值进行验证会更容易open 的值。如果它返回 true,您可以确定该文件是一个有效的 zip(文件后面当然可能有错误,但他们至少上传了类似于 zip 文件的内容)。

希望对你有所帮助。

【讨论】:

  • 感谢您的建议 - 我也用更多信息更新了我的问题.. :)
  • @ChrisW 我刚刚更新了答案,希望能更多地解决您的问题。
  • 非常感谢。 1 个更快(尽管可能很愚蠢!)问题:Zip::open 显然根据文档返回 resource 或整数。 === 运算符检查类型和相等性,但是如果不是整数,为什么资源与布尔值 true 的类型相同?
  • 是的,这令人困惑,但是面向对象的接口在成功打开时返回布尔值 true,在失败时返回 int,过程接口在成功时返回资源(=== true 将不起作用),在失败时返回整数.
猜你喜欢
  • 1970-01-01
  • 2019-01-26
  • 1970-01-01
  • 2011-08-25
  • 1970-01-01
  • 1970-01-01
  • 2016-12-18
  • 2016-09-20
  • 2011-06-17
相关资源
最近更新 更多