Completed
Pull Request — master (#3325)
by Emanuele
11:19
created

showCodeImage()   F

Complexity

Conditions 93

Size

Total Lines 339
Code Lines 189

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 8742

Importance

Changes 0
Metric Value
cc 93
eloc 189
dl 0
loc 339
rs 3.3333
c 0
b 0
f 0
nop 1
ccs 0
cts 242
cp 0
crap 8742

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
3
/**
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
 *
8
 * TrueType fonts supplied by www.LarabieFonts.com
9
 *
10
 * @name      ElkArte Forum
11
 * @copyright ElkArte Forum contributors
12
 * @license   BSD http://opensource.org/licenses/BSD-3-Clause
13
 *
14
 * This file contains code covered by:
15
 * copyright:	2011 Simple Machines (http://www.simplemachines.org)
16
 * license:  	BSD, See included LICENSE.TXT for terms and conditions.
17
 *
18
 * @version 1.1.6
19
 *
20
 */
21
22
/**
23
 * Create a thumbnail of the given source.
24
 *
25
 * @uses resizeImageFile() function to achieve the resize.
26
 * @package Graphics
27
 *
28
 * @param string $source The name of the source image
29
 * @param int $max_width The maximum allowed width
30
 * @param int $max_height The maximum allowed height
31
 *
32
 * @return boolean whether the thumbnail creation was successful.
33
 */
34
function createThumbnail($source, $max_width, $max_height)
35
{
36
	global $modSettings;
37
38
	$destName = $source . '_thumb.tmp';
39
40
	// Do the actual resize, thumbnails by default strip EXIF data to save space
41
	$format = !empty($modSettings['attachment_thumb_png']) ? 3 : 0;
42
	$success = resizeImageFile($source, $destName, $max_width, $max_height, $format, true);
43
44
	// Okay, we're done with the temporary stuff.
45
	$destName = substr($destName, 0, -4);
46
47
	if ($success && @rename($destName . '.tmp', $destName))
48
		return true;
49
	else
50
	{
51
		@unlink($destName . '.tmp');
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

51
		/** @scrutinizer ignore-unhandled */ @unlink($destName . '.tmp');

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...
52
		@touch($destName);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for touch(). 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

52
		/** @scrutinizer ignore-unhandled */ @touch($destName);

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...
53
		return false;
54
	}
55
}
56
57
/**
58
 * Used to re-encodes an image to a specified image format
59
 *
60
 * What it does:
61
 *
62
 * - creates a copy of the file at the same location as fileName.
63
 * - the file would have the format preferred_format if possible, otherwise the default format is jpeg.
64
 * - the function makes sure that all non-essential image contents are disposed.
65
 *
66
 * @package Graphics
67
 * @param string $fileName The path to the file
68
 * @param int $preferred_format The preferred format
69
 *   - 0 to automatically determine
70
 *   - 1 for gif
71
 *   - 2 for jpg
72
 *   - 3 for png
73
 *   - 6 for bmp
74
 *   - 15 for wbmp
75
 *
76
 * @return boolean true on success, false on failure.
77
 */
78
function reencodeImage($fileName, $preferred_format = 0)
79
{
80
	if (!resizeImageFile($fileName, $fileName . '.tmp', null, null, $preferred_format))
81
	{
82
		if (file_exists($fileName . '.tmp'))
83
			unlink($fileName . '.tmp');
84
85
		return false;
86
	}
87
88
	if (!unlink($fileName))
89
		return false;
90
91
	return rename($fileName . '.tmp', $fileName);
92
}
93
94
/**
95
 * Searches through the file to see if there's potentially harmful non-binary content.
96
 *
97
 * What it does:
98
 *
99
 * - if extensiveCheck is true, searches for asp/php short tags as well.
100
 *
101
 * @package Graphics
102
 *
103
 * @param string $fileName The path to the file
104
 * @param bool   $extensiveCheck = false if it should perform extensive checks
105
 *
106
 * @return bool Whether the image appears to be safe
107
 * @throws Elk_Exception attach_timeout
108
 */
109
function checkImageContents($fileName, $extensiveCheck = false)
110
{
111
	$fp = fopen($fileName, 'rb');
112
	if (!$fp)
0 ignored issues
show
introduced by
$fp is of type false|resource, thus it always evaluated to false.
Loading history...
113
	{
114
		loadLanguage('Post');
115
		throw new Elk_Exception('attach_timeout');
116
	}
117
118
	$prev_chunk = '';
119
	while (!feof($fp))
120
	{
121
		$cur_chunk = fread($fp, 8192);
122
		$test_chunk = $prev_chunk . $cur_chunk;
123
124
		// Though not exhaustive lists, better safe than sorry.
125
		if (!empty($extensiveCheck))
126
		{
127
			// Paranoid check. Some like it that way.
128
			if (preg_match('~<\\?php|<script\W|(?-i)[CFZ]WS[\x01-\x0E]~i', $test_chunk) === 1)
129
			{
130
				fclose($fp);
131
				return false;
132
			}
133
		}
134
		else
135
		{
136
			// Check for potential php injection
137
			if (preg_match('~<\\?php|<script\s+language\s*=\s*(?:php|"php"|\'php\')\s*>~i', $test_chunk) === 1)
138
			{
139
				fclose($fp);
140
				return false;
141
			}
142
		}
143
144
		$prev_chunk = $cur_chunk;
145
	}
146
147
	fclose($fp);
148
149
	return true;
150
}
151
152
/**
153
 * Sets a global $gd2 variable needed by some functions to determine
154
 * whether the GD2 library is present.
155
 *
156
 * @package Graphics
157
 *
158
 * @return bool Whether or not GD is available.
159
 */
160
function checkGD()
161
{
162
	global $gd2;
163
164
	// Check to see if GD is installed and what version.
165
	if (($extensionFunctions = get_extension_funcs('gd')) === false)
166
		return false;
167
168
	// Also determine if GD2 is installed and store it in a global.
169
	$gd2 = in_array('imagecreatetruecolor', $extensionFunctions) && function_exists('imagecreatetruecolor');
170
171
	return true;
172
}
173
174
/**
175
 * Checks whether the Imagick class is present.
176
 *
177
 * @package Graphics
178
 *
179
 * @return bool Whether or not the Imagick extension is available.
180
 */
181
function checkImagick()
182
{
183
	return class_exists('Imagick', false);
184
}
185
186
/**
187
 * See if we have enough memory to thumbnail an image
188
 *
189
 * @package Graphics
190
 * @param int[] $sizes image size
191
 *
192
 * @return bool Whether or not the memory is available.
193
 */
194
function imageMemoryCheck($sizes)
195
{
196
	global $modSettings;
197
198
	// Just to be sure
199
	if (!is_array($sizes) || $sizes[0] === -1)
0 ignored issues
show
introduced by
The condition is_array($sizes) is always true.
Loading history...
200
	{
201
		return true;
202
	}
203
204
	// Doing the old 'set it and hope' way?
205
	if (empty($modSettings['attachment_thumb_memory']))
206
	{
207
		detectServer()->setMemoryLimit('128M');
208
		return true;
209
	}
210
211
	// Determine the memory requirements for this image, note: if you want to use an image formula
212
	// W x H x bits/8 x channels x Overhead factor
213
	// You will need to account for single bit images as GD expands them to an 8 bit and will greatly
214
	// overun the calculated value.
215
	// The 5 below is simply a shortcut of 8bpp, 3 channels, 1.66 overhead
216
	$needed_memory = ($sizes[0] * $sizes[1] * 5);
217
218
	// If we need more, lets try to get it
219
	return detectServer()->setMemoryLimit($needed_memory, true);
220
}
221
222
/**
223
 * Resize an image from a remote location or a local file.
224
 *
225
 * What it does:
226
 *
227
 * - Puts the resized image at the destination location.
228
 * - The file would have the format preferred_format if possible,
229
 * otherwise the default format is jpeg.
230
 *
231
 * @package Graphics
232
 *
233
 * @param string $source The name of the source image
234
 * @param string $destination The name of the destination image
235
 * @param int $max_width The maximum allowed width
236
 * @param int $max_height The maximum allowed height
237
 * @param int $preferred_format Used by Imagick/resizeImage
238
 * @param bool $force_resize Always resize the image (force scale up)
239
 * @param bool $strip Allow IM to remove exif data as GD always will
240
 *
241
 * @return boolean Whether the thumbnail creation was successful.
242
 */
243
function resizeImageFile($source, $destination, $max_width, $max_height, $preferred_format = 0, $strip = false, $force_resize = true)
244
{
245
	// Nothing to do without GD or IM
246
	if (!checkGD() && !checkImagick())
247
		return false;
248
249
	if (!file_exists($source) && substr($source, 0, 7) !== 'http://' && substr($source, 0, 8) !== 'https://')
250
	{
251
		return false;
252
	}
253
254
	static $default_formats = array(
255
		'1' => 'gif',
256
		'2' => 'jpeg',
257
		'3' => 'png',
258
		'6' => 'bmp',
259
		'15' => 'wbmp'
260
	);
261
262
	require_once(SUBSDIR . '/Package.subs.php');
263
	require_once(SUBSDIR . '/Attachments.subs.php');
264
265
	// Get the image file, we have to work with something after all
266
	$fp_destination = fopen($destination, 'wb');
267
	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...
268
	{
269
		$fileContents = fetch_web_data($source);
270
271
		fwrite($fp_destination, $fileContents);
272
		fclose($fp_destination);
273
274
		$sizes = elk_getimagesize($destination);
275
	}
276
	elseif ($fp_destination)
0 ignored issues
show
introduced by
$fp_destination is of type false|resource, thus it always evaluated to false.
Loading history...
277
	{
278
		$sizes = elk_getimagesize($source);
279
280
		$fp_source = fopen($source, 'rb');
281
		if ($fp_source !== false)
282
		{
283
			while (!feof($fp_source))
284
			{
285
				fwrite($fp_destination, fread($fp_source, 8192));
286
			}
287
			fclose($fp_source);
288
		}
289
		else
290
			$sizes = array(-1, -1, -1);
291
292
		fclose($fp_destination);
293
	}
294
	// We can't get to the file.
295
	else
296
		$sizes = array(-1, -1, -1);
297
298
	// See if we have -or- can get the needed memory for this operation
299
	if (checkGD() && !imageMemoryCheck($sizes))
300
		return false;
301
302
	// A known and supported format?
303
	if (checkImagick() && isset($default_formats[$sizes[2]]))
304
	{
305
		return resizeImage(null, $destination, null, null, $max_width, $max_height, $force_resize, $preferred_format, $strip);
306
	}
307
	elseif (checkGD() && isset($default_formats[$sizes[2]]) && function_exists('imagecreatefrom' . $default_formats[$sizes[2]]))
308
	{
309
		$imagecreatefrom = 'imagecreatefrom' . $default_formats[$sizes[2]];
310
		if ($src_img = @$imagecreatefrom($destination))
311
		{
312
			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, $force_resize, $preferred_format, $strip);
0 ignored issues
show
introduced by
The condition $max_width === null is always false.
Loading history...
introduced by
The condition $max_height === null is always false.
Loading history...
313
		}
314
	}
315
316
	return false;
317
}
318
319
/**
320
 * Resize an image proportionally to fit within the defined max_width and max_height limits
321
 *
322
 * What it does:
323
 *
324
 * - Will do nothing to the image if the file fits within the size limits
325
 * - If Image Magick is present it will use those function over any GD solutions
326
 * - If GD2 is present, it'll use it to achieve better quality (imagecopyresampled)
327
 * - Saves the new image to destination_filename, in the preferred_format
328
 * if possible, default is jpeg.
329
 *
330
 * @uses GD
331
 * @uses Imagick
332
 *
333
 * @package Graphics
334
 * @param resource|null $src_img null for Imagick images, resource form imagecreatefrom for GD
335
 * @param string $destName
336
 * @param int $src_width The width of the source image
337
 * @param int $src_height The height of the source image
338
 * @param int $max_width The maximum allowed width
339
 * @param int $max_height The maximum allowed height
340
 * @param bool $force_resize = false Whether to override defaults and resize it
341
 * @param int $preferred_format - The preferred format
342
 *   - 0 to use jpeg
343
 *   - 1 for gif
344
 *   - 2 to force jpeg
345
 *   - 3 for png
346
 *   - 6 for bmp
347
 *   - 15 for wbmp
348
 * @param bool $strip Whether to have IM strip EXIF data as GD will
349
 *
350
 * @return bool Whether resize was successful.
351
 */
