PageRenderTime 53ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 1ms

/system/libraries/Upload.php

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