e80049fa48738892293fb514d47366b35c26ce0d
[living-lab-site.git] / system / libraries / Upload.php
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_type = preg_replace("/^(.+?);.*$/", "\\1", $_FILES[$field]['type']);
200                 $this->file_type = strtolower(trim(stripslashes($this->file_type), '"'));
201                 $this->file_name = $this->_prep_filename($_FILES[$field]['name']);
202                 $this->file_ext  = $this->get_extension($this->file_name);
203                 $this->client_name = $this->file_name;
204
205                 // Is the file type allowed to be uploaded?
206                 if ( ! $this->is_allowed_filetype())
207                 {
208                         $this->set_error('upload_invalid_filetype');
209                         return FALSE;
210                 }
211
212                 // if we're overriding, let's now make sure the new name and type is allowed
213                 if ($this->_file_name_override != '')
214                 {
215                         $this->file_name = $this->_prep_filename($this->_file_name_override);
216
217                         // If no extension was provided in the file_name config item, use the uploaded one
218                         if (strpos($this->_file_name_override, '.') === FALSE)
219                         {
220                                 $this->file_name .= $this->file_ext;
221                         }
222
223                         // An extension was provided, lets have it!
224                         else
225                         {
226                                 $this->file_ext  = $this->get_extension($this->_file_name_override);
227                         }
228
229                         if ( ! $this->is_allowed_filetype(TRUE))
230                         {
231                                 $this->set_error('upload_invalid_filetype');
232                                 return FALSE;
233                         }
234                 }
235
236                 // Convert the file size to kilobytes
237                 if ($this->file_size > 0)
238                 {
239                         $this->file_size = round($this->file_size/1024, 2);
240                 }
241
242                 // Is the file size within the allowed maximum?
243                 if ( ! $this->is_allowed_filesize())
244                 {
245                         $this->set_error('upload_invalid_filesize');
246                         return FALSE;
247                 }
248
249                 // Are the image dimensions within the allowed size?
250                 // Note: This can fail if the server has an open_basdir restriction.
251                 if ( ! $this->is_allowed_dimensions())
252                 {
253                         $this->set_error('upload_invalid_dimensions');
254                         return FALSE;
255                 }
256
257                 // Sanitize the file name for security
258                 $this->file_name = $this->clean_file_name($this->file_name);
259
260                 // Truncate the file name if it's too long
261                 if ($this->max_filename > 0)
262                 {
263                         $this->file_name = $this->limit_filename_length($this->file_name, $this->max_filename);
264                 }
265
266                 // Remove white spaces in the name
267                 if ($this->remove_spaces == TRUE)
268                 {
269                         $this->file_name = preg_replace("/\s+/", "_", $this->file_name);
270                 }
271
272                 /*
273                  * Validate the file name
274                  * This function appends an number onto the end of
275                  * the file if one with the same name already exists.
276                  * If it returns false there was a problem.
277                  */
278                 $this->orig_name = $this->file_name;
279
280                 if ($this->overwrite == FALSE)
281                 {
282                         $this->file_name = $this->set_filename($this->upload_path, $this->file_name);
283
284                         if ($this->file_name === FALSE)
285                         {
286                                 return FALSE;
287                         }
288                 }
289
290                 /*
291                  * Run the file through the XSS hacking filter
292                  * This helps prevent malicious code from being
293                  * embedded within a file.  Scripts can easily
294                  * be disguised as images or other file types.
295                  */
296                 if ($this->xss_clean)
297                 {
298                         if ($this->do_xss_clean() === FALSE)
299                         {
300                                 $this->set_error('upload_unable_to_write_file');
301                                 return FALSE;
302                         }
303                 }
304
305                 /*
306                  * Move the file to the final destination
307                  * To deal with different server configurations
308                  * we'll attempt to use copy() first.  If that fails
309                  * we'll use move_uploaded_file().  One of the two should
310                  * reliably work in most environments
311                  */
312                 if ( ! @copy($this->file_temp, $this->upload_path.$this->file_name))
313                 {
314                         if ( ! @move_uploaded_file($this->file_temp, $this->upload_path.$this->file_name))
315                         {
316                                 $this->set_error('upload_destination_error');
317                                 return FALSE;
318                         }
319                 }
320
321                 /*
322                  * Set the finalized image dimensions
323                  * This sets the image width/height (assuming the
324                  * file was an image).  We use this information
325                  * in the "data" function.
326                  */
327                 $this->set_image_properties($this->upload_path.$this->file_name);
328
329                 return TRUE;
330         }
331
332         // --------------------------------------------------------------------
333
334         /**
335          * Finalized Data Array
336          *
337          * Returns an associative array containing all of the information
338          * related to the upload, allowing the developer easy access in one array.
339          *
340          * @return      array
341          */
342         public function data()
343         {
344                 return array (
345                                                 'file_name'                     => $this->file_name,
346                                                 'file_type'                     => $this->file_type,
347                                                 'file_path'                     => $this->upload_path,
348                                                 'full_path'                     => $this->upload_path.$this->file_name,
349                                                 'raw_name'                      => str_replace($this->file_ext, '', $this->file_name),
350                                                 'orig_name'                     => $this->orig_name,
351                                                 'client_name'           => $this->client_name,
352                                                 'file_ext'                      => $this->file_ext,
353                                                 'file_size'                     => $this->file_size,
354                                                 'is_image'                      => $this->is_image(),
355                                                 'image_width'           => $this->image_width,
356                                                 'image_height'          => $this->image_height,
357                                                 'image_type'            => $this->image_type,
358                                                 'image_size_str'        => $this->image_size_str,
359                                         );
360         }
361
362         // --------------------------------------------------------------------
363
364         /**
365          * Set Upload Path
366          *
367          * @param       string
368          * @return      void
369          */
370         public function set_upload_path($path)
371         {
372                 // Make sure it has a trailing slash
373                 $this->upload_path = rtrim($path, '/').'/';
374         }
375
376         // --------------------------------------------------------------------
377
378         /**
379          * Set the file name
380          *
381          * This function takes a filename/path as input and looks for the
382          * existence of a file with the same name. If found, it will append a
383          * number to the end of the filename to avoid overwriting a pre-existing file.
384          *
385          * @param       string
386          * @param       string
387          * @return      string
388          */
389         public function set_filename($path, $filename)
390         {
391                 if ($this->encrypt_name == TRUE)
392                 {
393                         mt_srand();
394                         $filename = md5(uniqid(mt_rand())).$this->file_ext;
395                 }
396
397                 if ( ! file_exists($path.$filename))
398                 {
399                         return $filename;
400                 }
401
402                 $filename = str_replace($this->file_ext, '', $filename);
403
404                 $new_filename = '';
405                 for ($i = 1; $i < 100; $i++)
406                 {
407                         if ( ! file_exists($path.$filename.$i.$this->file_ext))
408                         {
409                                 $new_filename = $filename.$i.$this->file_ext;
410                                 break;
411                         }
412                 }
413
414                 if ($new_filename == '')
415                 {
416                         $this->set_error('upload_bad_filename');
417                         return FALSE;
418                 }
419                 else
420                 {
421                         return $new_filename;
422                 }
423         }
424
425         // --------------------------------------------------------------------
426
427         /**
428          * Set Maximum File Size
429          *
430          * @param       integer
431          * @return      void
432          */
433         public function set_max_filesize($n)
434         {
435                 $this->max_size = ((int) $n < 0) ? 0: (int) $n;
436         }
437
438         // --------------------------------------------------------------------
439
440         /**
441          * Set Maximum File Name Length
442          *
443          * @param       integer
444          * @return      void
445          */
446         public function set_max_filename($n)
447         {
448                 $this->max_filename = ((int) $n < 0) ? 0: (int) $n;
449         }
450
451         // --------------------------------------------------------------------
452
453         /**
454          * Set Maximum Image Width
455          *
456          * @param       integer
457          * @return      void
458          */
459         public function set_max_width($n)
460         {
461                 $this->max_width = ((int) $n < 0) ? 0: (int) $n;
462         }
463
464         // --------------------------------------------------------------------
465
466         /**
467          * Set Maximum Image Height
468          *
469          * @param       integer
470          * @return      void
471          */
472         public function set_max_height($n)
473         {
474                 $this->max_height = ((int) $n < 0) ? 0: (int) $n;
475         }
476
477         // --------------------------------------------------------------------
478
479         /**
480          * Set Allowed File Types
481          *
482          * @param       string
483          * @return      void
484          */
485         public function set_allowed_types($types)
486         {
487                 if ( ! is_array($types) && $types == '*')
488                 {
489                         $this->allowed_types = '*';
490                         return;
491                 }
492                 $this->allowed_types = explode('|', $types);
493         }
494
495         // --------------------------------------------------------------------
496
497         /**
498          * Set Image Properties
499          *
500          * Uses GD to determine the width/height/type of image
501          *
502          * @param       string
503          * @return      void
504          */
505         public function set_image_properties($path = '')
506         {
507                 if ( ! $this->is_image())
508                 {
509                         return;
510                 }
511
512                 if (function_exists('getimagesize'))
513                 {
514                         if (FALSE !== ($D = @getimagesize($path)))
515                         {
516                                 $types = array(1 => 'gif', 2 => 'jpeg', 3 => 'png');
517
518                                 $this->image_width              = $D['0'];
519                                 $this->image_height             = $D['1'];
520                                 $this->image_type               = ( ! isset($types[$D['2']])) ? 'unknown' : $types[$D['2']];
521                                 $this->image_size_str   = $D['3'];  // string containing height and width
522                         }
523                 }
524         }
525
526         // --------------------------------------------------------------------
527
528         /**
529          * Set XSS Clean
530          *
531          * Enables the XSS flag so that the file that was uploaded
532          * will be run through the XSS filter.
533          *
534          * @param       bool
535          * @return      void
536          */
537         public function set_xss_clean($flag = FALSE)
538         {
539                 $this->xss_clean = ($flag == TRUE) ? TRUE : FALSE;
540         }
541
542         // --------------------------------------------------------------------
543
544         /**
545          * Validate the image
546          *
547          * @return      bool
548          */
549         public function is_image()
550         {
551                 // IE will sometimes return odd mime-types during upload, so here we just standardize all
552                 // jpegs or pngs to the same file type.
553
554                 $png_mimes  = array('image/x-png');
555                 $jpeg_mimes = array('image/jpg', 'image/jpe', 'image/jpeg', 'image/pjpeg');
556
557                 if (in_array($this->file_type, $png_mimes))
558                 {
559                         $this->file_type = 'image/png';
560                 }
561
562                 if (in_array($this->file_type, $jpeg_mimes))
563                 {
564                         $this->file_type = 'image/jpeg';
565                 }
566
567                 $img_mimes = array(
568                                                         'image/gif',
569                                                         'image/jpeg',
570                                                         'image/png',
571                                                 );
572
573                 return (in_array($this->file_type, $img_mimes, TRUE)) ? TRUE : FALSE;
574         }
575
576         // --------------------------------------------------------------------
577
578         /**
579          * Verify that the filetype is allowed
580          *
581          * @return      bool
582          */
583         public function is_allowed_filetype($ignore_mime = FALSE)
584         {
585                 if ($this->allowed_types == '*')
586                 {
587                         return TRUE;
588                 }
589
590                 if (count($this->allowed_types) == 0 OR ! is_array($this->allowed_types))
591                 {
592                         $this->set_error('upload_no_file_types');
593                         return FALSE;
594                 }
595
596                 $ext = strtolower(ltrim($this->file_ext, '.'));
597
598                 if ( ! in_array($ext, $this->allowed_types))
599                 {
600                         return FALSE;
601                 }
602
603                 // Images get some additional checks
604                 $image_types = array('gif', 'jpg', 'jpeg', 'png', 'jpe');
605
606                 if (in_array($ext, $image_types))
607                 {
608                         if (getimagesize($this->file_temp) === FALSE)
609                         {
610                                 return FALSE;
611                         }
612                 }
613
614                 if ($ignore_mime === TRUE)
615                 {
616                         return TRUE;
617                 }
618
619                 $mime = $this->mimes_types($ext);
620
621                 if (is_array($mime))
622                 {
623                         if (in_array($this->file_type, $mime, TRUE))
624                         {
625                                 return TRUE;
626                         }
627                 }
628                 elseif ($mime == $this->file_type)
629                 {
630                                 return TRUE;
631                 }
632
633                 return FALSE;
634         }
635
636         // --------------------------------------------------------------------
637
638         /**
639          * Verify that the file is within the allowed size
640          *
641          * @return      bool
642          */
643         public function is_allowed_filesize()
644         {
645                 if ($this->max_size != 0  AND  $this->file_size > $this->max_size)
646                 {
647                         return FALSE;
648                 }
649                 else
650                 {
651                         return TRUE;
652                 }
653         }
654
655         // --------------------------------------------------------------------
656
657         /**
658          * Verify that the image is within the allowed width/height
659          *
660          * @return      bool
661          */
662         public function is_allowed_dimensions()
663         {
664                 if ( ! $this->is_image())
665                 {
666                         return TRUE;
667                 }
668
669                 if (function_exists('getimagesize'))
670                 {
671                         $D = @getimagesize($this->file_temp);
672
673                         if ($this->max_width > 0 AND $D['0'] > $this->max_width)
674                         {
675                                 return FALSE;
676                         }
677
678                         if ($this->max_height > 0 AND $D['1'] > $this->max_height)
679                         {
680                                 return FALSE;
681                         }
682
683                         return TRUE;
684                 }
685
686                 return TRUE;
687         }
688
689         // --------------------------------------------------------------------
690
691         /**
692          * Validate Upload Path
693          *
694          * Verifies that it is a valid upload path with proper permissions.
695          *
696          *
697          * @return      bool
698          */
699         public function validate_upload_path()
700         {
701                 if ($this->upload_path == '')
702                 {
703                         $this->set_error('upload_no_filepath');
704                         return FALSE;
705                 }
706
707                 if (function_exists('realpath') AND @realpath($this->upload_path) !== FALSE)
708                 {
709                         $this->upload_path = str_replace("\\", "/", realpath($this->upload_path));
710                 }
711
712                 if ( ! @is_dir($this->upload_path))
713                 {
714                         $this->set_error('upload_no_filepath');
715                         return FALSE;
716                 }
717
718                 if ( ! is_really_writable($this->upload_path))
719                 {
720                         $this->set_error('upload_not_writable');
721                         return FALSE;
722                 }
723
724                 $this->upload_path = preg_replace("/(.+?)\/*$/", "\\1/",  $this->upload_path);
725                 return TRUE;
726         }
727
728         // --------------------------------------------------------------------
729
730         /**
731          * Extract the file extension
732          *
733          * @param       string
734          * @return      string
735          */
736         public function get_extension($filename)
737         {
738                 $x = explode('.', $filename);
739                 return '.'.end($x);
740         }
741
742         // --------------------------------------------------------------------
743
744         /**
745          * Clean the file name for security
746          *
747          * @param       string
748          * @return      string
749          */
750         public function clean_file_name($filename)
751         {
752                 $bad = array(
753                                                 "<!--",
754                                                 "-->",
755                                                 "'",
756                                                 "<",
757                                                 ">",
758                                                 '"',
759                                                 '&',
760                                                 '$',
761                                                 '=',
762                                                 ';',
763                                                 '?',
764                                                 '/',
765                                                 "%20",
766                                                 "%22",
767                                                 "%3c",          // <
768                                                 "%253c",        // <
769                                                 "%3e",          // >
770                                                 "%0e",          // >
771                                                 "%28",          // (
772                                                 "%29",          // )
773                                                 "%2528",        // (
774                                                 "%26",          // &
775                                                 "%24",          // $
776                                                 "%3f",          // ?
777                                                 "%3b",          // ;
778                                                 "%3d"           // =
779                                         );
780
781                 $filename = str_replace($bad, '', $filename);
782
783                 return stripslashes($filename);
784         }
785
786         // --------------------------------------------------------------------
787
788         /**
789          * Limit the File Name Length
790          *
791          * @param       string
792          * @return      string
793          */
794         public function limit_filename_length($filename, $length)
795         {
796                 if (strlen($filename) < $length)
797                 {
798                         return $filename;
799                 }
800
801                 $ext = '';
802                 if (strpos($filename, '.') !== FALSE)
803                 {
804                         $parts          = explode('.', $filename);
805                         $ext            = '.'.array_pop($parts);
806                         $filename       = implode('.', $parts);
807                 }
808
809                 return substr($filename, 0, ($length - strlen($ext))).$ext;
810         }
811
812         // --------------------------------------------------------------------
813
814         /**
815          * Runs the file through the XSS clean function
816          *
817          * This prevents people from embedding malicious code in their files.
818          * I'm not sure that it won't negatively affect certain files in unexpected ways,
819          * but so far I haven't found that it causes trouble.
820          *
821          * @return      void
822          */
823         public function do_xss_clean()
824         {
825                 $file = $this->file_temp;
826
827                 if (filesize($file) == 0)
828                 {
829                         return FALSE;
830                 }
831
832                 if (function_exists('memory_get_usage') && memory_get_usage() && ini_get('memory_limit') != '')
833                 {
834                         $current = ini_get('memory_limit') * 1024 * 1024;
835
836                         // There was a bug/behavioural change in PHP 5.2, where numbers over one million get output
837                         // into scientific notation.  number_format() ensures this number is an integer
838                         // http://bugs.php.net/bug.php?id=43053
839
840                         $new_memory = number_format(ceil(filesize($file) + $current), 0, '.', '');
841
842                         ini_set('memory_limit', $new_memory); // When an integer is used, the value is measured in bytes. - PHP.net
843                 }
844
845                 // If the file being uploaded is an image, then we should have no problem with XSS attacks (in theory), but
846                 // IE can be fooled into mime-type detecting a malformed image as an html file, thus executing an XSS attack on anyone
847                 // using IE who looks at the image.  It does this by inspecting the first 255 bytes of an image.  To get around this
848                 // CI will itself look at the first 255 bytes of an image to determine its relative safety.  This can save a lot of
849                 // processor power and time if it is actually a clean image, as it will be in nearly all instances _except_ an
850                 // attempted XSS attack.
851
852                 if (function_exists('getimagesize') && @getimagesize($file) !== FALSE)
853                 {
854                         if (($file = @fopen($file, 'rb')) === FALSE) // "b" to force binary
855                         {
856                                 return FALSE; // Couldn't open the file, return FALSE
857                         }
858
859                         $opening_bytes = fread($file, 256);
860                         fclose($file);
861
862                         // These are known to throw IE into mime-type detection chaos
863                         // <a, <body, <head, <html, <img, <plaintext, <pre, <script, <table, <title
864                         // title is basically just in SVG, but we filter it anyhow
865
866                         if ( ! preg_match('/<(a|body|head|html|img|plaintext|pre|script|table|title)[\s>]/i', $opening_bytes))
867                         {
868                                 return TRUE; // its an image, no "triggers" detected in the first 256 bytes, we're good
869                         }
870                 }
871
872                 if (($data = @file_get_contents($file)) === FALSE)
873                 {
874                         return FALSE;
875                 }
876
877                 $CI =& get_instance();
878                 return $CI->security->xss_clean($data, TRUE);
879         }
880
881         // --------------------------------------------------------------------
882
883         /**
884          * Set an error message
885          *
886          * @param       string
887          * @return      void
888          */
889         public function set_error($msg)
890         {
891                 $CI =& get_instance();
892                 $CI->lang->load('upload');
893
894                 if (is_array($msg))
895                 {
896                         foreach ($msg as $val)
897                         {
898                                 $msg = ($CI->lang->line($val) == FALSE) ? $val : $CI->lang->line($val);
899                                 $this->error_msg[] = $msg;
900                                 log_message('error', $msg);
901                         }
902                 }
903                 else
904                 {
905                         $msg = ($CI->lang->line($msg) == FALSE) ? $msg : $CI->lang->line($msg);
906                         $this->error_msg[] = $msg;
907                         log_message('error', $msg);
908                 }
909         }
910
911         // --------------------------------------------------------------------
912
913         /**
914          * Display the error message
915          *
916          * @param       string
917          * @param       string
918          * @return      string
919          */
920         public function display_errors($open = '<p>', $close = '</p>')
921         {
922                 $str = '';
923                 foreach ($this->error_msg as $val)
924                 {
925                         $str .= $open.$val.$close;
926                 }
927
928                 return $str;
929         }
930
931         // --------------------------------------------------------------------
932
933         /**
934          * List of Mime Types
935          *
936          * This is a list of mime types.  We use it to validate
937          * the "allowed types" set by the developer
938          *
939          * @param       string
940          * @return      string
941          */
942         public function mimes_types($mime)
943         {
944                 global $mimes;
945
946                 if (count($this->mimes) == 0)
947                 {
948                         if (defined('ENVIRONMENT') AND is_file(APPPATH.'config/'.ENVIRONMENT.'/mimes'.EXT))
949                         {
950                                 include(APPPATH.'config/'.ENVIRONMENT.'/mimes'.EXT);
951                         }
952                         elseif (is_file(APPPATH.'config/mimes'.EXT))
953                         {
954                                 include(APPPATH.'config//mimes'.EXT);
955                         }
956                         else
957                         {
958                                 return FALSE;
959                         }
960
961                         $this->mimes = $mimes;
962                         unset($mimes);
963                 }
964
965                 return ( ! isset($this->mimes[$mime])) ? FALSE : $this->mimes[$mime];
966         }
967
968         // --------------------------------------------------------------------
969
970         /**
971          * Prep Filename
972          *
973          * Prevents possible script execution from Apache's handling of files multiple extensions
974          * http://httpd.apache.org/docs/1.3/mod/mod_mime.html#multipleext
975          *
976          * @param       string
977          * @return      string
978          */
979         protected function _prep_filename($filename)
980         {
981                 if (strpos($filename, '.') === FALSE OR $this->allowed_types == '*')
982                 {
983                         return $filename;
984                 }
985
986                 $parts          = explode('.', $filename);
987                 $ext            = array_pop($parts);
988                 $filename       = array_shift($parts);
989
990                 foreach ($parts as $part)
991                 {
992                         if ( ! in_array(strtolower($part), $this->allowed_types) OR $this->mimes_types(strtolower($part)) === FALSE)
993                         {
994                                 $filename .= '.'.$part.'_';
995                         }
996                         else
997                         {
998                                 $filename .= '.'.$part;
999                         }
1000                 }
1001
1002                 $filename .= '.'.$ext;
1003
1004                 return $filename;
1005         }
1006
1007         // --------------------------------------------------------------------
1008
1009 }
1010 // END Upload Class
1011
1012 /* End of file Upload.php */
1013 /* Location: ./system/libraries/Upload.php */