blob: 56062befbad465b077cb2e417e75a04a66956cb5 [file] [log] [blame]
Derek Jones4b9c6292011-07-01 17:40:48 -05001<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
Derek Allard2067d1a2008-11-13 22:59:24 +00002/**
3 * CodeIgniter
4 *
Greg Aker741de1c2010-11-10 14:52:57 -06005 * An open source application development framework for PHP 5.1.6 or newer
Derek Allard2067d1a2008-11-13 22:59:24 +00006 *
Derek Jonesf4a4bd82011-10-20 12:18:42 -05007 * NOTICE OF LICENSE
8 *
9 * Licensed under the Open Software License version 3.0
10 *
11 * This source file is subject to the Open Software License (OSL 3.0) that is
12 * bundled with this package in the files license.txt / license.rst. It is
13 * also available through the world wide web at this URL:
14 * http://opensource.org/licenses/OSL-3.0
15 * If you did not receive a copy of the license and are unable to obtain it
16 * through the world wide web, please send an email to
17 * licensing@ellislab.com so we can send you a copy immediately.
18 *
Derek Allard2067d1a2008-11-13 22:59:24 +000019 * @package CodeIgniter
Derek Jonesf4a4bd82011-10-20 12:18:42 -050020 * @author EllisLab Dev Team
21 * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. (http://ellislab.com/)
22 * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
Derek Allard2067d1a2008-11-13 22:59:24 +000023 * @link http://codeigniter.com
24 * @since Version 1.0
25 * @filesource
26 */
27
28// ------------------------------------------------------------------------
29
30/**
31 * File Uploading Class
32 *
33 * @package CodeIgniter
34 * @subpackage Libraries
35 * @category Uploads
Derek Jonesf4a4bd82011-10-20 12:18:42 -050036 * @author EllisLab Dev Team
Derek Allard2067d1a2008-11-13 22:59:24 +000037 * @link http://codeigniter.com/user_guide/libraries/file_uploading.html
38 */
39class CI_Upload {
Barry Mienydd671972010-10-04 16:33:58 +020040
Greg Aker58fdee82010-11-10 15:07:09 -060041 public $max_size = 0;
42 public $max_width = 0;
43 public $max_height = 0;
44 public $max_filename = 0;
Adam Jackettccbbea12011-08-21 16:19:11 -040045 public $max_filename_increment = 100;
Greg Aker58fdee82010-11-10 15:07:09 -060046 public $allowed_types = "";
47 public $file_temp = "";
48 public $file_name = "";
49 public $orig_name = "";
50 public $file_type = "";
51 public $file_size = "";
52 public $file_ext = "";
53 public $upload_path = "";
54 public $overwrite = FALSE;
55 public $encrypt_name = FALSE;
56 public $is_image = FALSE;
57 public $image_width = '';
58 public $image_height = '';
59 public $image_type = '';
60 public $image_size_str = '';
61 public $error_msg = array();
62 public $mimes = array();
63 public $remove_spaces = TRUE;
64 public $xss_clean = FALSE;
65 public $temp_prefix = "temp_file_";
66 public $client_name = '';
Barry Mienydd671972010-10-04 16:33:58 +020067
Greg Aker58fdee82010-11-10 15:07:09 -060068 protected $_file_name_override = '';
Barry Mienydd671972010-10-04 16:33:58 +020069
Derek Allard2067d1a2008-11-13 22:59:24 +000070 /**
71 * Constructor
72 *
73 * @access public
74 */
Greg Aker58fdee82010-11-10 15:07:09 -060075 public function __construct($props = array())
Derek Allard2067d1a2008-11-13 22:59:24 +000076 {
77 if (count($props) > 0)
78 {
79 $this->initialize($props);
80 }
Barry Mienydd671972010-10-04 16:33:58 +020081
Derek Allard2067d1a2008-11-13 22:59:24 +000082 log_message('debug', "Upload Class Initialized");
83 }
Barry Mienydd671972010-10-04 16:33:58 +020084
Derek Allard2067d1a2008-11-13 22:59:24 +000085 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +020086
Derek Allard2067d1a2008-11-13 22:59:24 +000087 /**
88 * Initialize preferences
89 *
Derek Allard2067d1a2008-11-13 22:59:24 +000090 * @param array
91 * @return void
Barry Mienydd671972010-10-04 16:33:58 +020092 */
Greg Aker58fdee82010-11-10 15:07:09 -060093 public function initialize($config = array())
Derek Allard2067d1a2008-11-13 22:59:24 +000094 {
95 $defaults = array(
Adam Jackettccbbea12011-08-21 16:19:11 -040096 'max_size' => 0,
97 'max_width' => 0,
98 'max_height' => 0,
99 'max_filename' => 0,
100 'max_filename_increment' => 100,
101 'allowed_types' => "",
102 'file_temp' => "",
103 'file_name' => "",
104 'orig_name' => "",
105 'file_type' => "",
106 'file_size' => "",
107 'file_ext' => "",
108 'upload_path' => "",
109 'overwrite' => FALSE,
110 'encrypt_name' => FALSE,
111 'is_image' => FALSE,
112 'image_width' => '',
113 'image_height' => '',
114 'image_type' => '',
115 'image_size_str' => '',
116 'error_msg' => array(),
117 'mimes' => array(),
118 'remove_spaces' => TRUE,
119 'xss_clean' => FALSE,
120 'temp_prefix' => "temp_file_",
121 'client_name' => ''
Barry Mienydd671972010-10-04 16:33:58 +0200122 );
123
124
Derek Allard2067d1a2008-11-13 22:59:24 +0000125 foreach ($defaults as $key => $val)
126 {
127 if (isset($config[$key]))
128 {
129 $method = 'set_'.$key;
130 if (method_exists($this, $method))
131 {
132 $this->$method($config[$key]);
133 }
134 else
135 {
136 $this->$key = $config[$key];
Barry Mienydd671972010-10-04 16:33:58 +0200137 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000138 }
139 else
140 {
141 $this->$key = $val;
142 }
143 }
Barry Mienydd671972010-10-04 16:33:58 +0200144
Derek Jonese9d723f2010-07-12 10:10:59 -0500145 // if a file_name was provided in the config, use it instead of the user input
146 // supplied file name for all uploads until initialized again
147 $this->_file_name_override = $this->file_name;
Derek Allard2067d1a2008-11-13 22:59:24 +0000148 }
Barry Mienydd671972010-10-04 16:33:58 +0200149
Derek Allard2067d1a2008-11-13 22:59:24 +0000150 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200151
Derek Allard2067d1a2008-11-13 22:59:24 +0000152 /**
153 * Perform the file upload
154 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000155 * @return bool
Barry Mienydd671972010-10-04 16:33:58 +0200156 */
Greg Aker58fdee82010-11-10 15:07:09 -0600157 public function do_upload($field = 'userfile')
Derek Allard2067d1a2008-11-13 22:59:24 +0000158 {
Eric Barnes92808342011-03-18 09:02:37 -0400159
Robin Sowell0ecc0622011-01-30 16:47:43 -0500160 // Is $_FILES[$field] set? If not, no reason to continue.
Derek Allard2067d1a2008-11-13 22:59:24 +0000161 if ( ! isset($_FILES[$field]))
162 {
163 $this->set_error('upload_no_file_selected');
164 return FALSE;
165 }
Barry Mienydd671972010-10-04 16:33:58 +0200166
Derek Allard2067d1a2008-11-13 22:59:24 +0000167 // Is the upload path valid?
168 if ( ! $this->validate_upload_path())
169 {
170 // errors will already be set by validate_upload_path() so just return FALSE
171 return FALSE;
172 }
173
174 // Was the file able to be uploaded? If not, determine the reason why.
175 if ( ! is_uploaded_file($_FILES[$field]['tmp_name']))
176 {
177 $error = ( ! isset($_FILES[$field]['error'])) ? 4 : $_FILES[$field]['error'];
178
179 switch($error)
180 {
181 case 1: // UPLOAD_ERR_INI_SIZE
182 $this->set_error('upload_file_exceeds_limit');
183 break;
184 case 2: // UPLOAD_ERR_FORM_SIZE
185 $this->set_error('upload_file_exceeds_form_limit');
186 break;
187 case 3: // UPLOAD_ERR_PARTIAL
Barry Mienydd671972010-10-04 16:33:58 +0200188 $this->set_error('upload_file_partial');
Derek Allard2067d1a2008-11-13 22:59:24 +0000189 break;
190 case 4: // UPLOAD_ERR_NO_FILE
Barry Mienydd671972010-10-04 16:33:58 +0200191 $this->set_error('upload_no_file_selected');
Derek Allard2067d1a2008-11-13 22:59:24 +0000192 break;
193 case 6: // UPLOAD_ERR_NO_TMP_DIR
194 $this->set_error('upload_no_temp_directory');
195 break;
196 case 7: // UPLOAD_ERR_CANT_WRITE
197 $this->set_error('upload_unable_to_write_file');
198 break;
199 case 8: // UPLOAD_ERR_EXTENSION
200 $this->set_error('upload_stopped_by_extension');
201 break;
Derek Jones4b9c6292011-07-01 17:40:48 -0500202 default : $this->set_error('upload_no_file_selected');
Derek Allard2067d1a2008-11-13 22:59:24 +0000203 break;
204 }
205
206 return FALSE;
207 }
208
Derek Jonese9d723f2010-07-12 10:10:59 -0500209
Derek Allard2067d1a2008-11-13 22:59:24 +0000210 // Set the uploaded data as class variables
Barry Mienydd671972010-10-04 16:33:58 +0200211 $this->file_temp = $_FILES[$field]['tmp_name'];
212 $this->file_size = $_FILES[$field]['size'];
Andrey Andreev3a3c9472011-09-24 14:25:33 +0300213 $this->_file_mime_type($_FILES[$field]);
214 $this->file_type = preg_replace("/^(.+?);.*$/", "\\1", $this->file_type);
Derek Jones616fb022010-04-22 16:52:18 -0500215 $this->file_type = strtolower(trim(stripslashes($this->file_type), '"'));
Derek Jonese9d723f2010-07-12 10:10:59 -0500216 $this->file_name = $this->_prep_filename($_FILES[$field]['name']);
217 $this->file_ext = $this->get_extension($this->file_name);
218 $this->client_name = $this->file_name;
Barry Mienydd671972010-10-04 16:33:58 +0200219
Derek Allard2067d1a2008-11-13 22:59:24 +0000220 // Is the file type allowed to be uploaded?
221 if ( ! $this->is_allowed_filetype())
222 {
223 $this->set_error('upload_invalid_filetype');
224 return FALSE;
225 }
226
Derek Jonese9d723f2010-07-12 10:10:59 -0500227 // if we're overriding, let's now make sure the new name and type is allowed
228 if ($this->_file_name_override != '')
229 {
230 $this->file_name = $this->_prep_filename($this->_file_name_override);
Phil Sturgeon1e74da22010-12-15 10:45:06 +0000231
232 // If no extension was provided in the file_name config item, use the uploaded one
Pascal Kriete14287f32011-02-14 13:39:34 -0500233 if (strpos($this->_file_name_override, '.') === FALSE)
Phil Sturgeon1e74da22010-12-15 10:45:06 +0000234 {
235 $this->file_name .= $this->file_ext;
236 }
237
238 // An extension was provided, lets have it!
239 else
240 {
241 $this->file_ext = $this->get_extension($this->_file_name_override);
242 }
Derek Jonese9d723f2010-07-12 10:10:59 -0500243
244 if ( ! $this->is_allowed_filetype(TRUE))
245 {
246 $this->set_error('upload_invalid_filetype');
Barry Mienydd671972010-10-04 16:33:58 +0200247 return FALSE;
Derek Jonese9d723f2010-07-12 10:10:59 -0500248 }
249 }
Barry Mienydd671972010-10-04 16:33:58 +0200250
Derek Jonese9d723f2010-07-12 10:10:59 -0500251 // Convert the file size to kilobytes
252 if ($this->file_size > 0)
253 {
254 $this->file_size = round($this->file_size/1024, 2);
255 }
256
Derek Allard2067d1a2008-11-13 22:59:24 +0000257 // Is the file size within the allowed maximum?
258 if ( ! $this->is_allowed_filesize())
259 {
260 $this->set_error('upload_invalid_filesize');
261 return FALSE;
262 }
263
264 // Are the image dimensions within the allowed size?
265 // Note: This can fail if the server has an open_basdir restriction.
266 if ( ! $this->is_allowed_dimensions())
267 {
268 $this->set_error('upload_invalid_dimensions');
269 return FALSE;
270 }
271
272 // Sanitize the file name for security
273 $this->file_name = $this->clean_file_name($this->file_name);
Barry Mienydd671972010-10-04 16:33:58 +0200274
Derek Allard2067d1a2008-11-13 22:59:24 +0000275 // Truncate the file name if it's too long
276 if ($this->max_filename > 0)
277 {
278 $this->file_name = $this->limit_filename_length($this->file_name, $this->max_filename);
279 }
280
281 // Remove white spaces in the name
282 if ($this->remove_spaces == TRUE)
283 {
284 $this->file_name = preg_replace("/\s+/", "_", $this->file_name);
285 }
286
287 /*
288 * Validate the file name
289 * This function appends an number onto the end of
290 * the file if one with the same name already exists.
291 * If it returns false there was a problem.
292 */
293 $this->orig_name = $this->file_name;
294
295 if ($this->overwrite == FALSE)
296 {
297 $this->file_name = $this->set_filename($this->upload_path, $this->file_name);
Barry Mienydd671972010-10-04 16:33:58 +0200298
Derek Allard2067d1a2008-11-13 22:59:24 +0000299 if ($this->file_name === FALSE)
300 {
301 return FALSE;
302 }
303 }
304
305 /*
Derek Jonese9d723f2010-07-12 10:10:59 -0500306 * Run the file through the XSS hacking filter
307 * This helps prevent malicious code from being
Derek Jones4b9c6292011-07-01 17:40:48 -0500308 * embedded within a file. Scripts can easily
Derek Jonese9d723f2010-07-12 10:10:59 -0500309 * be disguised as images or other file types.
310 */
311 if ($this->xss_clean)
312 {
313 if ($this->do_xss_clean() === FALSE)
314 {
315 $this->set_error('upload_unable_to_write_file');
316 return FALSE;
317 }
318 }
319
320 /*
Derek Allard2067d1a2008-11-13 22:59:24 +0000321 * Move the file to the final destination
322 * To deal with different server configurations
Derek Jones4b9c6292011-07-01 17:40:48 -0500323 * we'll attempt to use copy() first. If that fails
324 * we'll use move_uploaded_file(). One of the two should
Derek Allard2067d1a2008-11-13 22:59:24 +0000325 * reliably work in most environments
326 */
327 if ( ! @copy($this->file_temp, $this->upload_path.$this->file_name))
328 {
329 if ( ! @move_uploaded_file($this->file_temp, $this->upload_path.$this->file_name))
330 {
Barry Mienydd671972010-10-04 16:33:58 +0200331 $this->set_error('upload_destination_error');
332 return FALSE;
Derek Allard2067d1a2008-11-13 22:59:24 +0000333 }
334 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000335
336 /*
337 * Set the finalized image dimensions
338 * This sets the image width/height (assuming the
Derek Jones4b9c6292011-07-01 17:40:48 -0500339 * file was an image). We use this information
Derek Allard2067d1a2008-11-13 22:59:24 +0000340 * in the "data" function.
341 */
342 $this->set_image_properties($this->upload_path.$this->file_name);
343
344 return TRUE;
345 }
Barry Mienydd671972010-10-04 16:33:58 +0200346
Derek Allard2067d1a2008-11-13 22:59:24 +0000347 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200348
Derek Allard2067d1a2008-11-13 22:59:24 +0000349 /**
350 * Finalized Data Array
Barry Mienydd671972010-10-04 16:33:58 +0200351 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000352 * Returns an associative array containing all of the information
353 * related to the upload, allowing the developer easy access in one array.
354 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000355 * @return array
Barry Mienydd671972010-10-04 16:33:58 +0200356 */
Greg Aker58fdee82010-11-10 15:07:09 -0600357 public function data()
Derek Allard2067d1a2008-11-13 22:59:24 +0000358 {
359 return array (
360 'file_name' => $this->file_name,
361 'file_type' => $this->file_type,
362 'file_path' => $this->upload_path,
363 'full_path' => $this->upload_path.$this->file_name,
364 'raw_name' => str_replace($this->file_ext, '', $this->file_name),
365 'orig_name' => $this->orig_name,
Derek Jonese9d723f2010-07-12 10:10:59 -0500366 'client_name' => $this->client_name,
Derek Allard2067d1a2008-11-13 22:59:24 +0000367 'file_ext' => $this->file_ext,
368 'file_size' => $this->file_size,
369 'is_image' => $this->is_image(),
370 'image_width' => $this->image_width,
371 'image_height' => $this->image_height,
372 'image_type' => $this->image_type,
373 'image_size_str' => $this->image_size_str,
374 );
375 }
Barry Mienydd671972010-10-04 16:33:58 +0200376
Derek Allard2067d1a2008-11-13 22:59:24 +0000377 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200378
Derek Allard2067d1a2008-11-13 22:59:24 +0000379 /**
380 * Set Upload Path
381 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000382 * @param string
383 * @return void
Barry Mienydd671972010-10-04 16:33:58 +0200384 */
Greg Aker58fdee82010-11-10 15:07:09 -0600385 public function set_upload_path($path)
Derek Allard2067d1a2008-11-13 22:59:24 +0000386 {
387 // Make sure it has a trailing slash
388 $this->upload_path = rtrim($path, '/').'/';
389 }
Barry Mienydd671972010-10-04 16:33:58 +0200390
Derek Allard2067d1a2008-11-13 22:59:24 +0000391 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200392
Derek Allard2067d1a2008-11-13 22:59:24 +0000393 /**
394 * Set the file name
395 *
396 * This function takes a filename/path as input and looks for the
397 * existence of a file with the same name. If found, it will append a
398 * number to the end of the filename to avoid overwriting a pre-existing file.
399 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000400 * @param string
401 * @param string
402 * @return string
Barry Mienydd671972010-10-04 16:33:58 +0200403 */
Greg Aker58fdee82010-11-10 15:07:09 -0600404 public function set_filename($path, $filename)
Derek Allard2067d1a2008-11-13 22:59:24 +0000405 {
406 if ($this->encrypt_name == TRUE)
Barry Mienydd671972010-10-04 16:33:58 +0200407 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000408 mt_srand();
Barry Mienydd671972010-10-04 16:33:58 +0200409 $filename = md5(uniqid(mt_rand())).$this->file_ext;
Derek Allard2067d1a2008-11-13 22:59:24 +0000410 }
Barry Mienydd671972010-10-04 16:33:58 +0200411
Derek Allard2067d1a2008-11-13 22:59:24 +0000412 if ( ! file_exists($path.$filename))
413 {
414 return $filename;
415 }
Barry Mienydd671972010-10-04 16:33:58 +0200416
Derek Allard2067d1a2008-11-13 22:59:24 +0000417 $filename = str_replace($this->file_ext, '', $filename);
Barry Mienydd671972010-10-04 16:33:58 +0200418
Derek Allard2067d1a2008-11-13 22:59:24 +0000419 $new_filename = '';
Adam Jackettccbbea12011-08-21 16:19:11 -0400420 for ($i = 1; $i < $this->max_filename_increment; $i++)
Barry Mienydd671972010-10-04 16:33:58 +0200421 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000422 if ( ! file_exists($path.$filename.$i.$this->file_ext))
423 {
424 $new_filename = $filename.$i.$this->file_ext;
425 break;
426 }
427 }
428
429 if ($new_filename == '')
430 {
431 $this->set_error('upload_bad_filename');
432 return FALSE;
433 }
434 else
435 {
436 return $new_filename;
437 }
438 }
Barry Mienydd671972010-10-04 16:33:58 +0200439
Derek Allard2067d1a2008-11-13 22:59:24 +0000440 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200441
Derek Allard2067d1a2008-11-13 22:59:24 +0000442 /**
443 * Set Maximum File Size
444 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000445 * @param integer
446 * @return void
Barry Mienydd671972010-10-04 16:33:58 +0200447 */
Greg Aker58fdee82010-11-10 15:07:09 -0600448 public function set_max_filesize($n)
Derek Allard2067d1a2008-11-13 22:59:24 +0000449 {
450 $this->max_size = ((int) $n < 0) ? 0: (int) $n;
451 }
Barry Mienydd671972010-10-04 16:33:58 +0200452
Derek Allard2067d1a2008-11-13 22:59:24 +0000453 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200454
Derek Allard2067d1a2008-11-13 22:59:24 +0000455 /**
456 * Set Maximum File Name Length
457 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000458 * @param integer
459 * @return void
Barry Mienydd671972010-10-04 16:33:58 +0200460 */
Greg Aker58fdee82010-11-10 15:07:09 -0600461 public function set_max_filename($n)
Derek Allard2067d1a2008-11-13 22:59:24 +0000462 {
463 $this->max_filename = ((int) $n < 0) ? 0: (int) $n;
464 }
465
466 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200467
Derek Allard2067d1a2008-11-13 22:59:24 +0000468 /**
469 * Set Maximum Image Width
470 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000471 * @param integer
472 * @return void
Barry Mienydd671972010-10-04 16:33:58 +0200473 */
Greg Aker58fdee82010-11-10 15:07:09 -0600474 public function set_max_width($n)
Derek Allard2067d1a2008-11-13 22:59:24 +0000475 {
476 $this->max_width = ((int) $n < 0) ? 0: (int) $n;
477 }
Barry Mienydd671972010-10-04 16:33:58 +0200478
Derek Allard2067d1a2008-11-13 22:59:24 +0000479 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200480
Derek Allard2067d1a2008-11-13 22:59:24 +0000481 /**
482 * Set Maximum Image Height
483 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000484 * @param integer
485 * @return void
Barry Mienydd671972010-10-04 16:33:58 +0200486 */
Greg Aker58fdee82010-11-10 15:07:09 -0600487 public function set_max_height($n)
Derek Allard2067d1a2008-11-13 22:59:24 +0000488 {
489 $this->max_height = ((int) $n < 0) ? 0: (int) $n;
490 }
Barry Mienydd671972010-10-04 16:33:58 +0200491
Derek Allard2067d1a2008-11-13 22:59:24 +0000492 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200493
Derek Allard2067d1a2008-11-13 22:59:24 +0000494 /**
495 * Set Allowed File Types
496 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000497 * @param string
498 * @return void
Barry Mienydd671972010-10-04 16:33:58 +0200499 */
Greg Aker58fdee82010-11-10 15:07:09 -0600500 public function set_allowed_types($types)
Derek Allard2067d1a2008-11-13 22:59:24 +0000501 {
Derek Jonese12f64e2010-03-02 22:55:08 -0600502 if ( ! is_array($types) && $types == '*')
503 {
504 $this->allowed_types = '*';
505 return;
506 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000507 $this->allowed_types = explode('|', $types);
508 }
Barry Mienydd671972010-10-04 16:33:58 +0200509
Derek Allard2067d1a2008-11-13 22:59:24 +0000510 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200511
Derek Allard2067d1a2008-11-13 22:59:24 +0000512 /**
513 * Set Image Properties
514 *
515 * Uses GD to determine the width/height/type of image
516 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000517 * @param string
518 * @return void
Barry Mienydd671972010-10-04 16:33:58 +0200519 */
Greg Aker58fdee82010-11-10 15:07:09 -0600520 public function set_image_properties($path = '')
Derek Allard2067d1a2008-11-13 22:59:24 +0000521 {
522 if ( ! $this->is_image())
523 {
524 return;
525 }
526
527 if (function_exists('getimagesize'))
528 {
529 if (FALSE !== ($D = @getimagesize($path)))
Barry Mienydd671972010-10-04 16:33:58 +0200530 {
Derek Allard2067d1a2008-11-13 22:59:24 +0000531 $types = array(1 => 'gif', 2 => 'jpeg', 3 => 'png');
532
533 $this->image_width = $D['0'];
534 $this->image_height = $D['1'];
535 $this->image_type = ( ! isset($types[$D['2']])) ? 'unknown' : $types[$D['2']];
Derek Jones4b9c6292011-07-01 17:40:48 -0500536 $this->image_size_str = $D['3']; // string containing height and width
Derek Allard2067d1a2008-11-13 22:59:24 +0000537 }
538 }
539 }
Barry Mienydd671972010-10-04 16:33:58 +0200540
Derek Allard2067d1a2008-11-13 22:59:24 +0000541 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200542
Derek Allard2067d1a2008-11-13 22:59:24 +0000543 /**
544 * Set XSS Clean
545 *
546 * Enables the XSS flag so that the file that was uploaded
547 * will be run through the XSS filter.
548 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000549 * @param bool
550 * @return void
551 */
Greg Aker58fdee82010-11-10 15:07:09 -0600552 public function set_xss_clean($flag = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000553 {
554 $this->xss_clean = ($flag == TRUE) ? TRUE : FALSE;
555 }
Barry Mienydd671972010-10-04 16:33:58 +0200556
Derek Allard2067d1a2008-11-13 22:59:24 +0000557 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200558
Derek Allard2067d1a2008-11-13 22:59:24 +0000559 /**
560 * Validate the image
561 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000562 * @return bool
Barry Mienydd671972010-10-04 16:33:58 +0200563 */
Greg Aker58fdee82010-11-10 15:07:09 -0600564 public function is_image()
Derek Allard2067d1a2008-11-13 22:59:24 +0000565 {
566 // IE will sometimes return odd mime-types during upload, so here we just standardize all
567 // jpegs or pngs to the same file type.
568
Derek Jones4b9c6292011-07-01 17:40:48 -0500569 $png_mimes = array('image/x-png');
Derek Allard2067d1a2008-11-13 22:59:24 +0000570 $jpeg_mimes = array('image/jpg', 'image/jpe', 'image/jpeg', 'image/pjpeg');
Barry Mienydd671972010-10-04 16:33:58 +0200571
Derek Allard2067d1a2008-11-13 22:59:24 +0000572 if (in_array($this->file_type, $png_mimes))
573 {
574 $this->file_type = 'image/png';
575 }
Barry Mienydd671972010-10-04 16:33:58 +0200576
Derek Allard2067d1a2008-11-13 22:59:24 +0000577 if (in_array($this->file_type, $jpeg_mimes))
578 {
579 $this->file_type = 'image/jpeg';
580 }
581
582 $img_mimes = array(
583 'image/gif',
584 'image/jpeg',
585 'image/png',
Barry Mienydd671972010-10-04 16:33:58 +0200586 );
Derek Allard2067d1a2008-11-13 22:59:24 +0000587
588 return (in_array($this->file_type, $img_mimes, TRUE)) ? TRUE : FALSE;
589 }
Barry Mienydd671972010-10-04 16:33:58 +0200590
Derek Allard2067d1a2008-11-13 22:59:24 +0000591 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200592
Derek Allard2067d1a2008-11-13 22:59:24 +0000593 /**
594 * Verify that the filetype is allowed
595 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000596 * @return bool
Barry Mienydd671972010-10-04 16:33:58 +0200597 */
Greg Aker58fdee82010-11-10 15:07:09 -0600598 public function is_allowed_filetype($ignore_mime = FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +0000599 {
Derek Jonese12f64e2010-03-02 22:55:08 -0600600 if ($this->allowed_types == '*')
601 {
602 return TRUE;
603 }
Barry Mienydd671972010-10-04 16:33:58 +0200604
Derek Allard2067d1a2008-11-13 22:59:24 +0000605 if (count($this->allowed_types) == 0 OR ! is_array($this->allowed_types))
606 {
607 $this->set_error('upload_no_file_types');
608 return FALSE;
609 }
Barry Mienydd671972010-10-04 16:33:58 +0200610
Derek Jonese9d723f2010-07-12 10:10:59 -0500611 $ext = strtolower(ltrim($this->file_ext, '.'));
Barry Mienydd671972010-10-04 16:33:58 +0200612
Derek Jonese9d723f2010-07-12 10:10:59 -0500613 if ( ! in_array($ext, $this->allowed_types))
Derek Allard2067d1a2008-11-13 22:59:24 +0000614 {
Derek Jonese9d723f2010-07-12 10:10:59 -0500615 return FALSE;
616 }
Derek Jonesafa282f2009-02-10 17:11:52 +0000617
Barry Mienydd671972010-10-04 16:33:58 +0200618 // Images get some additional checks
Derek Jonese9d723f2010-07-12 10:10:59 -0500619 $image_types = array('gif', 'jpg', 'jpeg', 'png', 'jpe');
Barry Mienydd671972010-10-04 16:33:58 +0200620
Derek Jonese9d723f2010-07-12 10:10:59 -0500621 if (in_array($ext, $image_types))
622 {
623 if (getimagesize($this->file_temp) === FALSE)
Derek Jonesafa282f2009-02-10 17:11:52 +0000624 {
Derek Jonese9d723f2010-07-12 10:10:59 -0500625 return FALSE;
Barry Mienydd671972010-10-04 16:33:58 +0200626 }
Derek Jonese9d723f2010-07-12 10:10:59 -0500627 }
Barry Mienydd671972010-10-04 16:33:58 +0200628
Derek Jonese9d723f2010-07-12 10:10:59 -0500629 if ($ignore_mime === TRUE)
630 {
631 return TRUE;
632 }
Barry Mienydd671972010-10-04 16:33:58 +0200633
Derek Jonese9d723f2010-07-12 10:10:59 -0500634 $mime = $this->mimes_types($ext);
Barry Mienydd671972010-10-04 16:33:58 +0200635
Derek Jonese9d723f2010-07-12 10:10:59 -0500636 if (is_array($mime))
637 {
638 if (in_array($this->file_type, $mime, TRUE))
Derek Allard2067d1a2008-11-13 22:59:24 +0000639 {
Derek Jonese9d723f2010-07-12 10:10:59 -0500640 return TRUE;
Barry Mienydd671972010-10-04 16:33:58 +0200641 }
Derek Jonese9d723f2010-07-12 10:10:59 -0500642 }
643 elseif ($mime == $this->file_type)
644 {
645 return TRUE;
Derek Allard2067d1a2008-11-13 22:59:24 +0000646 }
Barry Mienydd671972010-10-04 16:33:58 +0200647
Derek Allard2067d1a2008-11-13 22:59:24 +0000648 return FALSE;
649 }
Barry Mienydd671972010-10-04 16:33:58 +0200650
Derek Allard2067d1a2008-11-13 22:59:24 +0000651 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200652
Derek Allard2067d1a2008-11-13 22:59:24 +0000653 /**
654 * Verify that the file is within the allowed size
655 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000656 * @return bool
Barry Mienydd671972010-10-04 16:33:58 +0200657 */
Greg Aker58fdee82010-11-10 15:07:09 -0600658 public function is_allowed_filesize()
Derek Allard2067d1a2008-11-13 22:59:24 +0000659 {
Derek Jones4b9c6292011-07-01 17:40:48 -0500660 if ($this->max_size != 0 AND $this->file_size > $this->max_size)
Derek Allard2067d1a2008-11-13 22:59:24 +0000661 {
662 return FALSE;
663 }
664 else
665 {
666 return TRUE;
667 }
668 }
Barry Mienydd671972010-10-04 16:33:58 +0200669
Derek Allard2067d1a2008-11-13 22:59:24 +0000670 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200671
Derek Allard2067d1a2008-11-13 22:59:24 +0000672 /**
673 * Verify that the image is within the allowed width/height
674 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000675 * @return bool
Barry Mienydd671972010-10-04 16:33:58 +0200676 */
Greg Aker58fdee82010-11-10 15:07:09 -0600677 public function is_allowed_dimensions()
Derek Allard2067d1a2008-11-13 22:59:24 +0000678 {
679 if ( ! $this->is_image())
680 {
681 return TRUE;
682 }
683
684 if (function_exists('getimagesize'))
685 {
686 $D = @getimagesize($this->file_temp);
687
688 if ($this->max_width > 0 AND $D['0'] > $this->max_width)
689 {
690 return FALSE;
691 }
692
693 if ($this->max_height > 0 AND $D['1'] > $this->max_height)
694 {
695 return FALSE;
696 }
697
698 return TRUE;
699 }
700
701 return TRUE;
702 }
Barry Mienydd671972010-10-04 16:33:58 +0200703
Derek Allard2067d1a2008-11-13 22:59:24 +0000704 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200705
Derek Allard2067d1a2008-11-13 22:59:24 +0000706 /**
707 * Validate Upload Path
708 *
709 * Verifies that it is a valid upload path with proper permissions.
710 *
711 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000712 * @return bool
Barry Mienydd671972010-10-04 16:33:58 +0200713 */
Greg Aker58fdee82010-11-10 15:07:09 -0600714 public function validate_upload_path()
Derek Allard2067d1a2008-11-13 22:59:24 +0000715 {
716 if ($this->upload_path == '')
717 {
718 $this->set_error('upload_no_filepath');
719 return FALSE;
720 }
Barry Mienydd671972010-10-04 16:33:58 +0200721
Derek Allard2067d1a2008-11-13 22:59:24 +0000722 if (function_exists('realpath') AND @realpath($this->upload_path) !== FALSE)
723 {
724 $this->upload_path = str_replace("\\", "/", realpath($this->upload_path));
725 }
726
727 if ( ! @is_dir($this->upload_path))
728 {
729 $this->set_error('upload_no_filepath');
730 return FALSE;
731 }
732
733 if ( ! is_really_writable($this->upload_path))
734 {
735 $this->set_error('upload_not_writable');
736 return FALSE;
737 }
738
Derek Jones4b9c6292011-07-01 17:40:48 -0500739 $this->upload_path = preg_replace("/(.+?)\/*$/", "\\1/", $this->upload_path);
Derek Allard2067d1a2008-11-13 22:59:24 +0000740 return TRUE;
741 }
Barry Mienydd671972010-10-04 16:33:58 +0200742
Derek Allard2067d1a2008-11-13 22:59:24 +0000743 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200744
Derek Allard2067d1a2008-11-13 22:59:24 +0000745 /**
746 * Extract the file extension
747 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000748 * @param string
749 * @return string
Barry Mienydd671972010-10-04 16:33:58 +0200750 */
Greg Aker58fdee82010-11-10 15:07:09 -0600751 public function get_extension($filename)
Derek Allard2067d1a2008-11-13 22:59:24 +0000752 {
753 $x = explode('.', $filename);
754 return '.'.end($x);
Barry Mienydd671972010-10-04 16:33:58 +0200755 }
756
Derek Allard2067d1a2008-11-13 22:59:24 +0000757 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200758
Derek Allard2067d1a2008-11-13 22:59:24 +0000759 /**
760 * Clean the file name for security
761 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000762 * @param string
763 * @return string
Barry Mienydd671972010-10-04 16:33:58 +0200764 */
Greg Aker58fdee82010-11-10 15:07:09 -0600765 public function clean_file_name($filename)
Derek Allard2067d1a2008-11-13 22:59:24 +0000766 {
767 $bad = array(
768 "<!--",
769 "-->",
770 "'",
771 "<",
772 ">",
773 '"',
774 '&',
775 '$',
776 '=',
777 ';',
778 '?',
779 '/',
780 "%20",
781 "%22",
782 "%3c", // <
Barry Mienydd671972010-10-04 16:33:58 +0200783 "%253c", // <
784 "%3e", // >
785 "%0e", // >
786 "%28", // (
787 "%29", // )
788 "%2528", // (
789 "%26", // &
790 "%24", // $
791 "%3f", // ?
792 "%3b", // ;
Derek Allard2067d1a2008-11-13 22:59:24 +0000793 "%3d" // =
794 );
Barry Mienydd671972010-10-04 16:33:58 +0200795
Derek Allard2067d1a2008-11-13 22:59:24 +0000796 $filename = str_replace($bad, '', $filename);
797
798 return stripslashes($filename);
799 }
800
801 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200802
Derek Allard2067d1a2008-11-13 22:59:24 +0000803 /**
804 * Limit the File Name Length
805 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000806 * @param string
807 * @return string
Barry Mienydd671972010-10-04 16:33:58 +0200808 */
Greg Aker58fdee82010-11-10 15:07:09 -0600809 public function limit_filename_length($filename, $length)
Derek Allard2067d1a2008-11-13 22:59:24 +0000810 {
811 if (strlen($filename) < $length)
812 {
813 return $filename;
814 }
Barry Mienydd671972010-10-04 16:33:58 +0200815
Derek Allard2067d1a2008-11-13 22:59:24 +0000816 $ext = '';
817 if (strpos($filename, '.') !== FALSE)
818 {
819 $parts = explode('.', $filename);
820 $ext = '.'.array_pop($parts);
821 $filename = implode('.', $parts);
822 }
Barry Mienydd671972010-10-04 16:33:58 +0200823
Derek Allard2067d1a2008-11-13 22:59:24 +0000824 return substr($filename, 0, ($length - strlen($ext))).$ext;
825 }
826
827 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200828
Derek Allard2067d1a2008-11-13 22:59:24 +0000829 /**
830 * Runs the file through the XSS clean function
831 *
832 * This prevents people from embedding malicious code in their files.
833 * I'm not sure that it won't negatively affect certain files in unexpected ways,
834 * but so far I haven't found that it causes trouble.
835 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000836 * @return void
Barry Mienydd671972010-10-04 16:33:58 +0200837 */
Greg Aker58fdee82010-11-10 15:07:09 -0600838 public function do_xss_clean()
Barry Mienydd671972010-10-04 16:33:58 +0200839 {
Derek Jonese9d723f2010-07-12 10:10:59 -0500840 $file = $this->file_temp;
Barry Mienydd671972010-10-04 16:33:58 +0200841
Derek Allard2067d1a2008-11-13 22:59:24 +0000842 if (filesize($file) == 0)
843 {
844 return FALSE;
845 }
Barry Mienydd671972010-10-04 16:33:58 +0200846
Greg Akerf82e51c2010-04-14 19:33:50 -0500847 if (function_exists('memory_get_usage') && memory_get_usage() && ini_get('memory_limit') != '')
848 {
849 $current = ini_get('memory_limit') * 1024 * 1024;
Barry Mienydd671972010-10-04 16:33:58 +0200850
Greg Akerc78a2592010-06-09 11:45:32 -0500851 // There was a bug/behavioural change in PHP 5.2, where numbers over one million get output
Derek Jones4b9c6292011-07-01 17:40:48 -0500852 // into scientific notation. number_format() ensures this number is an integer
Greg Akerc78a2592010-06-09 11:45:32 -0500853 // http://bugs.php.net/bug.php?id=43053
Barry Mienydd671972010-10-04 16:33:58 +0200854
Greg Akerc78a2592010-06-09 11:45:32 -0500855 $new_memory = number_format(ceil(filesize($file) + $current), 0, '.', '');
Barry Mienydd671972010-10-04 16:33:58 +0200856
Greg Akerc78a2592010-06-09 11:45:32 -0500857 ini_set('memory_limit', $new_memory); // When an integer is used, the value is measured in bytes. - PHP.net
Greg Akerf82e51c2010-04-14 19:33:50 -0500858 }
859
860 // If the file being uploaded is an image, then we should have no problem with XSS attacks (in theory), but
861 // IE can be fooled into mime-type detecting a malformed image as an html file, thus executing an XSS attack on anyone
Derek Jones4b9c6292011-07-01 17:40:48 -0500862 // using IE who looks at the image. It does this by inspecting the first 255 bytes of an image. To get around this
863 // CI will itself look at the first 255 bytes of an image to determine its relative safety. This can save a lot of
Barry Mienydd671972010-10-04 16:33:58 +0200864 // processor power and time if it is actually a clean image, as it will be in nearly all instances _except_ an
Greg Akerf82e51c2010-04-14 19:33:50 -0500865 // attempted XSS attack.
866
867 if (function_exists('getimagesize') && @getimagesize($file) !== FALSE)
868 {
Barry Mienydd671972010-10-04 16:33:58 +0200869 if (($file = @fopen($file, 'rb')) === FALSE) // "b" to force binary
870 {
Greg Akerf82e51c2010-04-14 19:33:50 -0500871 return FALSE; // Couldn't open the file, return FALSE
Barry Mienydd671972010-10-04 16:33:58 +0200872 }
Greg Akerf82e51c2010-04-14 19:33:50 -0500873
Barry Mienydd671972010-10-04 16:33:58 +0200874 $opening_bytes = fread($file, 256);
875 fclose($file);
Greg Akerf82e51c2010-04-14 19:33:50 -0500876
877 // These are known to throw IE into mime-type detection chaos
878 // <a, <body, <head, <html, <img, <plaintext, <pre, <script, <table, <title
879 // title is basically just in SVG, but we filter it anyhow
880
881 if ( ! preg_match('/<(a|body|head|html|img|plaintext|pre|script|table|title)[\s>]/i', $opening_bytes))
882 {
883 return TRUE; // its an image, no "triggers" detected in the first 256 bytes, we're good
884 }
885 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000886
887 if (($data = @file_get_contents($file)) === FALSE)
888 {
889 return FALSE;
890 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000891
Greg Akerf82e51c2010-04-14 19:33:50 -0500892 $CI =& get_instance();
Greg Akerf82e51c2010-04-14 19:33:50 -0500893 return $CI->security->xss_clean($data, TRUE);
Derek Allard2067d1a2008-11-13 22:59:24 +0000894 }
Barry Mienydd671972010-10-04 16:33:58 +0200895
Derek Allard2067d1a2008-11-13 22:59:24 +0000896 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200897
Derek Allard2067d1a2008-11-13 22:59:24 +0000898 /**
899 * Set an error message
900 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000901 * @param string
902 * @return void
Barry Mienydd671972010-10-04 16:33:58 +0200903 */
Greg Aker58fdee82010-11-10 15:07:09 -0600904 public function set_error($msg)
Derek Allard2067d1a2008-11-13 22:59:24 +0000905 {
Barry Mienydd671972010-10-04 16:33:58 +0200906 $CI =& get_instance();
Derek Allard2067d1a2008-11-13 22:59:24 +0000907 $CI->lang->load('upload');
Barry Mienydd671972010-10-04 16:33:58 +0200908
Derek Allard2067d1a2008-11-13 22:59:24 +0000909 if (is_array($msg))
910 {
911 foreach ($msg as $val)
912 {
Barry Mienydd671972010-10-04 16:33:58 +0200913 $msg = ($CI->lang->line($val) == FALSE) ? $val : $CI->lang->line($val);
Derek Allard2067d1a2008-11-13 22:59:24 +0000914 $this->error_msg[] = $msg;
915 log_message('error', $msg);
Barry Mienydd671972010-10-04 16:33:58 +0200916 }
Derek Allard2067d1a2008-11-13 22:59:24 +0000917 }
918 else
919 {
920 $msg = ($CI->lang->line($msg) == FALSE) ? $msg : $CI->lang->line($msg);
921 $this->error_msg[] = $msg;
922 log_message('error', $msg);
923 }
924 }
Barry Mienydd671972010-10-04 16:33:58 +0200925
Derek Allard2067d1a2008-11-13 22:59:24 +0000926 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200927
Derek Allard2067d1a2008-11-13 22:59:24 +0000928 /**
929 * Display the error message
930 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000931 * @param string
932 * @param string
933 * @return string
Barry Mienydd671972010-10-04 16:33:58 +0200934 */
Greg Aker58fdee82010-11-10 15:07:09 -0600935 public function display_errors($open = '<p>', $close = '</p>')
Derek Allard2067d1a2008-11-13 22:59:24 +0000936 {
937 $str = '';
938 foreach ($this->error_msg as $val)
939 {
940 $str .= $open.$val.$close;
941 }
Barry Mienydd671972010-10-04 16:33:58 +0200942
Derek Allard2067d1a2008-11-13 22:59:24 +0000943 return $str;
944 }
Barry Mienydd671972010-10-04 16:33:58 +0200945
Derek Allard2067d1a2008-11-13 22:59:24 +0000946 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200947
Derek Allard2067d1a2008-11-13 22:59:24 +0000948 /**
949 * List of Mime Types
950 *
Derek Jones4b9c6292011-07-01 17:40:48 -0500951 * This is a list of mime types. We use it to validate
Derek Allard2067d1a2008-11-13 22:59:24 +0000952 * the "allowed types" set by the developer
953 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000954 * @param string
955 * @return string
Barry Mienydd671972010-10-04 16:33:58 +0200956 */
Greg Aker58fdee82010-11-10 15:07:09 -0600957 public function mimes_types($mime)
Derek Allard2067d1a2008-11-13 22:59:24 +0000958 {
959 global $mimes;
Barry Mienydd671972010-10-04 16:33:58 +0200960
Derek Allard2067d1a2008-11-13 22:59:24 +0000961 if (count($this->mimes) == 0)
962 {
Greg Aker3a746652011-04-19 10:59:47 -0500963 if (defined('ENVIRONMENT') AND is_file(APPPATH.'config/'.ENVIRONMENT.'/mimes.php'))
bubbafoley0ea04142011-03-17 14:55:41 -0500964 {
Greg Aker3a746652011-04-19 10:59:47 -0500965 include(APPPATH.'config/'.ENVIRONMENT.'/mimes.php');
Eric Barnesfdd5b112011-03-21 21:28:58 -0400966 }
Greg Aker3a746652011-04-19 10:59:47 -0500967 elseif (is_file(APPPATH.'config/mimes.php'))
Eric Barnesfdd5b112011-03-21 21:28:58 -0400968 {
Greg Aker3a746652011-04-19 10:59:47 -0500969 include(APPPATH.'config//mimes.php');
bubbafoley0ea04142011-03-17 14:55:41 -0500970 }
971 else
972 {
Eric Barnesfdd5b112011-03-21 21:28:58 -0400973 return FALSE;
bubbafoley0ea04142011-03-17 14:55:41 -0500974 }
Eric Barnes92808342011-03-18 09:02:37 -0400975
Eric Barnesfdd5b112011-03-21 21:28:58 -0400976 $this->mimes = $mimes;
977 unset($mimes);
Derek Allard2067d1a2008-11-13 22:59:24 +0000978 }
Barry Mienydd671972010-10-04 16:33:58 +0200979
Derek Allard2067d1a2008-11-13 22:59:24 +0000980 return ( ! isset($this->mimes[$mime])) ? FALSE : $this->mimes[$mime];
981 }
982
983 // --------------------------------------------------------------------
Barry Mienydd671972010-10-04 16:33:58 +0200984
Derek Allard2067d1a2008-11-13 22:59:24 +0000985 /**
986 * Prep Filename
987 *
988 * Prevents possible script execution from Apache's handling of files multiple extensions
989 * http://httpd.apache.org/docs/1.3/mod/mod_mime.html#multipleext
990 *
Derek Allard2067d1a2008-11-13 22:59:24 +0000991 * @param string
992 * @return string
993 */
Greg Aker58fdee82010-11-10 15:07:09 -0600994 protected function _prep_filename($filename)
Derek Allard2067d1a2008-11-13 22:59:24 +0000995 {
Greg Aker924000e2010-07-22 11:04:58 -0500996 if (strpos($filename, '.') === FALSE OR $this->allowed_types == '*')
Derek Allard2067d1a2008-11-13 22:59:24 +0000997 {
998 return $filename;
999 }
Derek Allard616dab82009-02-16 15:44:32 +00001000
Derek Allard2067d1a2008-11-13 22:59:24 +00001001 $parts = explode('.', $filename);
1002 $ext = array_pop($parts);
1003 $filename = array_shift($parts);
Derek Allard616dab82009-02-16 15:44:32 +00001004
Derek Allard2067d1a2008-11-13 22:59:24 +00001005 foreach ($parts as $part)
1006 {
Derek Jonese9d723f2010-07-12 10:10:59 -05001007 if ( ! in_array(strtolower($part), $this->allowed_types) OR $this->mimes_types(strtolower($part)) === FALSE)
Derek Allard2067d1a2008-11-13 22:59:24 +00001008 {
1009 $filename .= '.'.$part.'_';
1010 }
1011 else
1012 {
1013 $filename .= '.'.$part;
1014 }
1015 }
Derek Allardd70b0642009-02-16 13:51:42 +00001016
Derek Allard2067d1a2008-11-13 22:59:24 +00001017 $filename .= '.'.$ext;
Barry Mienydd671972010-10-04 16:33:58 +02001018
Derek Allard2067d1a2008-11-13 22:59:24 +00001019 return $filename;
1020 }
1021
1022 // --------------------------------------------------------------------
1023
Andrey Andreev3a3c9472011-09-24 14:25:33 +03001024 /**
1025 * File MIME type
1026 *
1027 * Detects the (actual) MIME type of the uploaded file, if possible.
1028 * The input array is expected to be $_FILES[$field]
1029 *
1030 * @param array
1031 * @return void
1032 */
1033 protected function _file_mime_type($file)
1034 {
Andrey Andreev3a3c9472011-09-24 14:25:33 +03001035 // Use if the Fileinfo extension, if available (only versions above 5.3 support the FILEINFO_MIME_TYPE flag)
Andrey Andreevf300fb22011-09-26 10:27:25 +03001036 if (is_php('5.3') && function_exists('finfo_file'))
Andrey Andreev3a3c9472011-09-24 14:25:33 +03001037 {
1038 $finfo = new finfo(FILEINFO_MIME_TYPE);
1039 if ($finfo !== FALSE) // This is possible, if there is no magic MIME database file found on the system
1040 {
1041 $file_type = $finfo->file($file['tmp_name']);
1042
1043 /* According to the comments section of the PHP manual page,
1044 * it is possible that this function returns an empty string
Andrey Andreev2cec39f2011-09-24 22:59:37 +03001045 * for some files (e.g. if they don't exist in the magic MIME database)
Andrey Andreev3a3c9472011-09-24 14:25:33 +03001046 */
1047 if (strlen($file_type) > 1)
1048 {
Andrey Andreev2cec39f2011-09-24 22:59:37 +03001049 $this->file_type = $file_type;
Andrey Andreev3a3c9472011-09-24 14:25:33 +03001050 return;
1051 }
1052 }
1053 }
1054
1055 // Fall back to the deprecated mime_content_type(), if available
1056 if (function_exists('mime_content_type'))
1057 {
1058 $this->file_type = @mime_content_type($file['tmp_name']);
1059 return;
1060 }
1061
1062 /* This is an ugly hack, but UNIX-type systems provide a native way to detect the file type,
1063 * which is still more secure than depending on the value of $_FILES[$field]['type'].
1064 *
1065 * Notes:
1066 * - a 'W' in the substr() expression bellow, would mean that we're using Windows
1067 * - many system admins would disable the exec() function due to security concerns, hence the function_exists() check
1068 */
Andrey Andreev8b3cf632011-10-04 18:27:32 +03001069 if (DIRECTORY_SEPARATOR !== '\\' && function_exists('exec'))
Andrey Andreev3a3c9472011-09-24 14:25:33 +03001070 {
1071 $output = array();
1072 @exec('file --brief --mime-type ' . escapeshellarg($file['tmp_path']), $output, $return_code);
1073 if ($return_code === 0 && strlen($output[0]) > 0) // A return status code != 0 would mean failed execution
1074 {
Andrey Andreev420fe072011-09-24 14:45:44 +03001075 $this->file_type = rtrim($output[0]);
Andrey Andreev3a3c9472011-09-24 14:25:33 +03001076 return;
1077 }
1078 }
1079
1080 $this->file_type = $file['type'];
1081 }
1082
1083 // --------------------------------------------------------------------
1084
Derek Allard2067d1a2008-11-13 22:59:24 +00001085}
1086// END Upload Class
1087
1088/* End of file Upload.php */
Andrey Andreev3a3c9472011-09-24 14:25:33 +03001089/* Location: ./system/libraries/Upload.php */