352
function resizeImage($src_img, $destName, $src_width, $src_height, $max_width, $max_height, $force_resize = false, $preferred_format = 0, $strip = false)
353
{
354
	global $gd2;
355
356
	if (checkImagick())
357
	{
358
		// These are the file formats we know about
359
		static $default_formats = array(
360
			'1' => 'gif',
361
			'2' => 'jpeg',
362
			'3' => 'png',
363
			'6' => 'bmp',
364
			'15' => 'wbmp'
365
		);
366
		$preferred_format = empty($preferred_format) || !isset($default_formats[$preferred_format]) ? 2 : $preferred_format;
367
368
		// Since Imagick can throw exceptions, lets catch them
369
		try
370
		{
371
			// Get a new instance of Imagick for use
372
			$imagick = new Imagick($destName);
373
374
			// Set the input and output image size
375
			$src_width = empty($src_width) ? $imagick->getImageWidth() : $src_width;
376
			$src_height = empty($src_height) ? $imagick->getImageHeight() : $src_height;
377
378
			// The behavior of bestfit changed in Imagick 3.0.0 and it will now scale up, we prevent that
379
			$dest_width = empty($max_width) ? $src_width : ($force_resize ? $max_width : min($max_width, $src_width));
380
			$dest_height = empty($max_height) ? $src_height : ($force_resize ? $max_height :  min($max_height, $src_height));
381
382
			// Set jpeg image quality to 80
383
			if ($default_formats[$preferred_format] === 'jpeg')
384
			{
385
				$imagick->borderImage('white', 0, 0);
386
				$imagick->setImageCompression(Imagick::COMPRESSION_JPEG);
387
				$imagick->setImageCompressionQuality(80);
388
			}
389
390
			// Create a new image in our preferred format and resize it if needed
391
			$imagick->setImageFormat($default_formats[$preferred_format]);
392
			$imagick->resizeImage($dest_width, $dest_height, Imagick::FILTER_LANCZOS, 1, true);
393
394
			// Remove EXIF / ICC data?
395
			if ($strip)
396
			{
397
				$imagick->stripImage();
398
			}
399
400
			// Save the new image in the destination location
401
			$success = $imagick->writeImage($destName);
402
403
			// Free resources associated with the Imagick object
404
			$imagick->clear();
405
		}
406
		catch (Exception $e)
407
		{
408
			$success = false;
409
		}
410
411
		return !empty($success);
412
	}
413
	elseif (checkGD())
414
	{
415
		$success = false;
416
417
		// Determine whether to resize to max width or to max height (depending on the limits.)
418
		if (!empty($max_width) || !empty($max_height))
419
		{
420
			if (!empty($max_width) && (empty($max_height) || $src_height * $max_width / $src_width <= $max_height))
421
			{
422
				$dst_width = $max_width;
423
				$dst_height = floor($src_height * $max_width / $src_width);
424
			}
425
			elseif (!empty($max_height))
426
			{
427
				$dst_width = floor($src_width * $max_height / $src_height);
428
				$dst_height = $max_height;
429
			}
430
431
			// Don't bother resizing if it's already smaller...
432
			if (!empty($dst_width) && !empty($dst_height) && ($dst_width < $src_width || $dst_height < $src_height || $force_resize))
433
			{
434
				// (make a true color image, because it just looks better for resizing.)
435
				if ($gd2)
436
				{
437
					$dst_img = imagecreatetruecolor($dst_width, $dst_height);
438
439
					// Deal nicely with a PNG - because we can.
440
					if ((!empty($preferred_format)) && ($preferred_format == 3))
441
					{
442
						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

442
						imagealphablending(/** @scrutinizer ignore-type */ $dst_img, false);
Loading history...
443
						if (function_exists('imagesavealpha'))
444
							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

444
							imagesavealpha(/** @scrutinizer ignore-type */ $dst_img, true);
Loading history...
445
					}
446
				}
447
				else
448
					$dst_img = imagecreate($dst_width, $dst_height);
449
450
				// Resize it!
451
				if ($gd2)
452
					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

452
					imagecopyresampled(/** @scrutinizer ignore-type */ $dst_img, $src_img, 0, 0, 0, 0, $dst_width, $dst_height, $src_width, $src_height);
Loading history...
453
				else
454
					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

454
					imagecopyresamplebicubic(/** @scrutinizer ignore-type */ $dst_img, $src_img, 0, 0, 0, 0, $dst_width, $dst_height, $src_width, $src_height);
Loading history...
455
			}
456
			else
457
				$dst_img = $src_img;
458
		}
459
		else
460
			$dst_img = $src_img;
461
462
		// Save the image as ...
463
		if (!empty($preferred_format) && ($preferred_format == 3) && function_exists('imagepng'))
464
			$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

464
			$success = imagepng(/** @scrutinizer ignore-type */ $dst_img, $destName);
Loading history...
465
		elseif (!empty($preferred_format) && ($preferred_format == 1) && function_exists('imagegif'))
466
			$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

466
			$success = imagegif(/** @scrutinizer ignore-type */ $dst_img, $destName);
Loading history...
467
		elseif (function_exists('imagejpeg'))
468
			$success = imagejpeg($dst_img, $destName, 80);
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

468
			$success = imagejpeg(/** @scrutinizer ignore-type */ $dst_img, $destName, 80);
Loading history...
469
470
		// Free the memory.
471
		imagedestroy($src_img);
472
		if ($dst_img != $src_img)
473
			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

473
			imagedestroy(/** @scrutinizer ignore-type */ $dst_img);
Loading history...
474
475
		return $success;
476
	}
477
	// Without Imagick or GD, no image resizing at all.
478
	else
479
		return false;
480
}
481
482
/**
483
 * Calls GD or ImageMagick functions to correct an images orientation
484
 * based on the EXIF orientation flag
485
 *
486
 * @param string $image_name
487
 */
