通过swfupload/其他flash上传控件 -上传实现严谨验证文件类型
已经有一段时间没用swfupload,一来项目不需要实现多文件。二来想实现swfupload显示上传进度条,触发完成后的节点操作需要较严谨的js语句,且美化起来破繁。 当然利用swfupload上传不乏有效果美观的,如douban的swfupload照片上传、bbsmax的swfupload上传、QQ邮箱类swfupload的附件上传,都很不错。我也曾把douban的获取下来做了些应用。大家都知道通过flash上传的文件,mime 类型都被擦除 ,只能通过后缀判断文件的正确与否。从应用上来说无什么大影响。包括qq等大型应用,都是不管的,只判断后缀。
但是总是会有捣乱的,伪后缀上传文件。比如图片不是图片,压缩文件不是压缩文件。非图片的img后缀文件上传后,img标签一包含就显示一个大叉叉很不美观。并且安全上也会大打折扣。
在网上闲逛时发现了几篇文章
http://blog.csdn.net/piaolankeke/article/details/5873156
http://www.21andy.com/blog/20090624/1337.html
通过文件头信息判断文件的真实信息。如此不管mime类型被伪造了,被擦除了都无碍。
想知道更多,可以看看文件头的相关文章。
如此我们就能用来扩展swfupload上传了,实现在无mime类型的情况下严谨的验证文件类型
代码如下,在application/libraries下扩展CI_uoload的 _file_mime_type 方法
<?php
class MY_Upload extends CI_Upload
{
public $swf_mime = array(
"FFD8FF" => "image/jpeg",
"89504E47" => "image/png",
"47494638" => "image/gif",
"424D" => "image/bmp",
"3C3F786D6C"=> "text/xml",
"504B0304" => "application/x-zip");
public function __construct()
{
parent::__construct();
}
protected function _file_mime_type($file)
{
if(file_exists($file['tmp_name']))
{
//$this->file_type = 'application/octet-stream';
$check_file = @fopen($file['tmp_name'],'rb');
$bin = fread($check_file,15);
fclose($check_file);
foreach ($this->swf_mime as $bin_name => $mime_type)
{
$blen=strlen(pack("H*",$bin_name)); //得到文件头标记字节数
$tbin=substr($bin,0,intval($blen)); ///需要比较文件头长度
if(strtolower($bin_name)==strtolower(array_shift(unpack("H*",$tbin))))
{
$this->file_type = $mime_type;
return;
}
}
}
// Use if the Fileinfo extension, if available (only versions above 5.3 support the FILEINFO_MIME_TYPE flag)
if ( (float) substr(phpversion(), 0, 3) >= 5.3 && function_exists('finfo_file'))
{
$finfo = new finfo(FILEINFO_MIME_TYPE);
if ($finfo !== FALSE) // This is possible, if there is no magic MIME database file found on the system
{
$file_type = $finfo->file($file['tmp_name']);
/* According to the comments section of the PHP manual page,
* it is possible that this function returns an empty string
* for some files (e.g. if they don't exist in the magic MIME database)
*/
if (strlen($file_type) > 1)
{
$this->file_type = $file_type;
return;
}
}
}
// Fall back to the deprecated mime_content_type(), if available
if (function_exists('mime_content_type'))
{
$this->file_type = @mime_content_type($file['tmp_name']);
return;
}
/* This is an ugly hack, but UNIX-type systems provide a native way to detect the file type,
* which is still more secure than depending on the value of $_FILES[$field]['type'].
*
* Notes:
* - a 'W' in the substr() expression bellow, would mean that we're using Windows
* - many system admins would disable the exec() function due to security concerns, hence the function_exists() check
*/
if (DIRECTORY_SEPARATOR !== '\\' && function_exists('exec'))
{
$output = array();
@exec('file --brief --mime-type ' . escapeshellarg($file['tmp_path']), $output, $return_code);
if ($return_code === 0 && strlen($output) > 0) // A return status code != 0 would mean failed execution
{
$this->file_type = rtrim($output);
return;
}
}
$this->file_type = $file['type'];
}
}
1,代码在203,210上均验证通过可用。只是2.1.0 的upload原本就有问题。可以确准好本身逻辑无错再做替换验证。
2,另外网络上流传的几个文件头信息,都不是很准,各有各的说法,要准还需要自己通过软件多看看各类的文件头。
3,以上代码修改了 _file_mime_type 方法,删除了对mime的判断。
{:soso_e113:} 楼主好 谢谢你提供的方法 我做这个测试 我上传的jpg 二进制 显示 的是474946 我有点担心 不知道文件类型二进制在win和linux等平台下 是否有差异 为什么在win下的jpg上传 会有不同的二进制标识 我获取的非二进制,而是16进制头文件信息
你可以使用Ultraedit32 或者winhex 查看文件信息是否相同。
这应该不存在平台差异,我是在 类unix平台上测试的。
但是貌似个别文件的头文件信息不尽相同,具体的需要搜集相关资料,进行阅读。 {:1_1:}
页:
[1]