/lenasys/trunk

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/lenasys/trunk

« back to all changes in this revision

Viewing changes to codeigniter/system/libraries/Upload.php

  • Committer: galaxyAbstractor
  • Date: 2013-04-10 15:49:32 UTC
  • mto: (19.1.5 lenasys)
  • mto: This revision was merged to the branch mainline in revision 23.
  • Revision ID: galaxyabstractor@gmail.com-20130410154932-4vizlzk0ar5gykvi
* Added an simple admin panel to the codeviewer-cmssy stuff
* Redesigned a bit like the mockups - still stuff to come
* Implemented the codeviewer + admin panel again using the Framework CodeIgniter instead 

Show diffs side-by-side

added added

removed removed

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