已经有一段时间没用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]) > 0) // A return status code != 0 would mean failed execution { $this->file_type = rtrim($output[0]); return; } } $this->file_type = $file['type']; } }
1,代码在203,210上均验证通过可用。只是2.1.0 的upload原本就有问题。可以确准好本身逻辑无错再做替换验证。
2,另外网络上流传的几个文件头信息,都不是很准,各有各的说法,要准还需要自己通过软件多看看各类的文件头。
3,以上代码修改了 _file_mime_type 方法,删除了对mime的判断。
转载于:http://codeigniter.org.cn/forums/forum.php?mod=viewthread&tid=12116
浙公网安备 33010602011771号