Failed Conditions
Push — release-2.1 ( 8d1977...8da17b )
by Rick
06:19
created

resizeImage()   F

Complexity

Conditions 44
Paths 481

Size

Total Lines 116
Code Lines 71

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 44
eloc 71
nop 8
dl 0
loc 116
rs 0.7208
c 0
b 0
f 0
nc 481

How to fix   Long Method    Complexity    Many Parameters   

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:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
/**
4
 * This file deals with low-level graphics operations performed on images,
5
 * specially as needed for avatars (uploaded avatars), attachments, or
6
 * visual verification images.
7
 * It uses, for gifs at least, Gif Util. For more information on that,
8
 * please see its website.
9
 * TrueType fonts supplied by www.LarabieFonts.com
10
 *
11
 * Simple Machines Forum (SMF)
12
 *
13
 * @package SMF
14
 * @author Simple Machines https://www.simplemachines.org
15
 * @copyright 2020 Simple Machines and individual contributors
16
 * @license https://www.simplemachines.org/about/smf/license.php BSD
17
 *
18
 * @version 2.1 RC2
19
 */
20
21
if (!defined('SMF'))
22
	die('No direct access...');
23
24
/**
25
 * downloads a file from a url and stores it locally for avatar use by id_member.
26
 * - supports GIF, JPG, PNG, BMP and WBMP formats.
27
 * - detects if GD2 is available.
28
 * - uses resizeImageFile() to resize to max_width by max_height, and saves the result to a file.
29
 * - updates the database info for the member's avatar.
30
 * - returns whether the download and resize was successful.
31
 *
32
 * @param string $url The full path to the temporary file
33
 * @param int $memID The member ID
34
 * @param int $max_width The maximum allowed width for the avatar
35
 * @param int $max_height The maximum allowed height for the avatar
36
 * @return boolean Whether the download and resize was successful.
37
 *
38
 */
39
function downloadAvatar($url, $memID, $max_width, $max_height)
40
{
41
	global $modSettings, $sourcedir, $smcFunc;
42
43
	$ext = !empty($modSettings['avatar_download_png']) ? 'png' : 'jpeg';
44
	$destName = 'avatar_' . $memID . '_' . time() . '.' . $ext;
45
46
	// Just making sure there is a non-zero member.
47
	if (empty($memID))
48
		return false;
49
50
	require_once($sourcedir . '/ManageAttachments.php');
51
	removeAttachments(array('id_member' => $memID));
52
53
	$id_folder = 1;
54
	$avatar_hash = '';
55
	$attachID = $smcFunc['db_insert']('',
56
		'{db_prefix}attachments',
57
		array(
58
			'id_member' => 'int', 'attachment_type' => 'int', 'filename' => 'string-255', 'file_hash' => 'string-255', 'fileext' => 'string-8', 'size' => 'int',
59
			'id_folder' => 'int',
60
		),
61
		array(
62
			$memID, 1, $destName, $avatar_hash, $ext, 1,
63
			$id_folder,
64
		),
65
		array('id_attach'),
66
		1
67
	);
68
69
	// Retain this globally in case the script wants it.
70
	$modSettings['new_avatar_data'] = array(
71
		'id' => $attachID,
72
		'filename' => $destName,
73
		'type' => 1,
74
	);
75
76
	$destName = $modSettings['custom_avatar_dir'] . '/' . $destName . '.tmp';
77
78
	// Resize it.
79
	if (!empty($modSettings['avatar_download_png']))
80
		$success = resizeImageFile($url, $destName, $max_width, $max_height, 3);
81
	else
82
		$success = resizeImageFile($url, $destName, $max_width, $max_height);
83
84
	// Remove the .tmp extension.
85
	$destName = substr($destName, 0, -4);
86
87
	if ($success)
88
	{
89
		// Remove the .tmp extension from the attachment.
90
		if (rename($destName . '.tmp', $destName))
91
		{
92
			list ($width, $height) = getimagesize($destName);
93
			$mime_type = 'image/' . $ext;
94
95
			// Write filesize in the database.
96
			$smcFunc['db_query']('', '
97
				UPDATE {db_prefix}attachments
98
				SET size = {int:filesize}, width = {int:width}, height = {int:height},
99
					mime_type = {string:mime_type}
100
				WHERE id_attach = {int:current_attachment}',
101
				array(
102
					'filesize' => filesize($destName),
103
					'width' => (int) $width,
104
					'height' => (int) $height,
105
					'current_attachment' => $attachID,
106
					'mime_type' => $mime_type,
107
				)
108
			);
109
			return true;
110
		}
111
		else
112
			return false;
113
	}
114
	else
115
	{
116
		$smcFunc['db_query']('', '
117
			DELETE FROM {db_prefix}attachments
118
			WHERE id_attach = {int:current_attachment}',
119
			array(
120
				'current_attachment' => $attachID,
121
			)
122
		);
123
124
		@unlink($destName . '.tmp');
125
		return false;
126
	}
127
}
128
129
/**
130
 * Create a thumbnail of the given source.
131
 *
132
 * @uses resizeImageFile() function to achieve the resize.
133
 *
134
 * @param string $source The name of the source image
135
 * @param int $max_width The maximum allowed width
136
 * @param int $max_height The maximum allowed height
137
 * @return boolean Whether the thumbnail creation was successful.
138
 */
139
function createThumbnail($source, $max_width, $max_height)
140
{
141
	global $modSettings;
142
143
	$destName = $source . '_thumb.tmp';
144
145
	// Do the actual resize.
146
	if (!empty($modSettings['attachment_thumb_png']))
147
		$success = resizeImageFile($source, $destName, $max_width, $max_height, 3);
148
	else
149
		$success = resizeImageFile($source, $destName, $max_width, $max_height);
150
151
	// Okay, we're done with the temporary stuff.
152
	$destName = substr($destName, 0, -4);
153
154
	if ($success && @rename($destName . '.tmp', $destName))
155
		return true;
156
	else
157
	{
158
		@unlink($destName . '.tmp');
159
		@touch($destName);
160
		return false;
161
	}
162
}
163
164
/**
165
 * Used to re-econodes an image to a specified image format
166
 * - creates a copy of the file at the same location as fileName.
167
 * - the file would have the format preferred_format if possible, otherwise the default format is jpeg.
168
 * - the function makes sure that all non-essential image contents are disposed.
169
 *
170
 * @param string $fileName The path to the file
171
 * @param int $preferred_format The preferred format - 0 to automatically determine, 1 for gif, 2 for jpg, 3 for png, 6 for bmp and 15 for wbmp
172
 * @return boolean Whether the reencoding was successful
173
 */
174
function reencodeImage($fileName, $preferred_format = 0)
175
{
176
	if (!resizeImageFile($fileName, $fileName . '.tmp', null, null, $preferred_format))
177
	{
178
		if (file_exists($fileName . '.tmp'))
179
			unlink($fileName . '.tmp');
180
181
		return false;
182
	}
183
184
	if (!unlink($fileName))
185
		return false;
186
187
	if (!rename($fileName . '.tmp', $fileName))
188
		return false;
189
}
190
191
/**
192
 * Searches through the file to see if there's potentially harmful non-binary content.
193
 * - if extensiveCheck is true, searches for asp/php short tags as well.
194
 *
195
 * @param string $fileName The path to the file
196
 * @param bool $extensiveCheck Whether to perform extensive checks
197
 * @return bool Whether the image appears to be safe
198
 */
