我有一个网站,用于处理用户上传的文本文件,以确保它们实际上是文本文件我在PHP中检查mime类型,如下所示:
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mimeType = finfo_file($finfo, $filepath);
finfo_close($finfo);
大部分时间都可以正常工作。问题是有时上传的文件包含一些控制字符(不可打印的字符,如nul或stx)。尝试获取这些文件的mime类型总是返回application / octet-stream。例如,我有一个560行的文本文件,在第12行包含一个空字符,因此被识别为application / octet-stream
当检测到mime类型不起作用时,是否有任何安全可靠的方法来检查上传的文件是否为文本文件?
答案 0 :(得分:0)
原来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;
}