488
function autoRotateImage($image_name)
489
{
490
	if (checkImagick())
491
	{
492
		autoRotateImageWithIM($image_name);
493
	}
494
	elseif (checkGD())
495
	{
496
		autoRotateImageWithGD($image_name);
497
	}
498
}
499
500
/**
501
 * Autorotate an image based on its EXIF Orientation tag.
502
 *
503
 * What it does:
504
 *
505
 * - GD only
506
 * - Checks exif data for orientation flag and rotates image so its proper
507
 * - Does not update orientation flag as GD removes EXIF data
508
 * - Only works with jpeg images, could add TIFF as well
509
 * - Writes the update image back to $image_name
510
 *
511
 * @package Graphics
512
 * @uses GD
513
 * @param string $image_name full location of the file
514
 */
515
function autoRotateImageWithGD($image_name)
516
{
517
	// Read the EXIF data
518
	$exif = function_exists('exif_read_data') ? @exif_read_data($image_name) : array();
519
520
	// We're only interested in the exif orientation
521
	$orientation = isset($exif['Orientation']) ? $exif['Orientation'] : 0;
522
523
	// For now we only process jpeg images, so check that we have one
524
	$sizes = elk_getimagesize($image_name);
525
526
	// Not a jpeg or not rotated, done!
527
	if ($sizes[2] !== 2 || $orientation === 0 || !imageMemoryCheck($sizes))
528
	{
529
		return false;
530
	}
531
532
	// Load the image object so we can begin the transformation(s)
533
	$source = imagecreatefromjpeg($image_name);
534
535
	// Time to spin and mirror as needed
536
	switch ($orientation)
537
	{
538
		// 0 & 1 Not set or Normal
539
		case 0:
540
		case 1:
541
			break;
542
		// 2 Mirror image, Normal orientation
543
		case 2:
544
			$source = flopImageGD($source, $sizes);
0 ignored issues
show
Bug introduced by
It seems like $source can also be of type false; however, parameter $image of flopImageGD() 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

544
			$source = flopImageGD(/** @scrutinizer ignore-type */ $source, $sizes);
Loading history...
545
			break;
546
		// 3 Normal image, rotated 180
547
		case 3:
548
			$source = rotateImageGD($source, 180);
0 ignored issues
show
Bug introduced by
It seems like $source can also be of type false; however, parameter $image of rotateImageGD() 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

548
			$source = rotateImageGD(/** @scrutinizer ignore-type */ $source, 180);
Loading history...
549
			break;
550
		// 4 Mirror image, rotated 180
551
		case 4:
552
			$source = flipImageGD($source, $sizes);
0 ignored issues
show
Bug introduced by
It seems like $source can also be of type false; however, parameter $image of flipImageGD() 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

552
			$source = flipImageGD(/** @scrutinizer ignore-type */ $source, $sizes);
Loading history...
553
			break;
554
		// 5 Mirror image, rotated 90 CCW
555
		case 5:
556
			$source = flopImageGD($source, $sizes);
557
			$source = rotateImageGD($source, 90);
558
			break;
559
		// 6 Normal image, rotated 90 CCW
560
		case 6:
561
			$source = rotateImageGD($source, -90);
562
			break;
563
		// 7 Mirror image, rotated 90 CW
564
		case 7:
565
			$source = flopImageGD($source, $sizes);
566
			$source = rotateImageGD($source, -90);
567
			break;
568
		// 8 Normal image, rotated 90 CW
569
		case 8:
570
			$source = rotateImageGD($source, 90);
571
			break;
572
	}
573
574
	// Save the updated image, free resources
575
	imagejpeg($source, $image_name);
0 ignored issues
show
Bug introduced by
It seems like $source 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

575
	imagejpeg(/** @scrutinizer ignore-type */ $source, $image_name);
Loading history...
576
	imagedestroy($source);
0 ignored issues
show
Bug introduced by
It seems like $source 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

576
	imagedestroy(/** @scrutinizer ignore-type */ $source);
Loading history...
577
578
	return true;
579
}
580
581
/**
582
 * Autorotate an image based on its EXIF Orientation tag.
583
 *
584
 * What it does:
585
 *
586
 * - ImageMagick only
587
 * - Checks exif data for orientation flag and rotates image so its proper
588
 * - Updates orientation flag if rotation was required
589
 * - Writes the update image back to $image_name
590
 *
591
 * @uses Imagick
592
 * @param string $image_name
593
 */
594
function autoRotateImageWithIM($image_name)
595
{
596
	try
597
	{
598
		// Get a new instance of Imagick for use
599
		$image = new Imagick($image_name);
600
601
		// This method should exist if Imagick has been compiled against ImageMagick version
602
		// 6.3.0 or higher which is forever ago, but we check anyway ;)
603
		if (!method_exists($image, 'getImageOrientation'))
604
		{
605
			return false;
606
		}
607
608
		$orientation = $image->getImageOrientation();
609
		switch ($orientation)
610
		{
611
			// 0 & 1 Not set or Normal
612
			case Imagick::ORIENTATION_UNDEFINED:
613
			case Imagick::ORIENTATION_TOPLEFT:
614
				break;
615
			// 2 Mirror image, Normal orientation
616
			case Imagick::ORIENTATION_TOPRIGHT:
617
				$image->flopImage();
618
				break;
619
			// 3 Normal image, rotated 180
620
			case Imagick::ORIENTATION_BOTTOMRIGHT:
621
				$image->rotateImage('#000', 180);
622
				break;
623
			// 4 Mirror image, rotated 180
624
			case Imagick::ORIENTATION_BOTTOMLEFT:
625
				$image->flipImage();
626
				break;
627
			// 5 Mirror image, rotated 90 CCW
628
			case Imagick::ORIENTATION_LEFTTOP:
629
				$image->rotateImage('#000', 90);
630
				$image->flopImage();
631
				break;
632
			// 6 Normal image, rotated 90 CCW
633
			case Imagick::ORIENTATION_RIGHTTOP:
634
				$image->rotateImage('#000', 90);
635
				break;
636
			// 7 Mirror image, rotated 90 CW
637
			case Imagick::ORIENTATION_RIGHTBOTTOM:
638
				$image->rotateImage('#000', -90);
639
				$image->flopImage();
640
				break;
641
			// 8 Normal image, rotated 90 CW
642
			case Imagick::ORIENTATION_LEFTBOTTOM:
643
				$image->rotateImage('#000', -90);
644
				break;
645
		}
646
647
		// Now that it's auto-rotated, make sure the EXIF data is correctly updated
648
		if ($orientation >= 2)
649
		{
650
			$image->setImageOrientation(Imagick::ORIENTATION_TOPLEFT);
651
		}
652
653
		// Save the new image in the destination location
654
		$success = $image->writeImage($image_name);
655
656
		// Free resources associated with the Imagick object
657
		$image->clear();
658
	}
659
	catch (Exception $e)
660
	{
661
		$success = false;
662
	}
663
664
	return $success;
665
}
666
667
/**
668
 * Rotate an image by X degrees, GD function
669
 *
670
 * @param resource $image
671
 * @param int $degrees
672
 *
673
 * @package Graphics
674
 * @uses GD
675
 * @return resource
676
 */