199
function checkImageContents($fileName, $extensiveCheck = false)
200
{
201
	$fp = fopen($fileName, 'rb');
202
	if (!$fp)
0 ignored issues
show
introduced by
$fp is of type false|resource, thus it always evaluated to false.
Loading history...
203
		fatal_lang_error('attach_timeout');
204
205
	$prev_chunk = '';
206
	while (!feof($fp))
207
	{
208
		$cur_chunk = fread($fp, 8192);
209
210
		// Though not exhaustive lists, better safe than sorry.
211
		if (!empty($extensiveCheck))
212
		{
213
			// Paranoid check.  Use this if you have reason to distrust your host's security config.
214
			// Will result in MANY false positives, and is not suitable for photography sites.
215
			if (preg_match('~(iframe|\\<\\?|\\<%|html|eval|body|script\W|(?-i)[CFZ]WS[\x01-\x0E])~i', $prev_chunk . $cur_chunk) === 1)
216
			{
217
				fclose($fp);
218
				return false;
219
			}
220
		}
221
		else
222
		{
223
			// Check for potential infection - focus on clues for inline php & flash.
224
			// Will result in significantly fewer false positives than the paranoid check.
225
			if (preg_match('~(\\<\\?php\s|(?-i)[CFZ]WS[\x01-\x0E])~i', $prev_chunk . $cur_chunk) === 1)
226
			{
227
				fclose($fp);
228
				return false;
229
			}
230
		}
231
		$prev_chunk = $cur_chunk;
232
	}
233
	fclose($fp);
234
235
	return true;
236
}
237
238
/**
239
 * Sets a global $gd2 variable needed by some functions to determine
240
 * whether the GD2 library is present.
241
 *
242
 * @return bool Whether or not GD1 is available.
243
 */
244
function checkGD()
245
{
246
	global $gd2;
247
248
	// Check to see if GD is installed and what version.
249
	if (($extensionFunctions = get_extension_funcs('gd')) === false)
250
		return false;
251
252
	// Also determine if GD2 is installed and store it in a global.
253
	$gd2 = in_array('imagecreatetruecolor', $extensionFunctions) && function_exists('imagecreatetruecolor');
254
255
	return true;
256
}
257
258
/**
259
 * Checks whether the Imagick class is present.
260
 *
261
 * @return bool Whether or not the Imagick extension is available.
262
 */
263
function checkImagick()
264
{
265
	return class_exists('Imagick', false);
266
}
267
268
/**
269
 * Checks whether the MagickWand extension is present.
270
 *
271
 * @return bool Whether or not the MagickWand extension is available.
272
 */
273
function checkMagickWand()
274
{
275
	return function_exists('newMagickWand');
276
}
277
278
/**
279
 * See if we have enough memory to thumbnail an image
280
 *
281
 * @param array $sizes image size
282
 * @return bool Whether we do
283
 */
284
function imageMemoryCheck($sizes)
285
{
286
	global $modSettings;
287
288
	// doing the old 'set it and hope' way?
289
	if (empty($modSettings['attachment_thumb_memory']))
290
	{
291
		setMemoryLimit('128M');
292
		return true;
293
	}
294
295
	// Determine the memory requirements for this image, note: if you want to use an image formula W x H x bits/8 x channels x Overhead factor
296
	// you will need to account for single bit images as GD expands them to an 8 bit and will greatly overun the calculated value.  The 5 is
297
	// simply a shortcut of 8bpp, 3 channels, 1.66 overhead
298
	$needed_memory = ($sizes[0] * $sizes[1] * 5);
299
300
	// if we need more, lets try to get it
301
	return setMemoryLimit($needed_memory, true);
302
}
303
304
/**
305
 * Resizes an image from a remote location or a local file.
306
 * Puts the resized image at the destination location.
307
 * The file would have the format preferred_format if possible,
308
 * otherwise the default format is jpeg.
309
 *
310
 * @param string $source The path to the source image
311
 * @param string $destination The path to the destination image
312
 * @param int $max_width The maximum allowed width
313
 * @param int $max_height The maximum allowed height
314
 * @param int $preferred_format - The preferred format (0 to use jpeg, 1 for gif, 2 to force jpeg, 3 for png, 6 for bmp and 15 for wbmp)
315
 * @return bool Whether it succeeded.
316
 */
317
function resizeImageFile($source, $destination, $max_width, $max_height, $preferred_format = 0)
318
{
319
	global $sourcedir;
320
321
	// Nothing to do without GD or IM/MW
322
	if (!checkGD() && !checkImagick() && !checkMagickWand())
323
		return false;
324
325
	static $default_formats = array(
326
		'1' => 'gif',
327
		'2' => 'jpeg',
328
		'3' => 'png',
329
		'6' => 'bmp',
330
		'15' => 'wbmp'
331
	);
332
333
	// Get the image file, we have to work with something after all
334
	$fp_destination = fopen($destination, 'wb');
335
	if ($fp_destination && (substr($source, 0, 7) == 'http://' || substr($source, 0, 8) == 'https://'))
0 ignored issues
show
introduced by
$fp_destination is of type false|resource, thus it always evaluated to false.
Loading history...
336
	{
337
		$fileContents = fetch_web_data($source);
338
339
		$mime_valid = check_mime_type($fileContents, implode('|', array_map('image_type_to_mime_type', array_keys($default_formats))));
340
		if (empty($mime_valid))
341
			return false;
342
343
		fwrite($fp_destination, $fileContents);
344
		fclose($fp_destination);
345
346
		$sizes = @getimagesize($destination);
347
	}
348
	elseif ($fp_destination)
0 ignored issues
show
introduced by
$fp_destination is of type false|resource, thus it always evaluated to false.
Loading history...
349
	{
350
		$mime_valid = check_mime_type($source, implode('|', array_map('image_type_to_mime_type', array_keys($default_formats))), true);
351
		if (empty($mime_valid))
352
			return false;
353
354
		$sizes = @getimagesize($source);
355
356
		$fp_source = fopen($source, 'rb');
357
		if ($fp_source !== false)
358
		{
359
			while (!feof($fp_source))
360
				fwrite($fp_destination, fread($fp_source, 8192));
361
			fclose($fp_source);
362
		}
363
		else
364
			$sizes = array(-1, -1, -1);
365
		fclose($fp_destination);
366
	}
367
368
	// We can't get to the file. or a previous getimagesize failed.
369
	if (empty($sizes))
370
		$sizes = array(-1, -1, -1);
371
372
	// See if we have -or- can get the needed memory for this operation
373
	// ImageMagick isn't subject to PHP's memory limits :)
374
	if (!(checkIMagick() || checkMagickWand()) && checkGD() && !imageMemoryCheck($sizes))
375
		return false;
376
377
	// A known and supported format?
378
	// @todo test PSD and gif.
379
	if ((checkImagick() || checkMagickWand()) && isset($default_formats[$sizes[2]]))
380
	{
381
		return resizeImage(null, $destination, null, null, $max_width, $max_height, true, $preferred_format);
382
	}
383
	elseif (checkGD() && isset($default_formats[$sizes[2]]) && function_exists('imagecreatefrom' . $default_formats[$sizes[2]]))
384
	{
385
		$imagecreatefrom = 'imagecreatefrom' . $default_formats[$sizes[2]];
386
		if ($src_img = @$imagecreatefrom($destination))
387
		{
388
			return resizeImage($src_img, $destination, imagesx($src_img), imagesy($src_img), $max_width === null ? imagesx($src_img) : $max_width, $max_height === null ? imagesy($src_img) : $max_height, true, $preferred_format);
0 ignored issues
show
introduced by
The condition $max_height === null is always false.
Loading history...
introduced by
The condition $max_width === null is always false.
Loading history...
389
		}
390
	}
391
392
	return false;
393
}
394
395
/**
396
 * Resizes src_img proportionally to fit within max_width and max_height limits
397
 * if it is too large.
398
 * If GD2 is present, it'll use it to achieve better quality.
399
 * It saves the new image to destination_filename, as preferred_format
400
 * if possible, default is jpeg.
401
 *
402
 * @uses Imagemagick (IMagick or MagickWand extension) or GD
403
 *
404
 * @param resource $src_img The source image
405
 * @param string $destName The path to the destination image
406
 * @param int $src_width The width of the source image
407
 * @param int $src_height The height of the source image
408
 * @param int $max_width The maximum allowed width
409
 * @param int $max_height The maximum allowed height
410
 * @param bool $force_resize = false Whether to forcibly resize it
411
 * @param int $preferred_format - 1 for gif, 2 for jpeg, 3 for png, 6 for bmp or 15 for wbmp
412
 * @return bool Whether the resize was successful
413
 */
