在$_FILES数组中,type字段中的图片类型不能作为检测的途径。应为这个值是浏览器通过HTTP头发送过来的,是可以伪造的。例如:
首先在test.php中写入,然后修改文件名为test.jpg,并通过表单添加该文件。
服务端接收的数据如下:
1 2 3 4 5 6 7 8 9
| array ( 'pic' => array ( 'name' => 'test.jpg', 'type' => 'image/jpeg', 'tmp_name' => '/tmp/phpogAh98', 'error' => 0, 'size' => 0, ), )
|
网络上也有一些通过读取文件前2字节,来判断文件类型的代码。但这些方法既不严谨也不够安全。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| function file_type($filename) { $file = fopen($filename, "rb"); $bin = fread($file, 2); fclose($file); $strInfo = @unpack("C2chars", $bin); $typeCode = intval($strInfo['chars1'].$strInfo['chars2']); $fileType = ''; switch ($typeCode) { case 7790: $fileType = 'exe';break; case 7784: $fileType = 'midi';break; case 8297: $fileType = 'rar';break; case 8075: $fileType = 'zip';break; case 255216: $fileType = 'jpg';break; case 7173: $fileType = 'gif';break; case 6677: $fileType = 'bmp';break; case 13780: $fileType = 'png';break; default: $fileType = 'unknown: '.$typeCode; } if ($strInfo['chars1']=='-1' AND $strInfo['chars2']=='-40' ) return 'jpg'; if ($strInfo['chars1']=='-119' AND $strInfo['chars2']=='80' ) return 'png'; return $fileType; }
|
其实,在php中就有检测图片类型的方法。getimagesize。这个函数不需要GD等画图库的支持。打开文件失败或者不是有效的图片时返回false。
1 2 3 4 5 6 7 8 9
| array ( 0 => 460, 1 => 406, 2 => 2, 3 => 'width="460" height="406"', 'bits' => 8, 'channels' => 3, 'mime' => 'image/jpeg', )
|
正确的放回值中mime亦可用作进一步过滤图片类型。另外需要注意,当被检测的文件为空时,会产生警告:
1 2
| Notice: getimagesize(): Read error! in /fileupload/sample5/file_type_detect.php on line 2 false
|
可以使用filezie()函数先过滤掉空的文件。或者使用@getimagesize()抑制错误输出。