如何根据扩展名验证文件类型


How to validate a file type against its extension?

我想创建一个上传器脚本,我想定义一些允许上传的文件类型,通过重命名文件扩展名来防止作弊。我使用这个数组:PHP/Mime types-公共可用的Mime类型列表?首先,它检查是否允许文件扩展名(例如.xsl),然后使用finfo获取mimtype来检查该数组,看看mimetype是否与扩展名匹配。

我上传了一个.xsl文件,finfo将文件类型重新运行为application/octet流,但xsl扩展名的数组返回application/x-mexcel,因此它将不相等,也不会被验证。

我真的应该忘记mimetype与脚本的文件扩展名验证器的匹配吗?我应该只检查文件扩展名吗?或者我该怎么办?

基本上你做得对。你永远不应该依赖从上传表单发送的mime类型的头,因为你可以很容易地伪造它,或者它不存在,那么你通常会得到application/octet-stream头。

因此,检查文件扩展名是否与该文件扩展名允许的mime类型匹配将是一个很好的方法。

我看到你在这里链接了这个列表。这当然是一个很好的列表,但对php来说并不可用,因为数组中有太多的ovverriden,例如:

$mimeTypes = array(
    'xlm' => 'application/vnd.ms-excel',//overridden
    'xlm' => 'application/x-excel',
    'xls' => 'application/excel',//overridden
    'xls' => 'application/vnd.ms-excel'
);
var_dump( $mimeTypes );

这将只输出两个值,而不是四个值,您应该使用这样的数组:

$mimeTypes = array(
    'xlm' => array( 'application/vnd.ms-excel', 'application/x-excel' ),
    'xls' => array( 'application/excel', 'application/vnd.ms-excel' ),
    'txt' => array( 'text/plain' )
);
var_dump( $mimeTypes );

因此,如果您已经拥有文件扩展名,您可以简单地使用in_array()检查mimetype。

这是一个你可以解决的基本例子。注意:这不是一个有效的例子,但我想你知道我想指出的地方:

// you have your file, you said it´s excel but you uploaded it with extension txt
$filepath = "excel.txt";
if( strpos( $filepath, '.' ) === false ) {
    // no file extension
    // return ?
}
// get the file extension
// well there is surely a better way
$filenameParts = explode( ".", $filepath );
$fileExt = array_pop( $filenameParts );// return the las element of the array and REMOVES it from the array
// your fopen stuff to get the mime type
// ok let´s say we are getting back the follwing mime type
$fileMimeType = 'application/vnd.ms-excel';
// now check if filextension is in array and if mimetype for this extension is correct
if( isset( $mimeTypes[$fileExt] ) && in_array( $fileMimeType, $mimeTypes[$fileExt] ) ) {
    // file extension is OK AND mime type matches the file extension
} else {
    // not passed unknown file type, unknown mime type, or someone tricked you
    // your excel.txt should end up here
}