收藏本站 Archiver
    请 后使用快捷导航
    没有账号?入住 CI 中国社区
    查看: 7456|回复: 4

    [库 Library] 通过swfupload/其他flash上传控件 -上传实现严谨验证文件类型

    [复制链接]
    楼主
    发表于 2012年4月2日 16:19:16 | 只看该作者 回帖奖励 |倒序浏览 |
    已经有一段时间没用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复制代码

    <?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的判断。

    沙发
    发表于 2012年4月3日 22:59:49 | 只看该作者
    {:soso_e113:}
    藤椅
    发表于 2012年4月4日 13:31:43 | 只看该作者
    楼主好 谢谢你提供的方法 我做这个测试 我上传的jpg 二进制 显示 的是474946 我有点担心 不知道文件类型二进制在win和linux等平台下 是否有差异 为什么在win下的jpg上传 会有不同的二进制标识
    板凳
    楼主| 发表于 2012年4月4日 15:24:47 | 只看该作者
    我获取的非二进制,而是16进制头文件信息

    你可以使用Ultraedit32 或者winhex 查看文件信息是否相同。

    这应该不存在平台差异,我是在 类unix平台上测试的。

    但是貌似个别文件的头文件信息不尽相同,具体的需要搜集相关资料,进行阅读。
    报纸
    发表于 2014年10月18日 23:02:30 | 只看该作者
    返回列表
    您需要登录后才可以回帖 登录 | 入住 CI 中国社区

    本版积分规则

    AltStyle によって変換されたページ (->オリジナル) /