.rar、.zip文件MIME类型


.rar, .zip files MIME Type

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

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

来自freedompeace、Kiyarash和Sam Vloeberghs的答案:

.rar    application/vnd.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

对于上传:

mime类型的官方列表可以在互联网号码分配机构(IANA(找到。根据它们的列表,用于zipContent-Type报头是application/zip

2016年在IANA注册的rar文件的媒体类型为application/vnd.rar(请参阅https://www.iana.org/assignments/media-types/application/vnd.rar)。mime类型值application/x-rar-compressed在此之前就已经使用过,尽管在上面的文档中被标记为不推荐使用,但它仍然是常用的。

CCD_ 8的含义相当于:;我给你发了一个文件流,这个流的内容没有指定"(因此它也可以是ziprar文件(。服务器应该检测流的实际内容

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


下载:

如果您想下载一个zip文件,而不想下载其他文件,那么您应该只设置一个单独的Accept头值。如果服务器无法满足Accept标头请求的mime类型,则任何附加值集都将用作回退。

根据WC3规范:

application/zip, application/octet-stream 

将被解释为:";我更喜欢application/zip mime类型,但如果不能提供application/octet-stream(文件流(也可以

所以只有一个:

application/zip

将保证为您提供zip文件(或406 - Not Acceptable响应,以防服务器无法满足您的请求(。

您不应该信任$_FILES['upfile']['mime'],请自行检查MIME类型。为此,您可以使用fileinfo扩展,默认情况下从PHP 5.3.0开始启用。

  $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

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

虽然前者的匹配是正确的,但对于后者,IANA在此处报告https://www.iana.org/assignments/media-types/application/vnd.rar对于rar,CCD_ 24是一个不推荐使用的别名,而CCD_ 25是官方别名。因此,2020年IANA的正确媒体类型是:

  1. zip:application/zip
  2. rar:application/vnd.rar

在一个链接问题中,有一些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
    }
}

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

试试这个:

$allowedExtensions = array( 'mkv', 'mp3', 'flac' );
$temp = explode(".", $_FILES[$file]["name"]);
$extension = strtolower(end($temp));
if( in_array( $extension, $allowedExtensions ) ) { ///

以检查最后一个"之后的所有字符