677
function rotateImageGD($image, $degrees)
678
{
679
	// Kind of need this to do anything
680
	if (function_exists('imagerotate'))
681
	{
682
		// Use positive degrees so GD does not get confused
683
		$degrees -= floor($degrees / 360) * 360;
684
685
		// Rotate away
686
		$background = imagecolorallocatealpha($image, 255, 255, 255, 127);
687
		$image = imagerotate($image, $degrees, $background);
688
	}
689
690
	return $image;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $image could also return false which is incompatible with the documented return type resource. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
691
}
692
693
/**
694
 * Flop an image using GD functions by copying top to bottom / flop
695
 *
696
 * @param resource $image
697
 * @param array $sizes populated with getimagesize results
698
 *
699
 * @package Graphics
700
 * @uses GD
701
 * @return resource
702
 */
703
function flopImageGD($image, $sizes)
704
{
705
	return flipImageGD($image, $sizes, 'horizontal');
706
}
707
708
/**
709
 * Flip an image using GD function by copying top to bottom / flip vertical
710
 *
711
 * @param resource $image
712
 * @param array $sizes populated with getimagesize results
713
 * @param string $axis vertical for flip about vertical otherwise horizontal flip
714
 *
715
 * @package Graphics
716
 * @uses GD
717
 * @return resource
718
 */
719
function flipImageGD($image, $sizes, $axis = 'vertical')
720
{
721
	// If the built in function (php 5.5) is available, use it
722
	if (function_exists('imageflip'))
723
	{
724
		imageflip($image, $axis === 'vertical' ? IMG_FLIP_VERTICAL : IMG_FLIP_HORIZONTAL);
725
	}
726
	// Pixel mapping then
727
	else
728
	{
729
		$new = imagecreatetruecolor($sizes[0], $sizes[1]);
730
		imagealphablending($new, false);
0 ignored issues
show
Bug introduced by
It seems like $new 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

730
		imagealphablending(/** @scrutinizer ignore-type */ $new, false);
Loading history...
731
		imagesavealpha($new, true);
0 ignored issues
show
Bug introduced by
It seems like $new 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

731
		imagesavealpha(/** @scrutinizer ignore-type */ $new, true);
Loading history...
732
733
		if ($axis === 'vertical')
734
		{
735
			for ($y = 0; $y < $sizes[1]; $y++)
736
			{
737
				imagecopy($new, $image, 0, $y, 0, $sizes[1] - $y - 1, $sizes[0], 1);
0 ignored issues
show
Bug introduced by
It seems like $new 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

737
				imagecopy(/** @scrutinizer ignore-type */ $new, $image, 0, $y, 0, $sizes[1] - $y - 1, $sizes[0], 1);
Loading history...
738
			}
739
		}
740
		else
741
		{
742
			for ($x = 0; $x < $sizes[0]; $x++)
743
			{
744
				imagecopy($new, $image, $x, 0, $sizes[0] - $x - 1, 0, 1, $sizes[1]);
745
			}
746
		}
747
748
		$image = $new;
749
		unset($new);
750
	}
751
752
	return $image;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $image could also return false which is incompatible with the documented return type resource. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
753
}
754
755
/**
756
 * Copy / resize an image using GD bicubic methods
757
 *
758
 * What it does:
759
 *
760
 * - Used when imagecopyresample() is not available
761
 * - Uses bicubic resizing methods which are lower quality then imagecopyresample
762
 *
763
 * @package Graphics
764
 * @param resource $dst_img The destination image - a GD image resource
765
 * @param resource $src_img The source image - a GD image resource
766
 * @param int $dst_x The "x" coordinate of the destination image
767
 * @param int $dst_y The "y" coordinate of the destination image
768
 * @param int $src_x The "x" coordinate of the source image
769
 * @param int $src_y The "y" coordinate of the source image
770
 * @param int $dst_w The width of the destination image
771
 * @param int $dst_h The height of the destination image
772
 * @param int $src_w The width of the destination image
773
 * @param int $src_h The height of the destination image
774
 */
