Skip to content

Instantly share code, notes, and snippets.

@burtgithub
Forked from chzyer/php-header-file-type.md
Created September 10, 2019 02:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save burtgithub/8dc4f52f29507417b8a1f40c200df6c8 to your computer and use it in GitHub Desktop.
Save burtgithub/8dc4f52f29507417b8a1f40c200df6c8 to your computer and use it in GitHub Desktop.
[转] PHP分析文件头信息判断文件类型

我的话:

前阵子用PHP的上传功能貌似是能自动从文件头信息判断文件类型的而不是简单得从后缀名,因为最近在处理一个百度文库功能,需要处理上传文档功能,发现就算其他文件只要改后缀名就能伪装成文档的格式
下面是我在网上找到的所谓能判断文件类型,但是经过试验,不是很精准,因为OFFICE新出文件类型实际上是一个ZIP的压缩包,而07前版本的文件类型是srorage方式储存,可见,要实现完全正确的文件类型判断是一件很困难的事情...

PHP分析文件头信息判断文件类型

在用PHP上传文件时一般要限制可上传的文件类型,以保证系统的安全。文件类型通常通过文件的后缀进行判断,但这样只要用户把文件的后缀名修改一下就可以绕过检查而实现上传,但如果我们在判断文件名后缀的同时通过分析文件头信息判断文件类型,那些不怀好意的鸟人们再想捣乱可能就没那么简单了: 要分析文件头信息肯定要先读取文件,在PHP中,可以先用fopen()打开文件,然后通过fread()读取文件内容,不用全部读取,因为要判断文件类型我们只需要得到文件的前2个字节就足够了。得到的内容是二进制的,为了能在程序代码中做判断,需要把二进制数据转换成十进制数字的字符串,这时最关键的 unpack() 函数就派上用场了,unpack()函数主要用于二进制操作,我了解的也不多,看起来比较深奥,有时间好好研究下。 OK,还是把示例代码放上来吧:

$filename = "C:\\Program Files\\Apache Software Foundation\\Apache2.2\\htdocs\\excel\\Excel.xls";
$file = fopen($filename, "rb");
$bin = fread($file, 2); //只读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 255216:
		$fileType = 'jpg';
		break;
	case 7173:
		$fileType = 'gif';
		break;
	case 6677:
		$fileType = 'bmp';
		break;
	case 13780:
		$fileType = 'png';
		break;
	default:
		echo 'unknown';
}
echo 'this is a(an) '.$fileType.' file:'.$typeCode;
@burtgithub
Copy link
Author

$strInfo = @unpack("C2chars", $bin); 是大写C2chars

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment