判断文件类型在开发中非常常见的需求,很多开发者的做法是简单判断文件的扩展名,很遗憾,这种方法非常不靠谱,因为文件扩展名可以伪造,并且在Linux系统中,没有扩展名的概念!
这里推荐一种准确判断文件类型的方法:通过二进制文件头判断文件类型
代码非常简单,只需从文件流中读取前两个字节,再解包,即可判断出文件类型,并且大部分语言都支持,Python和PHP版示例参考:
Python版
# -*- coding: utf-8 -*-
import struct
file_type_map = {
'7790' : 'exe',
'7784' : 'midi',
'8075' : 'zip',
'8297' : 'rar',
'7173' : 'gif',
'6677' : 'bmp',
'13780' : 'png',
'255216' : 'jpg',
}
def get_file_type(filename):
fp = open(filename, 'rb')
str_info = struct.unpack_from("BB", fp.read(2))
str_code = '%d%d' % (str_info[0], str_info[1])
fp.close()
return 'unknown' if str_code not in file_type_map else file_type_map[str_code]
if __name__ == '__main__':
file_type = get_file_type('./test.png')
print(file_type)
PHP版
PHP有一个内置的专门用于判断图像类型的方法,exif_imagetype
,默认未开启,需要编译时候指定 --enable-exif
开启,并且只支持图像类型文件,所以不推荐使用。PHP同样可以通过二进制文件头判断文件类型
<?php
$file_type_map = array(
7790 => 'exe',
7784 => 'midi',
8075 => 'zip',
8297 => 'rar',
7173 => 'gif',
6677 => 'bmp',
13780 => 'png',
255216 => 'jpg',
);
function get_file_type($file) {
$filepath = realpath($file);
if (!($fp = @fopen($filepath, 'rb')))
return false;
$bin = fread($fp, 2);
fclose($fp);
$str_info = @unpack('C2chars', $bin);
$str_code = intval($str_info['chars1'].$str_info['chars2']);
global $file_type_map;
return $file_type_map[$str_code] ?: 'unknown';
}
$file_type = get_file_type('./test.png');
print($file_type);