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创建PDF中文文档
Oct 09 PHP
PHP在Web开发领域的优势
Oct 09 PHP
php self,$this,const,static,-&amp;gt;的使用
Oct 22 PHP
一个比较简单的PHP 分页分组类
Dec 10 PHP
简单的PHP留言本实例代码
May 09 PHP
PHP校验ISBN码的函数代码
Jan 17 PHP
php设计模式之命令模式的应用详解
May 21 PHP
PHP过滤★等特殊符号的正则
Jan 27 PHP
PHP实现过滤掉非汉字字符只保留中文字符
Jun 04 PHP
php+ajax实现无刷新的新闻留言系统
Dec 21 PHP
php伪静态验证码不显示的解决方案
Sep 26 PHP
laravel 判断查询数据库返回值的例子
Oct 11 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 文章采集正则代码
2009/12/28 PHP
Php连接及读取和写入mysql数据库的常用代码
2014/08/11 PHP
使用php的HTTP请求的库Requests实现美女图片墙
2015/02/22 PHP
PHP双向链表定义与用法示例
2018/01/31 PHP
php使用QueryList轻松采集js动态渲染页面方法
2018/09/11 PHP
PHP回调函数简单用法示例
2019/05/08 PHP
通过正则格式化url查询字符串实现代码
2012/12/28 Javascript
jQuery实现自动调整字体大小的方法
2015/06/15 Javascript
javascript常用功能汇总
2015/07/05 Javascript
javascript从定义到执行 你不知道的那些事
2016/01/04 Javascript
jquery+json实现分页效果
2016/03/07 Javascript
浅析JavaScript Array和string的转换(推荐)
2016/05/20 Javascript
Jquery-data的三种用法
2017/04/18 jQuery
如何使用pm2快速将项目部署到远程服务器
2019/03/12 Javascript
layui下拉框获取下拉值(select)的例子
2019/09/10 Javascript
axios如何取消重复无用的请求详解
2019/12/15 Javascript
js实现时间日期校验
2020/05/26 Javascript
详解webpack的clean-webpack-plugin插件报错
2020/10/16 Javascript
three.js 实现露珠滴落动画效果的示例代码
2021/03/01 Javascript
[00:48]完美“圣”典2016风云人物:xiao8宣传片
2016/11/30 DOTA
详解python3百度指数抓取实例
2016/12/12 Python
linux环境下的python安装过程图解(含setuptools)
2017/11/22 Python
利用Python如何生成hash值示例详解
2017/12/20 Python
基于Python中求和函数sum的用法详解
2018/06/28 Python
Python玩转加密的技巧【推荐】
2019/05/13 Python
python 两个数据库postgresql对比
2019/10/21 Python
HTML5 Canvas绘制文本及图片的基础教程
2016/03/14 HTML / CSS
实习生自我鉴定
2013/12/12 职场文书
高中学生干部学习的自我评价
2014/02/21 职场文书
室内设计专业毕业生求职信
2014/05/02 职场文书
优秀应届毕业生自荐书
2014/06/29 职场文书
党员教师自我剖析材料
2014/09/29 职场文书
学校师德师风整改措施
2014/10/27 职场文书
2015年暑期实践报告范文
2015/07/13 职场文书
SQL Server一个字符串拆分多行显示或者多行数据合并成一个字符串
2022/05/25 SQL Server
聊聊配置 Nginx 访问与错误日志的问题
2022/05/25 Servers