准确判断文件类型方法之二进制文件头

判断文件类型在开发中非常常见的需求,很多开发者的做法是简单判断文件的扩展名,很遗憾,这种方法非常不靠谱,因为文件扩展名可以伪造,并且在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);

Related post

微信公众号:程序员到架构师

最新文章

Return Top