414
function resizeImage($src_img, $destName, $src_width, $src_height, $max_width, $max_height, $force_resize = false, $preferred_format = 0)
415
{
416
	global $gd2, $modSettings;
417
418
	if (checkImagick() || checkMagickWand())
419
	{
420
		static $default_formats = array(
421
			'1' => 'gif',
422
			'2' => 'jpeg',
423
			'3' => 'png',
424
			'6' => 'bmp',
425
			'15' => 'wbmp'
426
		);
427
		$preferred_format = empty($preferred_format) || !isset($default_formats[$preferred_format]) ? 2 : $preferred_format;
428
429
		if (checkImagick())
430
		{
431
			$imagick = New Imagick($destName);
432
			$src_width = empty($src_width) ? $imagick->getImageWidth() : $src_width;
433
			$src_height = empty($src_height) ? $imagick->getImageHeight() : $src_height;
434
			$dest_width = empty($max_width) ? $src_width : $max_width;
435
			$dest_height = empty($max_height) ? $src_height : $max_height;
436
437
			if ($default_formats[$preferred_format] == 'jpeg')
438
				$imagick->setCompressionQuality(!empty($modSettings['avatar_jpeg_quality']) ? $modSettings['avatar_jpeg_quality'] : 82);
439
440
			$imagick->setImageFormat($default_formats[$preferred_format]);
441
			$imagick->resizeImage($dest_width, $dest_height, Imagick::FILTER_LANCZOS, 1, true);
442
			$success = $imagick->writeImage($destName);
443
		}
444
		else
445
		{
446
			$magick_wand = newMagickWand();
0 ignored issues
show
Bug introduced by
The function newMagickWand 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

446
			$magick_wand = /** @scrutinizer ignore-call */ newMagickWand();
Loading history...
447
			MagickReadImage($magick_wand, $destName);
0 ignored issues
show
Bug introduced by
The function MagickReadImage 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

447
			/** @scrutinizer ignore-call */ 
448
   MagickReadImage($magick_wand, $destName);
Loading history...
448
			$src_width = empty($src_width) ? MagickGetImageWidth($magick_wand) : $src_width;
0 ignored issues
show
Bug introduced by
The function MagickGetImageWidth 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

448
			$src_width = empty($src_width) ? /** @scrutinizer ignore-call */ MagickGetImageWidth($magick_wand) : $src_width;
Loading history...
449
			$src_height = empty($src_height) ? MagickGetImageSize($magick_wand) : $src_height;
0 ignored issues
show
Bug introduced by
The function MagickGetImageSize 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

449
			$src_height = empty($src_height) ? /** @scrutinizer ignore-call */ MagickGetImageSize($magick_wand) : $src_height;
Loading history...
450
			$dest_width = empty($max_width) ? $src_width : $max_width;
451
			$dest_height = empty($max_height) ? $src_height : $max_height;
452
453
			if ($default_formats[$preferred_format] == 'jpeg')
454
				MagickSetCompressionQuality($magick_wand, !empty($modSettings['avatar_jpeg_quality']) ? $modSettings['avatar_jpeg_quality'] : 82);
0 ignored issues
show
Bug introduced by
The function MagickSetCompressionQuality 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

454
				/** @scrutinizer ignore-call */ 
455
    MagickSetCompressionQuality($magick_wand, !empty($modSettings['avatar_jpeg_quality']) ? $modSettings['avatar_jpeg_quality'] : 82);
Loading history...
455
456
			MagickSetImageFormat($magick_wand, $default_formats[$preferred_format]);
0 ignored issues
show
Bug introduced by
The function MagickSetImageFormat 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

456
			/** @scrutinizer ignore-call */ 
457
   MagickSetImageFormat($magick_wand, $default_formats[$preferred_format]);
Loading history...
457
			MagickResizeImage($magick_wand, $dest_width, $dest_height, MW_LanczosFilter, 1, true);
0 ignored issues
show
Bug introduced by
The function MagickResizeImage 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

457
			/** @scrutinizer ignore-call */ 
458
   MagickResizeImage($magick_wand, $dest_width, $dest_height, MW_LanczosFilter, 1, true);
Loading history...
Bug introduced by
The constant MW_LanczosFilter was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
458
			$success = MagickWriteImage($magick_wand, $destName);
0 ignored issues
show
Bug introduced by
The function MagickWriteImage 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

458
			$success = /** @scrutinizer ignore-call */ MagickWriteImage($magick_wand, $destName);
Loading history...
459
		}
460
461
		return !empty($success);
462
	}
463
	elseif (checkGD())
464
	{
465
		$success = false;
466
467
		// Determine whether to resize to max width or to max height (depending on the limits.)
468
		if (!empty($max_width) || !empty($max_height))
469
		{
470
			if (!empty($max_width) && (empty($max_height) || round($src_height * $max_width / $src_width) <= $max_height))
471
			{
472
				$dst_width = $max_width;
473
				$dst_height = round($src_height * $max_width / $src_width);
474
			}
475
			elseif (!empty($max_height))
476
			{
477
				$dst_width = round($src_width * $max_height / $src_height);
478
				$dst_height = $max_height;
479
			}
480
481
			// Don't bother resizing if it's already smaller...
482
			if (!empty($dst_width) && !empty($dst_height) && ($dst_width < $src_width || $dst_height < $src_height || $force_resize))
483
			{
484
				// (make a true color image, because it just looks better for resizing.)
485
				if ($gd2)
486
				{
487
					$dst_img = imagecreatetruecolor($dst_width, $dst_height);
488
489
					// Deal nicely with a PNG - because we can.
490
					if ((!empty($preferred_format)) && ($preferred_format == 3))
491
					{
492
						imagealphablending($dst_img, false);
0 ignored issues
show
Bug introduced by
It seems like $dst_img can also be of type false; however, parameter $image of imagealphablending() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

492
						imagealphablending(/** @scrutinizer ignore-type */ $dst_img, false);
Loading history...
493
						if (function_exists('imagesavealpha'))
494
							imagesavealpha($dst_img, true);
0 ignored issues
show
Bug introduced by
It seems like $dst_img can also be of type false; however, parameter $image of imagesavealpha() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

494
							imagesavealpha(/** @scrutinizer ignore-type */ $dst_img, true);
Loading history...
495
					}
496
				}
497
				else
498
					$dst_img = imagecreate($dst_width, $dst_height);
499
500
				// Resize it!
501
				if ($gd2)
502
					imagecopyresampled($dst_img, $src_img, 0, 0, 0, 0, $dst_width, $dst_height, $src_width, $src_height);
0 ignored issues
show
Bug introduced by
It seems like $dst_img can also be of type false; however, parameter $dst_image of imagecopyresampled() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

502
					imagecopyresampled(/** @scrutinizer ignore-type */ $dst_img, $src_img, 0, 0, 0, 0, $dst_width, $dst_height, $src_width, $src_height);
Loading history...
503
				else
504
					imagecopyresamplebicubic($dst_img, $src_img, 0, 0, 0, 0, $dst_width, $dst_height, $src_width, $src_height);
0 ignored issues
show
Bug introduced by
It seems like $dst_img can also be of type false; however, parameter $dst_img of imagecopyresamplebicubic() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

504
					imagecopyresamplebicubic(/** @scrutinizer ignore-type */ $dst_img, $src_img, 0, 0, 0, 0, $dst_width, $dst_height, $src_width, $src_height);
Loading history...
505
			}
506
			else
507
				$dst_img = $src_img;
508
		}
509
		else
510
			$dst_img = $src_img;
511
512
		// Save the image as ...
513
		if (!empty($preferred_format) && ($preferred_format == 3) && function_exists('imagepng'))
514
			$success = imagepng($dst_img, $destName);
0 ignored issues
show
Bug introduced by
It seems like $dst_img can also be of type false; however, parameter $image of imagepng() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

514
			$success = imagepng(/** @scrutinizer ignore-type */ $dst_img, $destName);
Loading history...
515
		elseif (!empty($preferred_format) && ($preferred_format == 1) && function_exists('imagegif'))
516
			$success = imagegif($dst_img, $destName);
0 ignored issues
show
Bug introduced by
It seems like $dst_img can also be of type false; however, parameter $image of imagegif() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

516
			$success = imagegif(/** @scrutinizer ignore-type */ $dst_img, $destName);
Loading history...
517
		elseif (function_exists('imagejpeg'))
518
			$success = imagejpeg($dst_img, $destName, !empty($modSettings['avatar_jpeg_quality']) ? $modSettings['avatar_jpeg_quality'] : 82);
0 ignored issues
show
Bug introduced by
It seems like $dst_img can also be of type false; however, parameter $image of imagejpeg() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

518
			$success = imagejpeg(/** @scrutinizer ignore-type */ $dst_img, $destName, !empty($modSettings['avatar_jpeg_quality']) ? $modSettings['avatar_jpeg_quality'] : 82);
Loading history...
519
520
		// Free the memory.
521
		imagedestroy($src_img);
522
		if ($dst_img != $src_img)
523
			imagedestroy($dst_img);
0 ignored issues
show
Bug introduced by
It seems like $dst_img can also be of type false; however, parameter $image of imagedestroy() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

523
			imagedestroy(/** @scrutinizer ignore-type */ $dst_img);
Loading history...
524
525
		return $success;
526
	}
527
	else
528
		// Without GD, no image resizing at all.
529
		return false;
530
}
531
532
/**
533
 * Copy image.
534
 * Used when imagecopyresample() is not available.
535
 *
536
 * @param resource $dst_img The destination image - a GD image resource
537
 * @param resource $src_img The source image - a GD image resource
538
 * @param int $dst_x The "x" coordinate of the destination image
539
 * @param int $dst_y The "y" coordinate of the destination image
540
 * @param int $src_x The "x" coordinate of the source image
541
 * @param int $src_y The "y" coordinate of the source image
542
 * @param int $dst_w The width of the destination image
543
 * @param int $dst_h The height of the destination image
544
 * @param int $src_w The width of the destination image
545
 * @param int $src_h The height of the destination image
546
 */