775
function imagecopyresamplebicubic($dst_img, $src_img, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h)
776
{
777
	$palsize = imagecolorstotal($src_img);
778
	for ($i = 0; $i < $palsize; $i++)
779
	{
780
		$colors = imagecolorsforindex($src_img, $i);
781
		imagecolorallocate($dst_img, $colors['red'], $colors['green'], $colors['blue']);
782
	}
783
784
	$scaleX = ($src_w - 1) / $dst_w;
785
	$scaleY = ($src_h - 1) / $dst_h;
786
787
	$scaleX2 = (int) $scaleX / 2;
788
	$scaleY2 = (int) $scaleY / 2;
789
790
	for ($j = $src_y; $j < $dst_h; $j++)
791
	{
792
		$sY = (int) $j * $scaleY;
793
		$y13 = $sY + $scaleY2;
794
795
		for ($i = $src_x; $i < $dst_w; $i++)
796
		{
797
			$sX = (int) $i * $scaleX;
798
			$x34 = $sX + $scaleX2;
799
800
			$color1 = imagecolorsforindex($src_img, imagecolorat($src_img, $sX, $y13));
801
			$color2 = imagecolorsforindex($src_img, imagecolorat($src_img, $sX, $sY));
802
			$color3 = imagecolorsforindex($src_img, imagecolorat($src_img, $x34, $y13));
803
			$color4 = imagecolorsforindex($src_img, imagecolorat($src_img, $x34, $sY));
804
805
			$red = ($color1['red'] + $color2['red'] + $color3['red'] + $color4['red']) / 4;
806
			$green = ($color1['green'] + $color2['green'] + $color3['green'] + $color4['green']) / 4;
807
			$blue = ($color1['blue'] + $color2['blue'] + $color3['blue'] + $color4['blue']) / 4;
808
809
			$color = imagecolorresolve($dst_img, $red, $green, $blue);
810
			if ($color == -1)
811
			{
812
				if ($palsize++ < 256)
813
					imagecolorallocate($dst_img, $red, $green, $blue);
814
				$color = imagecolorclosest($dst_img, $red, $green, $blue);
815
			}
816
817
			imagesetpixel($dst_img, $i + $dst_x - $src_x, $j + $dst_y - $src_y, $color);
818
		}
819
	}
820
}
821
822
if (!function_exists('imagecreatefrombmp'))
823
{
824
	/**
825
	 * It is set only if it doesn't already exist (for forwards compatibility.)
826
	 *
827
	 * What it does:
828
	 *
829
	 * - It only supports uncompressed bitmaps.
830
	 * - It only supports standard windows bitmaps (no os/2 variants)
831
	 * - Returns an image identifier representing the bitmap image
832
	 * obtained from the given filename.
833
	 *
834
	 * @package Graphics
835
	 * @param string $filename The name of the file
836
	 * @return resource An image identifier representing the bitmap image
837
	 */
838
	function imagecreatefrombmp($filename)
839
	{
840
		global $gd2;
841
842
		$fp = fopen($filename, 'rb');
843
844
		$errors = error_reporting(0);
845
846
		// Unpack the general information about the Bitmap Image File, first 14 Bytes
847
		$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

847
		$header = unpack('vtype/Vsize/Vreserved/Voffset', fread(/** @scrutinizer ignore-type */ $fp, 14));
Loading history...
848
849
		// Unpack the DIB header, it stores detailed information about the bitmap image the pixel format, 40 Bytes long
850
		$info = unpack('Vsize/Vwidth/Vheight/vplanes/vbits/Vcompression/Vimagesize/Vxres/Vyres/Vncolor/Vcolorimportant', fread($fp, 40));
851
852
		// Not a standard bitmap, bail out
853
		if ($header['type'] != 0x4D42)
854
			return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type resource.
Loading history...
855
856
		// Create our image canvas with the given WxH
857
		if ($gd2)
858
			$dst_img = imagecreatetruecolor($info['width'], $info['height']);
859
		else
860
			$dst_img = imagecreate($info['width'], $info['height']);
861
862
		// Color bitCounts 1,4,8 have palette information we use
863
		$palette = array();
864
		if ($info['bits'] == 1 || $info['bits'] == 4 || $info['bits'] == 8)
865
		{
866
			$palette_size = $header['offset'] - 54;
867
868
			// Read the palette data
869
			$palettedata = fread($fp, $palette_size);
870
871
			// Create the rgb color array
872
			$n = 0;
873
			for ($j = 0; $j < $palette_size; $j++)
874
			{
875
				$b = ord($palettedata[$j++]);
876
				$g = ord($palettedata[$j++]);
877
				$r = ord($palettedata[$j++]);
878
879
				$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

879
				$palette[$n++] = imagecolorallocate(/** @scrutinizer ignore-type */ $dst_img, $r, $g, $b);
Loading history...
880
			}
881
		}
882
883
		$scan_line_size = ($info['bits'] * $info['width'] + 7) >> 3;
884
		$scan_line_align = $scan_line_size & 3 ? 4 - ($scan_line_size & 3) : 0;
885
886
		for ($y = 0, $l = $info['height'] - 1; $y < $info['height']; $y++, $l--)
887
		{
888
			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

888
			fseek(/** @scrutinizer ignore-type */ $fp, $header['offset'] + ($scan_line_size + $scan_line_align) * $l);
Loading history...
889
			$scan_line = fread($fp, $scan_line_size);
890
891
			if (strlen($scan_line) < $scan_line_size)
892
				continue;
893
894
			// 32 bits per pixel
895
			if ($info['bits'] == 32)
896
			{
897
				$x = 0;
898
				for ($j = 0; $j < $scan_line_size; $x++)
899
				{
900
					$b = ord($scan_line[$j++]);
901
					$g = ord($scan_line[$j++]);
902
					$r = ord($scan_line[$j++]);
903
					$j++;
904
905
					$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

905
					$color = imagecolorexact(/** @scrutinizer ignore-type */ $dst_img, $r, $g, $b);
Loading history...
906
					if ($color == -1)
907
					{
908
						$color = imagecolorallocate($dst_img, $r, $g, $b);
909
910
						// Gah!  Out of colors?  Stupid GD 1... try anyhow.
911
						if ($color == -1)
912
							$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

912
							$color = imagecolorclosest(/** @scrutinizer ignore-type */ $dst_img, $r, $g, $b);
Loading history...
913
					}
914
915
					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

915
					imagesetpixel(/** @scrutinizer ignore-type */ $dst_img, $x, $y, $color);
Loading history...
916
				}
917
			}
918
			// 24 bits per pixel
919
			elseif ($info['bits'] == 24)
920
			{
921
				$x = 0;
922
				for ($j = 0; $j < $scan_line_size; $x++)
923
				{
924
					$b = ord($scan_line[$j++]);
925
					$g = ord($scan_line[$j++]);
926
					$r = ord($scan_line[$j++]);
927
928
					$color = imagecolorexact($dst_img, $r, $g, $b);
929
					if ($color == -1)
930
					{
931
						$color = imagecolorallocate($dst_img, $r, $g, $b);
932
933
						// Gah!  Out of colors?  Stupid GD 1... try anyhow.
934
						if ($color == -1)
935
							$color = imagecolorclosest($dst_img, $r, $g, $b);
936
					}
937
938
					imagesetpixel($dst_img, $x, $y, $color);
939
				}
940
			}
941
			// 16 bits per pixel
942
			elseif ($info['bits'] == 16)
943
			{
944
				$x = 0;
945
				for ($j = 0; $j < $scan_line_size; $x++)
946
				{
947
					$b1 = ord($scan_line[$j++]);
948
					$b2 = ord($scan_line[$j++]);
949
950
					$word = $b2 * 256 + $b1;
951
952
					$b = (($word & 31) * 255) / 31;
953
					$g = ((($word >> 5) & 31) * 255) / 31;
954
					$r = ((($word >> 10) & 31) * 255) / 31;
955
956
					// Scale the image colors up properly.
957
					$color = imagecolorexact($dst_img, $r, $g, $b);
958
					if ($color == -1)
959
					{
960
						$color = imagecolorallocate($dst_img, $r, $g, $b);
961
962
						// Gah!  Out of colors?  Stupid GD 1... try anyhow.
963
						if ($color == -1)
964
							$color = imagecolorclosest($dst_img, $r, $g, $b);
965
					}
966
967
					imagesetpixel($dst_img, $x, $y, $color);
968
				}
969
			}
970
			// 8 bits per pixel
971
			elseif ($info['bits'] == 8)
972
			{
973
				$x = 0;
974
				for ($j = 0; $j < $scan_line_size; $x++)
975
					imagesetpixel($dst_img, $x, $y, $palette[ord($scan_line[$j++])]);
976
			}
977
			// 4 bits per pixel
978
			elseif ($info['bits'] == 4)
979
			{
980
				$x = 0;
981
				for ($j = 0; $j < $scan_line_size; $x++)
982
				{
983
					$byte = ord($scan_line[$j++]);
984
985
					imagesetpixel($dst_img, $x, $y, $palette[(int) ($byte / 16)]);
986
					if (++$x < $info['width'])
987
						imagesetpixel($dst_img, $x, $y, $palette[$byte & 15]);
988
				}
989
			}
990
			// 1 bit
991
			elseif ($info['bits'] == 1)
992
			{
993
				$x = 0;
994
				for ($j = 0; $j < $scan_line_size; $x++)
995
				{
996
					$byte = ord($scan_line[$j++]);
997
998
					imagesetpixel($dst_img, $x, $y, $palette[(($byte) & 128) != 0]);
999
					for ($shift = 1; $shift < 8; $shift++)
1000
					{
1001
						if (++$x < $info['width'])
1002
							imagesetpixel($dst_img, $x, $y, $palette[(($byte << $shift) & 128) != 0]);
1003
					}
1004
				}
1005
			}
1006
		}
1007
1008
		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

1008
		fclose(/** @scrutinizer ignore-type */ $fp);
Loading history...
1009
1010
		error_reporting($errors);
1011
1012
		return $dst_img;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $dst_img could also return false which is incompatible with the documented return type resource. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
1013
	}
1014
}
1015
1016
/**
1017
 * Show an image containing the visual verification code for registration.
1018
 *
1019
 * What it does:
1020
 *
1021
 * - Requires the GD extension.
1022
 * - Uses a random font for each letter from default_theme_dir/fonts.
1023
 * - Outputs a png if possible, otherwise a gif.
1024
 *
1025
 * @package Graphics
1026
 * @param string $code The code to display
1027
 *
1028
 * @return false|null false if something goes wrong.
1029
 */
