github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/themes/wind/static/libs/tinymce/plugins/jbimages/ci/system/libraries/Upload.php (about)

     1  <?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
     2  /**
     3   * CodeIgniter
     4   *
     5   * An open source application development framework for PHP 5.1.6 or newer
     6   *
     7   * @package		CodeIgniter
     8   * @author		ExpressionEngine Dev Team
     9   * @copyright	Copyright (c) 2008 - 2011, EllisLab, Inc.
    10   * @license		http://codeigniter.com/user_guide/license.html
    11   * @link		http://codeigniter.com
    12   * @since		Version 1.0
    13   * @filesource
    14   */
    15  
    16  // ------------------------------------------------------------------------
    17  
    18  /**
    19   * File Uploading Class
    20   *
    21   * @package		CodeIgniter
    22   * @subpackage	Libraries
    23   * @category	Uploads
    24   * @author		ExpressionEngine Dev Team
    25   * @link		http://codeigniter.com/user_guide/libraries/file_uploading.html
    26   */
    27  class CI_Upload {
    28  
    29  	public $max_size				= 0;
    30  	public $max_width				= 0;
    31  	public $max_height				= 0;
    32  	public $max_filename			= 0;
    33  	public $allowed_types			= "";
    34  	public $file_temp				= "";
    35  	public $file_name				= "";
    36  	public $orig_name				= "";
    37  	public $file_type				= "";
    38  	public $file_size				= "";
    39  	public $file_ext				= "";
    40  	public $upload_path				= "";
    41  	public $overwrite				= FALSE;
    42  	public $encrypt_name			= FALSE;
    43  	public $is_image				= FALSE;
    44  	public $image_width				= '';
    45  	public $image_height			= '';
    46  	public $image_type				= '';
    47  	public $image_size_str			= '';
    48  	public $error_msg				= array();
    49  	public $mimes					= array();
    50  	public $remove_spaces			= TRUE;
    51  	public $xss_clean				= FALSE;
    52  	public $temp_prefix				= "temp_file_";
    53  	public $client_name				= '';
    54  
    55  	protected $_file_name_override	= '';
    56  
    57  	/**
    58  	 * Constructor
    59  	 *
    60  	 * @access	public
    61  	 */
    62  	public function __construct($props = array())
    63  	{
    64  		if (count($props) > 0)
    65  		{
    66  			$this->initialize($props);
    67  		}
    68  
    69  		log_message('debug', "Upload Class Initialized");
    70  	}
    71  
    72  	// --------------------------------------------------------------------
    73  
    74  	/**
    75  	 * Initialize preferences
    76  	 *
    77  	 * @param	array
    78  	 * @return	void
    79  	 */
    80  	public function initialize($config = array())
    81  	{
    82  		$defaults = array(
    83  							'max_size'			=> 0,
    84  							'max_width'			=> 0,
    85  							'max_height'		=> 0,
    86  							'max_filename'		=> 0,
    87  							'allowed_types'		=> "",
    88  							'file_temp'			=> "",
    89  							'file_name'			=> "",
    90  							'orig_name'			=> "",
    91  							'file_type'			=> "",
    92  							'file_size'			=> "",
    93  							'file_ext'			=> "",
    94  							'upload_path'		=> "",
    95  							'overwrite'			=> FALSE,
    96  							'encrypt_name'		=> FALSE,
    97  							'is_image'			=> FALSE,
    98  							'image_width'		=> '',
    99  							'image_height'		=> '',
   100  							'image_type'		=> '',
   101  							'image_size_str'	=> '',
   102  							'error_msg'			=> array(),
   103  							'mimes'				=> array(),
   104  							'remove_spaces'		=> TRUE,
   105  							'xss_clean'			=> FALSE,
   106  							'temp_prefix'		=> "temp_file_",
   107  							'client_name'		=> ''
   108  						);
   109  
   110  
   111  		foreach ($defaults as $key => $val)
   112  		{
   113  			if (isset($config[$key]))
   114  			{
   115  				$method = 'set_'.$key;
   116  				if (method_exists($this, $method))
   117  				{
   118  					$this->$method($config[$key]);
   119  				}
   120  				else
   121  				{
   122  					$this->$key = $config[$key];
   123  				}
   124  			}
   125  			else
   126  			{
   127  				$this->$key = $val;
   128  			}
   129  		}
   130  
   131  		// if a file_name was provided in the config, use it instead of the user input
   132  		// supplied file name for all uploads until initialized again
   133  		$this->_file_name_override = $this->file_name;
   134  	}
   135  
   136  	// --------------------------------------------------------------------
   137  
   138  	/**
   139  	 * Perform the file upload
   140  	 *
   141  	 * @return	bool
   142  	 */
   143  	public function do_upload($field = 'userfile')
   144  	{
   145  
   146  	// Is $_FILES[$field] set? If not, no reason to continue.
   147  		if ( ! isset($_FILES[$field]))
   148  		{
   149  			$this->set_error('upload_no_file_selected');
   150  			return FALSE;
   151  		}
   152  
   153  		// Is the upload path valid?
   154  		if ( ! $this->validate_upload_path())
   155  		{
   156  			// errors will already be set by validate_upload_path() so just return FALSE
   157  			return FALSE;
   158  		}
   159  
   160  		// Was the file able to be uploaded? If not, determine the reason why.
   161  		if ( ! is_uploaded_file($_FILES[$field]['tmp_name']))
   162  		{
   163  			$error = ( ! isset($_FILES[$field]['error'])) ? 4 : $_FILES[$field]['error'];
   164  
   165  			switch($error)
   166  			{
   167  				case 1:	// UPLOAD_ERR_INI_SIZE
   168  					$this->set_error('upload_file_exceeds_limit');
   169  					break;
   170  				case 2: // UPLOAD_ERR_FORM_SIZE
   171  					$this->set_error('upload_file_exceeds_form_limit');
   172  					break;
   173  				case 3: // UPLOAD_ERR_PARTIAL
   174  					$this->set_error('upload_file_partial');
   175  					break;
   176  				case 4: // UPLOAD_ERR_NO_FILE
   177  					$this->set_error('upload_no_file_selected');
   178  					break;
   179  				case 6: // UPLOAD_ERR_NO_TMP_DIR
   180  					$this->set_error('upload_no_temp_directory');
   181  					break;
   182  				case 7: // UPLOAD_ERR_CANT_WRITE
   183  					$this->set_error('upload_unable_to_write_file');
   184  					break;
   185  				case 8: // UPLOAD_ERR_EXTENSION
   186  					$this->set_error('upload_stopped_by_extension');
   187  					break;
   188  				default :   $this->set_error('upload_no_file_selected');
   189  					break;
   190  			}
   191  
   192  			return FALSE;
   193  		}
   194  
   195  
   196  		// Set the uploaded data as class variables
   197  		$this->file_temp = $_FILES[$field]['tmp_name'];
   198  		$this->file_size = $_FILES[$field]['size'];
   199  		$this->_file_mime_type($_FILES[$field]);
   200  		$this->file_type = preg_replace("/^(.+?);.*$/", "\\1", $this->file_type);
   201  		$this->file_type = strtolower(trim(stripslashes($this->file_type), '"'));
   202  		$this->file_name = $this->_prep_filename($_FILES[$field]['name']);
   203  		$this->file_ext	 = $this->get_extension($this->file_name);
   204  		$this->client_name = $this->file_name;
   205  
   206  		// Is the file type allowed to be uploaded?
   207  		if ( ! $this->is_allowed_filetype())
   208  		{
   209  			$this->set_error('upload_invalid_filetype');
   210  			return FALSE;
   211  		}
   212  
   213  		// if we're overriding, let's now make sure the new name and type is allowed
   214  		if ($this->_file_name_override != '')
   215  		{
   216  			$this->file_name = $this->_prep_filename($this->_file_name_override);
   217  
   218  			// If no extension was provided in the file_name config item, use the uploaded one
   219  			if (strpos($this->_file_name_override, '.') === FALSE)
   220  			{
   221  				$this->file_name .= $this->file_ext;
   222  			}
   223  
   224  			// An extension was provided, lets have it!
   225  			else
   226  			{
   227  				$this->file_ext	 = $this->get_extension($this->_file_name_override);
   228  			}
   229  
   230  			if ( ! $this->is_allowed_filetype(TRUE))
   231  			{
   232  				$this->set_error('upload_invalid_filetype');
   233  				return FALSE;
   234  			}
   235  		}
   236  
   237  		// Convert the file size to kilobytes
   238  		if ($this->file_size > 0)
   239  		{
   240  			$this->file_size = round($this->file_size/1024, 2);
   241  		}
   242  
   243  		// Is the file size within the allowed maximum?
   244  		if ( ! $this->is_allowed_filesize())
   245  		{
   246  			$this->set_error('upload_invalid_filesize');
   247  			return FALSE;
   248  		}
   249  
   250  		// Are the image dimensions within the allowed size?
   251  		// Note: This can fail if the server has an open_basdir restriction.
   252  		if ( ! $this->is_allowed_dimensions())
   253  		{
   254  			$this->set_error('upload_invalid_dimensions');
   255  			return FALSE;
   256  		}
   257  
   258  		// Sanitize the file name for security
   259  		$this->file_name = $this->clean_file_name($this->file_name);
   260  
   261  		// Truncate the file name if it's too long
   262  		if ($this->max_filename > 0)
   263  		{
   264  			$this->file_name = $this->limit_filename_length($this->file_name, $this->max_filename);
   265  		}
   266  
   267  		// Remove white spaces in the name
   268  		if ($this->remove_spaces == TRUE)
   269  		{
   270  			$this->file_name = preg_replace("/\s+/", "_", $this->file_name);
   271  		}
   272  
   273  		/*
   274  		 * Validate the file name
   275  		 * This function appends an number onto the end of
   276  		 * the file if one with the same name already exists.
   277  		 * If it returns false there was a problem.
   278  		 */
   279  		$this->orig_name = $this->file_name;
   280  
   281  		if ($this->overwrite == FALSE)
   282  		{
   283  			$this->file_name = $this->set_filename($this->upload_path, $this->file_name);
   284  
   285  			if ($this->file_name === FALSE)
   286  			{
   287  				return FALSE;
   288  			}
   289  		}
   290  
   291  		/*
   292  		 * Run the file through the XSS hacking filter
   293  		 * This helps prevent malicious code from being
   294  		 * embedded within a file.  Scripts can easily
   295  		 * be disguised as images or other file types.
   296  		 */
   297  		if ($this->xss_clean)
   298  		{
   299  			if ($this->do_xss_clean() === FALSE)
   300  			{
   301  				$this->set_error('upload_unable_to_write_file');
   302  				return FALSE;
   303  			}
   304  		}
   305  
   306  		/*
   307  		 * Move the file to the final destination
   308  		 * To deal with different server configurations
   309  		 * we'll attempt to use copy() first.  If that fails
   310  		 * we'll use move_uploaded_file().  One of the two should
   311  		 * reliably work in most environments
   312  		 */
   313  		if ( ! @copy($this->file_temp, $this->upload_path.$this->file_name))
   314  		{
   315  			if ( ! @move_uploaded_file($this->file_temp, $this->upload_path.$this->file_name))
   316  			{
   317  				$this->set_error('upload_destination_error');
   318  				return FALSE;
   319  			}
   320  		}
   321  
   322  		/*
   323  		 * Set the finalized image dimensions
   324  		 * This sets the image width/height (assuming the
   325  		 * file was an image).  We use this information
   326  		 * in the "data" function.
   327  		 */
   328  		$this->set_image_properties($this->upload_path.$this->file_name);
   329  
   330  		return TRUE;
   331  	}
   332  
   333  	// --------------------------------------------------------------------
   334  
   335  	/**
   336  	 * Finalized Data Array
   337  	 *
   338  	 * Returns an associative array containing all of the information
   339  	 * related to the upload, allowing the developer easy access in one array.
   340  	 *
   341  	 * @return	array
   342  	 */
   343  	public function data()
   344  	{
   345  		return array (
   346  						'file_name'			=> $this->file_name,
   347  						'file_type'			=> $this->file_type,
   348  						'file_path'			=> $this->upload_path,
   349  						'full_path'			=> $this->upload_path.$this->file_name,
   350  						'raw_name'			=> str_replace($this->file_ext, '', $this->file_name),
   351  						'orig_name'			=> $this->orig_name,
   352  						'client_name'		=> $this->client_name,
   353  						'file_ext'			=> $this->file_ext,
   354  						'file_size'			=> $this->file_size,
   355  						'is_image'			=> $this->is_image(),
   356  						'image_width'		=> $this->image_width,
   357  						'image_height'		=> $this->image_height,
   358  						'image_type'		=> $this->image_type,
   359  						'image_size_str'	=> $this->image_size_str,
   360  					);
   361  	}
   362  
   363  	// --------------------------------------------------------------------
   364  
   365  	/**
   366  	 * Set Upload Path
   367  	 *
   368  	 * @param	string
   369  	 * @return	void
   370  	 */
   371  	public function set_upload_path($path)
   372  	{
   373  		// Make sure it has a trailing slash
   374  		$this->upload_path = rtrim($path, '/').'/';
   375  	}
   376  
   377  	// --------------------------------------------------------------------
   378  
   379  	/**
   380  	 * Set the file name
   381  	 *
   382  	 * This function takes a filename/path as input and looks for the
   383  	 * existence of a file with the same name. If found, it will append a
   384  	 * number to the end of the filename to avoid overwriting a pre-existing file.
   385  	 *
   386  	 * @param	string
   387  	 * @param	string
   388  	 * @return	string
   389  	 */
   390  	public function set_filename($path, $filename)
   391  	{
   392  		if ($this->encrypt_name == TRUE)
   393  		{
   394  			mt_srand();
   395  			$filename = md5(uniqid(mt_rand())).$this->file_ext;
   396  		}
   397  
   398  		if ( ! file_exists($path.$filename))
   399  		{
   400  			return $filename;
   401  		}
   402  
   403  		$filename = str_replace($this->file_ext, '', $filename);
   404  
   405  		$new_filename = '';
   406  		for ($i = 1; $i < 100; $i++)
   407  		{
   408  			if ( ! file_exists($path.$filename.$i.$this->file_ext))
   409  			{
   410  				$new_filename = $filename.$i.$this->file_ext;
   411  				break;
   412  			}
   413  		}
   414  
   415  		if ($new_filename == '')
   416  		{
   417  			$this->set_error('upload_bad_filename');
   418  			return FALSE;
   419  		}
   420  		else
   421  		{
   422  			return $new_filename;
   423  		}
   424  	}
   425  
   426  	// --------------------------------------------------------------------
   427  
   428  	/**
   429  	 * Set Maximum File Size
   430  	 *
   431  	 * @param	integer
   432  	 * @return	void
   433  	 */
   434  	public function set_max_filesize($n)
   435  	{
   436  		$this->max_size = ((int) $n < 0) ? 0: (int) $n;
   437  	}
   438  
   439  	// --------------------------------------------------------------------
   440  
   441  	/**
   442  	 * Set Maximum File Name Length
   443  	 *
   444  	 * @param	integer
   445  	 * @return	void
   446  	 */
   447  	public function set_max_filename($n)
   448  	{
   449  		$this->max_filename = ((int) $n < 0) ? 0: (int) $n;
   450  	}
   451  
   452  	// --------------------------------------------------------------------
   453  
   454  	/**
   455  	 * Set Maximum Image Width
   456  	 *
   457  	 * @param	integer
   458  	 * @return	void
   459  	 */
   460  	public function set_max_width($n)
   461  	{
   462  		$this->max_width = ((int) $n < 0) ? 0: (int) $n;
   463  	}
   464  
   465  	// --------------------------------------------------------------------
   466  
   467  	/**
   468  	 * Set Maximum Image Height
   469  	 *
   470  	 * @param	integer
   471  	 * @return	void
   472  	 */
   473  	public function set_max_height($n)
   474  	{
   475  		$this->max_height = ((int) $n < 0) ? 0: (int) $n;
   476  	}
   477  
   478  	// --------------------------------------------------------------------
   479  
   480  	/**
   481  	 * Set Allowed File Types
   482  	 *
   483  	 * @param	string
   484  	 * @return	void
   485  	 */
   486  	public function set_allowed_types($types)
   487  	{
   488  		if ( ! is_array($types) && $types == '*')
   489  		{
   490  			$this->allowed_types = '*';
   491  			return;
   492  		}
   493  		$this->allowed_types = explode('|', $types);
   494  	}
   495  
   496  	// --------------------------------------------------------------------
   497  
   498  	/**
   499  	 * Set Image Properties
   500  	 *
   501  	 * Uses GD to determine the width/height/type of image
   502  	 *
   503  	 * @param	string
   504  	 * @return	void
   505  	 */
   506  	public function set_image_properties($path = '')
   507  	{
   508  		if ( ! $this->is_image())
   509  		{
   510  			return;
   511  		}
   512  
   513  		if (function_exists('getimagesize'))
   514  		{
   515  			if (FALSE !== ($D = @getimagesize($path)))
   516  			{
   517  				$types = array(1 => 'gif', 2 => 'jpeg', 3 => 'png');
   518  
   519  				$this->image_width		= $D['0'];
   520  				$this->image_height		= $D['1'];
   521  				$this->image_type		= ( ! isset($types[$D['2']])) ? 'unknown' : $types[$D['2']];
   522  				$this->image_size_str	= $D['3'];  // string containing height and width
   523  			}
   524  		}
   525  	}
   526  
   527  	// --------------------------------------------------------------------
   528  
   529  	/**
   530  	 * Set XSS Clean
   531  	 *
   532  	 * Enables the XSS flag so that the file that was uploaded
   533  	 * will be run through the XSS filter.
   534  	 *
   535  	 * @param	bool
   536  	 * @return	void
   537  	 */
   538  	public function set_xss_clean($flag = FALSE)
   539  	{
   540  		$this->xss_clean = ($flag == TRUE) ? TRUE : FALSE;
   541  	}
   542  
   543  	// --------------------------------------------------------------------
   544  
   545  	/**
   546  	 * Validate the image
   547  	 *
   548  	 * @return	bool
   549  	 */
   550  	public function is_image()
   551  	{
   552  		// IE will sometimes return odd mime-types during upload, so here we just standardize all
   553  		// jpegs or pngs to the same file type.
   554  
   555  		$png_mimes  = array('image/x-png');
   556  		$jpeg_mimes = array('image/jpg', 'image/jpe', 'image/jpeg', 'image/pjpeg');
   557  
   558  		if (in_array($this->file_type, $png_mimes))
   559  		{
   560  			$this->file_type = 'image/png';
   561  		}
   562  
   563  		if (in_array($this->file_type, $jpeg_mimes))
   564  		{
   565  			$this->file_type = 'image/jpeg';
   566  		}
   567  
   568  		$img_mimes = array(
   569  							'image/gif',
   570  							'image/jpeg',
   571  							'image/png',
   572  						);
   573  
   574  		return (in_array($this->file_type, $img_mimes, TRUE)) ? TRUE : FALSE;
   575  	}
   576  
   577  	// --------------------------------------------------------------------
   578  
   579  	/**
   580  	 * Verify that the filetype is allowed
   581  	 *
   582  	 * @return	bool
   583  	 */
   584  	public function is_allowed_filetype($ignore_mime = FALSE)
   585  	{
   586  		if ($this->allowed_types == '*')
   587  		{
   588  			return TRUE;
   589  		}
   590  
   591  		if (count($this->allowed_types) == 0 OR ! is_array($this->allowed_types))
   592  		{
   593  			$this->set_error('upload_no_file_types');
   594  			return FALSE;
   595  		}
   596  
   597  		$ext = strtolower(ltrim($this->file_ext, '.'));
   598  
   599  		if ( ! in_array($ext, $this->allowed_types))
   600  		{
   601  			return FALSE;
   602  		}
   603  
   604  		// Images get some additional checks
   605  		$image_types = array('gif', 'jpg', 'jpeg', 'png', 'jpe');
   606  
   607  		if (in_array($ext, $image_types))
   608  		{
   609  			if (getimagesize($this->file_temp) === FALSE)
   610  			{
   611  				return FALSE;
   612  			}
   613  		}
   614  
   615  		if ($ignore_mime === TRUE)
   616  		{
   617  			return TRUE;
   618  		}
   619  
   620  		$mime = $this->mimes_types($ext);
   621  
   622  		if (is_array($mime))
   623  		{
   624  			if (in_array($this->file_type, $mime, TRUE))
   625  			{
   626  				return TRUE;
   627  			}
   628  		}
   629  		elseif ($mime == $this->file_type)
   630  		{
   631  				return TRUE;
   632  		}
   633  
   634  		return FALSE;
   635  	}
   636  
   637  	// --------------------------------------------------------------------
   638  
   639  	/**
   640  	 * Verify that the file is within the allowed size
   641  	 *
   642  	 * @return	bool
   643  	 */
   644  	public function is_allowed_filesize()
   645  	{
   646  		if ($this->max_size != 0  AND  $this->file_size > $this->max_size)
   647  		{
   648  			return FALSE;
   649  		}
   650  		else
   651  		{
   652  			return TRUE;
   653  		}
   654  	}
   655  
   656  	// --------------------------------------------------------------------
   657  
   658  	/**
   659  	 * Verify that the image is within the allowed width/height
   660  	 *
   661  	 * @return	bool
   662  	 */
   663  	public function is_allowed_dimensions()
   664  	{
   665  		if ( ! $this->is_image())
   666  		{
   667  			return TRUE;
   668  		}
   669  
   670  		if (function_exists('getimagesize'))
   671  		{
   672  			$D = @getimagesize($this->file_temp);
   673  
   674  			if ($this->max_width > 0 AND $D['0'] > $this->max_width)
   675  			{
   676  				return FALSE;
   677  			}
   678  
   679  			if ($this->max_height > 0 AND $D['1'] > $this->max_height)
   680  			{
   681  				return FALSE;
   682  			}
   683  
   684  			return TRUE;
   685  		}
   686  
   687  		return TRUE;
   688  	}
   689  
   690  	// --------------------------------------------------------------------
   691  
   692  	/**
   693  	 * Validate Upload Path
   694  	 *
   695  	 * Verifies that it is a valid upload path with proper permissions.
   696  	 *
   697  	 *
   698  	 * @return	bool
   699  	 */
   700  	public function validate_upload_path()
   701  	{
   702  		if ($this->upload_path == '')
   703  		{
   704  			$this->set_error('upload_no_filepath');
   705  			return FALSE;
   706  		}
   707  
   708  		if (function_exists('realpath') AND @realpath($this->upload_path) !== FALSE)
   709  		{
   710  			$this->upload_path = str_replace("\\", "/", realpath($this->upload_path));
   711  		}
   712  
   713  		if ( ! @is_dir($this->upload_path))
   714  		{
   715  			$this->set_error('upload_no_filepath');
   716  			return FALSE;
   717  		}
   718  
   719  		if ( ! is_really_writable($this->upload_path))
   720  		{
   721  			$this->set_error('upload_not_writable');
   722  			return FALSE;
   723  		}
   724  
   725  		$this->upload_path = preg_replace("/(.+?)\/*$/", "\\1/",  $this->upload_path);
   726  		return TRUE;
   727  	}
   728  
   729  	// --------------------------------------------------------------------
   730  
   731  	/**
   732  	 * Extract the file extension
   733  	 *
   734  	 * @param	string
   735  	 * @return	string
   736  	 */
   737  	public function get_extension($filename)
   738  	{
   739  		$x = explode('.', $filename);
   740  		return '.'.end($x);
   741  	}
   742  
   743  	// --------------------------------------------------------------------
   744  
   745  	/**
   746  	 * Clean the file name for security
   747  	 *
   748  	 * @param	string
   749  	 * @return	string
   750  	 */
   751  	public function clean_file_name($filename)
   752  	{
   753  		$bad = array(
   754  						"<!--",
   755  						"-->",
   756  						"'",
   757  						"<",
   758  						">",
   759  						'"',
   760  						'&',
   761  						'$',
   762  						'=',
   763  						';',
   764  						'?',
   765  						'/',
   766  						"%20",
   767  						"%22",
   768  						"%3c",		// <
   769  						"%253c",	// <
   770  						"%3e",		// >
   771  						"%0e",		// >
   772  						"%28",		// (
   773  						"%29",		// )
   774  						"%2528",	// (
   775  						"%26",		// &
   776  						"%24",		// $
   777  						"%3f",		// ?
   778  						"%3b",		// ;
   779  						"%3d"		// =
   780  					);
   781  
   782  		$filename = str_replace($bad, '', $filename);
   783  
   784  		return stripslashes($filename);
   785  	}
   786  
   787  	// --------------------------------------------------------------------
   788  
   789  	/**
   790  	 * Limit the File Name Length
   791  	 *
   792  	 * @param	string
   793  	 * @return	string
   794  	 */
   795  	public function limit_filename_length($filename, $length)
   796  	{
   797  		if (strlen($filename) < $length)
   798  		{
   799  			return $filename;
   800  		}
   801  
   802  		$ext = '';
   803  		if (strpos($filename, '.') !== FALSE)
   804  		{
   805  			$parts		= explode('.', $filename);
   806  			$ext		= '.'.array_pop($parts);
   807  			$filename	= implode('.', $parts);
   808  		}
   809  
   810  		return substr($filename, 0, ($length - strlen($ext))).$ext;
   811  	}
   812  
   813  	// --------------------------------------------------------------------
   814  
   815  	/**
   816  	 * Runs the file through the XSS clean function
   817  	 *
   818  	 * This prevents people from embedding malicious code in their files.
   819  	 * I'm not sure that it won't negatively affect certain files in unexpected ways,
   820  	 * but so far I haven't found that it causes trouble.
   821  	 *
   822  	 * @return	void
   823  	 */
   824  	public function do_xss_clean()
   825  	{
   826  		$file = $this->file_temp;
   827  
   828  		if (filesize($file) == 0)
   829  		{
   830  			return FALSE;
   831  		}
   832  
   833  		if (function_exists('memory_get_usage') && memory_get_usage() && ini_get('memory_limit') != '')
   834  		{
   835  			$current = ini_get('memory_limit') * 1024 * 1024;
   836  
   837  			// There was a bug/behavioural change in PHP 5.2, where numbers over one million get output
   838  			// into scientific notation.  number_format() ensures this number is an integer
   839  			// http://bugs.php.net/bug.php?id=43053
   840  
   841  			$new_memory = number_format(ceil(filesize($file) + $current), 0, '.', '');
   842  
   843  			ini_set('memory_limit', $new_memory); // When an integer is used, the value is measured in bytes. - PHP.net
   844  		}
   845  
   846  		// If the file being uploaded is an image, then we should have no problem with XSS attacks (in theory), but
   847  		// IE can be fooled into mime-type detecting a malformed image as an html file, thus executing an XSS attack on anyone
   848  		// using IE who looks at the image.  It does this by inspecting the first 255 bytes of an image.  To get around this
   849  		// CI will itself look at the first 255 bytes of an image to determine its relative safety.  This can save a lot of
   850  		// processor power and time if it is actually a clean image, as it will be in nearly all instances _except_ an
   851  		// attempted XSS attack.
   852  
   853  		if (function_exists('getimagesize') && @getimagesize($file) !== FALSE)
   854  		{
   855  			if (($file = @fopen($file, 'rb')) === FALSE) // "b" to force binary
   856  			{
   857  				return FALSE; // Couldn't open the file, return FALSE
   858  			}
   859  
   860  			$opening_bytes = fread($file, 256);
   861  			fclose($file);
   862  
   863  			// These are known to throw IE into mime-type detection chaos
   864  			// <a, <body, <head, <html, <img, <plaintext, <pre, <script, <table, <title
   865  			// title is basically just in SVG, but we filter it anyhow
   866  
   867  			if ( ! preg_match('/<(a|body|head|html|img|plaintext|pre|script|table|title)[\s>]/i', $opening_bytes))
   868  			{
   869  				return TRUE; // its an image, no "triggers" detected in the first 256 bytes, we're good
   870  			}
   871  			else
   872  			{
   873  				return FALSE;
   874  			}
   875  		}
   876  
   877  		if (($data = @file_get_contents($file)) === FALSE)
   878  		{
   879  			return FALSE;
   880  		}
   881  
   882  		$CI =& get_instance();
   883  		return $CI->security->xss_clean($data, TRUE);
   884  	}
   885  
   886  	// --------------------------------------------------------------------
   887  
   888  	/**
   889  	 * Set an error message
   890  	 *
   891  	 * @param	string
   892  	 * @return	void
   893  	 */
   894  	public function set_error($msg)
   895  	{
   896  		$CI =& get_instance();
   897  		$CI->lang->load('upload');
   898  
   899  		if (is_array($msg))
   900  		{
   901  			foreach ($msg as $val)
   902  			{
   903  				$msg = ($CI->lang->line($val) == FALSE) ? $val : $CI->lang->line($val);
   904  				$this->error_msg[] = $msg;
   905  				log_message('error', $msg);
   906  			}
   907  		}
   908  		else
   909  		{
   910  			$msg = ($CI->lang->line($msg) == FALSE) ? $msg : $CI->lang->line($msg);
   911  			$this->error_msg[] = $msg;
   912  			log_message('error', $msg);
   913  		}
   914  	}
   915  
   916  	// --------------------------------------------------------------------
   917  
   918  	/**
   919  	 * Display the error message
   920  	 *
   921  	 * @param	string
   922  	 * @param	string
   923  	 * @return	string
   924  	 */
   925  	public function display_errors($open = '<p>', $close = '</p>')
   926  	{
   927  		$str = '';
   928  		foreach ($this->error_msg as $val)
   929  		{
   930  			$str .= $open.$val.$close;
   931  		}
   932  
   933  		return $str;
   934  	}
   935  
   936  	// --------------------------------------------------------------------
   937  
   938  	/**
   939  	 * List of Mime Types
   940  	 *
   941  	 * This is a list of mime types.  We use it to validate
   942  	 * the "allowed types" set by the developer
   943  	 *
   944  	 * @param	string
   945  	 * @return	string
   946  	 */
   947  	public function mimes_types($mime)
   948  	{
   949  		global $mimes;
   950  
   951  		if (count($this->mimes) == 0)
   952  		{
   953  			if (defined('ENVIRONMENT') AND is_file(APPPATH.'config/'.ENVIRONMENT.'/mimes.php'))
   954  			{
   955  				include(APPPATH.'config/'.ENVIRONMENT.'/mimes.php');
   956  			}
   957  			elseif (is_file(APPPATH.'config/mimes.php'))
   958  			{
   959  				include(APPPATH.'config//mimes.php');
   960  			}
   961  			else
   962  			{
   963  				return FALSE;
   964  			}
   965  
   966  			$this->mimes = $mimes;
   967  			unset($mimes);
   968  		}
   969  
   970  		return ( ! isset($this->mimes[$mime])) ? FALSE : $this->mimes[$mime];
   971  	}
   972  
   973  	// --------------------------------------------------------------------
   974  
   975  	/**
   976  	 * Prep Filename
   977  	 *
   978  	 * Prevents possible script execution from Apache's handling of files multiple extensions
   979  	 * http://httpd.apache.org/docs/1.3/mod/mod_mime.html#multipleext
   980  	 *
   981  	 * @param	string
   982  	 * @return	string
   983  	 */
   984  	protected function _prep_filename($filename)
   985  	{
   986  		if (strpos($filename, '.') === FALSE OR $this->allowed_types == '*')
   987  		{
   988  			return $filename;
   989  		}
   990  
   991  		$parts		= explode('.', $filename);
   992  		$ext		= array_pop($parts);
   993  		$filename	= array_shift($parts);
   994  
   995  		foreach ($parts as $part)
   996  		{
   997  			if ( ! in_array(strtolower($part), $this->allowed_types) OR $this->mimes_types(strtolower($part)) === FALSE)
   998  			{
   999  				$filename .= '.'.$part.'_';
  1000  			}
  1001  			else
  1002  			{
  1003  				$filename .= '.'.$part;
  1004  			}
  1005  		}
  1006  
  1007  		$filename .= '.'.$ext;
  1008  
  1009  		return $filename;
  1010  	}
  1011  
  1012  	// --------------------------------------------------------------------
  1013  
  1014  	/**
  1015  	 * File MIME type
  1016  	 *
  1017  	 * Detects the (actual) MIME type of the uploaded file, if possible.
  1018  	 * The input array is expected to be $_FILES[$field]
  1019  	 *
  1020  	 * @param	array
  1021  	 * @return	void
  1022  	 */
  1023  	protected function _file_mime_type($file)
  1024  	{
  1025  		// We'll need this to validate the MIME info string (e.g. text/plain; charset=us-ascii)
  1026  		$regexp = '/^([a-z\-]+\/[a-z0-9\-\.\+]+)(;\s.+)?$/';
  1027  
  1028  		/* Fileinfo extension - most reliable method
  1029  		 *
  1030  		 * Unfortunately, prior to PHP 5.3 - it's only available as a PECL extension and the
  1031  		 * more convenient FILEINFO_MIME_TYPE flag doesn't exist.
  1032  		 */
  1033  		if (function_exists('finfo_file'))
  1034  		{
  1035  			$finfo = finfo_open(FILEINFO_MIME);
  1036  			if (is_resource($finfo)) // It is possible that a FALSE value is returned, if there is no magic MIME database file found on the system
  1037  			{
  1038  				$mime = @finfo_file($finfo, $file['tmp_name']);
  1039  				finfo_close($finfo);
  1040  
  1041  				/* According to the comments section of the PHP manual page,
  1042  				 * it is possible that this function returns an empty string
  1043  				 * for some files (e.g. if they don't exist in the magic MIME database)
  1044  				 */
  1045  				if (is_string($mime) && preg_match($regexp, $mime, $matches))
  1046  				{
  1047  					$this->file_type = $matches[1];
  1048  					return;
  1049  				}
  1050  			}
  1051  		}
  1052  
  1053  		/* This is an ugly hack, but UNIX-type systems provide a "native" way to detect the file type,
  1054  		 * which is still more secure than depending on the value of $_FILES[$field]['type'], and as it
  1055  		 * was reported in issue #750 (https://github.com/EllisLab/CodeIgniter/issues/750) - it's better
  1056  		 * than mime_content_type() as well, hence the attempts to try calling the command line with
  1057  		 * three different functions.
  1058  		 *
  1059  		 * Notes:
  1060  		 *	- the DIRECTORY_SEPARATOR comparison ensures that we're not on a Windows system
  1061  		 *	- many system admins would disable the exec(), shell_exec(), popen() and similar functions
  1062  		 *	  due to security concerns, hence the function_exists() checks
  1063  		 */
  1064  		if (DIRECTORY_SEPARATOR !== '\\')
  1065  		{
  1066  			$cmd = 'file --brief --mime ' . escapeshellarg($file['tmp_name']) . ' 2>&1';
  1067  
  1068  			if (function_exists('exec'))
  1069  			{
  1070  				/* This might look confusing, as $mime is being populated with all of the output when set in the second parameter.
  1071  				 * However, we only neeed the last line, which is the actual return value of exec(), and as such - it overwrites
  1072  				 * anything that could already be set for $mime previously. This effectively makes the second parameter a dummy
  1073  				 * value, which is only put to allow us to get the return status code.
  1074  				 */
  1075  				$mime = @exec($cmd, $mime, $return_status);
  1076  				if ($return_status === 0 && is_string($mime) && preg_match($regexp, $mime, $matches))
  1077  				{
  1078  					$this->file_type = $matches[1];
  1079  					return;
  1080  				}
  1081  			}
  1082  
  1083  			if ( (bool) @ini_get('safe_mode') === FALSE && function_exists('shell_exec'))
  1084  			{
  1085  				$mime = @shell_exec($cmd);
  1086  				if (strlen($mime) > 0)
  1087  				{
  1088  					$mime = explode("\n", trim($mime));
  1089  					if (preg_match($regexp, $mime[(count($mime) - 1)], $matches))
  1090  					{
  1091  						$this->file_type = $matches[1];
  1092  						return;
  1093  					}
  1094  				}
  1095  			}
  1096  
  1097  			if (function_exists('popen'))
  1098  			{
  1099  				$proc = @popen($cmd, 'r');
  1100  				if (is_resource($proc))
  1101  				{
  1102  					$mime = @fread($proc, 512);
  1103  					@pclose($proc);
  1104  					if ($mime !== FALSE)
  1105  					{
  1106  						$mime = explode("\n", trim($mime));
  1107  						if (preg_match($regexp, $mime[(count($mime) - 1)], $matches))
  1108  						{
  1109  							$this->file_type = $matches[1];
  1110  							return;
  1111  						}
  1112  					}
  1113  				}
  1114  			}
  1115  		}
  1116  
  1117  		// Fall back to the deprecated mime_content_type(), if available (still better than $_FILES[$field]['type'])
  1118  		if (function_exists('mime_content_type'))
  1119  		{
  1120  			$this->file_type = @mime_content_type($file['tmp_name']);
  1121  			if (strlen($this->file_type) > 0) // It's possible that mime_content_type() returns FALSE or an empty string
  1122  			{
  1123  				return;
  1124  			}
  1125  		}
  1126  
  1127  		$this->file_type = $file['type'];
  1128  	}
  1129  
  1130  	// --------------------------------------------------------------------
  1131  
  1132  }
  1133  // END Upload Class
  1134  
  1135  /* End of file Upload.php */
  1136  /* Location: ./system/libraries/Upload.php */