547
function imagecopyresamplebicubic($dst_img, $src_img, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h)
548
{
549
	$palsize = imagecolorstotal($src_img);
550
	for ($i = 0; $i < $palsize; $i++)
551
	{
552
		$colors = imagecolorsforindex($src_img, $i);
553
		imagecolorallocate($dst_img, $colors['red'], $colors['green'], $colors['blue']);
554
	}
555
556
	$scaleX = ($src_w - 1) / $dst_w;
557
	$scaleY = ($src_h - 1) / $dst_h;
558
559
	$scaleX2 = (int) $scaleX / 2;
560
	$scaleY2 = (int) $scaleY / 2;
561
562
	for ($j = $src_y; $j < $dst_h; $j++)
563
	{
564
		$sY = (int) $j * $scaleY;
565
		$y13 = $sY + $scaleY2;
566
567
		for ($i = $src_x; $i < $dst_w; $i++)
568
		{
569
			$sX = (int) $i * $scaleX;
570
			$x34 = $sX + $scaleX2;
571
572
			$color1 = imagecolorsforindex($src_img, imagecolorat($src_img, $sX, $y13));
573
			$color2 = imagecolorsforindex($src_img, imagecolorat($src_img, $sX, $sY));
574
			$color3 = imagecolorsforindex($src_img, imagecolorat($src_img, $x34, $y13));
575
			$color4 = imagecolorsforindex($src_img, imagecolorat($src_img, $x34, $sY));
576
577
			$red = ($color1['red'] + $color2['red'] + $color3['red'] + $color4['red']) / 4;
578
			$green = ($color1['green'] + $color2['green'] + $color3['green'] + $color4['green']) / 4;
579
			$blue = ($color1['blue'] + $color2['blue'] + $color3['blue'] + $color4['blue']) / 4;
580
581
			$color = imagecolorresolve($dst_img, $red, $green, $blue);
582
			if ($color == -1)
583
			{
584
				if ($palsize++ < 256)
585
					imagecolorallocate($dst_img, $red, $green, $blue);
586
				$color = imagecolorclosest($dst_img, $red, $green, $blue);
587
			}
588
589
			imagesetpixel($dst_img, $i + $dst_x - $src_x, $j + $dst_y - $src_y, $color);
590
		}
591
	}
592
}
593
594
if (!function_exists('imagecreatefrombmp'))
595
{
596
	/**
597
	 * It is set only if it doesn't already exist (for forwards compatiblity.)
598
	 * It only supports uncompressed bitmaps.
599
	 *
600
	 * @param string $filename The name of the file
601
	 * @return resource An image identifier representing the bitmap image
602
	 * obtained from the given filename.
603
	 */
604
	function imagecreatefrombmp($filename)
605
	{
606
		global $gd2;
607
608
		$fp = fopen($filename, 'rb');
609
610
		$errors = error_reporting(0);
611
612
		$header = unpack('vtype/Vsize/Vreserved/Voffset', fread($fp, 14));
0 ignored issues
show
Bug introduced by
It seems like $fp can also be of type false; however, parameter $handle of fread() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

612
		$header = unpack('vtype/Vsize/Vreserved/Voffset', fread(/** @scrutinizer ignore-type */ $fp, 14));
Loading history...
613
		$info = unpack('Vsize/Vwidth/Vheight/vplanes/vbits/Vcompression/Vimagesize/Vxres/Vyres/Vncolor/Vcolorimportant', fread($fp, 40));
614
615
		if ($header['type'] != 0x4D42)
616
			return false;
617
618
		if ($gd2)
619
			$dst_img = imagecreatetruecolor($info['width'], $info['height']);
620
		else
621
			$dst_img = imagecreate($info['width'], $info['height']);
622
623
		$palette_size = $header['offset'] - 54;
624
		$info['ncolor'] = $palette_size / 4;
625
626
		$palette = array();
627
628
		$palettedata = fread($fp, $palette_size);
629
		$n = 0;
630
		for ($j = 0; $j < $palette_size; $j++)
631
		{
632
			$b = ord($palettedata[$j++]);
633
			$g = ord($palettedata[$j++]);
634
			$r = ord($palettedata[$j++]);
635
636
			$palette[$n++] = imagecolorallocate($dst_img, $r, $g, $b);
0 ignored issues
show
Bug introduced by
It seems like $dst_img can also be of type false; however, parameter $image of imagecolorallocate() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

636
			$palette[$n++] = imagecolorallocate(/** @scrutinizer ignore-type */ $dst_img, $r, $g, $b);
Loading history...
637
		}
638
639
		$scan_line_size = ($info['bits'] * $info['width'] + 7) >> 3;
640
		$scan_line_align = $scan_line_size & 3 ? 4 - ($scan_line_size & 3) : 0;
641
642
		for ($y = 0, $l = $info['height'] - 1; $y < $info['height']; $y++, $l--)
643
		{
644
			fseek($fp, $header['offset'] + ($scan_line_size + $scan_line_align) * $l);
0 ignored issues
show
Bug introduced by
It seems like $fp can also be of type false; however, parameter $handle of fseek() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

644
			fseek(/** @scrutinizer ignore-type */ $fp, $header['offset'] + ($scan_line_size + $scan_line_align) * $l);
Loading history...
645
			$scan_line = fread($fp, $scan_line_size);
646
647
			if (strlen($scan_line) < $scan_line_size)
648
				continue;
649
650
			if ($info['bits'] == 32)
651
			{
652
				$x = 0;
653
				for ($j = 0; $j < $scan_line_size; $x++)
654
				{
655
					$b = ord($scan_line[$j++]);
656
					$g = ord($scan_line[$j++]);
657
					$r = ord($scan_line[$j++]);
658
					$j++;
659
660
					$color = imagecolorexact($dst_img, $r, $g, $b);
0 ignored issues
show
Bug introduced by
It seems like $dst_img can also be of type false; however, parameter $image of imagecolorexact() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

660
					$color = imagecolorexact(/** @scrutinizer ignore-type */ $dst_img, $r, $g, $b);
Loading history...
661
					if ($color == -1)
662
					{
663
						$color = imagecolorallocate($dst_img, $r, $g, $b);
664
665
						// Gah!  Out of colors?  Stupid GD 1... try anyhow.
666
						if ($color == -1)
667
							$color = imagecolorclosest($dst_img, $r, $g, $b);
0 ignored issues
show
Bug introduced by
It seems like $dst_img can also be of type false; however, parameter $image of imagecolorclosest() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

667
							$color = imagecolorclosest(/** @scrutinizer ignore-type */ $dst_img, $r, $g, $b);
Loading history...
668
					}
669
670
					imagesetpixel($dst_img, $x, $y, $color);
0 ignored issues
show
Bug introduced by
It seems like $dst_img can also be of type false; however, parameter $image of imagesetpixel() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

670
					imagesetpixel(/** @scrutinizer ignore-type */ $dst_img, $x, $y, $color);
Loading history...
671
				}
672
			}
673
			elseif ($info['bits'] == 24)
674
			{
675
				$x = 0;
676
				for ($j = 0; $j < $scan_line_size; $x++)
677
				{
678
					$b = ord($scan_line[$j++]);
679
					$g = ord($scan_line[$j++]);
680
					$r = ord($scan_line[$j++]);
681
682
					$color = imagecolorexact($dst_img, $r, $g, $b);
683
					if ($color == -1)
684
					{
685
						$color = imagecolorallocate($dst_img, $r, $g, $b);
686
687
						// Gah!  Out of colors?  Stupid GD 1... try anyhow.
688
						if ($color == -1)
689
							$color = imagecolorclosest($dst_img, $r, $g, $b);
690
					}
691
692
					imagesetpixel($dst_img, $x, $y, $color);
693
				}
694
			}
695
			elseif ($info['bits'] == 16)
696
			{
697
				$x = 0;
698
				for ($j = 0; $j < $scan_line_size; $x++)
699
				{
700
					$b1 = ord($scan_line[$j++]);
701
					$b2 = ord($scan_line[$j++]);
702
703
					$word = $b2 * 256 + $b1;
704
705
					$b = (($word & 31) * 255) / 31;
706
					$g = ((($word >> 5) & 31) * 255) / 31;
707
					$r = ((($word >> 10) & 31) * 255) / 31;
708
709
					// Scale the image colors up properly.
710
					$color = imagecolorexact($dst_img, $r, $g, $b);
711
					if ($color == -1)
712
					{
713
						$color = imagecolorallocate($dst_img, $r, $g, $b);
714
715
						// Gah!  Out of colors?  Stupid GD 1... try anyhow.
716
						if ($color == -1)
717
							$color = imagecolorclosest($dst_img, $r, $g, $b);
718
					}
719
720
					imagesetpixel($dst_img, $x, $y, $color);
721
				}
722
			}
723
			elseif ($info['bits'] == 8)
724
			{
725
				$x = 0;
726
				for ($j = 0; $j < $scan_line_size; $x++)
727
					imagesetpixel($dst_img, $x, $y, $palette[ord($scan_line[$j++])]);
728
			}
729
			elseif ($info['bits'] == 4)
730
			{
731
				$x = 0;
732
				for ($j = 0; $j < $scan_line_size; $x++)
733
				{
734
					$byte = ord($scan_line[$j++]);
735
736
					imagesetpixel($dst_img, $x, $y, $palette[(int) ($byte / 16)]);
737
738
					if (++$x < $info['width'])
739
						imagesetpixel($dst_img, $x, $y, $palette[$byte & 15]);
740
				}
741
			}
742
			elseif ($info['bits'] == 1)
743
			{
744
				$x = 0;
745
				for ($j = 0; $j < $scan_line_size; $x++)
746
				{
747
					$byte = ord($scan_line[$j++]);
748
749
					imagesetpixel($dst_img, $x, $y, $palette[(($byte) & 128) != 0]);
750
751
					for ($shift = 1; $shift < 8; $shift++)
752
					{
753
						if (++$x < $info['width'])
754
							imagesetpixel($dst_img, $x, $y, $palette[(($byte << $shift) & 128) != 0]);
755
					}
756
				}
757
			}
758
		}
759
760
		fclose($fp);
0 ignored issues
show
Bug introduced by
It seems like $fp can also be of type false; however, parameter $handle of fclose() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

760
		fclose(/** @scrutinizer ignore-type */ $fp);
Loading history...
761
762
		error_reporting($errors);
763
764
		return $dst_img;
765
	}
766
}
767
768
/**
769
 * Writes a gif file to disk as a png file.
770
 *
771
 * @param gif_file $gif A gif image resource
772
 * @param string $lpszFileName The name of the file
773
 * @param int $background_color The background color
774
 * @return bool Whether the operation was successful
775
 */
