upload   F
last analyzed

Complexity

Total Complexity 93

Size/Duplication

Total Lines 802
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 2
Bugs 1 Features 0
Metric Value
wmc 93
eloc 329
c 2
b 1
f 0
dl 0
loc 802
ccs 0
cts 491
cp 0
rs 2

27 Methods

Rating   Name   Duplication   Size   Complexity  
A generate_hidden_fields() 0 8 2
A set_username() 0 3 1
A prepare_file_update() 0 17 4
A quota_error() 0 8 2
A use_same_name() 0 10 3
A prune_orphan() 0 20 4
A set_file_limit() 0 3 1
A get_description() 0 8 2
A set_descriptions() 0 3 1
A get_rotating() 0 12 3
A file_to_database() 0 33 1
A set_allow_comments() 0 3 1
B get_images() 0 36 6
A set_image_num() 0 3 1
A set_names() 0 3 1
A new_error() 0 3 1
A get_name() 0 3 1
A set_rotating() 0 3 1
A set_up() 0 11 1
B update_image() 0 76 10
A get_current_upload_dir() 0 24 3
B upload_file() 0 32 7
A upload_zip() 0 31 3
A __construct() 0 20 1
B read_zip_folder() 0 56 11
B get_allowed_types() 0 31 8
C prepare_file() 0 88 13

How to fix   Complexity   

Complex Class

Complex classes like upload often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use upload, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * phpBB Gallery - Core Extension
4
 *
5
 * @package   phpbbgallery/core
6
 * @author    nickvergessen
7
 * @author    satanasov
8
 * @author    Leinad4Mind
9
 * @copyright 2007-2012 nickvergessen, 2014- satanasov, 2018- Leinad4Mind
10
 * @license   GPL-2.0-only
11
 */