1030
function showCodeImage($code)
1031
{
1032
	global $gd2, $settings, $user_info, $modSettings;
1033
1034
	if (!checkGD())
1035
		return false;
1036
1037
	// What type are we going to be doing?
1038
	// Note: The higher the value of visual_verification_type the harder the verification is
1039
	// from 0 as disabled through to 4 as "Very hard".
1040
	$imageType = $modSettings['visual_verification_type'];
1041
1042
	// Special case to allow the admin center to show samples.
1043
	if ($user_info['is_admin'] && isset($_GET['type']))
1044
		$imageType = (int) $_GET['type'];
1045
1046
	// Some quick references for what we do.
1047
	// Do we show no, low or high noise?
1048
	$noiseType = $imageType == 3 ? 'low' : ($imageType == 4 ? 'high' : ($imageType == 5 ? 'extreme' : 'none'));
1049
	// Can we have more than one font in use?
1050
	$varyFonts = $imageType > 1 ? true : false;
1051
	// Just a plain white background?
1052
	$simpleBGColor = $imageType < 3 ? true : false;
1053
	// Plain black foreground?
1054
	$simpleFGColor = $imageType == 0 ? true : false;
1055
	// High much to rotate each character.
1056
	$rotationType = $imageType == 1 ? 'none' : ($imageType > 3 ? 'low' : 'high');
1057
	// Do we show some characters inverse?
1058
	$showReverseChars = $imageType > 3 ? true : false;
1059
	// Special case for not showing any characters.
1060
	$disableChars = $imageType == 0 ? true : false;
1061
	// What do we do with the font colors. Are they one color, close to one color or random?
1062
	$fontColorType = $imageType == 1 ? 'plain' : ($imageType > 3 ? 'random' : 'cyclic');
1063
	// Are the fonts random sizes?
1064
	$fontSizeRandom = $imageType > 3 ? true : false;
1065
	// How much space between characters?
1066
	$fontHorSpace = $imageType > 3 ? 'high' : ($imageType == 1 ? 'medium' : 'minus');
1067
	// Where do characters sit on the image? (Fixed position or random/very random)
1068
	$fontVerPos = $imageType == 1 ? 'fixed' : ($imageType > 3 ? 'vrandom' : 'random');
1069
	// Make font semi-transparent?
1070
	$fontTrans = $imageType == 2 || $imageType == 3 ? true : false;
1071
	// Give the image a border?
1072
	$hasBorder = $simpleBGColor;
1073
1074
	// The amount of pixels in between characters.
1075
	$character_spacing = 1;
1076
1077
	// What color is the background - generally white unless we're on "hard".
1078
	if ($simpleBGColor)
1079
		$background_color = array(255, 255, 255);
1080
	else
1081
		$background_color = isset($settings['verification_background']) ? $settings['verification_background'] : array(236, 237, 243);
1082
1083
	// The color of the characters shown (red, green, blue).
1084
	if ($simpleFGColor)
1085
		$foreground_color = array(0, 0, 0);
1086
	else
1087
	{
1088
		$foreground_color = array(64, 101, 136);
1089
1090
		// Has the theme author requested a custom color?
1091
		if (isset($settings['verification_foreground']))
1092
			$foreground_color = $settings['verification_foreground'];
1093
	}
1094
1095
	if (!is_dir($settings['default_theme_dir'] . '/fonts'))
1096
		return false;
1097
1098
	// Can we use true type fonts?
1099
	$can_do_ttf = function_exists('imagettftext');
1100
1101
	// Get a list of the available fonts.
1102
	$font_dir = dir($settings['default_theme_dir'] . '/fonts');
1103
	$font_list = array();
1104
	$ttfont_list = array();
1105
	while ($entry = $font_dir->read())
1106
	{
1107
		if (preg_match('~^(.+)\.gdf$~', $entry, $matches) === 1)
1108
			$font_list[] = $entry;
1109
		elseif (preg_match('~^(.+)\.ttf$~', $entry, $matches) === 1)
1110
			$ttfont_list[] = $entry;
1111
	}
1112
1113
	if (empty($font_list) && ($can_do_ttf && empty($ttfont_list)))
1114
		return false;
1115
1116
	// For non-hard things don't even change fonts.
1117
	if (!$varyFonts)
1118
	{
1119
		$font_list = !empty($font_list) ? array($font_list[0]) : $font_list;
1120
1121
		// Try use Screenge if we can - it looks good!
1122
		if (in_array('VDS_New.ttf', $ttfont_list))
1123
			$ttfont_list = array('VDS_New.ttf');
1124
		else
1125
			$ttfont_list = empty($ttfont_list) ? array() : array($ttfont_list[0]);
1126
	}
1127
1128
	// Create a list of characters to be shown.
1129
	$characters = array();
1130
	$loaded_fonts = array();
1131
	$str_len = strlen($code);
1132
	for ($i = 0; $i < $str_len; $i++)
1133
	{
1134
		$characters[$i] = array(
1135
			'id' => $code[$i],
1136
			'font' => array_rand($can_do_ttf ? $ttfont_list : $font_list),
1137
		);
1138
1139
		$loaded_fonts[$characters[$i]['font']] = null;
1140
	}
1141
1142
	// Load all fonts and determine the maximum font height.
1143
	if (!$can_do_ttf)
1144
		foreach ($loaded_fonts as $font_index => $dummy)
1145
			$loaded_fonts[$font_index] = imageloadfont($settings['default_theme_dir'] . '/fonts/' . $font_list[$font_index]);
1146
1147
	// Determine the dimensions of each character.
1148
	$total_width = $character_spacing * strlen($code) + 50;
1149
	$max_height = 0;
1150
	foreach ($characters as $char_index => $character)
1151
	{
1152
		if ($can_do_ttf)
1153
		{
1154
			// GD2 handles font size differently.
1155
			if ($fontSizeRandom)
1156
				$font_size = $gd2 ? mt_rand(17, 19) : mt_rand(25, 27);
1157
			else
1158
				$font_size = $gd2 ? 17 : 27;
1159
1160
			$img_box = imagettfbbox($font_size, 0, $settings['default_theme_dir'] . '/fonts/' . $ttfont_list[$character['font']], $character['id']);
1161
1162
			$characters[$char_index]['width'] = abs($img_box[2] - $img_box[0]);
1163
			$characters[$char_index]['height'] = abs($img_box[7] - $img_box[1]);
1164
		}
1165
		else
1166
		{
1167
			$characters[$char_index]['width'] = imagefontwidth($loaded_fonts[$character['font']]);
1168
			$characters[$char_index]['height'] = imagefontheight($loaded_fonts[$character['font']]);
1169
		}
1170
1171
		$max_height = max($characters[$char_index]['height'] + 5, $max_height);
1172
		$total_width += $characters[$char_index]['width'] + 2;
1173
	}
1174
1175
	// Create an image.
1176
	$code_image = $gd2 ? imagecreatetruecolor($total_width, $max_height) : imagecreate($total_width, $max_height);
1177
1178
	// Draw the background.
1179
	$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

1179
	$bg_color = imagecolorallocate(/** @scrutinizer ignore-type */ $code_image, $background_color[0], $background_color[1], $background_color[2]);
Loading history...
1180
	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

1180
	imagefilledrectangle(/** @scrutinizer ignore-type */ $code_image, 0, 0, $total_width - 1, $max_height - 1, $bg_color);
Loading history...
1181
1182
	// Randomize the foreground color a little.
1183
	for ($i = 0; $i < 3; $i++)
1184
		$foreground_color[$i] = mt_rand(max($foreground_color[$i] - 3, 0), min($foreground_color[$i] + 3, 255));
1185
	$fg_color = imagecolorallocate($code_image, $foreground_color[0], $foreground_color[1], $foreground_color[2]);
1186
1187
	// Color for the noise dots.
1188
	$dotbgcolor = array();
1189
	for ($i = 0; $i < 3; $i++)
1190
		$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);
1191
	$randomness_color = imagecolorallocate($code_image, $dotbgcolor[0], $dotbgcolor[1], $dotbgcolor[2]);
1192
1193
	// Some squares/rectangles for new extreme level
1194
	if ($noiseType == 'extreme')
1195
	{
1196
		for ($i = 0; $i < rand(1, 5); $i++)
1197
		{
1198
			$x1 = rand(0, $total_width / 4);
1199
			$x2 = $x1 + round(rand($total_width / 4, $total_width));
1200
			$y1 = rand(0, $max_height);
1201
			$y2 = $y1 + round(rand(0, $max_height / 3));
1202
			imagefilledrectangle($code_image, $x1, $y1, $x2, $y2, mt_rand(0, 1) ? $fg_color : $randomness_color);
0 ignored issues
show
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

1202
			imagefilledrectangle($code_image, $x1, $y1, /** @scrutinizer ignore-type */ $x2, $y2, mt_rand(0, 1) ? $fg_color : $randomness_color);
Loading history...
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

1202
			imagefilledrectangle($code_image, $x1, $y1, $x2, /** @scrutinizer ignore-type */ $y2, mt_rand(0, 1) ? $fg_color : $randomness_color);
Loading history...
1203
		}
1204
	}
1205
1206
	// Fill in the characters.
1207
	if (!$disableChars)
1208
	{
1209
		$cur_x = 0;
1210
		$last_index = -1;
1211
		foreach ($characters as $char_index => $character)
1212
		{
1213
			// How much rotation will we give?
1214
			if ($rotationType == 'none')
1215
				$angle = 0;
1216
			else
1217
				$angle = mt_rand(-100, 100) / ($rotationType == 'high' ? 6 : 10);
1218
1219
			// What color shall we do it?
1220
			if ($fontColorType == 'cyclic')
1221
			{
1222
				// Here we'll pick from a set of acceptance types.
1223
				$colors = array(
1224
					array(10, 120, 95),
1225
					array(46, 81, 29),
1226
					array(4, 22, 154),
1227
					array(131, 9, 130),
1228
					array(0, 0, 0),
1229
					array(143, 39, 31),
1230
				);
1231
1232
				// Pick a color, but not the same one twice in a row
1233
				$new_index = $last_index;
1234
				while ($last_index == $new_index)
1235
					$new_index = mt_rand(0, count($colors) - 1);
1236
				$char_fg_color = $colors[$new_index];
1237
				$last_index = $new_index;
1238
			}
1239
			elseif ($fontColorType == 'random')
1240
				$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]));
1241
			else
1242
				$char_fg_color = array($foreground_color[0], $foreground_color[1], $foreground_color[2]);
1243
1244
			if (!empty($can_do_ttf))