776
function gif_outputAsPng($gif, $lpszFileName, $background_color = -1)
777
{
778
	if (!is_a($gif, 'gif_file') || $lpszFileName == '')
779
		return false;
780
781
	if (($fd = $gif->get_png_data($background_color)) === false)
782
		return false;
783
784
	if (($fh = @fopen($lpszFileName, 'wb')) === false)
785
		return false;
786
787
	@fwrite($fh, $fd, strlen($fd));
788
	@fflush($fh);
789
	@fclose($fh);
790
791
	return true;
792
}
793
794
/**
795
 * Show an image containing the visual verification code for registration.
796
 * Requires the GD extension.
797
 * Uses a random font for each letter from default_theme_dir/fonts.
798
 * Outputs a gif or a png (depending on whether gif ix supported).
799
 *
800
 * @param string $code The code to display
801
 * @return void|false False if something goes wrong.
802
 */
803
function showCodeImage($code)
804
{
805
	global $gd2, $settings, $user_info, $modSettings;
806
807
	// Note: The higher the value of visual_verification_type the harder the verification is - from 0 as disabled through to 4 as "Very hard".
808
809
	// What type are we going to be doing?
810
	$imageType = $modSettings['visual_verification_type'];
811
	// Special case to allow the admin center to show samples.
812
	if ($user_info['is_admin'] && isset($_GET['type']))
813
		$imageType = (int) $_GET['type'];
814
815
	// Some quick references for what we do.
816
	// Do we show no, low or high noise?
817
	$noiseType = $imageType == 3 ? 'low' : ($imageType == 4 ? 'high' : ($imageType == 5 ? 'extreme' : 'none'));
818
	// Can we have more than one font in use?
819
	$varyFonts = $imageType > 3 ? true : false;
820
	// Just a plain white background?
821
	$simpleBGColor = $imageType < 3 ? true : false;
822
	// Plain black foreground?
823
	$simpleFGColor = $imageType == 0 ? true : false;
824
	// High much to rotate each character.
825
	$rotationType = $imageType == 1 ? 'none' : ($imageType > 3 ? 'low' : 'high');
826
	// Do we show some characters inversed?
827
	$showReverseChars = $imageType > 3 ? true : false;
828
	// Special case for not showing any characters.
829
	$disableChars = $imageType == 0 ? true : false;
830
	// What do we do with the font colors. Are they one color, close to one color or random?
831
	$fontColorType = $imageType == 1 ? 'plain' : ($imageType > 3 ? 'random' : 'cyclic');
832
	// Are the fonts random sizes?
833
	$fontSizeRandom = $imageType > 3 ? true : false;
834
	// How much space between characters?
835
	$fontHorSpace = $imageType > 3 ? 'high' : ($imageType == 1 ? 'medium' : 'minus');
836
	// Where do characters sit on the image? (Fixed position or random/very random)
837
	$fontVerPos = $imageType == 1 ? 'fixed' : ($imageType > 3 ? 'vrandom' : 'random');
838
	// Make font semi-transparent?
839
	$fontTrans = $imageType == 2 || $imageType == 3 ? true : false;
840
	// Give the image a border?
841
	$hasBorder = $simpleBGColor;
842
843
	// The amount of pixels inbetween characters.
844
	$character_spacing = 1;
845
846
	// What color is the background - generally white unless we're on "hard".
847
	if ($simpleBGColor)
848
		$background_color = array(255, 255, 255);
849
	else
850
		$background_color = isset($settings['verification_background']) ? $settings['verification_background'] : array(236, 237, 243);
851
852
	// The color of the characters shown (red, green, blue).
853
	if ($simpleFGColor)
854
		$foreground_color = array(0, 0, 0);
855
	else
856
	{
857
		$foreground_color = array(64, 101, 136);
858
859
		// Has the theme author requested a custom color?
860
		if (isset($settings['verification_foreground']))
861
			$foreground_color = $settings['verification_foreground'];
862
	}
863
864
	if (!is_dir($settings['default_theme_dir'] . '/fonts'))
865
		return false;
866
867
	// Get a list of the available fonts.
868
	$font_dir = dir($settings['default_theme_dir'] . '/fonts');
869
	$font_list = array();
870
	$ttfont_list = array();
871
	$endian = unpack('v', pack('S', 0x00FF)) === 0x00FF;
872
	while ($entry = $font_dir->read())
873
	{
874
		if (preg_match('~^(.+)\.gdf$~', $entry, $matches) === 1)
875
		{
876
			if ($endian ^ (strpos($entry, '_end.gdf') === false))
877
				$font_list[] = $entry;
878
		}
879
		elseif (preg_match('~^(.+)\.ttf$~', $entry, $matches) === 1)
880
			$ttfont_list[] = $entry;
881
	}
882
883
	if (empty($font_list))
884
		return false;
885
886
	// For non-hard things don't even change fonts.
887
	if (!$varyFonts)
888
	{
889
		$font_list = array($font_list[0]);
890
		// Try use Screenge if we can - it looks good!
891
		if (in_array('AnonymousPro.ttf', $ttfont_list))
892
			$ttfont_list = array('AnonymousPro.ttf');
893
		else
894
			$ttfont_list = empty($ttfont_list) ? array() : array($ttfont_list[0]);
895
	}
896
897
	// Create a list of characters to be shown.
898
	$characters = array();
899
	$loaded_fonts = array();
900
	for ($i = 0; $i < strlen($code); $i++)
901
	{
902
		$characters[$i] = array(
903
			'id' => $code[$i],
904
			'font' => array_rand($font_list),
905
		);
906
907
		$loaded_fonts[$characters[$i]['font']] = null;
908
	}
909
910
	// Load all fonts and determine the maximum font height.
911
	foreach ($loaded_fonts as $font_index => $dummy)
912
		$loaded_fonts[$font_index] = imageloadfont($settings['default_theme_dir'] . '/fonts/' . $font_list[$font_index]);
913
914
	// Determine the dimensions of each character.
915
	if ($imageType == 4 || $imageType == 5)
916
		$extra = 80;
917
	else
918
		$extra = 45;
919
920
	$total_width = $character_spacing * strlen($code) + $extra;
921
	$max_height = 0;
922
	foreach ($characters as $char_index => $character)
923
	{
924
		$characters[$char_index]['width'] = imagefontwidth($loaded_fonts[$character['font']]);
925
		$characters[$char_index]['height'] = imagefontheight($loaded_fonts[$character['font']]);
926
927
		$max_height = max($characters[$char_index]['height'] + 5, $max_height);
928
		$total_width += $characters[$char_index]['width'];
929
	}
930
931
	// Create an image.
932
	$code_image = $gd2 ? imagecreatetruecolor($total_width, $max_height) : imagecreate($total_width, $max_height);
933
934
	// Draw the background.
935
	$bg_color = imagecolorallocate($code_image, $background_color[0], $background_color[1], $background_color[2]);
0 ignored issues
show
Bug introduced by
It seems like $code_image can also be of type false; however, parameter $image of imagecolorallocate() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

935
	$bg_color = imagecolorallocate(/** @scrutinizer ignore-type */ $code_image, $background_color[0], $background_color[1], $background_color[2]);
Loading history...
936
	imagefilledrectangle($code_image, 0, 0, $total_width - 1, $max_height - 1, $bg_color);
0 ignored issues
show
Bug introduced by
It seems like $code_image can also be of type false; however, parameter $image of imagefilledrectangle() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

936
	imagefilledrectangle(/** @scrutinizer ignore-type */ $code_image, 0, 0, $total_width - 1, $max_height - 1, $bg_color);
Loading history...
937
938
	// Randomize the foreground color a little.
939
	for ($i = 0; $i < 3; $i++)
940
		$foreground_color[$i] = mt_rand(max($foreground_color[$i] - 3, 0), min($foreground_color[$i] + 3, 255));
941
	$fg_color = imagecolorallocate($code_image, $foreground_color[0], $foreground_color[1], $foreground_color[2]);
942
943
	// Color for the dots.
944
	for ($i = 0; $i < 3; $i++)
945
		$dotbgcolor[$i] = $background_color[$i] < $foreground_color[$i] ? mt_rand(0, max($foreground_color[$i] - 20, 0)) : mt_rand(min($foreground_color[$i] + 20, 255), 255);
946
	$randomness_color = imagecolorallocate($code_image, $dotbgcolor[0], $dotbgcolor[1], $dotbgcolor[2]);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $dotbgcolor does not seem to be defined for all execution paths leading up to this point.
Loading history...
947
948
	// Some squares/rectanges for new extreme level
949
	if ($noiseType == 'extreme')
950
	{
951
		for ($i = 0; $i < mt_rand(1, 5); $i++)
952
		{
953
			$x1 = mt_rand(0, $total_width / 4);
954
			$x2 = $x1 + round(rand($total_width / 4, $total_width));
955
			$y1 = mt_rand(0, $max_height);
956
			$y2 = $y1 + round(rand(0, $max_height / 3));
957
			imagefilledrectangle($code_image, $x1, $y1, $x2, $y2, mt_rand(0, 1) ? $fg_color : $randomness_color);
0 ignored issues
show
Bug introduced by
$y2 of type double is incompatible with the type integer expected by parameter $y2 of imagefilledrectangle(). ( Ignorable by Annotation )

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

957
			imagefilledrectangle($code_image, $x1, $y1, $x2, /** @scrutinizer ignore-type */ $y2, mt_rand(0, 1) ? $fg_color : $randomness_color);
Loading history...
Bug introduced by
$x2 of type double is incompatible with the type integer expected by parameter $x2 of imagefilledrectangle(). ( Ignorable by Annotation )

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

957
			imagefilledrectangle($code_image, $x1, $y1, /** @scrutinizer ignore-type */ $x2, $y2, mt_rand(0, 1) ? $fg_color : $randomness_color);
Loading history...
958
		}
959
	}
960
961
	// Fill in the characters.
962
	if (!$disableChars)
963
	{
964
		$cur_x = 0;
965
		foreach ($characters as $char_index => $character)
966
		{
967
			// Can we use true type fonts?
968
			$can_do_ttf = function_exists('imagettftext');
969
970
			// How much rotation will we give?
971
			if ($rotationType == 'none')
972
				$angle = 0;
973
			else
974
				$angle = mt_rand(-100, 100) / ($rotationType == 'high' ? 6 : 10);
975
976
			// What color shall we do it?
977
			if ($fontColorType == 'cyclic')
978
			{
979
				// Here we'll pick from a set of acceptance types.
980
				$colors = array(
981
					array(10, 120, 95),
982
					array(46, 81, 29),
983
					array(4, 22, 154),
984
					array(131, 9, 130),
985
					array(0, 0, 0),
986
					array(143, 39, 31),
987
				);
988
				if (!isset($last_index))
989
					$last_index = -1;
990
				$new_index = $last_index;
991
				while ($last_index == $new_index)
992
					$new_index = mt_rand(0, count($colors) - 1);
993
				$char_fg_color = $colors[$new_index];
994
				$last_index = $new_index;
995
			}
996
			elseif ($fontColorType == 'random')
997
				$char_fg_color = array(mt_rand(max($foreground_color[0] - 2, 0), $foreground_color[0]), mt_rand(max($foreground_color[1] - 2, 0), $foreground_color[1]), mt_rand(max($foreground_color[2] - 2, 0), $foreground_color[2]));
998
			else
999
				$char_fg_color = array($foreground_color[0], $foreground_color[1], $foreground_color[2]);
1000
1001
			if (!empty($can_do_ttf))
1002
			{
1003
				// GD2 handles font size differently.
1004
				if ($fontSizeRandom)
1005
					$font_size = $gd2 ? mt_rand(17, 19) : mt_rand(18, 25);
1006
				else
1007
					$font_size = $gd2 ? 18 : 24;
1008
1009
				// Work out the sizes - also fix the character width cause TTF not quite so wide!
1010
				$font_x = $fontHorSpace == 'minus' && $cur_x > 0 ? $cur_x - 3 : $cur_x + 5;
1011
				$font_y = $max_height - ($fontVerPos == 'vrandom' ? mt_rand(2, 8) : ($fontVerPos == 'random' ? mt_rand(3, 5) : 5));
1012
1013
				// What font face?
1014
				if (!empty($ttfont_list))
1015
					$fontface = $settings['default_theme_dir'] . '/fonts/' . $ttfont_list[mt_rand(0, count($ttfont_list) - 1)];
1016
1017
				// What color are we to do it in?
1018
				$is_reverse = $showReverseChars ? mt_rand(0, 1) : false;
1019
				$char_color = function_exists('imagecolorallocatealpha') && $fontTrans ? imagecolorallocatealpha($code_image, $char_fg_color[0], $char_fg_color[1], $char_fg_color[2], 50) : imagecolorallocate($code_image, $char_fg_color[0], $char_fg_color[1], $char_fg_color[2]);
0 ignored issues
show
Bug introduced by
It seems like $code_image can also be of type false; however, parameter $image of imagecolorallocatealpha() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

1019
				$char_color = function_exists('imagecolorallocatealpha') && $fontTrans ? imagecolorallocatealpha(/** @scrutinizer ignore-type */ $code_image, $char_fg_color[0], $char_fg_color[1], $char_fg_color[2], 50) : imagecolorallocate($code_image, $char_fg_color[0], $char_fg_color[1], $char_fg_color[2]);
Loading history...
1020
1021
				$fontcord = @imagettftext($code_image, $font_size, $angle, $font_x, $font_y, $char_color, $fontface, $character['id']);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $fontface does not seem to be defined for all execution paths leading up to this point.
Loading history...
Bug introduced by
It seems like $code_image can also be of type false; however, parameter $image of imagettftext() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

1021
				$fontcord = @imagettftext(/** @scrutinizer ignore-type */ $code_image, $font_size, $angle, $font_x, $font_y, $char_color, $fontface, $character['id']);
Loading history...
1022
				if (empty($fontcord))
1023
					$can_do_ttf = false;
1024
				elseif ($is_reverse)
0 ignored issues
show
Bug Best Practice introduced by
The expression $is_reverse 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...
1025
				{
1026
					imagefilledpolygon($code_image, $fontcord, 4, $fg_color);
0 ignored issues
show
Bug introduced by
It seems like $code_image can also be of type false; however, parameter $image of imagefilledpolygon() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

1026
					imagefilledpolygon(/** @scrutinizer ignore-type */ $code_image, $fontcord, 4, $fg_color);
Loading history...
1027
					// Put the character back!
1028
					imagettftext($code_image, $font_size, $angle, $font_x, $font_y, $randomness_color, $fontface, $character['id']);
1029
				}
1030
1031
				if ($can_do_ttf)
1032
					$cur_x = max($fontcord[2], $fontcord[4]) + ($angle == 0 ? 0 : 3);
1033
			}
1034
1035
			if (!$can_do_ttf)
1036
			{
1037
				// Rotating the characters a little...
1038
				if (function_exists('imagerotate'))
1039
				{
1040
					$char_image = $gd2 ? imagecreatetruecolor($character['width'], $character['height']) : imagecreate($character['width'], $character['height']);
1041
					$char_bgcolor = imagecolorallocate($char_image, $background_color[0], $background_color[1], $background_color[2]);
1042
					imagefilledrectangle($char_image, 0, 0, $character['width'] - 1, $character['height'] - 1, $char_bgcolor);
1043
					imagechar($char_image, $loaded_fonts[$character['font']], 0, 0, $character['id'], imagecolorallocate($char_image, $char_fg_color[0], $char_fg_color[1], $char_fg_color[2]));
0 ignored issues
show
Bug introduced by
It seems like $char_image can also be of type false; however, parameter $image of imagechar() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

1043
					imagechar(/** @scrutinizer ignore-type */ $char_image, $loaded_fonts[$character['font']], 0, 0, $character['id'], imagecolorallocate($char_image, $char_fg_color[0], $char_fg_color[1], $char_fg_color[2]));
Loading history...
1044
					$rotated_char = imagerotate($char_image, mt_rand(-100, 100) / 10, $char_bgcolor);
0 ignored issues
show
Bug introduced by
It seems like $char_image can also be of type false; however, parameter $image of imagerotate() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

1044
					$rotated_char = imagerotate(/** @scrutinizer ignore-type */ $char_image, mt_rand(-100, 100) / 10, $char_bgcolor);
Loading history...
1045
					imagecopy($code_image, $rotated_char, $cur_x, 0, 0, 0, $character['width'], $character['height']);
0 ignored issues
show
Bug introduced by
It seems like $code_image can also be of type false; however, parameter $dst_im of imagecopy() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

1045
					imagecopy(/** @scrutinizer ignore-type */ $code_image, $rotated_char, $cur_x, 0, 0, 0, $character['width'], $character['height']);
Loading history...
Bug introduced by
It seems like $rotated_char can also be of type false; however, parameter $src_im of imagecopy() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

1045
					imagecopy($code_image, /** @scrutinizer ignore-type */ $rotated_char, $cur_x, 0, 0, 0, $character['width'], $character['height']);
Loading history...
1046
					imagedestroy($rotated_char);
0 ignored issues
show
Bug introduced by
It seems like $rotated_char can also be of type false; however, parameter $image of imagedestroy() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

1046
					imagedestroy(/** @scrutinizer ignore-type */ $rotated_char);
Loading history...
1047
					imagedestroy($char_image);
1048
				}
1049
1050
				// Sorry, no rotation available.
1051
				else
1052
					imagechar($code_image, $loaded_fonts[$character['font']], $cur_x, floor(($max_height - $character['height']) / 2), $character['id'], imagecolorallocate($code_image, $char_fg_color[0], $char_fg_color[1], $char_fg_color[2]));
0 ignored issues
show
Bug introduced by
floor($max_height - $character['height'] / 2) of type double is incompatible with the type integer expected by parameter $y of imagechar(). ( Ignorable by Annotation )

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

1052
					imagechar($code_image, $loaded_fonts[$character['font']], $cur_x, /** @scrutinizer ignore-type */ floor(($max_height - $character['height']) / 2), $character['id'], imagecolorallocate($code_image, $char_fg_color[0], $char_fg_color[1], $char_fg_color[2]));
Loading history...
1053
				$cur_x += $character['width'] + $character_spacing;
1054
			}
1055
		}
1056
	}
1057
	// If disabled just show a cross.
1058
	else
1059
	{
1060
		imageline($code_image, 0, 0, $total_width, $max_height, $fg_color);
0 ignored issues
show
Bug introduced by
It seems like $code_image can also be of type false; however, parameter $image of imageline() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

1060
		imageline(/** @scrutinizer ignore-type */ $code_image, 0, 0, $total_width, $max_height, $fg_color);
Loading history...
1061
		imageline($code_image, 0, $max_height, $total_width, 0, $fg_color);
1062
	}
1063
1064
	// Make the background color transparent on the hard image.
1065
	if (!$simpleBGColor)
1066
		imagecolortransparent($code_image, $bg_color);
0 ignored issues
show
Bug introduced by
It seems like $code_image can also be of type false; however, parameter $image of imagecolortransparent() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

1066
		imagecolortransparent(/** @scrutinizer ignore-type */ $code_image, $bg_color);
Loading history...
1067
	if ($hasBorder)
1068
		imagerectangle($code_image, 0, 0, $total_width - 1, $max_height - 1, $fg_color);
0 ignored issues
show
Bug introduced by
It seems like $code_image can also be of type false; however, parameter $image of imagerectangle() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

1068
		imagerectangle(/** @scrutinizer ignore-type */ $code_image, 0, 0, $total_width - 1, $max_height - 1, $fg_color);
Loading history...
1069
1070
	// Add some noise to the background?
1071
	if ($noiseType != 'none')
1072
	{
1073
		for ($i = mt_rand(0, 2); $i < $max_height; $i += mt_rand(1, 2))
1074
			for ($j = mt_rand(0, 10); $j < $total_width; $j += mt_rand(1, 10))
1075
				imagesetpixel($code_image, $j, $i, mt_rand(0, 1) ? $fg_color : $randomness_color);
0 ignored issues
show
Bug introduced by
It seems like $code_image can also be of type false; however, parameter $image of imagesetpixel() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

1075
				imagesetpixel(/** @scrutinizer ignore-type */ $code_image, $j, $i, mt_rand(0, 1) ? $fg_color : $randomness_color);
Loading history...
1076
1077
		// Put in some lines too?
1078
		if ($noiseType != 'extreme')
1079
		{
1080
			$num_lines = $noiseType == 'high' ? mt_rand(3, 7) : mt_rand(2, 5);
1081
			for ($i = 0; $i < $num_lines; $i++)
1082
			{
1083
				if (mt_rand(0, 1))
1084
				{
1085
					$x1 = mt_rand(0, $total_width);
1086
					$x2 = mt_rand(0, $total_width);
1087
					$y1 = 0;
1088
					$y2 = $max_height;
1089
				}
1090
				else
1091
				{
1092
					$y1 = mt_rand(0, $max_height);
1093
					$y2 = mt_rand(0, $max_height);
1094
					$x1 = 0;
1095
					$x2 = $total_width;
1096
				}
1097
				imagesetthickness($code_image, mt_rand(1, 2));
0 ignored issues
show
Bug introduced by
It seems like $code_image can also be of type false; however, parameter $image of imagesetthickness() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

1097
				imagesetthickness(/** @scrutinizer ignore-type */ $code_image, mt_rand(1, 2));
Loading history...
1098
				imageline($code_image, $x1, $y1, $x2, $y2, mt_rand(0, 1) ? $fg_color : $randomness_color);
1099
			}
1100
		}
1101
		else
1102
		{
1103
			// Put in some ellipse
1104
			$num_ellipse = $noiseType == 'extreme' ? mt_rand(6, 12) : mt_rand(2, 6);
1105
			for ($i = 0; $i < $num_ellipse; $i++)
1106
			{
1107
				$x1 = round(rand(($total_width / 4) * -1, $total_width + ($total_width / 4)));
1108
				$x2 = round(rand($total_width / 2, 2 * $total_width));
1109
				$y1 = round(rand(($max_height / 4) * -1, $max_height + ($max_height / 4)));
1110
				$y2 = round(rand($max_height / 2, 2 * $max_height));
1111
				imageellipse($code_image, $x1, $y1, $x2, $y2, mt_rand(0, 1) ? $fg_color : $randomness_color);
0 ignored issues
show
Bug introduced by
$y2 of type double is incompatible with the type integer expected by parameter $height of imageellipse(). ( Ignorable by Annotation )

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

1111
				imageellipse($code_image, $x1, $y1, $x2, /** @scrutinizer ignore-type */ $y2, mt_rand(0, 1) ? $fg_color : $randomness_color);
Loading history...
Bug introduced by
$y1 of type double is incompatible with the type integer expected by parameter $cy of imageellipse(). ( Ignorable by Annotation )

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

1111
				imageellipse($code_image, $x1, /** @scrutinizer ignore-type */ $y1, $x2, $y2, mt_rand(0, 1) ? $fg_color : $randomness_color);
Loading history...
Bug introduced by
$x1 of type double is incompatible with the type integer expected by parameter $cx of imageellipse(). ( Ignorable by Annotation )

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

1111
				imageellipse($code_image, /** @scrutinizer ignore-type */ $x1, $y1, $x2, $y2, mt_rand(0, 1) ? $fg_color : $randomness_color);
Loading history...
Bug introduced by
$x2 of type double is incompatible with the type integer expected by parameter $width of imageellipse(). ( Ignorable by Annotation )

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

1111
				imageellipse($code_image, $x1, $y1, /** @scrutinizer ignore-type */ $x2, $y2, mt_rand(0, 1) ? $fg_color : $randomness_color);
Loading history...
Bug introduced by
It seems like $code_image can also be of type false; however, parameter $image of imageellipse() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

1111
				imageellipse(/** @scrutinizer ignore-type */ $code_image, $x1, $y1, $x2, $y2, mt_rand(0, 1) ? $fg_color : $randomness_color);
Loading history...
1112
			}
1113
		}
1114
	}
1115
1116
	// Show the image.
1117
	if (function_exists('imagegif'))
1118
	{
1119
		header('content-type: image/gif');
1120
		imagegif($code_image);
0 ignored issues
show
Bug introduced by
It seems like $code_image can also be of type false; however, parameter $image of imagegif() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

1120
		imagegif(/** @scrutinizer ignore-type */ $code_image);
Loading history...
1121
	}
1122
	else
1123
	{
1124
		header('content-type: image/png');
1125
		imagepng($code_image);
0 ignored issues
show
Bug introduced by
It seems like $code_image can also be of type false; however, parameter $image of imagepng() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

1125
		imagepng(/** @scrutinizer ignore-type */ $code_image);
Loading history...
1126
	}
1127
1128
	// Bail out.
1129
	imagedestroy($code_image);
1130
	die();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
1131
}
1132
1133
/**
1134
 * Show a letter for the visual verification code.
1135
 * Alternative function for showCodeImage() in case GD is missing.
1136
 * Includes an image from a random sub directory of default_theme_dir/fonts.
1137
 *
1138
 * @param string $letter A letter to show as an image
1139
 * @return void|false False if something went wrong
1140
 */
