Completed
Push — master ( 9113ef...548441 )
by Kenji
15s queued 11s
created

CI_Upload::do_upload()   F

Complexity

Conditions 34
Paths 2112

Size

Total Lines 211

Duplication

Lines 211
Ratio 100 %

Importance

Changes 0
Metric Value
cc 34
nc 2112
nop 1
dl 211
loc 211
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * CodeIgniter
4
 *
5
 * An open source application development framework for PHP
6
 *
7
 * This content is released under the MIT License (MIT)
8
 *
9
 * Copyright (c) 2014 - 2016, British Columbia Institute of Technology
10
 *
11
 * Permission is hereby granted, free of charge, to any person obtaining a copy
12
 * of this software and associated documentation files (the "Software"), to deal
13
 * in the Software without restriction, including without limitation the rights
14
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
 * copies of the Software, and to permit persons to whom the Software is
16
 * furnished to do so, subject to the following conditions:
17
 *
18
 * The above copyright notice and this permission notice shall be included in
19
 * all copies or substantial portions of the Software.
20
 *
21
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27
 * THE SOFTWARE.
28
 *
29
 * @package	CodeIgniter
30
 * @author	EllisLab Dev Team
31
 * @copyright	Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
32
 * @copyright	Copyright (c) 2014 - 2016, British Columbia Institute of Technology (http://bcit.ca/)
33
 * @license	http://opensource.org/licenses/MIT	MIT License
34
 * @link	https://codeigniter.com
35
 * @since	Version 1.0.0
36
 * @filesource
37
 */
38
defined('BASEPATH') OR exit('No direct script access allowed');
39
40
/**
41
 * File Uploading Class (Modified by ci-phpunit-test)
42
 *
43
 * @package		CodeIgniter
44
 * @subpackage	Libraries
45
 * @category	Uploads
46
 * @author		EllisLab Dev Team
47
 * @link		https://codeigniter.com/user_guide/libraries/file_uploading.html
48
 */
49 View Code Duplication
class CI_Upload {
0 ignored issues
show
Duplication introduced by
This class seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
50
51
	/**
52
	 * Maximum file size
53
	 *
54
	 * @var	int
55
	 */
56
	public $max_size = 0;
57
58
	/**
59
	 * Maximum image width
60
	 *
61
	 * @var	int
62
	 */
63
	public $max_width = 0;
64
65
	/**
66
	 * Maximum image height
67
	 *
68
	 * @var	int
69
	 */
70
	public $max_height = 0;
71
72
	/**
73
	 * Minimum image width
74
	 *
75
	 * @var	int
76
	 */
77
	public $min_width = 0;
78
79
	/**
80
	 * Minimum image height
81
	 *
82
	 * @var	int
83
	 */
84
	public $min_height = 0;
85
86
	/**
87
	 * Maximum filename length
88
	 *
89
	 * @var	int
90
	 */
91
	public $max_filename = 0;
92
93
	/**
94
	 * Maximum duplicate filename increment ID
95
	 *
96
	 * @var	int
97
	 */
98
	public $max_filename_increment = 100;
99
100
	/**
101
	 * Allowed file types
102
	 *
103
	 * @var	string
104
	 */
105
	public $allowed_types = '';
106
107
	/**
108
	 * Temporary filename
109
	 *
110
	 * @var	string
111
	 */
112
	public $file_temp = '';
113
114
	/**
115
	 * Filename
116
	 *
117
	 * @var	string
118
	 */
119
	public $file_name = '';
120
121
	/**
122
	 * Original filename
123
	 *
124
	 * @var	string
125
	 */
126
	public $orig_name = '';
127
128
	/**
129
	 * File type
130
	 *
131
	 * @var	string
132
	 */
133
	public $file_type = '';
134
135
	/**
136
	 * File size
137
	 *
138
	 * @var	int
139
	 */
140
	public $file_size = NULL;
141
142
	/**
143
	 * Filename extension
144
	 *
145
	 * @var	string
146
	 */
147
	public $file_ext = '';
148
149
	/**
150
	 * Force filename extension to lowercase
151
	 *
152
	 * @var	string
153
	 */
154
	public $file_ext_tolower = FALSE;
155
156
	/**
157
	 * Upload path
158
	 *
159
	 * @var	string
160
	 */
161
	public $upload_path = '';
162
163
	/**
164
	 * Overwrite flag
165
	 *
166
	 * @var	bool
167
	 */
168
	public $overwrite = FALSE;
169
170
	/**
171
	 * Obfuscate filename flag
172
	 *
173
	 * @var	bool
174
	 */
175
	public $encrypt_name = FALSE;
176
177
	/**
178
	 * Is image flag
179
	 *
180
	 * @var	bool
181
	 */
182
	public $is_image = FALSE;
183
184
	/**
185
	 * Image width
186
	 *
187
	 * @var	int
188
	 */
189
	public $image_width = NULL;
190
191
	/**
192
	 * Image height
193
	 *
194
	 * @var	int
195
	 */
196
	public $image_height = NULL;
197
198
	/**
199
	 * Image type
200
	 *
201
	 * @var	string
202
	 */
203
	public $image_type = '';
204
205
	/**
206
	 * Image size string
207
	 *
208
	 * @var	string
209
	 */
210
	public $image_size_str = '';
211
212
	/**
213
	 * Error messages list
214
	 *
215
	 * @var	array
216
	 */
217
	public $error_msg = array();
218
219
	/**
220
	 * Remove spaces flag
221
	 *
222
	 * @var	bool
223
	 */
224
	public $remove_spaces = TRUE;
225
226
	/**
227
	 * MIME detection flag
228
	 *
229
	 * @var	bool
230
	 */
231
	public $detect_mime = TRUE;
232
233
	/**
234
	 * XSS filter flag
235
	 *
236
	 * @var	bool
237
	 */
238
	public $xss_clean = FALSE;
239
240
	/**
241
	 * Apache mod_mime fix flag
242
	 *
243
	 * @var	bool
244
	 */
245
	public $mod_mime_fix = TRUE;
246
247
	/**
248
	 * Temporary filename prefix
249
	 *
250
	 * @var	string
251
	 */
252
	public $temp_prefix = 'temp_file_';
253
254
	/**
255
	 * Filename sent by the client
256
	 *
257
	 * @var	bool
258
	 */
259
	public $client_name = '';
260
261
	// --------------------------------------------------------------------
262
263
	/**
264
	 * Filename override
265
	 *
266
	 * @var	string
267
	 */
268
	protected $_file_name_override = '';
269
270
	/**
271
	 * MIME types list
272
	 *
273
	 * @var	array
274
	 */
275
	protected $_mimes = array();
276
277
	/**
278
	 * CI Singleton
279
	 *
280
	 * @var	object
281
	 */
282
	protected $_CI;
283
284
	// --------------------------------------------------------------------
285
286
	/**
287
	 * Constructor
288
	 *
289
	 * @param	array	$config
290
	 * @return	void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
291
	 *
292
	 * @codeCoverageIgnore
293
	 */
294
	public function __construct($config = array())
295
	{
296
		empty($config) OR $this->initialize($config, FALSE);
297
298
		$this->_mimes =& get_mimes();
299
		$this->_CI =& get_instance();
300
301
		log_message('info', 'Upload Class Initialized');
302
	}
303
304
	// --------------------------------------------------------------------
305
306
	/**
307
	 * Initialize preferences
308
	 *
309
	 * @param	array	$config
310
	 * @param	bool	$reset
311
	 * @return	CI_Upload
312
	 *
313
	 * @codeCoverageIgnore
314
	 */
315
	public function initialize(array $config = array(), $reset = TRUE)
316
	{
317
		$reflection = new ReflectionClass($this);
318
319
		if ($reset === TRUE)
320
		{
321
			$defaults = $reflection->getDefaultProperties();
322
			foreach (array_keys($defaults) as $key)
323
			{
324
				if ($key[0] === '_')
325
				{
326
					continue;
327
				}
328
329
				if (isset($config[$key]))
330
				{
331
					if ($reflection->hasMethod('set_'.$key))
332
					{
333
						$this->{'set_'.$key}($config[$key]);
334
					}
335
					else
336
					{
337
						$this->$key = $config[$key];
338
					}
339
				}
340
				else
341
				{
342
					$this->$key = $defaults[$key];
343
				}
344
			}
345
		}
346
		else
347
		{
348
			foreach ($config as $key => &$value)
349
			{
350
				if ($key[0] !== '_' && $reflection->hasProperty($key))
351
				{
352
					if ($reflection->hasMethod('set_'.$key))
353
					{
354
						$this->{'set_'.$key}($value);
355
					}
356
					else
357
					{
358
						$this->$key = $value;
359
					}
360
				}
361
			}
362
		}
363
364
		// if a file_name was provided in the config, use it instead of the user input
365
		// supplied file name for all uploads until initialized again
366
		$this->_file_name_override = $this->file_name;
367
		return $this;
368
	}
369
370
	// --------------------------------------------------------------------
371
372
	/**
373
	 * Perform the file upload
374
	 *
375
	 * @param	string	$field
376
	 * @return	bool
377
	 *
378
	 * modified by ci-phpunit-test
379
	 */
380
	public function do_upload($field = 'userfile')
381
	{
382
		// Is $_FILES[$field] set? If not, no reason to continue.
383
		if (isset($_FILES[$field]))
384
		{
385
			$_file = $_FILES[$field];
386
		}
387
		// Does the field name contain array notation?
388
		elseif (($c = preg_match_all('/(?:^[^\[]+)|\[[^]]*\]/', $field, $matches)) > 1)
389
		{
390
			$_file = $_FILES;
391
			for ($i = 0; $i < $c; $i++)
392
			{
393
				// We can't track numeric iterations, only full field names are accepted
394
				if (($field = trim($matches[0][$i], '[]')) === '' OR ! isset($_file[$field]))
395
				{
396
					$_file = NULL;
397
					break;
398
				}
399
400
				$_file = $_file[$field];
401
			}
402
		}
403
404
		if ( ! isset($_file))
405
		{
406
			$this->set_error('upload_no_file_selected', 'debug');
407
			return FALSE;
408
		}
409
410
		// Is the upload path valid?
411
		if ( ! $this->validate_upload_path())
412
		{
413
			// errors will already be set by validate_upload_path() so just return FALSE
414
			return FALSE;
415
		}
416
417
		// Was the file able to be uploaded? If not, determine the reason why.
418
		if ( ! file_exists($_file['tmp_name']))	// modified by ci-phpunit-test
419
		{
420
			$error = isset($_file['error']) ? $_file['error'] : 4;
421
422
			switch ($error)
423
			{
424
				case UPLOAD_ERR_INI_SIZE:
425
					$this->set_error('upload_file_exceeds_limit', 'info');
426
					break;
427
				case UPLOAD_ERR_FORM_SIZE:
428
					$this->set_error('upload_file_exceeds_form_limit', 'info');
429
					break;
430
				case UPLOAD_ERR_PARTIAL:
431
					$this->set_error('upload_file_partial', 'debug');
432
					break;
433
				case UPLOAD_ERR_NO_FILE:
434
					$this->set_error('upload_no_file_selected', 'debug');
435
					break;
436
				case UPLOAD_ERR_NO_TMP_DIR:
437
					$this->set_error('upload_no_temp_directory', 'error');
438
					break;
439
				case UPLOAD_ERR_CANT_WRITE:
440
					$this->set_error('upload_unable_to_write_file', 'error');
441
					break;
442
				case UPLOAD_ERR_EXTENSION:
443
					$this->set_error('upload_stopped_by_extension', 'debug');
444
					break;
445
				default:
446
					$this->set_error('upload_no_file_selected', 'debug');
447
					break;
448
			}
449
450
			return FALSE;
451
		}
452
453
		// Set the uploaded data as class variables
454
		$this->file_temp = $_file['tmp_name'];
455
		$this->file_size = $_file['size'];
456
457
		// Skip MIME type detection?
458
		if ($this->detect_mime !== FALSE)
459
		{
460
			$this->_file_mime_type($_file);
461
		}
462
463
		$this->file_type = preg_replace('/^(.+?);.*$/', '\\1', $this->file_type);
464
		$this->file_type = strtolower(trim(stripslashes($this->file_type), '"'));
465
		$this->file_name = $this->_prep_filename($_file['name']);
466
		$this->file_ext	 = $this->get_extension($this->file_name);
467
		$this->client_name = $this->file_name;
0 ignored issues
show
Documentation Bug introduced by
The property $client_name was declared of type boolean, but $this->file_name is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
468
469
		// Is the file type allowed to be uploaded?
470
		if ( ! $this->is_allowed_filetype())
471
		{
472
			$this->set_error('upload_invalid_filetype', 'debug');
473
			return FALSE;
474
		}
475
476
		// if we're overriding, let's now make sure the new name and type is allowed
477
		if ($this->_file_name_override !== '')
478
		{
479
			$this->file_name = $this->_prep_filename($this->_file_name_override);
480
481
			// If no extension was provided in the file_name config item, use the uploaded one
482
			if (strpos($this->_file_name_override, '.') === FALSE)
483
			{
484
				$this->file_name .= $this->file_ext;
485
			}
486
			else
487
			{
488
				// An extension was provided, let's have it!
489
				$this->file_ext	= $this->get_extension($this->_file_name_override);
490
			}
491
492
			if ( ! $this->is_allowed_filetype(TRUE))
493
			{
494
				$this->set_error('upload_invalid_filetype', 'debug');
495
				return FALSE;
496
			}
497
		}
498
499
		// Convert the file size to kilobytes
500
		if ($this->file_size > 0)
501
		{
502
			$this->file_size = round($this->file_size/1024, 2);
0 ignored issues
show
Documentation Bug introduced by
The property $file_size was declared of type integer, but round($this->file_size / 1024, 2) is of type double. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
503
		}
504
505
		// Is the file size within the allowed maximum?
506
		if ( ! $this->is_allowed_filesize())
507
		{
508
			$this->set_error('upload_invalid_filesize', 'info');
509
			return FALSE;
510
		}
511
512
		// Are the image dimensions within the allowed size?
513
		// Note: This can fail if the server has an open_basedir restriction.
514
		if ( ! $this->is_allowed_dimensions())
515
		{
516
			$this->set_error('upload_invalid_dimensions', 'info');
517
			return FALSE;
518
		}
519
520
		// Sanitize the file name for security
521
		$this->file_name = $this->_CI->security->sanitize_filename($this->file_name);
522
523
		// Truncate the file name if it's too long
524
		if ($this->max_filename > 0)
525
		{
526
			$this->file_name = $this->limit_filename_length($this->file_name, $this->max_filename);
527
		}
528
529
		// Remove white spaces in the name
530
		if ($this->remove_spaces === TRUE)
531
		{
532
			$this->file_name = preg_replace('/\s+/', '_', $this->file_name);
533
		}
534
535
		if ($this->file_ext_tolower && ($ext_length = strlen($this->file_ext)))
536
		{
537
			// file_ext was previously lower-cased by a get_extension() call
538
			$this->file_name = substr($this->file_name, 0, -$ext_length).$this->file_ext;
539
		}
540
541
		/*
542
		 * Validate the file name
543
		 * This function appends an number onto the end of
544
		 * the file if one with the same name already exists.
545
		 * If it returns false there was a problem.
546
		 */
547
		$this->orig_name = $this->file_name;
548
		if (FALSE === ($this->file_name = $this->set_filename($this->upload_path, $this->file_name)))
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->set_filename($thi...path, $this->file_name) can also be of type false. However, the property $file_name is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
549
		{
550
			return FALSE;
551
		}
552
553
		/*
554
		 * Run the file through the XSS hacking filter
555
		 * This helps prevent malicious code from being
556
		 * embedded within a file. Scripts can easily
557
		 * be disguised as images or other file types.
558
		 */
559
		if ($this->xss_clean && $this->do_xss_clean() === FALSE)
560
		{
561
			$this->set_error('upload_unable_to_write_file', 'error');
562
			return FALSE;
563
		}
564
565
		/*
566
		 * Move the file to the final destination
567
		 * To deal with different server configurations
568
		 * we'll attempt to use copy() first. If that fails
569
		 * we'll use move_uploaded_file(). One of the two should
570
		 * reliably work in most environments
571
		 */
572
		if ( ! @copy($this->file_temp, $this->upload_path.$this->file_name))
573
		{
574
			if ( ! @move_uploaded_file($this->file_temp, $this->upload_path.$this->file_name))
575
			{
576
				$this->set_error('upload_destination_error', 'error');
577
				return FALSE;
578
			}
579
		}
580
581
		/*
582
		 * Set the finalized image dimensions
583
		 * This sets the image width/height (assuming the
584
		 * file was an image). We use this information
585
		 * in the "data" function.
586
		 */
587
		$this->set_image_properties($this->upload_path.$this->file_name);
588
589
		return TRUE;
590
	}
591
592
	// --------------------------------------------------------------------
593
594
	/**
595
	 * Finalized Data Array
596
	 *
597
	 * Returns an associative array containing all of the information
598
	 * related to the upload, allowing the developer easy access in one array.
599
	 *
600
	 * @param	string	$index
601
	 * @return	mixed
602
	 *
603
	 * @codeCoverageIgnore
604
	 */
605
	public function data($index = NULL)
606
	{
607
		$data = array(
608
				'file_name'		=> $this->file_name,
609
				'file_type'		=> $this->file_type,
610
				'file_path'		=> $this->upload_path,
611
				'full_path'		=> $this->upload_path.$this->file_name,
612
				'raw_name'		=> substr($this->file_name, 0, -strlen($this->file_ext)),
613
				'orig_name'		=> $this->orig_name,
614
				'client_name'		=> $this->client_name,
615
				'file_ext'		=> $this->file_ext,
616
				'file_size'		=> $this->file_size,
617
				'is_image'		=> $this->is_image(),
618
				'image_width'		=> $this->image_width,
619
				'image_height'		=> $this->image_height,
620
				'image_type'		=> $this->image_type,
621
				'image_size_str'	=> $this->image_size_str,
622
			);
623
624
		if ( ! empty($index))
625
		{
626
			return isset($data[$index]) ? $data[$index] : NULL;
627
		}
628
629
		return $data;
630
	}
631
632
	// --------------------------------------------------------------------
633
634
	/**
635
	 * Set Upload Path
636
	 *
637
	 * @param	string	$path
638
	 * @return	CI_Upload
639
	 */
640
	public function set_upload_path($path)
641
	{
642
		// Make sure it has a trailing slash
643
		$this->upload_path = rtrim($path, '/').'/';
644
		return $this;
645
	}
646
647
	// --------------------------------------------------------------------
648
649
	/**
650
	 * Set the file name
651
	 *
652
	 * This function takes a filename/path as input and looks for the
653
	 * existence of a file with the same name. If found, it will append a
654
	 * number to the end of the filename to avoid overwriting a pre-existing file.
655
	 *
656
	 * @param	string	$path
657
	 * @param	string	$filename
658
	 * @return	string
659
	 *
660
	 * @codeCoverageIgnore
661
	 */
662
	public function set_filename($path, $filename)
663
	{
664
		if ($this->encrypt_name === TRUE)
665
		{
666
			$filename = md5(uniqid(mt_rand())).$this->file_ext;
667
		}
668
669
		if ($this->overwrite === TRUE OR ! file_exists($path.$filename))
670
		{
671
			return $filename;
672
		}
673
674
		$filename = str_replace($this->file_ext, '', $filename);
675
676
		$new_filename = '';
677
		for ($i = 1; $i < $this->max_filename_increment; $i++)
678
		{
679
			if ( ! file_exists($path.$filename.$i.$this->file_ext))
680
			{
681
				$new_filename = $filename.$i.$this->file_ext;
682
				break;
683
			}
684
		}
685
686
		if ($new_filename === '')
687
		{
688
			$this->set_error('upload_bad_filename', 'debug');
689
			return FALSE;
690
		}
691
		else
692
		{
693
			return $new_filename;
694
		}
695
	}
696
697
	// --------------------------------------------------------------------
698
699
	/**
700
	 * Set Maximum File Size
701
	 *
702
	 * @param	int	$n
703
	 * @return	CI_Upload
704
	 */
705
	public function set_max_filesize($n)
706
	{
707
		$this->max_size = ($n < 0) ? 0 : (int) $n;
708
		return $this;
709
	}
710
711
	// --------------------------------------------------------------------
712
713
	/**
714
	 * Set Maximum File Size
715
	 *
716
	 * An internal alias to set_max_filesize() to help with configuration
717
	 * as initialize() will look for a set_<property_name>() method ...
718
	 *
719
	 * @param	int	$n
720
	 * @return	CI_Upload
721
	 */
722
	protected function set_max_size($n)
723
	{
724
		return $this->set_max_filesize($n);
725
	}
726
727
	// --------------------------------------------------------------------
728
729
	/**
730
	 * Set Maximum File Name Length
731
	 *
732
	 * @param	int	$n
733
	 * @return	CI_Upload
734
	 *
735
	 * @codeCoverageIgnore
736
	 */
737
	public function set_max_filename($n)
738
	{
739
		$this->max_filename = ($n < 0) ? 0 : (int) $n;
740
		return $this;
741
	}
742
743
	// --------------------------------------------------------------------
744
745
	/**
746
	 * Set Maximum Image Width
747
	 *
748
	 * @param	int	$n
749
	 * @return	CI_Upload
750
	 */
751
	public function set_max_width($n)
752
	{
753
		$this->max_width = ($n < 0) ? 0 : (int) $n;
754
		return $this;
755
	}
756
757
	// --------------------------------------------------------------------
758
759
	/**
760
	 * Set Maximum Image Height
761
	 *
762
	 * @param	int	$n
763
	 * @return	CI_Upload
764
	 */
765
	public function set_max_height($n)
766
	{
767
		$this->max_height = ($n < 0) ? 0 : (int) $n;
768
		return $this;
769
	}
770
771
	// --------------------------------------------------------------------
772
773
	/**
774
	 * Set minimum image width
775
	 *
776
	 * @param	int	$n
777
	 * @return	CI_Upload
778
	 *
779
	 * @codeCoverageIgnore
780
	 */
781
	public function set_min_width($n)
782
	{
783
		$this->min_width = ($n < 0) ? 0 : (int) $n;
784
		return $this;
785
	}
786
787
	// --------------------------------------------------------------------
788
789
	/**
790
	 * Set minimum image height
791
	 *
792
	 * @param	int	$n
793
	 * @return	CI_Upload
794
	 *
795
	 * @codeCoverageIgnore
796
	 */
797
	public function set_min_height($n)
798
	{
799
		$this->min_height = ($n < 0) ? 0 : (int) $n;
800
		return $this;
801
	}
802
803
	// --------------------------------------------------------------------
804
805
	/**
806
	 * Set Allowed File Types
807
	 *
808
	 * @param	mixed	$types
809
	 * @return	CI_Upload
810
	 */
811
	public function set_allowed_types($types)
812
	{
813
		$this->allowed_types = (is_array($types) OR $types === '*')
0 ignored issues
show
Documentation Bug introduced by
It seems like (is_array($types) or $ty... : explode('|', $types) can also be of type array. However, the property $allowed_types is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
814
			? $types
815
			: explode('|', $types);
816
		return $this;
817
	}
818
819
	// --------------------------------------------------------------------
820
821
	/**
822
	 * Set Image Properties
823
	 *
824
	 * Uses GD to determine the width/height/type of image
825
	 *
826
	 * @param	string	$path
827
	 * @return	CI_Upload
828
	 */
829
	public function set_image_properties($path = '')
830
	{
831
		if ($this->is_image() && function_exists('getimagesize'))
832
		{
833
			if (FALSE !== ($D = @getimagesize($path)))
834
			{
835
				$types = array(1 => 'gif', 2 => 'jpeg', 3 => 'png');
836
837
				$this->image_width	= $D[0];
838
				$this->image_height	= $D[1];
839
				$this->image_type	= isset($types[$D[2]]) ? $types[$D[2]] : 'unknown';
840
				$this->image_size_str	= $D[3]; // string containing height and width
841
			}
842
		}
843
844
		return $this;
845
	}
846
847
	// --------------------------------------------------------------------
848
849
	/**
850
	 * Set XSS Clean
851
	 *
852
	 * Enables the XSS flag so that the file that was uploaded
853
	 * will be run through the XSS filter.
854
	 *
855
	 * @param	bool	$flag
856
	 * @return	CI_Upload
857
	 *
858
	 * @codeCoverageIgnore
859
	 */
860
	public function set_xss_clean($flag = FALSE)
861
	{
862
		$this->xss_clean = ($flag === TRUE);
863
		return $this;
864
	}
865
866
	// --------------------------------------------------------------------
867
868
	/**
869
	 * Validate the image
870
	 *
871
	 * @return	bool
872
	 *
873
	 * @codeCoverageIgnore
874
	 */
875
	public function is_image()
876
	{
877
		// IE will sometimes return odd mime-types during upload, so here we just standardize all
878
		// jpegs or pngs to the same file type.
879
880
		$png_mimes  = array('image/x-png');
881
		$jpeg_mimes = array('image/jpg', 'image/jpe', 'image/jpeg', 'image/pjpeg');
882
883
		if (in_array($this->file_type, $png_mimes))
884
		{
885
			$this->file_type = 'image/png';
886
		}
887
		elseif (in_array($this->file_type, $jpeg_mimes))
888
		{
889
			$this->file_type = 'image/jpeg';
890
		}
891
892
		$img_mimes = array('image/gif',	'image/jpeg', 'image/png');
893
894
		return in_array($this->file_type, $img_mimes, TRUE);
895
	}
896
897
	// --------------------------------------------------------------------
898
899
	/**
900
	 * Verify that the filetype is allowed
901
	 *
902
	 * @param	bool	$ignore_mime
903
	 * @return	bool
904
	 *
905
	 * @codeCoverageIgnore
906
	 */
907
	public function is_allowed_filetype($ignore_mime = FALSE)
908
	{
909
		if ($this->allowed_types === '*')
910
		{
911
			return TRUE;
912
		}
913
914
		if (empty($this->allowed_types) OR ! is_array($this->allowed_types))
915
		{
916
			$this->set_error('upload_no_file_types', 'debug');
917
			return FALSE;
918
		}
919
920
		$ext = strtolower(ltrim($this->file_ext, '.'));
921
922
		if ( ! in_array($ext, $this->allowed_types, TRUE))
923
		{
924
			return FALSE;
925
		}
926
927
		// Images get some additional checks
928
		if (in_array($ext, array('gif', 'jpg', 'jpeg', 'jpe', 'png'), TRUE) && @getimagesize($this->file_temp) === FALSE)
929
		{
930
			return FALSE;
931
		}
932
933
		if ($ignore_mime === TRUE)
934
		{
935
			return TRUE;
936
		}
937
938
		if (isset($this->_mimes[$ext]))
939
		{
940
			return is_array($this->_mimes[$ext])
941
				? in_array($this->file_type, $this->_mimes[$ext], TRUE)
942
				: ($this->_mimes[$ext] === $this->file_type);
943
		}
944
945
		return FALSE;
946
	}
947
948
	// --------------------------------------------------------------------
949
950
	/**
951
	 * Verify that the file is within the allowed size
952
	 *
953
	 * @return	bool
954
	 *
955
	 * @codeCoverageIgnore
956
	 */
957
	public function is_allowed_filesize()
958
	{
959
		return ($this->max_size === 0 OR $this->max_size > $this->file_size);
960
	}
961
962
	// --------------------------------------------------------------------
963
964
	/**
965
	 * Verify that the image is within the allowed width/height
966
	 *
967
	 * @return	bool
968
	 *
969
	 * @codeCoverageIgnore
970
	 */
971
	public function is_allowed_dimensions()
972
	{
973
		if ( ! $this->is_image())
974
		{
975
			return TRUE;
976
		}
977
978
		if (function_exists('getimagesize'))
979
		{
980
			$D = @getimagesize($this->file_temp);
981
982
			if ($this->max_width > 0 && $D[0] > $this->max_width)
983
			{
984
				return FALSE;
985
			}
986
987
			if ($this->max_height > 0 && $D[1] > $this->max_height)
988
			{
989
				return FALSE;
990
			}
991
992
			if ($this->min_width > 0 && $D[0] < $this->min_width)
993
			{
994
				return FALSE;
995
			}
996
997
			if ($this->min_height > 0 && $D[1] < $this->min_height)
998
			{
999
				return FALSE;
1000
			}
1001
		}
1002
1003
		return TRUE;
1004
	}
1005
1006
	// --------------------------------------------------------------------
1007
1008
	/**
1009
	 * Validate Upload Path
1010
	 *
1011
	 * Verifies that it is a valid upload path with proper permissions.
1012
	 *
1013
	 * @return	bool
1014
	 *
1015
	 * @codeCoverageIgnore
1016
	 */
1017
	public function validate_upload_path()
1018
	{
1019
		if ($this->upload_path === '')
1020
		{
1021
			$this->set_error('upload_no_filepath', 'error');
1022
			return FALSE;
1023
		}
1024
1025
		if (realpath($this->upload_path) !== FALSE)
1026
		{
1027
			$this->upload_path = str_replace('\\', '/', realpath($this->upload_path));
1028
		}
1029
1030
		if ( ! is_dir($this->upload_path))
1031
		{
1032
			$this->set_error('upload_no_filepath', 'error');
1033
			return FALSE;
1034
		}
1035
1036
		if ( ! is_really_writable($this->upload_path))
1037
		{
1038
			$this->set_error('upload_not_writable', 'error');
1039
			return FALSE;
1040
		}
1041
1042
		$this->upload_path = preg_replace('/(.+?)\/*$/', '\\1/',  $this->upload_path);
1043
		return TRUE;
1044
	}
1045
1046
	// --------------------------------------------------------------------
1047
1048
	/**
1049
	 * Extract the file extension
1050
	 *
1051
	 * @param	string	$filename
1052
	 * @return	string
1053
	 *
1054
	 * @codeCoverageIgnore
1055
	 */
1056
	public function get_extension($filename)
1057
	{
1058
		$x = explode('.', $filename);
1059
1060
		if (count($x) === 1)
1061
		{
1062
			return '';
1063
		}
1064
1065
		$ext = ($this->file_ext_tolower) ? strtolower(end($x)) : end($x);
1066
		return '.'.$ext;
1067
	}
1068
1069
	// --------------------------------------------------------------------
1070
1071
	/**
1072
	 * Limit the File Name Length
1073
	 *
1074
	 * @param	string	$filename
1075
	 * @param	int	$length
1076
	 * @return	string
1077
	 *
1078
	 * @codeCoverageIgnore
1079
	 */
1080
	public function limit_filename_length($filename, $length)
1081
	{
1082
		if (strlen($filename) < $length)
1083
		{
1084
			return $filename;
1085
		}
1086
1087
		$ext = '';
1088
		if (strpos($filename, '.') !== FALSE)
1089
		{
1090
			$parts		= explode('.', $filename);
1091
			$ext		= '.'.array_pop($parts);
1092
			$filename	= implode('.', $parts);
1093
		}
1094
1095
		return substr($filename, 0, ($length - strlen($ext))).$ext;
1096
	}
1097
1098
	// --------------------------------------------------------------------
1099
1100
	/**
1101
	 * Runs the file through the XSS clean function
1102
	 *
1103
	 * This prevents people from embedding malicious code in their files.
1104
	 * I'm not sure that it won't negatively affect certain files in unexpected ways,
1105
	 * but so far I haven't found that it causes trouble.
1106
	 *
1107
	 * @return	string
1108
	 *
1109
	 * @codeCoverageIgnore
1110
	 */
1111
	public function do_xss_clean()
1112
	{
1113
		$file = $this->file_temp;
1114
1115
		if (filesize($file) == 0)
0 ignored issues
show
Bug Best Practice introduced by
The return type of return FALSE; (false) is incompatible with the return type documented by CI_Upload::do_xss_clean of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
1116
		{
1117
			return FALSE;
1118
		}
1119
1120
		if (memory_get_usage() && ($memory_limit = ini_get('memory_limit')) > 0)
1121
		{
1122
			$memory_limit = str_split($memory_limit, strspn($memory_limit, '1234567890'));
1123
			if ( ! empty($memory_limit[1]))
1124
			{
1125
				switch ($memory_limit[1][0])
1126
				{
1127
					case 'g':
1128
					case 'G':
1129
						$memory_limit[0] *= 1024 * 1024 * 1024;
1130
						break;
1131
					case 'm':
1132
					case 'M':
1133
						$memory_limit[0] *= 1024 * 1024;
1134
						break;
1135
					default:
1136
						break;
1137
				}
1138
			}
1139
1140
			$memory_limit = (int) ceil(filesize($file) + $memory_limit[0]);
1141
			ini_set('memory_limit', $memory_limit); // When an integer is used, the value is measured in bytes. - PHP.net
1142
		}
1143
1144
		// If the file being uploaded is an image, then we should have no problem with XSS attacks (in theory), but
1145
		// IE can be fooled into mime-type detecting a malformed image as an html file, thus executing an XSS attack on anyone
1146
		// using IE who looks at the image. It does this by inspecting the first 255 bytes of an image. To get around this
1147
		// CI will itself look at the first 255 bytes of an image to determine its relative safety. This can save a lot of
1148
		// processor power and time if it is actually a clean image, as it will be in nearly all instances _except_ an
1149
		// attempted XSS attack.
1150
1151
		if (function_exists('getimagesize') && @getimagesize($file) !== FALSE)
1152
		{
1153
			if (($file = @fopen($file, 'rb')) === FALSE) // "b" to force binary
0 ignored issues
show
Bug Best Practice introduced by
The return type of return FALSE; (false) is incompatible with the return type documented by CI_Upload::do_xss_clean of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
1154
			{
1155
				return FALSE; // Couldn't open the file, return FALSE
1156
			}
1157
1158
			$opening_bytes = fread($file, 256);
1159
			fclose($file);
1160
1161
			// These are known to throw IE into mime-type detection chaos
1162
			// <a, <body, <head, <html, <img, <plaintext, <pre, <script, <table, <title
1163
			// title is basically just in SVG, but we filter it anyhow
1164
0 ignored issues
show
Bug Best Practice introduced by
The return type of return !preg_match('/<(a...>]/i', $opening_bytes); (boolean) is incompatible with the return type documented by CI_Upload::do_xss_clean of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
1165
			// if it's an image or no "triggers" detected in the first 256 bytes - we're good
1166
			return ! preg_match('/<(a|body|head|html|img|plaintext|pre|script|table|title)[\s>]/i', $opening_bytes);
1167
		}
1168
1169
		if (($data = @file_get_contents($file)) === FALSE)
0 ignored issues
show
Bug Best Practice introduced by
The return type of return FALSE; (false) is incompatible with the return type documented by CI_Upload::do_xss_clean of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
1170
		{
1171
			return FALSE;
1172
		}
1173
1174
		return $this->_CI->security->xss_clean($data, TRUE);
1175
	}
1176
1177
	// --------------------------------------------------------------------
1178
1179
	/**
1180
	 * Set an error message
1181
	 *
1182
	 * @param	string	$msg
1183
	 * @return	CI_Upload
1184
	 *
1185
	 * @codeCoverageIgnore
1186
	 */
1187
	public function set_error($msg, $log_level = 'error')
1188
	{
1189
		$this->_CI->lang->load('upload');
1190
1191
		is_array($msg) OR $msg = array($msg);
1192
		foreach ($msg as $val)
1193
		{
1194
			$msg = ($this->_CI->lang->line($val) === FALSE) ? $val : $this->_CI->lang->line($val);
1195
			$this->error_msg[] = $msg;
1196
			log_message($log_level, $msg);
1197
		}
1198
1199
		return $this;
1200
	}
1201
1202
	// --------------------------------------------------------------------
1203
1204
	/**
1205
	 * Display the error message
1206
	 *
1207
	 * @param	string	$open
1208
	 * @param	string	$close
1209
	 * @return	string
1210
	 *
1211
	 * @codeCoverageIgnore
1212
	 */
1213
	public function display_errors($open = '<p>', $close = '</p>')
1214
	{
1215
		return (count($this->error_msg) > 0) ? $open.implode($close.$open, $this->error_msg).$close : '';
1216
	}
1217
1218
	// --------------------------------------------------------------------
1219
1220
	/**
1221
	 * Prep Filename
1222
	 *
1223
	 * Prevents possible script execution from Apache's handling
1224
	 * of files' multiple extensions.
1225
	 *
1226
	 * @link	http://httpd.apache.org/docs/1.3/mod/mod_mime.html#multipleext
1227
	 *
1228
	 * @param	string	$filename
1229
	 * @return	string
1230
	 *
1231
	 * @codeCoverageIgnore
1232
	 */
1233
	protected function _prep_filename($filename)
1234
	{
1235
		if ($this->mod_mime_fix === FALSE OR $this->allowed_types === '*' OR ($ext_pos = strrpos($filename, '.')) === FALSE)
1236
		{
1237
			return $filename;
1238
		}
1239
1240
		$ext = substr($filename, $ext_pos);
1241
		$filename = substr($filename, 0, $ext_pos);
1242
		return str_replace('.', '_', $filename).$ext;
1243
	}
1244
1245
	// --------------------------------------------------------------------
1246
1247
	/**
1248
	 * File MIME type
1249
	 *
1250
	 * Detects the (actual) MIME type of the uploaded file, if possible.
1251
	 * The input array is expected to be $_FILES[$field]
1252
	 *
1253
	 * @param	array	$file
1254
	 * @return	void
1255
	 *
1256
	 * @codeCoverageIgnore
1257
	 */
1258
	protected function _file_mime_type($file)
1259
	{
1260
		// We'll need this to validate the MIME info string (e.g. text/plain; charset=us-ascii)
1261
		$regexp = '/^([a-z\-]+\/[a-z0-9\-\.\+]+)(;\s.+)?$/';
1262
1263
		// Fileinfo extension - most reliable method
1264
		$finfo = @finfo_open(FILEINFO_MIME);
1265
		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
1266
		{
1267
			$mime = @finfo_file($finfo, $file['tmp_name']);
1268
			finfo_close($finfo);
1269
1270
			/* According to the comments section of the PHP manual page,
1271
			 * it is possible that this function returns an empty string
1272
			 * for some files (e.g. if they don't exist in the magic MIME database)
1273
			 */
1274
			if (is_string($mime) && preg_match($regexp, $mime, $matches))
1275
			{
1276
				$this->file_type = $matches[1];
1277
				return;
1278
			}
1279
		}
1280
1281
		/* This is an ugly hack, but UNIX-type systems provide a "native" way to detect the file type,
1282
		 * which is still more secure than depending on the value of $_FILES[$field]['type'], and as it
1283
		 * was reported in issue #750 (https://github.com/EllisLab/CodeIgniter/issues/750) - it's better
1284
		 * than mime_content_type() as well, hence the attempts to try calling the command line with
1285
		 * three different functions.
1286
		 *
1287
		 * Notes:
1288
		 *	- the DIRECTORY_SEPARATOR comparison ensures that we're not on a Windows system
1289
		 *	- many system admins would disable the exec(), shell_exec(), popen() and similar functions
1290
		 *	  due to security concerns, hence the function_usable() checks
1291
		 */
1292
		if (DIRECTORY_SEPARATOR !== '\\')
1293
		{
1294
			$cmd = function_exists('escapeshellarg')
1295
				? 'file --brief --mime '.escapeshellarg($file['tmp_name']).' 2>&1'
1296
				: 'file --brief --mime '.$file['tmp_name'].' 2>&1';
1297
1298
			if (function_usable('exec'))
1299
			{
1300
				/* This might look confusing, as $mime is being populated with all of the output when set in the second parameter.
1301
				 * However, we only need the last line, which is the actual return value of exec(), and as such - it overwrites
1302
				 * anything that could already be set for $mime previously. This effectively makes the second parameter a dummy
1303
				 * value, which is only put to allow us to get the return status code.
1304
				 */
1305
				$mime = @exec($cmd, $mime, $return_status);
1306
				if ($return_status === 0 && is_string($mime) && preg_match($regexp, $mime, $matches))
1307
				{
1308
					$this->file_type = $matches[1];
1309
					return;
1310
				}
1311
			}
1312
1313
			if ( ! ini_get('safe_mode') && function_usable('shell_exec'))
1314
			{
1315
				$mime = @shell_exec($cmd);
1316
				if (strlen($mime) > 0)
1317
				{
1318
					$mime = explode("\n", trim($mime));
1319
					if (preg_match($regexp, $mime[(count($mime) - 1)], $matches))
1320
					{
1321
						$this->file_type = $matches[1];
1322
						return;
1323
					}
1324
				}
1325
			}
1326
1327
			if (function_usable('popen'))
1328
			{
1329
				$proc = @popen($cmd, 'r');
1330
				if (is_resource($proc))
1331
				{
1332
					$mime = @fread($proc, 512);
1333
					@pclose($proc);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1334
					if ($mime !== FALSE)
1335
					{
1336
						$mime = explode("\n", trim($mime));
1337
						if (preg_match($regexp, $mime[(count($mime) - 1)], $matches))
1338
						{
1339
							$this->file_type = $matches[1];
1340
							return;
1341
						}
1342
					}
1343
				}
1344
			}
1345
		}
1346
1347
		// Fall back to the deprecated mime_content_type(), if available (still better than $_FILES[$field]['type'])
1348
		if (function_exists('mime_content_type'))
1349
		{
1350
			$this->file_type = @mime_content_type($file['tmp_name']);
1351
			if (strlen($this->file_type) > 0) // It's possible that mime_content_type() returns FALSE or an empty string
1352
			{
1353
				return;
1354
			}
1355
		}
1356
1357
		$this->file_type = $file['type'];
1358
	}
1359
1360
}
1361