>  기사  >  백엔드 개발  >  php判断上传文件文件类型的安全方法

php判断上传文件文件类型的安全方法

WBOY
WBOY원래의
2016-06-20 13:01:011436검색

在使用 php 进行文件的上传和存储时,很多人都会给文件进行重名命并保存到可写文件夹下,然后我们在其中一个失误的地方便是采用上传文件的扩展名作为判断文件类型的依据。

这样做其实与后门大开无异,举一个简单的例子,通过扩展名判断一般是字符串的截取判断,或者是使用$_FILE数组判断,然后如果用户上传的文件名为 image.php.png, image.png.php, image.php%****.png 之类的话,判断就会出错。

另外,$_FILES['type']可能被篡改。

下面是我判断文件名的方法:

读取文件头四个字节作为判断。         

下面直接上代码

我实现的是仅支持word和pdf文件,且文件大小小于512kb:

	$tmpname = $_FILES ['userfile'] ['tmp_name'];
	if(is_uploaded_file($tmpname)) {
		$mimetype = detectMIME($tmpname);
		$tuozhanming = getFileExt($filename, $mimetype);
		if($tuozhanming == "type_error"){
			echo '仅支持word和pdf文件,且文件大小小于512kb:<a href=".%24reurl.">请重试</a>';
			exit();
		}
	}else{
		$_FILES ['userfile'] ['error'] = 6;
	}

	if ($_FILES ['userfile'] ['error'] > 0) {
		echo 'Problem: ';
		switch ($_FILES ['userfile'] ['error']) {
			case 1 :
				echo '上传文件过大:<a href=".%24reurl.">请重试</a>';
				break;
			case 2 :
				echo '上传文件过大:<a href=".%24reurl.">请重试</a>';
				break;
			case 3 :
				echo '文件上传丢失:<a href=".%24reurl.">请重试</a>';
				break;
			case 4 :
				echo '无文件被上传:<a href=".%24reurl.">请重试</a>';
				break;
			case 6 :
				echo '仅支持word和pdf文件,且文件大小小于512kb:<a href=".%24reurl.">请重试</a>';
				break;
			case 7 :
				echo '上传文件存储失败:<a href=".%24reurl.">请重试</a>';
				break;
		}
		exit ();
	}
	//判断文件类型
	//上传文件 
	$_FILES ['userfile'] ['name'] = time () . "." . $tuozhanming;
	$upfile = '../uploads/' . $_FILES ['userfile'] ['name'];

	if ( !move_uploaded_file ( $_FILES ['userfile'] ['tmp_name'], $upfile )) {
		echo 'Problem: 文件移动失败';
		exit ();
	}
	
}

function detectMIME($filename) {
	$file = fopen ( $filename, "rb" );
	$finfo = finfo_open ( FILEINFO_MIME );
	if (! $finfo) {
		// 直接读取文件的前4个字节,根据硬编码判断
		$file = fopen ( $filename, "rb" );
		$bin = fread ( $file, 4 ); //只读文件头4字节
		fclose ( $file );
		$strInfo = @unpack ( "C4chars", $bin );
		//dechex() 函数把十进制转换为十六进制。
		$typeCode = dechex ( $strInfo ['chars1'] ) . 
                            dechex ( $strInfo ['chars2'] ) . 
                            dechex ( $strInfo ['chars3'] ) . 
                            dechex ( $strInfo ['chars4'] );
		$type = '';
		switch ($typeCode) //硬编码值查表
		{
			case "504b34" :
				$type = 'application/zip; charset=binary';
				break;
			case "d0cf11e0" :
				$type = 'application/vnd.ms-office; charset=binary';
				break;
			case "25504446" :
				$type = 'application/pdf; charset=binary';
				break;
			default :
				$type = 'application/vnd.ms-office; charset=binary';
				break;
		}
	} else {
		//finfo_file return information of a file
		$type = finfo_file ( $finfo, $filename );
	}
	return $type;

function getFileExt($filename, $type) {
	switch ($type) {
		case "application/zip; charset=binary" :
			$extType = "docx";
			break;
		case "application/vnd.ms-office; charset=binary" :
			$extType = "doc";
			break;
		case "application/msword; charset=binary" :
    			$extType = "doc";
   			break;
		case "application/pdf; charset=binary" :
			$extType = "pdf";
			break;
		default :
			$extType = "type_error";
			break;
	}
	return $extType;
}

 


성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.