1245
			{
1246
				// GD2 handles font size differently.
1247
				if ($fontSizeRandom)
1248
					$font_size = $gd2 ? mt_rand(17, 19) : mt_rand(18, 25);
1249
				else
1250
					$font_size = $gd2 ? 18 : 24;
1251
1252
				// Work out the sizes - also fix the character width cause TTF not quite so wide!
1253
				$font_x = $fontHorSpace === 'minus' && $cur_x > 0 ? $cur_x - 3 : $cur_x + 5;
1254
				$font_y = $max_height - ($fontVerPos === 'vrandom' ? mt_rand(2, 8) : ($fontVerPos === 'random' ? mt_rand(3, 5) : 5));
1255
1256
				// What font face?
1257
				if (!empty($ttfont_list))
1258
					$fontface = $settings['default_theme_dir'] . '/fonts/' . $ttfont_list[mt_rand(0, count($ttfont_list) - 1)];
1259
1260
				// What color are we to do it in?
1261
				$is_reverse = $showReverseChars ? mt_rand(0, 1) : false;
1262
				$char_color = $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

1262
				$char_color = $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...
1263
1264
				$fontcord = @imagettftext($code_image, $font_size, $angle, $font_x, $font_y, $char_color, $fontface, $character['id']);
0 ignored issues
show
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

1264
				$fontcord = @imagettftext(/** @scrutinizer ignore-type */ $code_image, $font_size, $angle, $font_x, $font_y, $char_color, $fontface, $character['id']);
Loading history...
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...
1265
				if (empty($fontcord))
1266
					$can_do_ttf = false;
1267
				elseif ($is_reverse !== false)
1268
				{
1269
					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

1269
					imagefilledpolygon(/** @scrutinizer ignore-type */ $code_image, $fontcord, 4, $fg_color);
Loading history...
1270
1271
					// Put the character back!
1272
					imagettftext($code_image, $font_size, $angle, $font_x, $font_y, $randomness_color, $fontface, $character['id']);
1273
				}
1274
1275
				if ($can_do_ttf)
1276
					$cur_x = max($fontcord[2], $fontcord[4]) + ($angle == 0 ? 0 : 3);
1277
			}
1278
1279
			if (!$can_do_ttf)
1280
			{
1281
				$char_image = $gd2 ? imagecreatetruecolor($character['width'], $character['height']) : imagecreate($character['width'], $character['height']);
1282
				$char_bgcolor = imagecolorallocate($char_image, $background_color[0], $background_color[1], $background_color[2]);
1283
				imagefilledrectangle($char_image, 0, 0, $character['width'] - 1, $character['height'] - 1, $char_bgcolor);
1284
				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

1284
				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...
1285
				$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

1285
				$rotated_char = imagerotate(/** @scrutinizer ignore-type */ $char_image, mt_rand(-100, 100) / 10, $char_bgcolor);
Loading history...
1286
				imagecopy($code_image, $rotated_char, $cur_x, 0, 0, 0, $character['width'], $character['height']);
0 ignored issues
show
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

1286
				imagecopy($code_image, /** @scrutinizer ignore-type */ $rotated_char, $cur_x, 0, 0, 0, $character['width'], $character['height']);
Loading history...
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

1286
				imagecopy(/** @scrutinizer ignore-type */ $code_image, $rotated_char, $cur_x, 0, 0, 0, $character['width'], $character['height']);
Loading history...
1287
				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

1287
				imagedestroy(/** @scrutinizer ignore-type */ $rotated_char);
Loading history...
1288
				imagedestroy($char_image);
1289
1290
				$cur_x += $character['width'] + $character_spacing;
1291
			}
1292
		}
1293
	}
1294
	// If disabled just show a cross.
1295
	else
1296
	{
1297
		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

1297
		imageline(/** @scrutinizer ignore-type */ $code_image, 0, 0, $total_width, $max_height, $fg_color);
Loading history...
1298
		imageline($code_image, 0, $max_height, $total_width, 0, $fg_color);
1299
	}
1300
1301
	// Make the background color transparent on the hard image.
1302
	if (!$simpleBGColor)
1303
		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

1303
		imagecolortransparent(/** @scrutinizer ignore-type */ $code_image, $bg_color);
Loading history...
1304
1305
	if ($hasBorder)
1306
		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

1306
		imagerectangle(/** @scrutinizer ignore-type */ $code_image, 0, 0, $total_width - 1, $max_height - 1, $fg_color);
Loading history...
1307
1308
	// Add some noise to the background?
1309
	if ($noiseType != 'none')
