/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: gustav.hartvigsson at gmail
  • Date: 2013-04-03 11:52:56 UTC
  • Revision ID: gustav.hartvigsson@gmail.com-20130403115256-sz6zermzoom4lifc
Ignored .DS_Store files.

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 */