170

我正在开发一个简单的 php 上传脚本,用户只能上传 ZIP 和 RAR 文件。

我应该使用哪些 MIME 类型来检查$_FILES[x][type]?(请提供完整列表)

4

6 回答 6

290

来自自由和平组织、Kiyarash 和 Sam Vloeberghs 的回答:

.rar    application/x-rar-compressed, application/octet-stream
.zip    application/zip, application/octet-stream, application/x-zip-compressed, multipart/x-zip

我也会检查文件名。这是检查文件是 RAR 还是 ZIP 文件的方法。我通过创建一个快速的命令行应用程序对其进行了测试。

<?php

if (isRarOrZip($argv[1])) {
    echo 'It is probably a RAR or ZIP file.';
} else {
    echo 'It is probably not a RAR or ZIP file.';
}

function isRarOrZip($file) {
    // get the first 7 bytes
    $bytes = file_get_contents($file, FALSE, NULL, 0, 7);
    $ext = strtolower(substr($file, - 4));

    // RAR magic number: Rar!\x1A\x07\x00
    // http://en.wikipedia.org/wiki/RAR
    if ($ext == '.rar' and bin2hex($bytes) == '526172211a0700') {
        return TRUE;
    }

    // ZIP magic number: none, though PK\003\004, PK\005\006 (empty archive), 
    // or PK\007\008 (spanned archive) are common.
    // http://en.wikipedia.org/wiki/ZIP_(file_format)
    if ($ext == '.zip' and substr($bytes, 0, 2) == 'PK') {
        return TRUE;
    }

    return FALSE;
}

请注意,它仍然不是 100% 确定的,但它可能已经足够好了。

$ rar.exe l somefile.zip
somefile.zip is not RAR archive

但即使 WinRAR 也将非 RAR 文件检测为 SFX 存档:

$ rar.exe l somefile.srr
SFX Volume somefile.srr
于 2011-08-11T14:22:43.297 回答
38

上传:

可以在Internet 号码分配机构 (IANA)上找到 MIME 类型的官方列表。根据他们的列表Content-Type标题zipapplication/zip

文件的媒体类型rar未在 IANA 正式注册,但非官方常用的 mime-type 值为application/x-rar-compressed.

application/octet-stream相当于:“我向您发送一个文件流,但未指定该流的内容”(因此它也可以是一个ziprar文件,这是真的)。服务器应该检测流的实际内容是什么。

注意:对于上传而言,依赖标头中设置的 mime 类型是不安全的Content-Type。标头在客户端上设置,可以设置为任何随机值。相反,您可以使用php 文件信息函数来检测服务器上的文件 mime 类型。


下载:

如果你想下载一个zip文件而不是别的,你应该只设置一个Accept标题值。任何附加值设置将用作备用,以防服务器无法满足您Accept请求的标头 MIME 类型。

根据WC3规范

application/zip, application/octet-stream 

将被解释为:“我更喜欢application/zipmime 类型,但如果你不能提供这个application/octet-stream(文件流)也可以”。

所以只有一个:

application/zip

将向您保证一个zip文件(或406 - Not Acceptable在服务器无法满足您的请求的情况下做出响应)。

于 2015-04-09T13:22:03.220 回答
6

你不应该相信$_FILES['upfile']['mime'],自己检查 MIME 类型。为此,您可以使用从 PHP 5.3.0 开始默认启用的fileinfoextension

  $fileInfo = new finfo(FILEINFO_MIME_TYPE);
  $fileMime = $fileInfo->file($_FILES['upfile']['tmp_name']);
  $validMimes = array( 
    'zip' => 'application/zip',
    'rar' => 'application/x-rar',
  );

  $fileExt = array_search($fileMime, $validMimes, true);
  if($fileExt != 'zip' && $fileExt != 'rar')
    throw new RuntimeException('Invalid file format.');

注意:不要忘记启用扩展php.ini并重新启动服务器:

extension=php_fileinfo.dll
于 2015-11-06T13:31:23.620 回答
2

我分别看到了许多针对 zip 和 rar 媒体类型application/zip和rar 的答案报告application/x-rar-compressed

虽然前一个匹配是正确的,但对于后一个 IANA 在这里报告https://www.iana.org/assignments/media-types/application/vnd.rar rarapplication/x-rar-compressed是一个已弃用的别名,而是application/vnd.rar官方别名。因此,2020 年 IANA 的正确媒体类型是:

  1. zipapplication/zip
  2. rarapplication/vnd.rar
于 2020-09-07T14:24:57.457 回答
0

一个链接的问题中,有一些 Objective-C 代码可以获取文件 URL 的 mime 类型。我基于该 Objective-C 代码创建了一个 Swift 扩展来获取 mime 类型:

import Foundation
import MobileCoreServices

extension URL {
    var mimeType: String? {
        guard self.pathExtension.count != 0 else {
            return nil
        }

        let pathExtension = self.pathExtension as CFString
        if let preferredIdentifier = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, pathExtension, nil) {
            guard let mimeType = UTTypeCopyPreferredTagWithClass(preferredIdentifier.takeRetainedValue(), kUTTagClassMIMEType) else {
                return nil
            }
            return mimeType.takeRetainedValue() as String
        }

        return nil
    }
}
于 2018-11-01T08:06:33.110 回答
-3

由于扩展名可能包含或多或少的三个字符,因此无论扩展名的长度如何,以下都将测试扩展名。

试试这个:

$allowedExtensions = array( 'mkv', 'mp3', 'flac' );

$temp = explode(".", $_FILES[$file]["name"]);
$extension = strtolower(end($temp));

if( in_array( $extension, $allowedExtensions ) ) { ///

检查最后一个 '.' 之后的所有字符

于 2015-02-20T09:10:05.803 回答