12
13
namespace phpbbgallery\core;
14
15
class upload
16
{
17
	/**
18
	* @var \phpbb\user
0 ignored issues
show
Bug introduced by
The type phpbb\user was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
19
	*/
20
	protected $user;
21
22
	/**
23
	* @var \phpbb\language\language
0 ignored issues
show
Bug introduced by
The type phpbb\language\language was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
24
	*/
25
	protected $language;
26
27
	/**
28
	* @var \phpbb\db\driver\driver_interface
0 ignored issues
show
Bug introduced by
The type phpbb\db\driver\driver_interface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
29
	*/
30
	protected $db;
31
32
	/**
33
	* @var \phpbb\event\dispatcher_interface
0 ignored issues
show
Bug introduced by
The type phpbb\event\dispatcher_interface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
34
	*/
35
	protected $phpbb_dispatcher;
36
37
	/**
38
	* @var \phpbb\request\request
0 ignored issues
show
Bug introduced by
The type phpbb\request\request was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
39
	*/
40
	protected $request;
41
42
	/**
43
	* @var \phpbb\files\upload
0 ignored issues
show
Bug introduced by
The type phpbb\files\upload was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
44
	*/
45
	protected $file_upload;
46
47
	/**
48
	* @var \phpbbgallery\core\image\image
49
	*/
50
	protected $gallery_image;
51
52
	/**
53
	* @var \phpbbgallery\core\config
54
	*/
55
	protected $gallery_config;
56
57
	/**
58
	* @var \phpbbgallery\core\url
59
	*/
60
	protected $gallery_url;
61
62
	/**
63
	* @var \phpbbgallery\core\block
64
	*/
65
	protected $block;
66
67
	/**
68
	* @var \phpbbgallery\core\file\file
69
	*/
70
	protected $tools;
71
72
	/**
73
	* @var string
74
	*/
75
	protected $images_table;
76
77
	/**
78
	* @var string
79
	*/
80
	protected $root_path;
81
82
	/**
83
	* @var string
84
	*/
85
	protected $php_ext;
86
87
	/**
88
	* Number of Files per Directory
89
	*
90
	* If this constant is set to a value >0 the gallery will create a new directory,
91
	* when the current directory has more files in it than set here.
92
	*/
93
	const NUM_FILES_PER_DIR = 0;
94
95
	/**
96
	* Objects: phpBB Upload, 2 Files and Image-Functions
97
	*/
98
	private $upload = null;
0 ignored issues
show
introduced by
The private property $upload is not used, and could be removed.
Loading history...
99
	private $file = null;
100
	private $zip_file = null;
101
	//private $tools = null;
102
103
	/**
104
	* Basic variables...
105
	*/
106
	public $loaded_files = 0;
107
	public $uploaded_files = 0;
108
	public $errors = array();
109
	public $images = array();
110
	public $image_data = array();
111
	public $array_id2row = array();
112
	public $error_prefix = '';
113
	public $max_filesize = 0;
114
	private $file_limit = 0;
115
	private $album_id = 0;
116
	private $file_count = 0;
117
	private $image_num = 0;
118
	private $allow_comments = false;
119
	private $sent_quota_error = false;
120
	private $username = '';
121
	private $file_descriptions = array();
122
	private $file_names = array();
123
	private $file_rotating = array();
124
125
	var $min_width = 0;
126
	var $min_height = 0;
127
	var $max_width = 0;
128
	var $max_height = 0;
129
130
	/**
131
	 * Constructor
132
	 *
133
	 * @param \phpbb\user                       $user           phpBB User class
134
	 * @param \phpbb\language\language          $language
135
	 * @param \phpbb\db\driver\driver_interface $db
136
	 * @param \phpbb\event\dispatcher_interface $phpbb_dispatcher
137
	 * @param \phpbb\request\request            $request
138
	 * @param \phpbb\files\upload               $file_upload
139
	 * @param \phpbbgallery\core\image\image    $gallery_image
140
	 * @param \phpbbgallery\core\config         $gallery_config Gallery Config
141
	 * @param \phpbbgallery\core\url            $gallery_url    Gallery url
142
	 * @param block                             $block
143
	 * @param file\file                         $gallery_file
144
	 * @param                                   $images_table
145
	 * @param                                   $root_path
146
	 * @param                                   $php_ext
147
	 */
148
	public function __construct(\phpbb\user $user, \phpbb\language\language $language, \phpbb\db\driver\driver_interface $db,
149
		\phpbb\event\dispatcher_interface $phpbb_dispatcher, \phpbb\request\request $request, \phpbb\files\upload $file_upload,
150
		\phpbbgallery\core\image\image $gallery_image, \phpbbgallery\core\config $gallery_config, \phpbbgallery\core\url $gallery_url,
151
		\phpbbgallery\core\block $block, \phpbbgallery\core\file\file $gallery_file,
152
		$images_table, $root_path, $php_ext)
153
	{
154
		$this->user = $user;
155
		$this->language = $language;
156
		$this->db = $db;
157
		$this->phpbb_dispatcher = $phpbb_dispatcher;
158
		$this->request = $request;
159
		$this->file_upload = $file_upload;
160
		$this->gallery_image = $gallery_image;
161
		$this->gallery_config = $gallery_config;
162
		$this->gallery_url	= $gallery_url;
163
		$this->block = $block;
164
		$this->tools = $gallery_file;
165
		$this->images_table = $images_table;
166
		$this->root_path = $root_path;
167
		$this->php_ext = $php_ext;
168
	}
169
170
	/**
171
	 * As we have to use construct for setting up infrastructure the right way,
172
	 * we'll be creating this setup function that should setup everything.
173
	 * @param     $album_id 	Album ID we are uploading to
174
	 * @param int $num_files	Number of files we upload
175
	 */
176
	public function set_up($album_id, $num_files = 0)
177
	{
178
		//$this->upload = new \fileupload();
179
		//$this->upload->fileupload('', $this->get_allowed_types(), (4 * $this->gallery_config->get('max_filesize')));
180
		$this->file_upload->set_allowed_extensions($this->get_allowed_types());
181
182
		$this->album_id = (int) $album_id;
183
		$this->file_limit = (int) $num_files;
184
		$this->username = $this->user->data['username'];
185
186
		$this->max_filesize = 4 * $this->gallery_config->get('max_filesize');
187
	}
188
189
	/**
190
	 * Upload a file and then call the function for reading the zip or preparing the image
191
	 *
192
	 * @param $file_count
193
	 * @return bool
194
	 */
195
	public function upload_file($file_count)
196
	{
197
		if ($this->file_limit && ($this->uploaded_files >= $this->file_limit))
198
		{
199
			$this->quota_error();
200
			return false;
201
		}
202
		$this->file_count = (int) $file_count;
203
204
		//$this->files = $this->form_upload('files');
205
		$files = $this->file_upload->handle_upload('phpbbgallery.core.files.types.multiform', 'files');
206
207
		foreach ($files as $var)
208
		{
209
			$this->file = $var;
210
			if (!$this->file->get('uploadname'))
211
			{
212
				return false;
213
			}
214
215
			if ($this->file->get('extension') == 'zip')
216
			{
217
				$this->zip_file = $this->file;
218
				$this->upload_zip();
219
			}
220
			else
221
			{
222
				$image_id = $this->prepare_file();
223
				if ($image_id)
0 ignored issues
show
Bug Best Practice introduced by
The expression $image_id of type false|integer is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
224
				{
225
					$this->uploaded_files++;
226
					$this->images[] = (int) $image_id;
227
				}
228
			}
229
		}
230
	}
231
232
	/**
233
	* Upload a zip file and save the images into the import/ directory.
234
	*/
235
	public function upload_zip()
236
	{
237
		if (!class_exists('compress_zip'))
238
		{
239
			include_once($this->root_path . 'includes/functions_compress.' . $this->php_ext);
240
		}
241
242
		$tmp_dir = $this->gallery_url->path('import') . 'tmp_' . md5(unique_id()) . '/';
0 ignored issues
show
Bug introduced by
The function unique_id was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

242
		$tmp_dir = $this->gallery_url->path('import') . 'tmp_' . md5(/** @scrutinizer ignore-call */ unique_id()) . '/';
Loading history...
243
244
		$this->zip_file->clean_filename('unique_ext');
245
		$this->zip_file->move_file(substr($this->gallery_url->path('import_noroot'), 0, -1), false, false, CHMOD_ALL);
0 ignored issues
show
Bug introduced by
The constant phpbbgallery\core\CHMOD_ALL was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
246
		if (!empty($this->zip_file->error))
247
		{
248
			$this->zip_file->remove();
249
			$this->new_error($this->language->lang('UPLOAD_ERROR', $this->zip_file->get('uploadname'), implode('<br />&raquo; ', $this->zip_file->error)));
250
			return false;
251
		}
252
253
		$compress = new \compress_zip('r', $this->zip_file->get('destination_file'));
0 ignored issues
show
Bug introduced by
The type compress_zip was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
254
		$compress->extract($tmp_dir);
255
		$compress->close();
256
257
		$this->zip_file->remove();
258
259
		// Remove zip from allowed extensions
260
		$this->file_upload->set_allowed_extensions($this->get_allowed_types(false, true));
261
262
		$this->read_zip_folder($tmp_dir);
263
264
		// Read zip from allowed extensions
265
		$this->file_upload->set_allowed_extensions($this->get_allowed_types());
266
	}
267
268
	/**
269
	 * Read a folder from the zip, "upload" the images and remove the rest.
270
	 *
271
	 * @param $current_dir
272
	 */
273
	public function read_zip_folder($current_dir)
274
	{
275
		$handle = opendir($current_dir);
276
		while ($file = readdir($handle))
277
		{
278
			if ($file == '.' || $file == '..')
279
			{
280
				continue;
281
			}
282
			if (is_dir($current_dir . $file))
283
			{
284
				$this->read_zip_folder($current_dir . $file . '/');
285
			}
286
			else if (in_array(utf8_substr(strtolower($file), utf8_strrpos($file, '.') + 1), self::get_allowed_types(false, true)))
0 ignored issues
show
Bug introduced by
The function utf8_strrpos was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

286
			else if (in_array(utf8_substr(strtolower($file), /** @scrutinizer ignore-call */ utf8_strrpos($file, '.') + 1), self::get_allowed_types(false, true)))
Loading history...
Bug Best Practice introduced by
The method phpbbgallery\core\upload::get_allowed_types() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

286
			else if (in_array(utf8_substr(strtolower($file), utf8_strrpos($file, '.') + 1), self::/** @scrutinizer ignore-call */ get_allowed_types(false, true)))
Loading history...
Bug introduced by
The function utf8_substr was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

286
			else if (in_array(/** @scrutinizer ignore-call */ utf8_substr(strtolower($file), utf8_strrpos($file, '.') + 1), self::get_allowed_types(false, true)))
Loading history...
287
			{
288
				if (!$this->file_limit || ($this->uploaded_files < $this->file_limit))
289
				{
290
					$file_info = array(
291
						'type'	=> $this->tools->mimetype_by_filename($file),
292
						'size'	=> filesize($current_dir . $file),
293
						'realname' => $file
294
					);
295
					$this->file = $this->file_upload->handle_upload('files.types.local', $current_dir . $file, $file_info);
296
					if ($this->file->error)
297
					{
298
						$this->new_error($this->language->lang('UPLOAD_ERROR', $this->file->get('uploadname'), implode('<br />&raquo; ', $this->file->error)));
299
					}
300
					$image_id = $this->prepare_file();
301
302
					if ($image_id)
0 ignored issues
show
Bug Best Practice introduced by
The expression $image_id of type false|integer is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
303
					{
304
						$this->uploaded_files++;
305
						$this->images[] = (int) $image_id;
306
					}
307
					else
308
					{
309
						if ($this->file->error)
310
						{
311
							$this->new_error($this->language->lang('UPLOAD_ERROR', $this->file->get('uploadname'), implode('<br />&raquo; ', $this->file->error)));
312
						}
313
					}
314
				}
315
				else
316
				{
317
					$this->quota_error();
318
					@unlink($current_dir . $file);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for unlink(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

318
					/** @scrutinizer ignore-unhandled */ @unlink($current_dir . $file);

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...
319
				}
320
321
			}
322
			else
323
			{
324
				@unlink($current_dir . $file);
325
			}
326
		}
327
		closedir($handle);
328
		@rmdir($current_dir);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for rmdir(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

328
		/** @scrutinizer ignore-unhandled */ @rmdir($current_dir);

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...
329
	}
330
331
	/**
332
	 * Update image information in the database: name, description, status, contest, ...
333
	 *
334
	 * @param int $image_id
335
	 * @param bool $needs_approval
336
	 * @param bool $is_in_contest
337
	 * @return bool
338
	 */
339
	public function update_image($image_id, $needs_approval = false, $is_in_contest = false)
340
	{
341
		if ($this->file_limit && ($this->uploaded_files > $this->file_limit))
342
		{
343
			$this->new_error($this->language->lang('UPLOAD_ERROR', $this->image_data[$image_id]['image_name'], $this->language->lang('QUOTA_REACHED')));
344
			return false;
345
		}
346
		$this->file_count = (int) $this->array_id2row[$image_id];
347
348
		// Create message parser instance
349
		if (!class_exists('parse_message'))
350
		{
351
			include_once($this->root_path . 'includes/message_parser.' . $this->php_ext);
352
		}
353
		$message_parser = new \parse_message();
0 ignored issues
show
Bug introduced by
The type parse_message was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
354
		$message_parser->message	= utf8_normalize_nfc($this->get_description());
0 ignored issues
show
Bug introduced by
The function utf8_normalize_nfc was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

354
		$message_parser->message	= /** @scrutinizer ignore-call */ utf8_normalize_nfc($this->get_description());
Loading history...
355
		if ($message_parser->message)
356
		{
357
			$message_parser->parse(true, true, true, true, false, true, true, true);
358
		}
359
360
		$sql_ary = array(
361
			'image_status'				=> ($needs_approval) ? $this->block->get_image_status_unapproved() : $this->block->get_image_status_approved(),
362
			'image_contest'				=> ($is_in_contest) ? $this->block->get_in_contest() : $this->block->get_no_contest(),
363
			'image_desc'				=> $message_parser->message,
364
			'image_desc_uid'			=> $message_parser->bbcode_uid,
365
			'image_desc_bitfield'		=> $message_parser->bbcode_bitfield,
366
			'image_time'				=> time() + $this->file_count,
367
		);
368
		$new_image_name = $this->get_name();
369
		if (($new_image_name != '') && ($new_image_name != $this->image_data[$image_id]['image_name']))
370
		{
371
			$sql_ary = array_merge($sql_ary, array(
372
				'image_name'		=> $new_image_name,
373
				'image_name_clean'	=> utf8_clean_string($new_image_name),
0 ignored issues
show
Bug introduced by
The function utf8_clean_string was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

373
				'image_name_clean'	=> /** @scrutinizer ignore-call */ utf8_clean_string($new_image_name),
Loading history...
374
			));
375
		}
376
377
		$additional_sql_data = array();
378
		$image_data = $this->image_data[$image_id];
379
		$file_link = $this->gallery_url->path('upload') . $this->image_data[$image_id]['image_filename'];
380
381
		/**
382
		* Event upload image before
383
		*
384
		* @event phpbbgallery.core.upload.update_image_before
385
		* @var	array	additional_sql_data		array of additional settings
386
		* @var	array	image_data				array of image_data
387
		* @var	string	file_link				link to file
388
		* @since 1.2.0
389
		*/
390
		$vars = array('additional_sql_data', 'image_data', 'file_link');
391
		extract($this->phpbb_dispatcher->trigger_event('phpbbgallery.core.upload.update_image_before', compact($vars)));
392
393
		// Rotate image
394
		if (!$this->prepare_file_update($image_id))
395
		{
396
			/**
397
			* Event upload image update
398
			*
399
			* @event phpbbgallery.core.upload.update_image_nofilechange
400
			* @var	array	additional_sql_data		array of additional settings
401
			* @since 1.2.0
402
			*/
403
			$vars = array('additional_sql_data');
404
			extract($this->phpbb_dispatcher->trigger_event('phpbbgallery.core.upload.update_image_nofilechange', compact($vars)));
405
		}
406
407
		$sql_ary = array_merge($sql_ary, $additional_sql_data);
408
409
		$sql = 'UPDATE ' . $this->images_table. ' 
410
			SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . '
411
			WHERE image_id = ' . (int) $image_id;
412
		$this->db->sql_query($sql);
413
414
		return true;
415
	}
416
417
	/**
418
	* Prepare file on upload: rotate and resize
419
	*/
420
	public function prepare_file()
421
	{
422
		$upload_dir = $this->get_current_upload_dir();
423
424
		// Rename the file, move it to the correct location and set chmod
425
		if (!$upload_dir)
426
		{
427
			$this->file->clean_filename('unique_ext');
428
			$this->file->move_file(substr($this->gallery_url->path('upload'), 0, -1), false, false, CHMOD_ALL);
0 ignored issues
show
Bug introduced by
The constant phpbbgallery\core\CHMOD_ALL was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
429
		}
430
		else
431
		{
432
			// Okay, this looks hacky, but what we do here is, we store the directory name in the filename.
433
			// However phpBB strips directories form the filename, when moving, so we need to specify that again.
434
			$this->file->clean_filename('unique_ext', $upload_dir . '/');
435
			$this->file->move_file($this->gallery_url->path('upload_noroot') . $upload_dir, false, false, CHMOD_ALL);
436
		}
437
438
		if (!empty($this->file->error))
439
		{
440
			$this->file->remove();
441
			$this->new_error($this->language->lang('UPLOAD_ERROR', $this->file->get('uploadname'), implode('<br />&raquo; ', $this->file->error)));
442
			return false;
443
		}
444
		@chmod($this->file->get('destination_file'), 0655);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for chmod(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

444
		/** @scrutinizer ignore-unhandled */ @chmod($this->file->get('destination_file'), 0655);

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...
445
		$additional_sql_data = array();
446
		$file = $this->file;
447
448
		/**
449
		* Event upload image update
450
		*
451
		* @event phpbbgallery.core.upload.prepare_file_before
452
		* @var	array	additional_sql_data		array of additional settings
453
		* @var	array	file					File object
454
		* @since 1.2.0
455
		*/
456
		$vars = array('additional_sql_data', 'file');
457
		extract($this->phpbb_dispatcher->trigger_event('phpbbgallery.core.upload.prepare_file_before', compact($vars)));
458
459
		$this->tools->set_image_options($this->max_filesize, $this->gallery_config->get('max_height'), $this->gallery_config->get('max_width'));
460
		$this->tools->set_image_data($this->file->get('destination_file'), '', $this->file->get('filesize'), true);
461
462
		// Rotate the image
463
		if ($this->gallery_config->get('allow_rotate') && $this->get_rotating())
464
		{
465
			$this->tools->rotate_image($this->get_rotating(), $this->gallery_config->get('allow_resize'));
466
			if ($this->tools->rotated)
467
			{
468
				$this->file->height = $this->tools->image_size['height'];
469
				$this->file->width = $this->tools->image_size['width'];
470
			}
471
		}
472
473
		// Resize oversized images
474
		if (($this->file->get('width') > $this->gallery_config->get('max_width')) || ($this->file->get('height') > $this->gallery_config->get('max_height')))
475
		{
476
			if ($this->gallery_config->get('allow_resize'))
477
			{
478
				$this->tools->resize_image($this->gallery_config->get('max_width'), $this->gallery_config->get('max_height'));
479
				if ($this->tools->resized)
480
				{
481
					//$this->file->height = $this->tools->image_size['height'];
482
					//$this->file->width = $this->tools->image_size['width'];
483
				}
484
			}
485
			else
486
			{
487
				$this->file->remove();
488
				$this->new_error($this->language->lang('UPLOAD_ERROR', $this->file->get('uploadname'), $this->language->lang('UPLOAD_IMAGE_SIZE_TOO_BIG')));
489
				return false;
490
			}
491
		}
492
493
		if ($this->file->get('filesize') > (1.2 * $this->max_filesize))
494
		{
495
			$this->file->remove();
496
			$this->new_error($this->language->lang('UPLOAD_ERROR', $this->file->get('uploadname'), $this->language->lang('BAD_UPLOAD_FILE_SIZE')));
497
			return false;
498
		}
499
500
		if ($this->tools->rotated || $this->tools->resized)
501
		{
502
			$this->tools->write_image($this->file->get('destination_file'), $this->gallery_config->get('jpg_quality'), true);
503
		}
504
505
		// Everything okay, now add the file to the database and return the image_id
506
507
		return $this->file_to_database($additional_sql_data);
508
	}
509
510
	/**
511
	 * Prepare file on second upload step.
512
	 * You can still rotate the image there.
513
	 *
514
	 * @param $image_id
515
	 * @return mixed
516
	 */
517
	public function prepare_file_update($image_id)
518
	{
519
		$this->tools->set_image_options($this->max_filesize, $this->gallery_config->get('max_height'), $this->gallery_config->get('max_width'));
520
		$this->tools->set_image_data($this->gallery_url->path('upload') . $this->image_data[$image_id]['image_filename'], '', 0, true);
521
522
		// Rotate the image
523
		if ($this->gallery_config->get('allow_rotate') && $this->get_rotating())
524
		{
525
			$this->tools->rotate_image($this->get_rotating(),$this->gallery_config->get('allow_resize'));
526
			if ($this->tools->rotated)
527
			{
528
				$this->tools->write_image($this->tools->image_source, $this->gallery_config->get('jpg_quality'), true);
529
				@unlink($this->gallery_url->path('thumbnail') . $this->image_data[$image_id]['image_filename']);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for unlink(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

529
				/** @scrutinizer ignore-unhandled */ @unlink($this->gallery_url->path('thumbnail') . $this->image_data[$image_id]['image_filename']);

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...
530
				@unlink($this->gallery_url->path('medium') . $this->image_data[$image_id]['image_filename']);
531
			}
532
		}
533
		return $this->tools->rotated;
534
	}
535
536
	/**
537
	 * Insert the file into the database
538
	 *
539
	 * @param $additional_sql_ary
540
	 * @return int
541
	 */
542
	public function file_to_database($additional_sql_ary)
543
	{
544
		$image_name = str_replace("_", "_", utf8_substr($this->file->get('uploadname'), 0, utf8_strrpos($this->file->get('uploadname'), '.')));
0 ignored issues
show
Bug introduced by
The function utf8_strrpos was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

544
		$image_name = str_replace("_", "_", utf8_substr($this->file->get('uploadname'), 0, /** @scrutinizer ignore-call */ utf8_strrpos($this->file->get('uploadname'), '.')));
Loading history...
Bug introduced by
The function utf8_substr was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

544
		$image_name = str_replace("_", "_", /** @scrutinizer ignore-call */ utf8_substr($this->file->get('uploadname'), 0, utf8_strrpos($this->file->get('uploadname'), '.')));
Loading history...
545
546
		$sql_ary = array_merge(array(
547
			'image_name'			=> $image_name,
548
			'image_name_clean'		=> utf8_clean_string($image_name),
0 ignored issues
show
Bug introduced by
The function utf8_clean_string was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

548
			'image_name_clean'		=> /** @scrutinizer ignore-call */ utf8_clean_string($image_name),
Loading history...
549
			'image_filename' 		=> $this->file->get('realname'),
550
			'filesize_upload'		=> $this->file->get('filesize'),
551
			'image_time'			=> time() + $this->file_count,
552
553
			'image_user_id'			=> $this->user->data['user_id'],
554
			'image_user_colour'		=> $this->user->data['user_colour'],
555
			'image_username'		=> $this->username,
556
			'image_username_clean'	=> utf8_clean_string($this->username),
557
			'image_user_ip'			=> $this->user->ip,
558
559
			'image_album_id'		=> $this->album_id,
560
			'image_status'			=> $this->block->get_image_status_orphan(),
561
			'image_contest'			=> $this->block->get_no_contest(),
562
			'image_allow_comments'	=> $this->allow_comments,
563
			'image_desc'			=> '',
564
			'image_desc_uid'		=> '',
565
			'image_desc_bitfield'	=> '',
566
		), $additional_sql_ary);
567
568
		$sql = 'INSERT INTO ' . $this->images_table . ' ' . $this->db->sql_build_array('INSERT', $sql_ary);
569
		$this->db->sql_query($sql);
570
571
		$image_id = (int) $this->db->sql_nextid();
572
		$this->image_data[$image_id] = $sql_ary;
573
574
		return $image_id;
575
	}
576
577
	/**
578
	 * Delete orphan uploaded files, which are older than half an hour...
579
	 *
580
	 * @param int $time
581
	 */
582
	public function prune_orphan($time = 0)
583
	{
584
		$prunetime = (int) (($time) ? $time : (time() - 1800));
585
586
		$sql = 'SELECT image_id, image_filename
587
			FROM ' . $this->images_table . '
588
			WHERE image_status = ' . (int) $this->block->get_image_status_orphan() . '
589
				AND image_time < ' . (int) $prunetime;
590
		$result = $this->db->sql_query($sql);
591
		$images = $filenames = array();
592
		while ($row = $this->db->sql_fetchrow($result))
593
		{
594
			$images[] = (int) $row['image_id'];
595
			$filenames[(int) $row['image_id']] = $row['image_filename'];
596
		}
597
		$this->db->sql_freeresult($result);
598
599
		if ($images)
600
		{
601
			$this->gallery_image->delete_images($images, $filenames, false);
602
		}
603
	}
604
605
	/**
606
	 * Get the current upload dir (doh!)
607
	 * @return int|mixed|string
608
	 */
609
	private function get_current_upload_dir()
610
	{
611
		if (self::NUM_FILES_PER_DIR <= 0)
612
		{
613
			return 0;
614
		}
615
616
		// This code is never invoked. It's left here for future implementation.
617
		$this->gallery_config->inc('current_upload_dir_size', 1);
618
		if ($this->gallery_config->get('current_upload_dir_size') >= self::NUM_FILES_PER_DIR)
619
		{
620
			$this->gallery_config->set('current_upload_dir_size', 0);
621
			$this->gallery_config->inc('current_upload_dir', 1);
622
			@mkdir($this->gallery_url->path('upload') . $this->gallery_config->get('current_upload_dir'));
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for mkdir(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

622
			/** @scrutinizer ignore-unhandled */ @mkdir($this->gallery_url->path('upload') . $this->gallery_config->get('current_upload_dir'));

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...
623
			@mkdir($this->gallery_url->path('medium') . $this->gallery_config->get('current_upload_dir'));
624
			@mkdir($this->gallery_url->path('thumbnail') . $this->gallery_config->get('current_upload_dir'));
625
			@copy($this->gallery_url->path('upload') . 'index.htm', $this->gallery_url->path('upload') . $this->gallery_config->get('current_upload_dir') . '/index.htm');
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for copy(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

625
			/** @scrutinizer ignore-unhandled */ @copy($this->gallery_url->path('upload') . 'index.htm', $this->gallery_url->path('upload') . $this->gallery_config->get('current_upload_dir') . '/index.htm');

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...
626
			@copy($this->gallery_url->path('upload') . 'index.htm', $this->gallery_url->path('medium') . $this->gallery_config->get('current_upload_dir') . '/index.htm');
627
			@copy($this->gallery_url->path('upload') . 'index.htm', $this->gallery_url->path('thumbnail') . $this->gallery_config->get('current_upload_dir') . '/index.htm');
628
			@copy($this->gallery_url->path('upload') . '.htaccess', $this->gallery_url->path('upload') . $this->gallery_config->get('current_upload_dir') . '/.htaccess');
629
			@copy($this->gallery_url->path('upload') . '.htaccess', $this->gallery_url->path('medium') . $this->gallery_config->get('current_upload_dir') . '/.htaccess');
630
			@copy($this->gallery_url->path('upload') . '.htaccess', $this->gallery_url->path('thumbnail') . $this->gallery_config->get('current_upload_dir') . '/.htaccess');
631
		}
632
		return $this->gallery_config->get('current_upload_dir');
633
	}
634
635
	public function quota_error()
636
	{
637
		if ($this->sent_quota_error)
638
		{
639
			return;
640
		}
641
		$this->new_error($this->language->lang('USER_REACHED_QUOTA_SHORT', $this->file_limit));
642
		$this->sent_quota_error = true;
643
	}
644
645
	public function new_error($error_msg)
646
	{
647
		$this->errors[] = $error_msg;
648
	}
649
650
	public function set_file_limit($num_files)
651
	{
652
		$this->file_limit = (int) $num_files;
653
	}
654
655
	public function set_username($username)
656
	{
657
		$this->username = $username;
658
	}
659
660
	public function set_rotating($data)
661
	{
662
		$this->file_rotating = array_map('intval', $data);
663
	}
664
665
	public function set_allow_comments($value)
666
	{
667
		$this->allow_comments = $value;
668
	}
669
670
	public function set_descriptions($descs)
671
	{
672
		$this->file_descriptions = $descs;
673
	}
674
675
	public function set_names($names)
676
	{
677
		$this->file_names = $names;
678
	}
679
680
	public function set_image_num($num)
681
	{
682
		$this->image_num = (int) $num;
683
	}
684
685
	public function use_same_name($use_same_name)
686
	{
687
		if ($use_same_name)
688
		{
689
			$image_name = $this->file_names[0];
690
			$image_desc = $this->file_descriptions[0];
691
			for ($i = 0; $i < sizeof($this->file_names); $i++)
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function sizeof() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
692
			{
693
				$this->file_names[$i] = str_replace('{NUM}', ($this->image_num + $i), $image_name);
694
				$this->file_descriptions[$i] = str_replace('{NUM}', ($this->image_num + $i), $image_desc);
695
			}
696
		}
697
	}
698
699
	public function get_rotating()
700
	{
701
		if (!isset($this->file_rotating[$this->file_count]))
702
		{
703
			// If the template is still outdated, you'd get an error here...
704
			return 0;
705
		}
706
		if (($this->file_rotating[$this->file_count] % 90) != 0)
707
		{
708
			return 0;
709
		}
710
		return $this->file_rotating[$this->file_count];
711
	}
712
713
	public function get_name()
714
	{
715
		return utf8_normalize_nfc($this->file_names[$this->file_count]);
0 ignored issues
show
Bug introduced by
The function utf8_normalize_nfc was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

715
		return /** @scrutinizer ignore-call */ utf8_normalize_nfc($this->file_names[$this->file_count]);
Loading history...
716
	}
717
718
	public function get_description()
719
	{
720
		if (!isset($this->file_descriptions[$this->file_count]))
721
		{
722
			// If the template is still outdated, you'd get a general error later...
723
			return '';
724
		}
725
		return utf8_normalize_nfc($this->file_descriptions[$this->file_count]);
0 ignored issues
show
Bug introduced by
The function utf8_normalize_nfc was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

725
		return /** @scrutinizer ignore-call */ utf8_normalize_nfc($this->file_descriptions[$this->file_count]);
Loading history...
726
	}
727
728
	public function get_images($uploaded_ids)
729
	{
730
		$image_ids = $filenames = array();
731
		foreach ($uploaded_ids as $row => $check)
732
		{
733
			if (strpos($check, '$') == false)
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing strpos($check, '$') of type integer to the boolean false. If you are specifically checking for 0, consider using something more explicit like === 0 instead.
Loading history...
734
			{
735
				continue;
736
			}
737
			list($image_id, $filename) = explode('$', $check);
738
			$image_ids[] = (int) $image_id;
739
			$filenames[$image_id] = $filename;
740
			$this->array_id2row[$image_id] = $row;
741
		}
742
743
		if (empty($image_ids))
744
		{
745
			return;
746
		}
747
748
		$sql = 'SELECT *
749
			FROM ' . $this->images_table . '
750
			WHERE image_status = ' . (int) $this->block->get_image_status_orphan() . '
751
				AND ' . $this->db->sql_in_set('image_id', $image_ids);
752
		$result = $this->db->sql_query($sql);
753
754
		while ($row = $this->db->sql_fetchrow($result))
755
		{
756
			if ($filenames[$row['image_id']] == substr($row['image_filename'], 0, 8))
757
			{
758
				$this->images[] = (int) $row['image_id'];
759
				$this->image_data[(int) $row['image_id']] = $row;
760
				$this->loaded_files++;
761
			}
762
		}
763
		$this->db->sql_freeresult($result);
764
	}
765
766
	/**
767
	 * Get an array of allowed file types or file extensions
768
	 *
769
	 * @param bool $get_types
770
	 * @param bool $ignore_zip
771
	 * @return array
772
	 */
773
	public function get_allowed_types($get_types = false, $ignore_zip = false)
774
	{
775
		$extensions = $types = array();
776
		if ($this->gallery_config->get('allow_jpg'))
777
		{
778
			$types[] = $this->language->lang('FILETYPES_JPG');
779
			$extensions[] = 'jpg';
780
			$extensions[] = 'jpeg';
781
		}
782
		if ($this->gallery_config->get('allow_gif'))
783
		{
784
			$types[] = $this->language->lang('FILETYPES_GIF');
785
			$extensions[] = 'gif';
786
		}
787
		if ($this->gallery_config->get('allow_png'))
788
		{
789
			$types[] = $this->language->lang('FILETYPES_PNG');
790
			$extensions[] = 'png';
791
		}
792
		if ($this->gallery_config->get('allow_webp'))
793
		{
794
			$types[] = $this->language->lang('FILETYPES_WEBP');
795
			$extensions[] = 'webp';
796
		}
797
		if (!$ignore_zip && $this->gallery_config->get('allow_zip'))
798
		{
799
			$types[] = $this->language->lang('FILETYPES_ZIP');
800
			$extensions[] = 'zip';
801
		}
802
803
		return ($get_types) ? $types : $extensions;
804
	}
805
806
	/**
807
	* Generate some kind of check so users only complete the upload for their images
808
	*/
809
	public function generate_hidden_fields()
810
	{
811
		$checks = array();
812
		foreach ($this->images as $image_id)
813
		{
814
			$checks[] = $image_id . '$' . substr($this->image_data[$image_id]['image_filename'], 0, 8);
815
		}
816
		return $checks;
817
	}
818
819
}
820