如果 mime 类型检测失败,是否有安全可靠的方法来检查文件是否为文本文件?
Is there a safe and reliable way to check if a file is a text file if mime type detecting fails?
我有一个处理用户上传的文本文件的网站,为了确保它们实际上是文本文件,我在 PHP 中检查了 mime 类型,如下所示:
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mimeType = finfo_file($finfo, $filepath);
finfo_close($finfo);
大多数时候效果很好。问题是有时上传的文件包含一些控制字符(不可打印的字符,如 nul 或 stx)。始终尝试获取这些文件的 MIME 类型 returns application/octet-stream。例如,我有一个 560 行长的文本文件,第 12 行包含一个空字符,因此被识别为 application/octet-stream
在检测mime类型无效的情况下,有什么安全可靠的方法可以检测上传的文件是否为文本文件?
原来 php 中的大多数文件读取函数都是 binary safe,这回答了我关于如何安全读取文件的问题。
我最终通过计算控制字符数解决了我的问题。如果文件的一块包含超过 1% 的控制字符,我认为它不是文本文件。
下面的函数适用于我使用它的目的(即使它只适用于 UTF-8 文件)
public static function isTextFile($filepath)
{
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mimeType = finfo_file($finfo, $filepath);
finfo_close($finfo);
if(substr($mimeType, 0, 5) === "text/") {
return true;
}
if($mimeType !== "application/octet-stream") {
return false;
}
$handle = fopen($filepath, 'rb');
while (!feof($handle)) {
$chunk = fread($handle, 4096);
$controlCharCount = 0;
if(($length = strlen($chunk)) === 0) {
continue;
}
for($i = 0; $i < $length; $i++) {
if($chunk[$i] !== "\r" && $chunk[$i] !== "\n" && ctype_cntrl($chunk[$i])) {
$controlCharCount++;
}
}
if(100 - $controlCharCount / $length * 100 < 99.0) {
return false;
}
}
fclose($handle);
return true;
}
我有一个处理用户上传的文本文件的网站,为了确保它们实际上是文本文件,我在 PHP 中检查了 mime 类型,如下所示:
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mimeType = finfo_file($finfo, $filepath);
finfo_close($finfo);
大多数时候效果很好。问题是有时上传的文件包含一些控制字符(不可打印的字符,如 nul 或 stx)。始终尝试获取这些文件的 MIME 类型 returns application/octet-stream。例如,我有一个 560 行长的文本文件,第 12 行包含一个空字符,因此被识别为 application/octet-stream
在检测mime类型无效的情况下,有什么安全可靠的方法可以检测上传的文件是否为文本文件?
原来 php 中的大多数文件读取函数都是 binary safe,这回答了我关于如何安全读取文件的问题。
我最终通过计算控制字符数解决了我的问题。如果文件的一块包含超过 1% 的控制字符,我认为它不是文本文件。
下面的函数适用于我使用它的目的(即使它只适用于 UTF-8 文件)
public static function isTextFile($filepath)
{
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mimeType = finfo_file($finfo, $filepath);
finfo_close($finfo);
if(substr($mimeType, 0, 5) === "text/") {
return true;
}
if($mimeType !== "application/octet-stream") {
return false;
}
$handle = fopen($filepath, 'rb');
while (!feof($handle)) {
$chunk = fread($handle, 4096);
$controlCharCount = 0;
if(($length = strlen($chunk)) === 0) {
continue;
}
for($i = 0; $i < $length; $i++) {
if($chunk[$i] !== "\r" && $chunk[$i] !== "\n" && ctype_cntrl($chunk[$i])) {
$controlCharCount++;
}
}
if(100 - $controlCharCount / $length * 100 < 99.0) {
return false;
}
}
fclose($handle);
return true;
}