php检测上传excel文件类型的示例代码

发布时间:2019-08-18编辑:脚本学堂
分享一例php代码,用于检测上传的excel文件的类型,一种比较高端检测上传文件类型的方法,有需要的朋友参考学习下。

本节内容:
检测上传excel文件类型

为大家介绍一种比较高端检测上传文件类型的方法,可以防止后缀名修改等低端的检测错误。

MIME类型
在把输出结果传送到浏览器上的时候,浏览器必须启动适当的应用程序来处理这个输出文档。这可以通过多种类型MIME(multipurpose internet mail extensions)来完成。在http中,MIME类型被定义在content-type header中。

例如,如果客户端上传一个excel文件到服务器上,那么这是的mime类型就是“application/vnd.ms-excel”。在php中,可以通过$_FILE["type"]获得上传文件类型。
最早的HTTP协议中,并没有附加的数据类型信息,所有传送的数据都被客户端解释为HTML文档,而为了支持多媒体数据类型,HTTP协议中就使用了附加在文档之前的MIME数据类型信息来标识数据类型。

每个MIME类型由两部分组成,前面是数据的大类别,后面定义具体的种类。(具体可以查询mime类型表)

文件检测弊端
文件扩展名检测漏洞(ps:文件扩展名可以被任意伪造)
文件MIME类型判断不能使用$_FILES['userfile']['type'](ps:根据PHP官方的文档说明,该值完全可以被伪造!
黑客只需修改浏览器的post请求头即可绕过这段代码检查,进而上传任意类型的文件!)

检测方法(针对excel)
通过文件扩展名判断是03的excel文件还是07的excel文件
根据不同的文件,获取不同文件的二进制数据,和file_signature进行对比,我截了03和07的excel的二进制数据图,工具是madedit,大家参考下:
1,03的excel
03的excel

2,07的excel(07可以参考zip检测)
07的excel

检测程序:
 

复制代码 代码示例:
<?php
/**
 * Detect upload file type
 * 检测上传文件的excel文件类型
 * @param array $file           
 * @return bool $flag
 * @site www.jb200.com
 */ 
private function detectUploadFileMIME($file) { 
    // 1.through the file extension judgement 03 or 07 
    $flag = 0; 
    $file_array = explode ( ".", $file ["name"] ); 
    $file_extension = strtolower ( array_pop ( $file_array ) ); 
     
    // 2.through the binary content to detect the file 
    switch ($file_extension) { 
        case "xls" : 
            // 2003 excel 
            $fh = fopen ( $file ["tmp_name"], "rb" ); 
            $bin = fread ( $fh, 8 ); 
            fclose ( $fh ); 
            $strinfo = @unpack ( "C8chars", $bin ); 
            $typecode = ""; 
            foreach ( $strinfo as $num ) { 
                $typecode .= dechex ( $num ); 
            } 
            if ($typecode == "d0cf11e0a1b11ae1") { 
                $flag = 1; 
            } 
            break
        case "xlsx" : 
            // 2007 excel 
            $fh = fopen ( $file ["tmp_name"], "rb" ); 
            $bin = fread ( $fh, 4 ); 
            fclose ( $fh ); 
            $strinfo = @unpack ( "C4chars", $bin ); 
            $typecode = ""; 
            foreach ( $strinfo as $num ) { 
                $typecode .= dechex ( $num ); 
            } 
            echo $typecode; 
            if ($typecode == "504b34") { 
                $flag = 1; 
            } 
            break; 
    } 
     
    // 3.return the flag 
    return $flag;