GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

Issues (423)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

system/libraries/Upload.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 49 and the first side effect is on line 38.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
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 - 2015, 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. (http://ellislab.com/)
32
 * @copyright	Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/)
33
 * @license	http://opensource.org/licenses/MIT	MIT License
34
 * @link	http://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
42
 *
43
 * @package		CodeIgniter
44
 * @subpackage	Libraries
45
 * @category	Uploads
46
 * @author		EllisLab Dev Team
47
 * @link		http://codeigniter.com/user_guide/libraries/file_uploading.html
48
 */
49
class CI_Upload {
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	$props
290
	 * @return	void
291
	 */
292
	public function __construct($config = array())
293
	{
294
		empty($config) OR $this->initialize($config, FALSE);
295
296
		$this->_mimes =& get_mimes();
297
		$this->_CI =& get_instance();
298
299
		log_message('info', 'Upload Class Initialized');
300
	}
301
302
	// --------------------------------------------------------------------
303
304
	/**
305
	 * Initialize preferences
306
	 *
307
	 * @param	array	$config
308
	 * @param	bool	$reset
309
	 * @return	CI_Upload
310
	 */
311
	public function initialize(array $config = array(), $reset = TRUE)
312
	{
313
		$reflection = new ReflectionClass($this);
314
315
		if ($reset === TRUE)
316
		{
317
			$defaults = $reflection->getDefaultProperties();
318
			foreach (array_keys($defaults) as $key)
319
			{
320
				if ($key[0] === '_')
321
				{
322
					continue;
323
				}
324
325
				if (isset($config[$key]))
326
				{
327
					if ($reflection->hasMethod('set_'.$key))
328
					{
329
						$this->{'set_'.$key}($config[$key]);
330
					}
331
					else
332
					{
333
						$this->$key = $config[$key];
334
					}
335
				}
336
				else
337
				{
338
					$this->$key = $defaults[$key];
339
				}
340
			}
341
		}
342
		else
343
		{
344
			foreach ($config as $key => &$value)
345
			{
346
				if ($key[0] !== '_' && $reflection->hasProperty($key))
347
				{
348
					if ($reflection->hasMethod('set_'.$key))
349
					{
350
						$this->{'set_'.$key}($value);
351
					}
352
					else
353
					{
354
						$this->$key = $value;
355
					}
356
				}
357
			}
358
		}
359
360
		// if a file_name was provided in the config, use it instead of the user input
361
		// supplied file name for all uploads until initialized again
362
		$this->_file_name_override = $this->file_name;
363
		return $this;
364
	}
365
366
	// --------------------------------------------------------------------
367
368
	/**
369
	 * Perform the file upload
370
	 *
371
	 * @param	string	$field
372
	 * @return	bool
373
	 */
374
	public function do_upload($field = 'userfile')
375
	{
376
		// Is $_FILES[$field] set? If not, no reason to continue.
377
		if (isset($_FILES[$field]))
378
		{
379
			$_file = $_FILES[$field];
380
		}
381
		// Does the field name contain array notation?
382 View Code Duplication
		elseif (($c = preg_match_all('/(?:^[^\[]+)|\[[^]]*\]/', $field, $matches)) > 1)
383
		{
384
			$_file = $_FILES;
385
			for ($i = 0; $i < $c; $i++)
386
			{
387
				// We can't track numeric iterations, only full field names are accepted
388
				if (($field = trim($matches[0][$i], '[]')) === '' OR ! isset($_file[$field]))
389
				{
390
					$_file = NULL;
391
					break;
392
				}
393
394
				$_file = $_file[$field];
395
			}
396
		}
397
398
		if ( ! isset($_file))
399
		{
400
			$this->set_error('upload_no_file_selected', 'debug');
401
			return FALSE;
402
		}
403
404
		// Is the upload path valid?
405
		if ( ! $this->validate_upload_path())
406
		{
407
			// errors will already be set by validate_upload_path() so just return FALSE
408
			return FALSE;
409
		}
410
411
		// Was the file able to be uploaded? If not, determine the reason why.
412
		if ( ! is_uploaded_file($_file['tmp_name']))
413
		{
414
			$error = isset($_file['error']) ? $_file['error'] : 4;
415
416
			switch ($error)
417
			{
418
				case UPLOAD_ERR_INI_SIZE:
419
					$this->set_error('upload_file_exceeds_limit', 'info');
420
					break;
421
				case UPLOAD_ERR_FORM_SIZE:
422
					$this->set_error('upload_file_exceeds_form_limit', 'info');
423
					break;
424
				case UPLOAD_ERR_PARTIAL:
425
					$this->set_error('upload_file_partial', 'debug');
426
					break;
427
				case UPLOAD_ERR_NO_FILE:
428
					$this->set_error('upload_no_file_selected', 'debug');
429
					break;
430
				case UPLOAD_ERR_NO_TMP_DIR:
431
					$this->set_error('upload_no_temp_directory', 'error');
432
					break;
433
				case UPLOAD_ERR_CANT_WRITE:
434
					$this->set_error('upload_unable_to_write_file', 'error');
435
					break;
436
				case UPLOAD_ERR_EXTENSION:
437
					$this->set_error('upload_stopped_by_extension', 'debug');
438
					break;
439
				default:
440
					$this->set_error('upload_no_file_selected', 'debug');
441
					break;
442
			}
443
444
			return FALSE;
445
		}
446
447
		// Set the uploaded data as class variables
448
		$this->file_temp = $_file['tmp_name'];
449
		$this->file_size = $_file['size'];
450
451
		// Skip MIME type detection?
452
		if ($this->detect_mime !== FALSE)
453
		{
454
			$this->_file_mime_type($_file);
455
		}
456
457
		$this->file_type = preg_replace('/^(.+?);.*$/', '\\1', $this->file_type);
458
		$this->file_type = strtolower(trim(stripslashes($this->file_type), '"'));
459
		$this->file_name = $this->_prep_filename($_file['name']);
460
		$this->file_ext	 = $this->get_extension($this->file_name);
461
		$this->client_name = $this->file_name;
462
463
		// Is the file type allowed to be uploaded?
464
		if ( ! $this->is_allowed_filetype())
465
		{
466
			$this->set_error('upload_invalid_filetype', 'debug');
467
			return FALSE;
468
		}
469
470
		// if we're overriding, let's now make sure the new name and type is allowed
471
		if ($this->_file_name_override !== '')
472
		{
473
			$this->file_name = $this->_prep_filename($this->_file_name_override);
474
475
			// If no extension was provided in the file_name config item, use the uploaded one
476
			if (strpos($this->_file_name_override, '.') === FALSE)
477
			{
478
				$this->file_name .= $this->file_ext;
479
			}
480
			else
481
			{
482
				// An extension was provided, let's have it!
483
				$this->file_ext	= $this->get_extension($this->_file_name_override);
484
			}
485
486
			if ( ! $this->is_allowed_filetype(TRUE))
487
			{
488
				$this->set_error('upload_invalid_filetype', 'debug');
489
				return FALSE;
490
			}
491
		}
492
493
		// Convert the file size to kilobytes
494
		if ($this->file_size > 0)
495
		{
496
			$this->file_size = round($this->file_size/1024, 2);
497
		}
498
499
		// Is the file size within the allowed maximum?
500
		if ( ! $this->is_allowed_filesize())
501
		{
502
			$this->set_error('upload_invalid_filesize', 'info');
503
			return FALSE;
504
		}
505
506
		// Are the image dimensions within the allowed size?
507
		// Note: This can fail if the server has an open_basedir restriction.
508
		if ( ! $this->is_allowed_dimensions())
509
		{
510
			$this->set_error('upload_invalid_dimensions', 'info');
511
			return FALSE;
512
		}
513
514
		// Sanitize the file name for security
515
		$this->file_name = $this->_CI->security->sanitize_filename($this->file_name);
516
517
		// Truncate the file name if it's too long
518
		if ($this->max_filename > 0)
519
		{
520
			$this->file_name = $this->limit_filename_length($this->file_name, $this->max_filename);
521
		}
522
523
		// Remove white spaces in the name
524
		if ($this->remove_spaces === TRUE)
525
		{
526
			$this->file_name = preg_replace('/\s+/', '_', $this->file_name);
527
		}
528
529
		/*
530
		 * Validate the file name
531
		 * This function appends an number onto the end of
532
		 * the file if one with the same name already exists.
533
		 * If it returns false there was a problem.
534
		 */
535
		$this->orig_name = $this->file_name;
536
		if (FALSE === ($this->file_name = $this->set_filename($this->upload_path, $this->file_name)))
537
		{
538
			return FALSE;
539
		}
540
541
		/*
542
		 * Run the file through the XSS hacking filter
543
		 * This helps prevent malicious code from being
544
		 * embedded within a file. Scripts can easily
545
		 * be disguised as images or other file types.
546
		 */
547
		if ($this->xss_clean && $this->do_xss_clean() === FALSE)
548
		{
549
			$this->set_error('upload_unable_to_write_file', 'error');
550
			return FALSE;
551
		}
552
553
		/*
554
		 * Move the file to the final destination
555
		 * To deal with different server configurations
556
		 * we'll attempt to use copy() first. If that fails
557
		 * we'll use move_uploaded_file(). One of the two should
558
		 * reliably work in most environments
559
		 */
560
		if ( ! @copy($this->file_temp, $this->upload_path.$this->file_name))
561
		{
562
			if ( ! @move_uploaded_file($this->file_temp, $this->upload_path.$this->file_name))
563
			{
564
				$this->set_error('upload_destination_error', 'error');
565
				return FALSE;
566
			}
567
		}
568
569
		/*
570
		 * Set the finalized image dimensions
571
		 * This sets the image width/height (assuming the
572
		 * file was an image). We use this information
573
		 * in the "data" function.
574
		 */
575
		$this->set_image_properties($this->upload_path.$this->file_name);
576
577
		return TRUE;
578
	}
579
580
	// --------------------------------------------------------------------
581
582
	/**
583
	 * Finalized Data Array
584
	 *
585
	 * Returns an associative array containing all of the information
586
	 * related to the upload, allowing the developer easy access in one array.
587
	 *
588
	 * @param	string	$index
589
	 * @return	mixed
590
	 */
591
	public function data($index = NULL)
592
	{
593
		$data = array(
594
				'file_name'		=> $this->file_name,
595
				'file_type'		=> $this->file_type,
596
				'file_path'		=> $this->upload_path,
597
				'full_path'		=> $this->upload_path.$this->file_name,
598
				'raw_name'		=> str_replace($this->file_ext, '', $this->file_name),
599
				'orig_name'		=> $this->orig_name,
600
				'client_name'		=> $this->client_name,
601
				'file_ext'		=> $this->file_ext,
602
				'file_size'		=> $this->file_size,
603
				'is_image'		=> $this->is_image(),
604
				'image_width'		=> $this->image_width,
605
				'image_height'		=> $this->image_height,
606
				'image_type'		=> $this->image_type,
607
				'image_size_str'	=> $this->image_size_str,
608
			);
609
610
		if ( ! empty($index))
611
		{
612
			return isset($data[$index]) ? $data[$index] : NULL;
613
		}
614
615
		return $data;
616
	}
617
618
	// --------------------------------------------------------------------
619
620
	/**
621
	 * Set Upload Path
622
	 *
623
	 * @param	string	$path
624
	 * @return	CI_Upload
625
	 */
626
	public function set_upload_path($path)
627
	{
628
		// Make sure it has a trailing slash
629
		$this->upload_path = rtrim($path, '/').'/';
630
		return $this;
631
	}
632
633
	// --------------------------------------------------------------------
634
635
	/**
636
	 * Set the file name
637
	 *
638
	 * This function takes a filename/path as input and looks for the
639
	 * existence of a file with the same name. If found, it will append a
640
	 * number to the end of the filename to avoid overwriting a pre-existing file.
641
	 *
642
	 * @param	string	$path
643
	 * @param	string	$filename
644
	 * @return	string
645
	 */
646
	public function set_filename($path, $filename)
647
	{
648
		if ($this->encrypt_name === TRUE)
649
		{
650
			$filename = md5(uniqid(mt_rand())).$this->file_ext;
651
		}
652
653
		if ($this->overwrite === TRUE OR ! file_exists($path.$filename))
654
		{
655
			return $filename;
656
		}
657
658
		$filename = str_replace($this->file_ext, '', $filename);
659
660
		$new_filename = '';
661
		for ($i = 1; $i < $this->max_filename_increment; $i++)
662
		{
663
			if ( ! file_exists($path.$filename.$i.$this->file_ext))
664
			{
665
				$new_filename = $filename.$i.$this->file_ext;
666
				break;
667
			}
668
		}
669
670
		if ($new_filename === '')
671
		{
672
			$this->set_error('upload_bad_filename', 'debug');
673
			return FALSE;
674
		}
675
		else
676
		{
677
			return $new_filename;
678
		}
679
	}
680
681
	// --------------------------------------------------------------------
682
683
	/**
684
	 * Set Maximum File Size
685
	 *
686
	 * @param	int	$n
687
	 * @return	CI_Upload
688
	 */
689
	public function set_max_filesize($n)
690
	{
691
		$this->max_size = ($n < 0) ? 0 : (int) $n;
692
		return $this;
693
	}
694
695
	// --------------------------------------------------------------------
696
697
	/**
698
	 * Set Maximum File Size
699
	 *
700
	 * An internal alias to set_max_filesize() to help with configuration
701
	 * as initialize() will look for a set_<property_name>() method ...
702
	 *
703
	 * @param	int	$n
704
	 * @return	CI_Upload
705
	 */
706
	protected function set_max_size($n)
707
	{
708
		return $this->set_max_filesize($n);
709
	}
710
711
	// --------------------------------------------------------------------
712
713
	/**
714
	 * Set Maximum File Name Length
715
	 *
716
	 * @param	int	$n
717
	 * @return	CI_Upload
718
	 */
719
	public function set_max_filename($n)
720
	{
721
		$this->max_filename = ($n < 0) ? 0 : (int) $n;
722
		return $this;
723
	}
724
725
	// --------------------------------------------------------------------
726
727
	/**
728
	 * Set Maximum Image Width
729
	 *
730
	 * @param	int	$n
731
	 * @return	CI_Upload
732
	 */
733
	public function set_max_width($n)
734
	{
735
		$this->max_width = ($n < 0) ? 0 : (int) $n;
736
		return $this;
737
	}
738
739
	// --------------------------------------------------------------------
740
741
	/**
742
	 * Set Maximum Image Height
743
	 *
744
	 * @param	int	$n
745
	 * @return	CI_Upload
746
	 */
747
	public function set_max_height($n)
748
	{
749
		$this->max_height = ($n < 0) ? 0 : (int) $n;
750
		return $this;
751
	}
752
753
	// --------------------------------------------------------------------
754
755
	/**
756
	 * Set minimum image width
757
	 *
758
	 * @param	int	$n
759
	 * @return	CI_Upload
760
	 */
761
	public function set_min_width($n)
762
	{
763
		$this->min_width = ($n < 0) ? 0 : (int) $n;
764
		return $this;
765
	}
766
767
	// --------------------------------------------------------------------
768
769
	/**
770
	 * Set minimum image height
771
	 *
772
	 * @param	int	$n
773
	 * @return	CI_Upload
774
	 */
775
	public function set_min_height($n)
776
	{
777
		$this->min_height = ($n < 0) ? 0 : (int) $n;
778
		return $this;
779
	}
780
781
	// --------------------------------------------------------------------
782
783
	/**
784
	 * Set Allowed File Types
785
	 *
786
	 * @param	mixed	$types
787
	 * @return	CI_Upload
788
	 */
789
	public function set_allowed_types($types)
790
	{
791
		$this->allowed_types = (is_array($types) OR $types === '*')
792
			? $types
793
			: explode('|', $types);
794
		return $this;
795
	}
796
797
	// --------------------------------------------------------------------
798
799
	/**
800
	 * Set Image Properties
801
	 *
802
	 * Uses GD to determine the width/height/type of image
803
	 *
804
	 * @param	string	$path
805
	 * @return	CI_Upload
806
	 */
807
	public function set_image_properties($path = '')
808
	{
809
		if ($this->is_image() && function_exists('getimagesize'))
810
		{
811
			if (FALSE !== ($D = @getimagesize($path)))
812
			{
813
				$types = array(1 => 'gif', 2 => 'jpeg', 3 => 'png');
814
815
				$this->image_width	= $D[0];
816
				$this->image_height	= $D[1];
817
				$this->image_type	= isset($types[$D[2]]) ? $types[$D[2]] : 'unknown';
818
				$this->image_size_str	= $D[3]; // string containing height and width
819
			}
820
		}
821
822
		return $this;
823
	}
824
825
	// --------------------------------------------------------------------
826
827
	/**
828
	 * Set XSS Clean
829
	 *
830
	 * Enables the XSS flag so that the file that was uploaded
831
	 * will be run through the XSS filter.
832
	 *
833
	 * @param	bool	$flag
834
	 * @return	CI_Upload
835
	 */
836
	public function set_xss_clean($flag = FALSE)
837
	{
838
		$this->xss_clean = ($flag === TRUE);
839
		return $this;
840
	}
841
842
	// --------------------------------------------------------------------
843
844
	/**
845
	 * Validate the image
846
	 *
847
	 * @return	bool
848
	 */
849
	public function is_image()
850
	{
851
		// IE will sometimes return odd mime-types during upload, so here we just standardize all
852
		// jpegs or pngs to the same file type.
853
854
		$png_mimes  = array('image/x-png');
855
		$jpeg_mimes = array('image/jpg', 'image/jpe', 'image/jpeg', 'image/pjpeg');
856
857
		if (in_array($this->file_type, $png_mimes))
858
		{
859
			$this->file_type = 'image/png';
860
		}
861
		elseif (in_array($this->file_type, $jpeg_mimes))
862
		{
863
			$this->file_type = 'image/jpeg';
864
		}
865
866
		$img_mimes = array('image/gif',	'image/jpeg', 'image/png');
867
868
		return in_array($this->file_type, $img_mimes, TRUE);
869
	}
870
871
	// --------------------------------------------------------------------
872
873
	/**
874
	 * Verify that the filetype is allowed
875
	 *
876
	 * @param	bool	$ignore_mime
877
	 * @return	bool
878
	 */
879
	public function is_allowed_filetype($ignore_mime = FALSE)
880
	{
881
		if ($this->allowed_types === '*')
882
		{
883
			return TRUE;
884
		}
885
886
		if (empty($this->allowed_types) OR ! is_array($this->allowed_types))
887
		{
888
			$this->set_error('upload_no_file_types', 'debug');
889
			return FALSE;
890
		}
891
892
		$ext = strtolower(ltrim($this->file_ext, '.'));
893
894
		if ( ! in_array($ext, $this->allowed_types, TRUE))
895
		{
896
			return FALSE;
897
		}
898
899
		// Images get some additional checks
900
		if (in_array($ext, array('gif', 'jpg', 'jpeg', 'jpe', 'png'), TRUE) && @getimagesize($this->file_temp) === FALSE)
901
		{
902
			return FALSE;
903
		}
904
905
		if ($ignore_mime === TRUE)
906
		{
907
			return TRUE;
908
		}
909
910
		if (isset($this->_mimes[$ext]))
911
		{
912
			return is_array($this->_mimes[$ext])
913
				? in_array($this->file_type, $this->_mimes[$ext], TRUE)
914
				: ($this->_mimes[$ext] === $this->file_type);
915
		}
916
917
		return FALSE;
918
	}
919
920
	// --------------------------------------------------------------------
921
922
	/**
923
	 * Verify that the file is within the allowed size
924
	 *
925
	 * @return	bool
926
	 */
927
	public function is_allowed_filesize()
928
	{
929
		return ($this->max_size === 0 OR $this->max_size > $this->file_size);
930
	}
931
932
	// --------------------------------------------------------------------
933
934
	/**
935
	 * Verify that the image is within the allowed width/height
936
	 *
937
	 * @return	bool
938
	 */
939
	public function is_allowed_dimensions()
940
	{
941
		if ( ! $this->is_image())
942
		{
943
			return TRUE;
944
		}
945
946
		if (function_exists('getimagesize'))
947
		{
948
			$D = @getimagesize($this->file_temp);
949
950
			if ($this->max_width > 0 && $D[0] > $this->max_width)
951
			{
952
				return FALSE;
953
			}
954
955
			if ($this->max_height > 0 && $D[1] > $this->max_height)
956
			{
957
				return FALSE;
958
			}
959
960
			if ($this->min_width > 0 && $D[0] < $this->min_width)
961
			{
962
				return FALSE;
963
			}
964
965
			if ($this->min_height > 0 && $D[1] < $this->min_height)
966
			{
967
				return FALSE;
968
			}
969
		}
970
971
		return TRUE;
972
	}
973
974
	// --------------------------------------------------------------------
975
976
	/**
977
	 * Validate Upload Path
978
	 *
979
	 * Verifies that it is a valid upload path with proper permissions.
980
	 *
981
	 * @return	bool
982
	 */
983
	public function validate_upload_path()
984
	{
985
		if ($this->upload_path === '')
986
		{
987
			$this->set_error('upload_no_filepath', 'error');
988
			return FALSE;
989
		}
990
991
		if (realpath($this->upload_path) !== FALSE)
992
		{
993
			$this->upload_path = str_replace('\\', '/', realpath($this->upload_path));
994
		}
995
996
		if ( ! is_dir($this->upload_path))
997
		{
998
			$this->set_error('upload_no_filepath', 'error');
999
			return FALSE;
1000
		}
1001
1002
		if ( ! is_really_writable($this->upload_path))
1003
		{
1004
			$this->set_error('upload_not_writable', 'error');
1005
			return FALSE;
1006
		}
1007
1008
		$this->upload_path = preg_replace('/(.+?)\/*$/', '\\1/',  $this->upload_path);
1009
		return TRUE;
1010
	}
1011
1012
	// --------------------------------------------------------------------
1013
1014
	/**
1015
	 * Extract the file extension
1016
	 *
1017
	 * @param	string	$filename
1018
	 * @return	string
1019
	 */
1020
	public function get_extension($filename)
1021
	{
1022
		$x = explode('.', $filename);
1023
1024
		if (count($x) === 1)
1025
		{
1026
			return '';
1027
		}
1028
1029
		$ext = ($this->file_ext_tolower) ? strtolower(end($x)) : end($x);
1030
		return '.'.$ext;
1031
	}
1032
1033
	// --------------------------------------------------------------------
1034
1035
	/**
1036
	 * Limit the File Name Length
1037
	 *
1038
	 * @param	string	$filename
1039
	 * @param	int	$length
1040
	 * @return	string
1041
	 */
1042
	public function limit_filename_length($filename, $length)
1043
	{
1044
		if (strlen($filename) < $length)
1045
		{
1046
			return $filename;
1047
		}
1048
1049
		$ext = '';
1050
		if (strpos($filename, '.') !== FALSE)
1051
		{
1052
			$parts		= explode('.', $filename);
1053
			$ext		= '.'.array_pop($parts);
1054
			$filename	= implode('.', $parts);
1055
		}
1056
1057
		return substr($filename, 0, ($length - strlen($ext))).$ext;
1058
	}
1059
1060
	// --------------------------------------------------------------------
1061
1062
	/**
1063
	 * Runs the file through the XSS clean function
1064
	 *
1065
	 * This prevents people from embedding malicious code in their files.
1066
	 * I'm not sure that it won't negatively affect certain files in unexpected ways,
1067
	 * but so far I haven't found that it causes trouble.
1068
	 *
1069
	 * @return	string
1070
	 */
1071
	public function do_xss_clean()
1072
	{
1073
		$file = $this->file_temp;
1074
1075
		if (filesize($file) == 0)
1076
		{
1077
			return FALSE;
1078
		}
1079
1080
		if (memory_get_usage() && ($memory_limit = ini_get('memory_limit')))
1081
		{
1082
			$memory_limit *= 1024 * 1024;
1083
1084
			// There was a bug/behavioural change in PHP 5.2, where numbers over one million get output
1085
			// into scientific notation. number_format() ensures this number is an integer
1086
			// http://bugs.php.net/bug.php?id=43053
1087
1088
			$memory_limit = number_format(ceil(filesize($file) + $memory_limit), 0, '.', '');
1089
1090
			ini_set('memory_limit', $memory_limit); // When an integer is used, the value is measured in bytes. - PHP.net
1091
		}
1092
1093
		// If the file being uploaded is an image, then we should have no problem with XSS attacks (in theory), but
1094
		// IE can be fooled into mime-type detecting a malformed image as an html file, thus executing an XSS attack on anyone
1095
		// using IE who looks at the image. It does this by inspecting the first 255 bytes of an image. To get around this
1096
		// CI will itself look at the first 255 bytes of an image to determine its relative safety. This can save a lot of
1097
		// processor power and time if it is actually a clean image, as it will be in nearly all instances _except_ an
1098
		// attempted XSS attack.
1099
1100
		if (function_exists('getimagesize') && @getimagesize($file) !== FALSE)
1101
		{
1102
			if (($file = @fopen($file, 'rb')) === FALSE) // "b" to force binary
1103
			{
1104
				return FALSE; // Couldn't open the file, return FALSE
1105
			}
1106
1107
			$opening_bytes = fread($file, 256);
1108
			fclose($file);
1109
1110
			// These are known to throw IE into mime-type detection chaos
1111
			// <a, <body, <head, <html, <img, <plaintext, <pre, <script, <table, <title
1112
			// title is basically just in SVG, but we filter it anyhow
1113
1114
			// if it's an image or no "triggers" detected in the first 256 bytes - we're good
1115
			return ! preg_match('/<(a|body|head|html|img|plaintext|pre|script|table|title)[\s>]/i', $opening_bytes);
1116
		}
1117
1118
		if (($data = @file_get_contents($file)) === FALSE)
1119
		{
1120
			return FALSE;
1121
		}
1122
1123
		return $this->_CI->security->xss_clean($data, TRUE);
1124
	}
1125
1126
	// --------------------------------------------------------------------
1127
1128
	/**
1129
	 * Set an error message
1130
	 *
1131
	 * @param	string	$msg
1132
	 * @return	CI_Upload
1133
	 */
1134
	public function set_error($msg, $log_level = 'error')
1135
	{
1136
		$this->_CI->lang->load('upload');
1137
1138
		is_array($msg) OR $msg = array($msg);
1139
		foreach ($msg as $val)
1140
		{
1141
			$msg = ($this->_CI->lang->line($val) === FALSE) ? $val : $this->_CI->lang->line($val);
1142
			$this->error_msg[] = $msg;
1143
			log_message($log_level, $msg);
1144
		}
1145
1146
		return $this;
1147
	}
1148
1149
	// --------------------------------------------------------------------
1150
1151
	/**
1152
	 * Display the error message
1153
	 *
1154
	 * @param	string	$open
1155
	 * @param	string	$close
1156
	 * @return	string
1157
	 */
1158
	public function display_errors($open = '<p>', $close = '</p>')
1159
	{
1160
		return (count($this->error_msg) > 0) ? $open.implode($close.$open, $this->error_msg).$close : '';
1161
	}
1162
1163
	// --------------------------------------------------------------------
1164
1165
	/**
1166
	 * Prep Filename
1167
	 *
1168
	 * Prevents possible script execution from Apache's handling
1169
	 * of files' multiple extensions.
1170
	 *
1171
	 * @link	http://httpd.apache.org/docs/1.3/mod/mod_mime.html#multipleext
1172
	 *
1173
	 * @param	string	$filename
1174
	 * @return	string
1175
	 */
1176
	protected function _prep_filename($filename)
1177
	{
1178
		if ($this->mod_mime_fix === FALSE OR $this->allowed_types === '*' OR ($ext_pos = strrpos($filename, '.')) === FALSE)
1179
		{
1180
			return $filename;
1181
		}
1182
1183
		$ext = substr($filename, $ext_pos);
1184
		$filename = substr($filename, 0, $ext_pos);
1185
		return str_replace('.', '_', $filename).$ext;
1186
	}
1187
1188
	// --------------------------------------------------------------------
1189
1190
	/**
1191
	 * File MIME type
1192
	 *
1193
	 * Detects the (actual) MIME type of the uploaded file, if possible.
1194
	 * The input array is expected to be $_FILES[$field]
1195
	 *
1196
	 * @param	array	$file
1197
	 * @return	void
1198
	 */
1199
	protected function _file_mime_type($file)
1200
	{
1201
		// We'll need this to validate the MIME info string (e.g. text/plain; charset=us-ascii)
1202
		$regexp = '/^([a-z\-]+\/[a-z0-9\-\.\+]+)(;\s.+)?$/';
1203
1204
		/* Fileinfo extension - most reliable method
1205
		 *
1206
		 * Unfortunately, prior to PHP 5.3 - it's only available as a PECL extension and the
1207
		 * more convenient FILEINFO_MIME_TYPE flag doesn't exist.
1208
		 */
1209 View Code Duplication
		if (function_exists('finfo_file'))
1210
		{
1211
			$finfo = @finfo_open(FILEINFO_MIME);
1212
			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
1213
			{
1214
				$mime = @finfo_file($finfo, $file['tmp_name']);
1215
				finfo_close($finfo);
1216
1217
				/* According to the comments section of the PHP manual page,
1218
				 * it is possible that this function returns an empty string
1219
				 * for some files (e.g. if they don't exist in the magic MIME database)
1220
				 */
1221
				if (is_string($mime) && preg_match($regexp, $mime, $matches))
1222
				{
1223
					$this->file_type = $matches[1];
1224
					return;
1225
				}
1226
			}
1227
		}
1228
1229
		/* This is an ugly hack, but UNIX-type systems provide a "native" way to detect the file type,
1230
		 * which is still more secure than depending on the value of $_FILES[$field]['type'], and as it
1231
		 * was reported in issue #750 (https://github.com/EllisLab/CodeIgniter/issues/750) - it's better
1232
		 * than mime_content_type() as well, hence the attempts to try calling the command line with
1233
		 * three different functions.
1234
		 *
1235
		 * Notes:
1236
		 *	- the DIRECTORY_SEPARATOR comparison ensures that we're not on a Windows system
1237
		 *	- many system admins would disable the exec(), shell_exec(), popen() and similar functions
1238
		 *	  due to security concerns, hence the function_usable() checks
1239
		 */
1240
		if (DIRECTORY_SEPARATOR !== '\\')
1241
		{
1242
			$cmd = function_exists('escapeshellarg')
1243
				? 'file --brief --mime '.escapeshellarg($file['tmp_name']).' 2>&1'
1244
				: 'file --brief --mime '.$file['tmp_name'].' 2>&1';
1245
1246
			if (function_usable('exec'))
1247
			{
1248
				/* This might look confusing, as $mime is being populated with all of the output when set in the second parameter.
1249
				 * However, we only need the last line, which is the actual return value of exec(), and as such - it overwrites
1250
				 * anything that could already be set for $mime previously. This effectively makes the second parameter a dummy
1251
				 * value, which is only put to allow us to get the return status code.
1252
				 */
1253
				$mime = @exec($cmd, $mime, $return_status);
1254
				if ($return_status === 0 && is_string($mime) && preg_match($regexp, $mime, $matches))
1255
				{
1256
					$this->file_type = $matches[1];
1257
					return;
1258
				}
1259
			}
1260
1261
			if ( ! ini_get('safe_mode') && function_usable('shell_exec'))
1262
			{
1263
				$mime = @shell_exec($cmd);
1264
				if (strlen($mime) > 0)
1265
				{
1266
					$mime = explode("\n", trim($mime));
1267
					if (preg_match($regexp, $mime[(count($mime) - 1)], $matches))
1268
					{
1269
						$this->file_type = $matches[1];
1270
						return;
1271
					}
1272
				}
1273
			}
1274
1275
			if (function_usable('popen'))
1276
			{
1277
				$proc = @popen($cmd, 'r');
1278 View Code Duplication
				if (is_resource($proc))
1279
				{
1280
					$mime = @fread($proc, 512);
1281
					@pclose($proc);
1282
					if ($mime !== FALSE)
1283
					{
1284
						$mime = explode("\n", trim($mime));
1285
						if (preg_match($regexp, $mime[(count($mime) - 1)], $matches))
1286
						{
1287
							$this->file_type = $matches[1];
1288
							return;
1289
						}
1290
					}
1291
				}
1292
			}
1293
		}
1294
1295
		// Fall back to the deprecated mime_content_type(), if available (still better than $_FILES[$field]['type'])
0 ignored issues
show
Unused Code Comprehensibility introduced by
38% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1296
		if (function_exists('mime_content_type'))
1297
		{
1298
			$this->file_type = @mime_content_type($file['tmp_name']);
1299
			if (strlen($this->file_type) > 0) // It's possible that mime_content_type() returns FALSE or an empty string
1300
			{
1301
				return;
1302
			}
1303
		}
1304
1305
		$this->file_type = $file['type'];
1306
	}
1307
1308
}
1309