1141
function showLetterImage($letter)
1142
{
1143
	global $settings;
1144
1145
	if (!is_dir($settings['default_theme_dir'] . '/fonts'))
1146
		return false;
1147
1148
	// Get a list of the available font directories.
1149
	$font_dir = dir($settings['default_theme_dir'] . '/fonts');
1150
	$font_list = array();
1151
	while ($entry = $font_dir->read())
1152
		if ($entry[0] !== '.' && is_dir($settings['default_theme_dir'] . '/fonts/' . $entry) && file_exists($settings['default_theme_dir'] . '/fonts/' . $entry . '.gdf'))
1153
			$font_list[] = $entry;
1154
1155
	if (empty($font_list))
1156
		return false;
1157
1158
	// Pick a random font.
1159
	$random_font = $font_list[array_rand($font_list)];
1160
1161
	// Check if the given letter exists.
1162
	if (!file_exists($settings['default_theme_dir'] . '/fonts/' . $random_font . '/' . strtoupper($letter) . '.png'))
1163
		return false;
1164
1165
	// Include it!
1166
	header('content-type: image/png');
1167
	include($settings['default_theme_dir'] . '/fonts/' . $random_font . '/' . strtoupper($letter) . '.png');
1168
1169
	// Nothing more to come.
1170
	die();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
1171
}
1172
1173
?>