1310
	{
1311
		for ($i = mt_rand(0, 2); $i < $max_height; $i += mt_rand(1, 2))
1312
			for ($j = mt_rand(0, 10); $j < $total_width; $j += mt_rand(1, 10))
1313
				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

1313
				imagesetpixel(/** @scrutinizer ignore-type */ $code_image, $j, $i, mt_rand(0, 1) ? $fg_color : $randomness_color);
Loading history...
1314
1315
		// Put in some lines too?
1316
		if ($noiseType != 'extreme')
1317
		{
1318
			$num_lines = $noiseType == 'high' ? mt_rand(3, 7) : mt_rand(2, 5);
1319
			for ($i = 0; $i < $num_lines; $i++)
1320
			{
1321
				if (mt_rand(0, 1))
1322
				{
1323
					$x1 = mt_rand(0, $total_width);
1324
					$x2 = mt_rand(0, $total_width);
1325
					$y1 = 0;
1326
					$y2 = $max_height;
1327
				}
1328
				else
1329
				{
1330
					$y1 = mt_rand(0, $max_height);
1331
					$y2 = mt_rand(0, $max_height);
1332
					$x1 = 0;
1333
					$x2 = $total_width;
1334
				}
1335
				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

1335
				imagesetthickness(/** @scrutinizer ignore-type */ $code_image, mt_rand(1, 2));
Loading history...
1336
				imageline($code_image, $x1, $y1, $x2, $y2, mt_rand(0, 1) ? $fg_color : $randomness_color);
1337
			}
1338
		}
1339
		else
1340
		{
1341
			// Put in some ellipse
1342
			$num_ellipse = $noiseType == 'extreme' ? mt_rand(6, 12) : mt_rand(2, 6);
1343
			for ($i = 0; $i < $num_ellipse; $i++)
1344
			{
1345
				$x1 = round(rand(($total_width / 4) * -1, $total_width + ($total_width / 4)));
1346
				$x2 = round(rand($total_width / 2, 2 * $total_width));
1347
				$y1 = round(rand(($max_height / 4) * -1, $max_height + ($max_height / 4)));
1348
				$y2 = round(rand($max_height / 2, 2 * $max_height));
1349
				imageellipse($code_image, $x1, $y1, $x2, $y2, mt_rand(0, 1) ? $fg_color : $randomness_color);
0 ignored issues
show
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

1349
				imageellipse($code_image, $x1, $y1, /** @scrutinizer ignore-type */ $x2, $y2, mt_rand(0, 1) ? $fg_color : $randomness_color);
Loading history...
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

1349
				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

1349
				imageellipse($code_image, $x1, /** @scrutinizer ignore-type */ $y1, $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

1349
				imageellipse(/** @scrutinizer ignore-type */ $code_image, $x1, $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

1349
				imageellipse($code_image, /** @scrutinizer ignore-type */ $x1, $y1, $x2, $y2, mt_rand(0, 1) ? $fg_color : $randomness_color);
Loading history...
1350
			}
1351
		}
1352
	}
1353
1354
	// Show the image.
1355
	if (function_exists('imagepng'))
1356
	{
1357
		header('Content-type: image/png');
1358
		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

1358
		imagepng(/** @scrutinizer ignore-type */ $code_image);
Loading history...
1359
	}
1360
	else
1361
	{
1362
		header('Content-type: image/gif');
1363
		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

1363
		imagegif(/** @scrutinizer ignore-type */ $code_image);
Loading history...
1364
	}
1365
1366
	// Bail out.
1367
	imagedestroy($code_image);
1368
	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...
1369
}
1370
1371
/**
1372
 * Show a letter for the visual verification code.
1373
 *
1374
 * - Alternative function for showCodeImage() in case GD is missing.
1375
 * - Includes an image from a random sub directory of default_theme_dir/fonts.
1376
 *
1377
 * @package Graphics
1378
 * @param string $letter A letter to show as an image
1379
 *
1380
 * @return false|null false if something goes wrong.
1381
 */
1382
function showLetterImage($letter)
1383
{
1384
	global $settings;
1385
1386
	if (!is_dir($settings['default_theme_dir'] . '/fonts'))
1387
		return false;
1388
1389
	// Get a list of the available font directories.
1390
	$font_dir = dir($settings['default_theme_dir'] . '/fonts');
1391
	$font_list = array();
1392
	while ($entry = $font_dir->read())
1393
		if ($entry[0] !== '.' && is_dir($settings['default_theme_dir'] . '/fonts/' . $entry) && file_exists($settings['default_theme_dir'] . '/fonts/' . $entry . '.gdf'))
1394
			$font_list[] = $entry;
1395
1396
	if (empty($font_list))
1397
		return false;
1398
1399
	// Pick a random font.
1400
	$random_font = $font_list[array_rand($font_list)];
1401
1402
	// Check if the given letter exists.
1403
	if (!file_exists($settings['default_theme_dir'] . '/fonts/' . $random_font . '/' . $letter . '.gif'))
1404
		return false;
1405
1406
	// Include it!
1407
	header('Content-type: image/gif');
1408
	include($settings['default_theme_dir'] . '/fonts/' . $random_font . '/' . $letter . '.gif');
1409
1410
	// Nothing more to come.
1411
	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...
1412
}
1413
1414
/**
1415
 * Simple function to generate an image containing some text.
1416
 * It uses preferentially Imagick if present, otherwise GD.
1417
 * Font and size are fixed.
1418
 *
1419
 * @package Graphics
1420
 *
1421
 * @param string $text The text the image should contain
1422
 * @param int $width Width of the final image
1423
 * @param int $height Height of the image
1424
 * @param string $format Type of the image (valid types are png, jpeg, gif)
1425
 *
1426
 * @return boolean|resource The image or false if neither Imagick nor GD are found
1427
 */
1428
function generateTextImage($text, $width = 100, $height = 100, $format = 'png')
1429
{
1430
	$valid_formats = array('jpeg', 'png', 'gif');
1431
	if (!in_array($format, $valid_formats))
1432
	{
1433
		$format = 'png';
1434
	}
1435
1436
	if (checkImagick() === true)
1437
	{
1438
		return generateTextImageWithIM($text, $width, $height, $format);
1439
	}
1440
	elseif (checkGD() === true)
1441
	{
1442
		return generateTextImageWithGD($text, $width, $height, $format);
1443
	}
1444
	else
1445
	{
1446
		return false;
1447
	}
1448
}
1449
1450
/**
1451
 * Simple function to generate an image containing some text.
1452
 * It uses preferentially Imagick if present, otherwise GD.
1453
 * Font and size are fixed.
1454
 *
1455
 * @uses GD
1456
 *
1457
 * @package Graphics
1458
 *
1459
 * @param string $text The text the image should contain
1460
 * @param int $width Width of the final image
1461
 * @param int $height Height of the image
1462
 * @param string $format Type of the image (valid types are png, jpeg, gif)
1463
 *
1464
 * @return resource|boolean The image
1465
 */
1466
function generateTextImageWithGD($text, $width = 100, $height = 100, $format = 'png')
1467
{
1468
	global $settings;
1469
1470
	$create_function = 'image' . $format;
1471
1472
	// Create a white filled box
1473
	$image = imagecreate($width, $height);
1474
	imagecolorallocate($image, 255, 255, 255);
0 ignored issues
show
Bug introduced by
It seems like $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

1474
	imagecolorallocate(/** @scrutinizer ignore-type */ $image, 255, 255, 255);
Loading history...
1475
1476
	$text_color = imagecolorallocate($image, 0, 0, 0);
1477
	$font = $settings['default_theme_dir'] . '/fonts/VDS_New.ttf';
1478
1479
	// The loop is to try to fit the text into the image.
1480
	$true_type = function_exists('imagettftext');
1481
	$font_size = $true_type ? 28 : 5;
1482
	do
1483
	{
1484
		if ($true_type)
1485
		{
1486
			$metric = imagettfbbox($font_size, 0, $font, $text);
1487
			$text_width = abs($metric[4] - $metric[0]);
1488
			$text_height = abs($metric[5] - $metric[1]);
1489
		}
1490
		else
1491
		{
1492
			$text_width = imagefontwidth($font_size) * strlen($text);
1493
			$text_height = imagefontheight($font_size);
1494
		}
1495
	} while ($text_width > $width && $font_size-- > 1);
1496
1497
	$w_offset = ($width - $text_width) / 2;
1498
	$h_offset = $true_type ? ($height / 2) + ($text_height / 2) : ($height - $text_height) / 2;
1499
1500
	if ($true_type)
1501
	{
1502
		imagettftext($image, $font_size, 0, $w_offset, $h_offset, $text_color, $font, $text);
0 ignored issues
show
Bug introduced by
$w_offset of type double is incompatible with the type integer expected by parameter $x of imagettftext(). ( Ignorable by Annotation )

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

1502
		imagettftext($image, $font_size, 0, /** @scrutinizer ignore-type */ $w_offset, $h_offset, $text_color, $font, $text);
Loading history...
Bug introduced by
It seems like $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

1502
		imagettftext(/** @scrutinizer ignore-type */ $image, $font_size, 0, $w_offset, $h_offset, $text_color, $font, $text);
Loading history...
Bug introduced by
$h_offset of type double is incompatible with the type integer expected by parameter $y of imagettftext(). ( Ignorable by Annotation )

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

1502
		imagettftext($image, $font_size, 0, $w_offset, /** @scrutinizer ignore-type */ $h_offset, $text_color, $font, $text);
Loading history...
1503
	}
1504
	else
1505
	{
1506
		imagestring($image, $font_size, $w_offset, $h_offset, $text, $text_color);
0 ignored issues
show
Bug introduced by
It seems like $image can also be of type false; however, parameter $image of imagestring() 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

1506
		imagestring(/** @scrutinizer ignore-type */ $image, $font_size, $w_offset, $h_offset, $text, $text_color);
Loading history...
Bug introduced by
$w_offset of type double is incompatible with the type integer expected by parameter $x of imagestring(). ( Ignorable by Annotation )

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

1506
		imagestring($image, $font_size, /** @scrutinizer ignore-type */ $w_offset, $h_offset, $text, $text_color);
Loading history...
Bug introduced by
$h_offset of type double is incompatible with the type integer expected by parameter $y of imagestring(). ( Ignorable by Annotation )

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

1506
		imagestring($image, $font_size, $w_offset, /** @scrutinizer ignore-type */ $h_offset, $text, $text_color);
Loading history...
1507
	}
1508
1509
	// Capture the image string
1510
	ob_start();
1511
	$result = $create_function($image);
1512
	$image = ob_get_contents();
1513
	ob_end_clean();
1514
1515
	return $result ? $image : false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $result ? $image : false also could return the type string which is incompatible with the documented return type boolean|resource.
Loading history...
1516
}
1517
1518
/**
1519
 * Function to generate an image containing some text.
1520
 * It uses Imagick, Font and size are fixed to fit within width
1521
 *
1522
 * @uses Imagick
1523
 *
1524
 * @package Graphics
1525
 *
1526
 * @param string $text The text the image should contain
1527
 * @param int $width Width of the final image
1528
 * @param int $height Height of the image
1529
 * @param string $format Type of the image (valid types are png, jpeg, gif)
1530
 *
1531
 * @return boolean|resource The image or false on error
1532
 */
1533
function generateTextImageWithIM($text, $width = 100, $height = 100, $format = 'png')
1534
{
1535
	global $settings;
1536
1537
	try
1538
	{
1539
		$image = new Imagick();
1540
		$image->newImage($width, $height, new ImagickPixel('white'));
1541
		$image->setImageFormat($format);
1542
1543
		// 28pt is ~2em given default font stack
1544
		$font_size = 28;
1545
1546
		$draw = new ImagickDraw();
1547
		$draw->setStrokeColor(new ImagickPixel('#000000'));
1548
		$draw->setFillColor(new ImagickPixel('#000000'));
1549
		$draw->setStrokeWidth(0);
1550
		$draw->setTextAlignment(Imagick::ALIGN_CENTER);
1551
		$draw->setFont($settings['default_theme_dir'] . '/fonts/VDS_New.ttf');
1552
1553
		// Make sure the text will fit the the allowed space
1554
		do
1555
		{
1556
			$draw->setFontSize($font_size);
1557
			$metric = $image->queryFontMetrics($draw, $text);
1558
			$text_width = (int) $metric['textWidth'];
1559
		} while ($text_width > $width && $font_size-- > 1);
1560
1561
		// Place text in center of block
1562
		$image->annotateImage($draw, $width / 2, $height / 2 + $font_size / 4, 0, $text);
1563
		$image = $image->getImageBlob();
1564
1565
		return $image;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $image returns the type string which is incompatible with the documented return type boolean|resource.
Loading history...
1566
	}
1567
	catch (Exception $e)
1568
	{
1569
		return false;
1570
	}
1571
}
1572