| 注册
请输入搜索内容

热门搜索

Java Linux MySQL PHP JavaScript Hibernate jQuery Nginx
FedUzi
10年前发布

CodeIgniter多文件上传

CodeIgniter多文件上传    

<?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    * @author  Conveyor Group <steven@conveyorgroup.com>    * @link  https://github.com/stvnthomas/CodeIgniter-2.1-Multi-Upload    */    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;     }    }