使用PHP检查文件是否为压缩文档(zip或rar)

15

我如何在不知道扩展名的情况下检查文件是否已被归档(zip或rar),我需要使用PHP来查找它。

由于文件信息(Fileinfo)未安装,而且服务器上安装其他任何软件包都是不可能的,因此我无法使用该方法。

更新:

Zip模块未安装,我不能安装额外的软件包。 我不想使用mime_content_type因为它已被弃用。

谢谢


mime_content_type已被弃用,而Fileinfo在服务器上未安装,我无法安装它。 - keepwalking
1
$zip = zip_open($file); if(is_resource($zip)){ //它是zip } else { //它不是zip } | 但对于rar,我不确定 - Senad Meškin
1
你应该在问题中提到这一点,这样就不会得到建议使用“Fileinfo”的答案。显然,你提供的信息越多,你得到的答案就越好。 - Felix Kling
如果未安装Fileinfo,则安装它。否则,重新发明轮子并为相关的文件类型编写自己的代码。或者使用Google搜索现有的库来解决这个问题。 - hakre
RAR和ZIP文件在文件的前几个字节中都有魔数。读取大约10个字节并检查这些数字非常容易。 - Marc B
6个回答

14
< p >从 od -c 输出:

  0000000    R   a   r   ! 032  \a  \0 317 220   s  \0  \0  \r  \0  \0  \0

  0000000    P   K 003 004  \n  \0  \0  \0  \0  \0  \0  \0   !  \0  \0  \0

您可以使用类似以下的内容:

您可以使用类似以下的内容:

<?php

$fh = @fopen($argv[1], "r");

if (!$fh) {
  print "ERROR: couldn't open file.\n";
  exit(126);
}

$blob = fgets($fh, 5);

fclose($fh);

if (strpos($blob, 'Rar') !== false) {
  print "Looks like a Rar.\n";
} else
if (strpos($blob, 'PK') !== false) {
  print "Looks like a ZIP.\n";
} else {
  print "I dunno.\n";
  exit(1);
}

?>

我的输出:

ghoti@baz:~ 423$ ./filephp.php A2.rar
Looks like a Rar.
ghoti@baz:~ 424$ ./filephp.php OLDIE.zip 
Looks like a ZIP.
ghoti@baz:~ 425$ ./filephp.php 1-11-1.PDF 
I dunno.
ghoti@baz:~ 426$ 

感谢你的回答,Fish! - lilHar
strpos($blob, 'PK') !== false 对于 .odt(OpenDocument)文件返回 true。 - om1
1
@om1 .. 是的。OpenDocument 文件是 ZIP 文件。尝试使用 unzip -v yadda.odt 查看里面的内容。如果您想正确地识别 ZIP 文件的内容,则需要查看前五个字节以外的内容。 - ghoti

7

要测试一个文件是否为zip存档文件,您可以使用open_zip函数尝试将其作为zip打开。对于rar文件,您需要安装PECL rar(最好版本至少为2.0.0) - 有关更多详细信息,请参见http://php.net/manual/en/book.rar.php。代码可能如下所示:

if(is_resource($zip = zip_open($filename)))
{
    zip_close($zip);
    //this is a zip archive
}
elseif(($rar = RarArchive::open($filename)) !== FALSE)
{
    $rar->close();
    //this is a rar archive
}
else
{
    //this is not a zip or rar archive
}

如果存档文件受密码保护,您可能需要做一些额外的工作。阅读相应的 PHP 手册页面以获取更多详细信息。


顺便说一下,第一个 if 缺少括号。 - Shadi
另外,如果文件大小为零,则会返回“this is a zip”。使用“if(filesize($zipfile)== 0)return false;”返回“this is not a zip”。 - Shadi
@RenanCavalieri 我的例子不是生产代码,而是展示可以做什么的演示。 - Aleks G
自PHP 8起,函数zip_open()已被弃用。https://www.php.net/manual/en/function.zip-open.php - Matt Smith
打开 zip 的新 PHP 功能是:https://www.php.net/manual/en/ziparchive.open.php - Matt Smith

2

fileinfo 函数应该可以帮助您完成此操作,通过检查文件的 MIME 类型:

$finfo = finfo_open(FILEINFO_MIME_TYPE);
echo finfo_file($finfo, $filename); // This will return the mime-type
finfo_close($finfo);

这在某些系统上容易在Office 2007+文档(DOCX、XLSX、PPTX)上失败,因此必须进行手动检查。 - flu

2
您可以输出unix文件命令的信息并解析它(假设您可以执行系统命令,这是不好的实践)。以下是centos“file filename”输出示例。
``` [rr@localhost images] (master)# file ui-anim_basic_16x16.gif ui-anim_basic_16x16.gif: GIF图像数据,版本89a,16 x 16 [rr@localhost images] (master)# file ui-icons_454545_256x240.png ui-icons_454545_256x240.png: PNG图像数据,256 x 240,8位调色板,无交错 [rr@localhost vendors] (master)# file jquery-validation-1.9.0.zip jquery-validation-1.9.0.zip: Zip归档数据,至少需要v1.0才能解压缩 ```
另外,就像其他人建议的那样,您可以读取几个字节并检查它们是否匹配签名。
对于rar:
``` 识别字符十六进制:52 61 72 21 1A 07 00,ASCII:Rar! ```
对于zip:
``` 识别字符十六进制:50 4B 03 04,ASCII:PK ```

2

读取文件的前10个字节。如果它们是(80,75,3,4,20,0,0,0,8,0),那么这是一个ZIP文件。 RAR文件的前7个字节为:(82,97,114,33,26,7,0) 如果您在文本编辑器(例如Notepad ++)中打开ZIP文件,则会看到: PK [ETX] [EOT] [DC4] [NUL] [NUL] [NUL] [BS] [NUL].... -> 上面列出了字符的Ascii代码。 对于RAR文件,情况如下: Rar![SUB] [BEL] [NUL] .... 因此,只需读取文件的前10个字节,就可以确定它是ZIP还是RAR存档。 干杯


2
如果问题涉及到在 PHP 中进行检查,我不知道 Notepad++ 或任何文本编辑器相关的解决方案是否有帮助。 - Tom
3
你应该只检查前4个字节是否为"\x50\x4b\x03\x04",因为它们是PKZip文件唯一的标识。例如,第5和第6个字节指示了提取所需的PKZip版本(在你的例子中为2.0),这可能会有所不同。参见:ZIP文件的结构 - flu

1
<?php

function isZipFile($filepath){
    $fh = fopen($filepath,'r');
    $bytes = fread($fh,4);
    fclose($fh);
    return ('504b0304' === bin2hex($bytes));
}

感谢flu提供的有关zip文件规范的有用链接。


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