codeigniter教程之多文件上传使用示例


Posted in PHP onFebruary 11, 2014
<?php if(!defined("BASEPATH")){ exit("No direct script access allowed"); }
 /**
  * Multi-Upload
  * 
  * Extends CodeIgniters native Upload class to add support for multiple
  * uploads.
  *
  * @package  CodeIgniter
  * @subpackage Libraries
  * @category Uploads
  */
  class MY_Upload extends CI_Upload {

   /**
    * Properties
    */
     protected $_multi_upload_data   = array();
    protected $_multi_file_name_override = "";

   /**
    * Initialize preferences
    *
    * @access public
    * @param array
    * @return void
    */
    public function initialize($config = array()){
     //Upload default settings.
     $defaults = array(
         "max_size"   => 0,
         "max_width"   => 0,
         "max_height"  => 0,
         "max_filename"  => 0,
         "allowed_types"  => "",
         "file_temp"   => "",
         "file_name"   => "",
         "orig_name"   => "",
         "file_type"   => "",
         "file_size"   => "",
         "file_ext"   => "",
         "upload_path"  => "",
         "overwrite"   => FALSE,
         "encrypt_name"  => FALSE,
         "is_image"   => FALSE,
         "image_width"  => "",
         "image_height"  => "",
         "image_type"  => "",
         "image_size_str" => "",
         "error_msg"   => array(),
         "mimes"    => array(),
         "remove_spaces"  => TRUE,
         "xss_clean"   => FALSE,
         "temp_prefix"  => "temp_file_",
         "client_name"  => ""
        );
     //Set each configuration.
     foreach($defaults as $key => $val){
      if(isset($config[$key])){
       $method = "set_{$key}";
       if(method_exists($this, $method)){
        $this->$method($config[$key]);
       } else {
        $this->$key = $config[$key];
       }
      } else {
       $this->$key = $val;
      }
     }
     //Check if file_name was provided.
     if(!empty($this->file_name)){
      //Multiple file upload.
      if(is_array($this->file_name)){
       //Clear file name override.
       $this->_file_name_override = "";
       //Set multiple file name override.
       $this->_multi_file_name_override = $this->file_name;
      //Single file upload.
      } else {
       //Set file name override.
       $this->_file_name_override = $this->file_name;
       //Clear multiple file name override.
       $this->_multi_file_name_override = "";
      }
     }
    }

   /**
    * File MIME Type
    * 
    * Detects the (actual) MIME type of the uploaded file, if possible.
    * The input array is expected to be $_FILES[$field].
    * 
    * In the case of multiple uploads, a optional second argument may be
    * passed specifying which array element of the $_FILES[$field] array
    * elements should be referenced (name, type, tmp_name, etc).
    *
    * @access protected
    * @param $file array
    * @param $count int
    * @return void
    */
    protected function _file_mime_type($file, $count=0){
     //Mutliple file?
     if(is_array($file["name"])){
      $tmp_name = $file["tmp_name"][$count];
      $type = $file["type"][$count];
     //Single file.
     } else {
      $tmp_name = $file["tmp_name"];
      $type = $file["type"];
     }
     //We'll need this to validate the MIME info string (e.g. text/plain; charset=us-ascii).
     $regexp = "/^([a-z\-]+\/[a-z0-9\-\.\+]+)(;\s.+)?$/";
     /* Fileinfo Extension - most reliable method.
      * 
      * Unfortunately, prior to PHP 5.3 - it's only available as a PECL extension and the
      * more convenient FILEINFO_MIME_TYPE flag doesn't exist.
      */
       if(function_exists("finfo_file")){
        $finfo = finfo_open(FILEINFO_MIME);
       if(is_resource($finfo)){
        $mime = @finfo_file($finfo, $tmp_name);
        finfo_close($finfo);
        /* 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(is_string($mime) && preg_match($regexp, $mime, $matches)){
           $this->file_type = $matches[1];
          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'], and as it
      * was reported in issue #750 (https://github.com/EllisLab/CodeIgniter/issues/750) - it's better
      * than mime_content_type() as well, hence the attempts to try calling the command line with
      * three different functions.
      *
      * Notes:
      * - the DIRECTORY_SEPARATOR comparison ensures that we're not on a Windows system
      * - many system admins would disable the exec(), shell_exec(), popen() and similar functions
      *   due to security concerns, hence the function_exists() checks
      */
       if(DIRECTORY_SEPARATOR !== "\\"){
        $cmd = "file --brief --mime ".escapeshellarg($tmp_name)." 2>&1";
       if(function_exists("exec")){
        /* This might look confusing, as $mime is being populated with all of the output when set in the second parameter.
         * However, we only neeed the last line, which is the actual return value of exec(), and as such - it overwrites
         * anything that could already be set for $mime previously. This effectively makes the second parameter a dummy
         * value, which is only put to allow us to get the return status code.
         */
         $mime = @exec($cmd, $mime, $return_status);
         if($return_status === 0 && is_string($mime) && preg_match($regexp, $mime, $matches)){
          $this->file_type = $matches[1];
          return;
         }
       }
       }
      if((bool)@ini_get("safe_mode") === FALSE && function_exists("shell_exec")){
       $mime = @shell_exec($cmd);
       if(strlen($mime) > 0){
        $mime = explode("\n", trim($mime));
        if(preg_match($regexp, $mime[(count($mime) - 1)], $matches)){
         $this->file_type = $matches[1];
         return;
        }
       }
      }
      if(function_exists("popen")){
       $proc = @popen($cmd, "r");
       if(is_resource($proc)){
        $mime = @fread($proc, 512);
        @pclose($proc);
        if($mime !== FALSE){
         $mime = explode("\n", trim($mime));
         if(preg_match($regexp, $mime[(count($mime) - 1)], $matches)){
          $this->file_type = $matches[1];
          return;
         }
        }
       }
      }
      //Fall back to the deprecated mime_content_type(), if available (still better than $_FILES[$field]["type"])
      if(function_exists("mime_content_type")){
       $this->file_type = @mime_content_type($tmp_name);
       //It's possible that mime_content_type() returns FALSE or an empty string.
       if(strlen($this->file_type) > 0){
        return;
       }
      }
      //If all else fails, use $_FILES default mime type.
      $this->file_type = $type;
    }

   /**
    * Set Multiple Upload Data
    *
    * @access protected
    * @return void
    */
    protected function set_multi_upload_data(){
     $this->_multi_upload_data[] = array(
      "file_name"   => $this->file_name,
      "file_type"   => $this->file_type,
      "file_path"   => $this->upload_path,
      "full_path"   => $this->upload_path.$this->file_name,
      "raw_name"   => str_replace($this->file_ext, "", $this->file_name),
      "orig_name"   => $this->orig_name,
      "client_name"  => $this->client_name,
      "file_ext"   => $this->file_ext,
      "file_size"   => $this->file_size,
      "is_image"   => $this->is_image(),
      "image_width"  => $this->image_width,
      "image_height"  => $this->image_height,
      "image_type"  => $this->image_type,
      "image_size_str" => $this->image_size_str
     );
    }

   /**
    * Get Multiple Upload Data
    *
    * @access public
    * @return array
    */
    public function get_multi_upload_data(){
     return $this->_multi_upload_data;
    }

   /**
    * Multile File Upload
    *
    * @access public
    * @param string
    * @return mixed
    */
    public function do_multi_upload($field){
     //Is $_FILES[$field] set? If not, no reason to continue.
     if(!isset($_FILES[$field])){ return false; }
     //Is this really a multi upload?
     if(!is_array($_FILES[$field]["name"])){
      //Fallback to do_upload method.
      return $this->do_upload($field);
     }
     //Is the upload path valid?
     if(!$this->validate_upload_path()){
      //Errors will already be set by validate_upload_path() so just return FALSE
      return FALSE;
     }
     //Every file will have a separate entry in each of the $_FILES associative array elements (name, type, etc).
     //Loop through $_FILES[$field]["name"] as representative of total number of files. Use count as key in
     //corresponding elements of the $_FILES[$field] elements.
     for($i=0; $i<count($_FILES[$field]["name"]); $i++){
      //Was the file able to be uploaded? If not, determine the reason why.
      if(!is_uploaded_file($_FILES[$field]["tmp_name"][$i])){
       //Determine error number.
       $error = (!isset($_FILES[$field]["error"][$i])) ? 4 : $_FILES[$field]["error"][$i];
       //Set error.
       switch($error){
        //UPLOAD_ERR_INI_SIZE
        case 1:
         $this->set_error("upload_file_exceeds_limit");
        break;
        //UPLOAD_ERR_FORM_SIZE
        case 2:
         $this->set_error("upload_file_exceeds_form_limit");
        break;
        //UPLOAD_ERR_PARTIAL
        case 3:
         $this->set_error("upload_file_partial");
        break;
        //UPLOAD_ERR_NO_FILE
        case 4:
         $this->set_error("upload_no_file_selected");
        break;
        //UPLOAD_ERR_NO_TMP_DIR
        case 6:
         $this->set_error("upload_no_temp_directory");
        break;
        //UPLOAD_ERR_CANT_WRITE
        case 7:
         $this->set_error("upload_unable_to_write_file");
        break;
        //UPLOAD_ERR_EXTENSION
        case 8:
         $this->set_error("upload_stopped_by_extension");
        break;
        default:
         $this->set_error("upload_no_file_selected");
        break;
       }
       //Return failed upload.
       return FALSE;
      }
      //Set current file data as class variables.
      $this->file_temp = $_FILES[$field]["tmp_name"][$i];
      $this->file_size = $_FILES[$field]["size"][$i];
      $this->_file_mime_type($_FILES[$field], $i);
      $this->file_type = preg_replace("/^(.+?);.*$/", "\\1", $this->file_type);
      $this->file_type = strtolower(trim(stripslashes($this->file_type), '"'));
      $this->file_name = $this->_prep_filename($_FILES[$field]["name"][$i]);
      $this->file_ext  = $this->get_extension($this->file_name);
      $this->client_name = $this->file_name;
      //Is the file type allowed to be uploaded?
      if(!$this->is_allowed_filetype()){
       $this->set_error("upload_invalid_filetype");
       return FALSE;
      }
      //If we're overriding, let's now make sure the new name and type is allowed.
      //Check if a filename was supplied for the current file. Otherwise, use it's given name.
      if(!empty($this->_multi_file_name_override[$i])){
       $this->file_name = $this->_prep_filename($this->_multi_file_name_override[$i]);
       //If no extension was provided in the file_name config item, use the uploaded one.
       if(strpos($this->_multi_file_name_override[$i], ".") === FALSE){
        $this->file_name .= $this->file_ext;
       //An extension was provided, lets have it!
       } else {
        $this->file_ext = $this->get_extension($this->_multi_file_name_override[$i]);
       }
       if(!$this->is_allowed_filetype(TRUE)){
        $this->set_error("upload_invalid_filetype");
        return FALSE;
       }
      }
      //Convert the file size to kilobytes.
      if($this->file_size > 0){
       $this->file_size = round($this->file_size/1024, 2);
      }
      //Is the file size within the allowed maximum?
      if(!$this->is_allowed_filesize()){
       $this->set_error("upload_invalid_filesize");
       return FALSE;
      }
      //Are the image dimensions within the allowed size?
      //Note: This can fail if the server has an open_basdir restriction.
      if(!$this->is_allowed_dimensions()){
       $this->set_error("upload_invalid_dimensions");
       return FALSE;
      }
      //Sanitize the file name for security.
      $this->file_name = $this->clean_file_name($this->file_name);
      //Truncate the file name if it's too long
      if($this->max_filename > 0){
       $this->file_name = $this->limit_filename_length($this->file_name, $this->max_filename);
      }
      //Remove white spaces in the name
      if($this->remove_spaces == TRUE){
       $this->file_name = preg_replace("/\s+/", "_", $this->file_name);
      }
      /* Validate the file name
       * This function appends an number onto the end of
       * the file if one with the same name already exists.
       * If it returns false there was a problem.
       */
       $this->orig_name = $this->file_name;
       if($this->overwrite == FALSE){
        $this->file_name = $this->set_filename($this->upload_path, $this->file_name);
        if($this->file_name === FALSE){
         return FALSE;
        }
       }
      /* Run the file through the XSS hacking filter
       * This helps prevent malicious code from being
       * embedded within a file.  Scripts can easily
       * be disguised as images or other file types.
       */
       if($this->xss_clean){
        if($this->do_xss_clean() === FALSE){
         $this->set_error("upload_unable_to_write_file");
         return FALSE;
        }
       }
      /* Move the file to the final destination
       * To deal with different server configurations
       * we'll attempt to use copy() first.  If that fails
       * we'll use move_uploaded_file().  One of the two should
       * reliably work in most environments
       */
       if(!@copy($this->file_temp, $this->upload_path.$this->file_name)){
        if(!@move_uploaded_file($this->file_temp, $this->upload_path.$this->file_name)){
         $this->set_error("upload_destination_error");
         return FALSE;
        }
       }
      /* Set the finalized image dimensions
       * This sets the image width/height (assuming the
       * file was an image).  We use this information
       * in the "data" function.
       */
       $this->set_image_properties($this->upload_path.$this->file_name);
      //Set current file data to multi_file_upload_data.
      $this->set_multi_upload_data();
     }
     //Return all file upload data.
     return TRUE;
   }
  }
PHP 相关文章推荐
php.ini 中文版
Oct 28 PHP
global.php
Dec 09 PHP
cmd下运行php脚本
Nov 25 PHP
php cookie的操作实现代码(登录)
Dec 29 PHP
php生成图形验证码几种方法小结
Aug 15 PHP
php广告加载类用法实例
Sep 23 PHP
php生成shtml类用法实例
Dec 09 PHP
PHP使用curl函数发送Post请求的注意事项
Nov 26 PHP
Zend Framework基于Command命令行建立ZF项目的方法
Feb 18 PHP
PHP实现的多维数组排序算法分析
Feb 10 PHP
Laravel模型事件的实现原理详解
Mar 14 PHP
PHP实现的权重算法示例【可用于游戏根据权限来随机物品】
Feb 15 PHP
php创建sprite
Feb 11 #PHP
PHP循环结构实例讲解
Feb 10 #PHP
更改localhost为其他名字的方法
Feb 10 #PHP
php 获取SWF动画截图示例代码
Feb 10 #PHP
php导入csv文件碰到乱码问题的解决方法
Feb 10 #PHP
php判断正常访问和外部访问的示例
Feb 10 #PHP
php利用单例模式实现日志处理类库
Feb 10 #PHP
You might like
学习php中的正则表达式
2014/08/17 PHP
PHP结合Mysql数据库实现留言板功能
2016/03/04 PHP
javascript学习(一)构建自己的JS库
2013/01/02 Javascript
Jquery 实现checkbox全选方法
2015/01/28 Javascript
JavaScript实现标题栏文字轮播效果代码
2015/10/24 Javascript
jQuery弹簧插件编写基础之“又见弹窗”
2015/12/11 Javascript
jquery实现页面常用的返回顶部效果
2016/03/04 Javascript
基于css3新属性transform及原生js实现鼠标拖动3d立方体旋转
2016/06/12 Javascript
微信小程序 后台登录(非微信账号)实例详解
2017/03/31 Javascript
node实现的爬虫功能示例
2018/05/04 Javascript
微信开发之企业付款到银行卡接口开发的示例代码
2018/09/18 Javascript
小程序实现留言板
2018/11/02 Javascript
vue 使用element-ui中的Notification自定义按钮并实现关闭功能及如何处理多个通知
2019/08/17 Javascript
jQuery实现简易聊天框
2020/02/08 jQuery
python实现的用于搜索文件并进行内容替换的类实例
2015/06/28 Python
Python cx_freeze打包工具处理问题思路及解决办法
2016/02/13 Python
Python通过OpenCV的findContours获取轮廓并切割实例
2018/01/05 Python
基于循环神经网络(RNN)实现影评情感分类
2018/03/26 Python
Python3实现的简单三级菜单功能示例
2019/03/12 Python
详解python中init方法和随机数方法
2019/03/13 Python
CSS3 三维变形实现立体方块特效源码
2016/12/15 HTML / CSS
目前不被任何主流浏览器支持的CSS3属性汇总
2014/07/21 HTML / CSS
美国第一香水网站:Perfume.com
2017/01/23 全球购物
西班牙最大的婴儿用品网上商店:Bebitus
2019/05/30 全球购物
物业招聘计划书
2014/01/10 职场文书
小学端午节活动方案
2014/03/13 职场文书
工程售后服务承诺书
2014/05/21 职场文书
机械专业求职信
2014/05/25 职场文书
民族学专业职业生涯规划范文:积跬步以至千里
2014/09/11 职场文书
团委副书记工作总结
2015/08/14 职场文书
小学班主任工作随笔
2015/08/15 职场文书
2016年幼儿园万圣节活动总结
2016/04/05 职场文书
涨工资申请书应该怎么写?
2019/07/08 职场文书
公司要求试用期员工提交“述职报告”,该怎么写?
2019/07/17 职场文书
nginx配置文件使用环境变量的操作方法
2021/06/02 Servers
Python实现批量自动整理文件
2022/03/16 Python