Completed
Pull Request — master (#2914)
by Emanuele
22:22 queued 15:01
created

Graphics.subs.php ➔ autoRotateImageWithGD()   C

Complexity

Conditions 16
Paths 44

Size

Total Lines 65
Code Lines 37

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 16
eloc 37
nc 44
nop 1
dl 0
loc 65
rs 5.9197
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
3
/**
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 software is a derived product, based on:
15
 *
16
 * Simple Machines Forum (SMF)
17
 * copyright:	2011 Simple Machines (http://www.simplemachines.org)
18
 * license:  	BSD, See included LICENSE.TXT for terms and conditions.
19
 *
20
 * @version 1.0.10
21
 *
22
 */
23
24
if (!defined('ELK'))
25
	die('No access...');
26
27
/**
28
 * Create a thumbnail of the given source.
29
 *
30
 * @uses resizeImageFile() function to achieve the resize.
31
 *
32
 * @package Graphics
33
 * @param string $source
34
 * @param int $max_width
35
 * @param int $max_height
36
 * @return boolean whether the thumbnail creation was successful.
37
 */
38
function createThumbnail($source, $max_width, $max_height)
39
{
40
	global $modSettings;
41
42
	$destName = $source . '_thumb.tmp';
43
44
	// Do the actual resize.
45
	if (!empty($modSettings['attachment_thumb_png']))
46
		$success = resizeImageFile($source, $destName, $max_width, $max_height, 3);
47
	else
48
		$success = resizeImageFile($source, $destName, $max_width, $max_height);
49
50
	// Okay, we're done with the temporary stuff.
51
	$destName = substr($destName, 0, -4);
52
53
	if ($success && @rename($destName . '.tmp', $destName))
54
		return true;
55
	else
56
	{
57
		@unlink($destName . '.tmp');
58
		@touch($destName);
59
		return false;
60
	}
61
}
62
63
/**
64
 * Used to re-econodes an image to a specifed image format
65
 *
66
 * - creates a copy of the file at the same location as fileName.
67
 * - the file would have the format preferred_format if possible, otherwise the default format is jpeg.
68
 * - the function makes sure that all non-essential image contents are disposed.
69
 *
70
 * @package Graphics
71
 * @param string $fileName
72
 * @param int $preferred_format = 0
73
 * @return boolean true on success, false on failure.
74
 */
75
function reencodeImage($fileName, $preferred_format = 0)
76
{
77
	if (!resizeImageFile($fileName, $fileName . '.tmp', null, null, $preferred_format))
78
	{
79
		if (file_exists($fileName . '.tmp'))
80
			unlink($fileName . '.tmp');
81
82
		return false;
83
	}
84
85
	if (!unlink($fileName))
86
		return false;
87
88
	if (!rename($fileName . '.tmp', $fileName))
0 ignored issues
show
Unused Code introduced by
This if statement, and the following return statement can be replaced with return rename($fileName . '.tmp', $fileName);.
Loading history...
89
		return false;
90
91
	return true;
92
}
93
94
/**
95
 * Searches through the file to see if there's potentialy harmful non-binary content.
96
 *
97
 * - if extensiveCheck is true, searches for asp/php short tags as well.
98
 *
99
 * @package Graphics
100
 * @param string $fileName
101
 * @param bool $extensiveCheck = false
102
 */
103
function checkImageContents($fileName, $extensiveCheck = false)
104
{
105
	$fp = fopen($fileName, 'rb');
106
	if (!$fp)
107
		fatal_lang_error('attach_timeout');
108
109
	$prev_chunk = '';
110
	while (!feof($fp))
111
	{
112
		$cur_chunk = fread($fp, 8192);
113
114
		// Though not exhaustive lists, better safe than sorry.
115
		if (!empty($extensiveCheck))
116
		{
117
			// Paranoid check. Some like it that way.
118
			if (preg_match('~(iframe|\\<\\?|\\<%|html|eval|body|script\W|(?-i)[CFZ]WS[\x01-\x0E])~i', $prev_chunk . $cur_chunk) === 1)
119
			{
120
				fclose($fp);
121
				return false;
122
			}
123
		}
124
		else
125
		{
126
			// Check for potential infection
127
			if (preg_match('~(iframe|(?<!cellTextIs)html|eval|body|script\W|(?-i)[CFZ]WS[\x01-\x0E])~i', $prev_chunk . $cur_chunk) === 1)
128
			{
129
				fclose($fp);
130
				return false;
131
			}
132
		}
133
		$prev_chunk = $cur_chunk;
134
	}
135
	fclose($fp);
136
137
	return true;
138
}
139
140
/**
141
 * Sets a global $gd2 variable needed by some functions to determine
142
 * whether the GD2 library is present.
143
 *
144
 * @package Graphics
145
 */
146
function checkGD()
147
{
148
	global $gd2;
149
150
	// Check to see if GD is installed and what version.
151
	if (($extensionFunctions = get_extension_funcs('gd')) === false)
152
		return false;
153
154
	// Also determine if GD2 is installed and store it in a global.
155
	$gd2 = in_array('imagecreatetruecolor', $extensionFunctions) && function_exists('imagecreatetruecolor');
156
157
	return true;
158
}
159
160
/**
161
 * Checks whether the Imagick class is present.
162
 *
163
 * @package Graphics
164
 */
165
function checkImagick()
166
{
167
	return class_exists('Imagick', false);
168
}
169
170
/**
171
 * See if we have enough memory to thumbnail an image
172
 *
173
 * @package Graphics
174
 * @param int[] $sizes image size
175
 */
176
function imageMemoryCheck($sizes)
177
{
178
	global $modSettings;
179
180
	// Doing the old 'set it and hope' way?
181
	if (empty($modSettings['attachment_thumb_memory']))
182
	{
183
		setMemoryLimit('128M');
184
		return true;
185
	}
186
187
	// Determine the memory requirements for this image, note: if you want to use an image formula
188
	// W x H x bits/8 x channels x Overhead factor
189
	// You will need to account for single bit images as GD expands them to an 8 bit and will greatly
190
	// overun the calculated value.
191
	// The 5 below is simply a shortcut of 8bpp, 3 channels, 1.66 overhead
192
	$needed_memory = ($sizes[0] * $sizes[1] * 5);
193
194
	// If we need more, lets try to get it
195
	return setMemoryLimit($needed_memory, true);
196
}
197
198
/**
199
 * Resizes an image from a remote location or a local file.
200
 *
201
 * - Puts the resized image at the destination location.
202
 * - The file would have the format preferred_format if possible,
203
 * otherwise the default format is jpeg.
204
 *
205
 * @package Graphics
206
 * @param string $source
207
 * @param string $destination
208
 * @param int $max_width
209
 * @param int $max_height
210
 * @param int $preferred_format = 0
211
 */
212
function resizeImageFile($source, $destination, $max_width, $max_height, $preferred_format = 0)
213
{
214
	// Nothing to do without GD or IM
215
	if (!checkGD() && !checkImagick())
216
		return false;
217
218
	static $default_formats = array(
219
		'1' => 'gif',
220
		'2' => 'jpeg',
221
		'3' => 'png',
222
		'6' => 'bmp',
223
		'15' => 'wbmp'
224
	);
225
226
	require_once(SUBSDIR . '/Package.subs.php');
227
228
	// Get the image file, we have to work with something after all
229
	$fp_destination = fopen($destination, 'wb');
230
	if ($fp_destination && (substr($source, 0, 7) == 'http://' || substr($source, 0, 8) == 'https://'))
231
	{
232
		$fileContents = fetch_web_data($source);
233
234
		fwrite($fp_destination, $fileContents);
235
		fclose($fp_destination);
236
237
		$sizes = @getimagesize($destination);
238
	}
239
	elseif ($fp_destination)
240
	{
241
		$sizes = @getimagesize($source);
242
243
		$fp_source = fopen($source, 'rb');
244
		if ($fp_source !== false)
245
		{
246
			while (!feof($fp_source))
247
				fwrite($fp_destination, fread($fp_source, 8192));
248
			fclose($fp_source);
249
		}
250
		else
251
			$sizes = array(-1, -1, -1);
252
		fclose($fp_destination);
253
	}
254
	// We can't get to the file.
255
	else
256
		$sizes = array(-1, -1, -1);
257
258
	// See if we have -or- can get the needed memory for this operation
259
	if (checkGD() && !imageMemoryCheck($sizes))
260
		return false;
261
262
	// A known and supported format?
263
	if (checkImagick() && isset($default_formats[$sizes[2]]))
264
		return resizeImage(null, $destination, null, null, $max_width, $max_height, true, $preferred_format);
265
	elseif (checkGD() && isset($default_formats[$sizes[2]]) && function_exists('imagecreatefrom' . $default_formats[$sizes[2]]))
266
	{
267
		$imagecreatefrom = 'imagecreatefrom' . $default_formats[$sizes[2]];
268
		if ($src_img = @$imagecreatefrom($destination))
269
			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);
270
	}
271
272
	return false;
273
}
274
275
/**
276
 * Resizes an image proportionally to fit within the defined max_width and max_height limits
277
 *
278
 * - Will do nothing to the image if the file fits within the size limits
279
 * - If Image Magick is present it will use those function over any GD solutions
280
 * - If GD2 is present, it'll use it to achieve better quality (imagecopyresampled)
281
 * - Saves the new image to destination_filename, in the preferred_format
282
 * if possible, default is jpeg.
283
 *
284
 * @uses GD
285
 * @uses Imagick
286
 *
287
 * @package Graphics
288
 * @param resource|null $src_img null for Imagick images, resource form imagecreatefrom for GD
289
 * @param string $destName
290
 * @param int $src_width
291
 * @param int $src_height
292
 * @param int $max_width
293
 * @param int $max_height
294
 * @param bool $force_resize = false
295
 * @param int $preferred_format = 0
296
 */
297
function resizeImage($src_img, $destName, $src_width, $src_height, $max_width, $max_height, $force_resize = false, $preferred_format = 0)
298
{
299
	global $gd2;
300
301
	if (checkImagick())
302
	{
303
		// These are the file formats we know about
304
		static $default_formats = array(
305
			'1' => 'gif',
306
			'2' => 'jpeg',
307
			'3' => 'png',
308
			'6' => 'bmp',
309
			'15' => 'wbmp'
310
		);
311
		$preferred_format = empty($preferred_format) || !isset($default_formats[$preferred_format]) ? 2 : $preferred_format;
312
313
		// Since Imagick can throw exceptions, lets catch them
314
		try
315
		{
316
			// Get a new instance of Imagick for use
317
			$imagick = new Imagick($destName);
318
319
			// Set the input and output image size
320
			$src_width = empty($src_width) ? $imagick->getImageWidth() : $src_width;
321
			$src_height = empty($src_height) ? $imagick->getImageHeight() : $src_height;
322
323
			// The behavior of bestfit changed in Imagick 3.0.0 and it will now scale up, we prevent that
324
			$dest_width = empty($max_width) ? $src_width : min($max_width, $src_width);
325
			$dest_height = empty($max_height) ? $src_height : min($max_height, $src_height);
326
327
			// Set jpeg image quality to 80
328
			if ($default_formats[$preferred_format] === 'jpeg')
329
			{
330
				$imagick->borderImage('white', 0, 0);
331
				$imagick->setImageCompression(Imagick::COMPRESSION_JPEG);
332
				$imagick->setImageCompressionQuality(80);
333
			}
334
335
			// Create a new image in our prefered format and resize it if needed
336
			$imagick->setImageFormat($default_formats[$preferred_format]);
337
			$imagick->resizeImage($dest_width, $dest_height, Imagick::FILTER_LANCZOS, 1, true);
338
339
			// Save the new image in the destination location
340
			$success = $imagick->writeImage($destName);
341
342
			// Free resources associated with the Imagick object
343
			$imagick->clear();
344
		}
345
		catch(Exception $e)
346
		{
347
			// Not currently used, but here is the error
348
			$success = $e->getMessage();
0 ignored issues
show
Unused Code introduced by
$success is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
349
			$success = false;
350
		}
351
352
		return !empty($success);
353
	}
354
	elseif (checkGD())
355
	{
356
		$success = false;
357
358
		// Determine whether to resize to max width or to max height (depending on the limits.)
359
		if (!empty($max_width) || !empty($max_height))
360
		{
361
			if (!empty($max_width) && (empty($max_height) || $src_height * $max_width / $src_width <= $max_height))
362
			{
363
				$dst_width = $max_width;
364
				$dst_height = floor($src_height * $max_width / $src_width);
365
			}
366
			elseif (!empty($max_height))
367
			{
368
				$dst_width = floor($src_width * $max_height / $src_height);
369
				$dst_height = $max_height;
370
			}
371
372
			// Don't bother resizing if it's already smaller...
373
			if (!empty($dst_width) && !empty($dst_height) && ($dst_width < $src_width || $dst_height < $src_height || $force_resize))
374
			{
375
				// (make a true color image, because it just looks better for resizing.)
376
				if ($gd2)
377
				{
378
					$dst_img = imagecreatetruecolor($dst_width, $dst_height);
379
380
					// Deal nicely with a PNG - because we can.
381
					if ((!empty($preferred_format)) && ($preferred_format == 3))
382
					{
383
						imagealphablending($dst_img, false);
384
						if (function_exists('imagesavealpha'))
385
							imagesavealpha($dst_img, true);
386
					}
387
				}
388
				else
389
					$dst_img = imagecreate($dst_width, $dst_height);
390
391
				// Resize it!
392
				if ($gd2)
393
					imagecopyresampled($dst_img, $src_img, 0, 0, 0, 0, $dst_width, $dst_height, $src_width, $src_height);
394
				else
395
					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 $src_img defined by parameter $src_img on line 297 can also be of type null; however, imagecopyresamplebicubic() does only seem to accept resource, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
396
			}
397
			else
398
				$dst_img = $src_img;
399
		}
400
		else
401
			$dst_img = $src_img;
402
403
		// Save the image as ...
404
		if (!empty($preferred_format) && ($preferred_format == 3) && function_exists('imagepng'))
405
			$success = imagepng($dst_img, $destName);
406
		elseif (!empty($preferred_format) && ($preferred_format == 1) && function_exists('imagegif'))
407
			$success = imagegif($dst_img, $destName);
408
		elseif (function_exists('imagejpeg'))
409
			$success = imagejpeg($dst_img, $destName, 80);
410
411
		// Free the memory.
412
		imagedestroy($src_img);
413
		if ($dst_img != $src_img)
414
			imagedestroy($dst_img);
415
416
		return $success;
417
	}
418
	// Without Imagick or GD, no image resizing at all.
419
	else
420
		return false;
421
}
422
423
/**
424
 * Calls GD or ImageMagick functions to correct an images orientation
425
 * based on the EXIF orientation flag
426
 *
427
 * @param string $image_name
428
 */
429
function autoRotateImage($image_name)
430
{
431
	if (checkImagick())
432
	{
433
		autoRotateImageWithIM($image_name);
0 ignored issues
show
Documentation introduced by
$image_name is of type string, but the function expects a object.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
434
	}
435
	elseif (checkGD())
436
	{
437
		autoRotateImageWithGD($image_name);
438
	}
439
}
440
441
/**
442
 * Autorotate an image based on its EXIF Orientation tag.
443
 *
444
 * What it does:
445
 * - GD only
446
 * - Checks exif data for orientation flag and rotates image so its proper
447
 * - Does not update orientation flag as GD removes EXIF data
448
 * - Only works with jpeg images, could add TIFF as well
449
 * - Writes the update image back to $image_name
450
 *
451
 * @package Graphics
452
 * @uses GD
453
 * @param string $image_name full location of the file
454
 */
455
function autoRotateImageWithGD($image_name)
456
{
457
	// Read the EXIF data
458
	$exif = function_exists('exif_read_data') ? @exif_read_data($image_name) : array();
459
460
	// We're only interested in the exif orientation
461
	$orientation = isset($exif['Orientation']) ? $exif['Orientation'] : 0;
462
463
	// For now we only process jpeg images, so check that we have one
464
	$sizes = @getimagesize($image_name);
465
466
	// Not a jpeg or not rotated, done!
467
	if ($sizes === false || $sizes[2] !== 2 || $orientation === 0 || !imageMemoryCheck($sizes))
468
	{
469
		return false;
470
	}
471
472
	// Load the image object so we can begin the transformation(s)
473
	$source = imagecreatefromjpeg($image_name);
474
475
	// Time to spin and mirror as needed
476
	switch ($orientation)
477
	{
478
		// 0 & 1 Not set or Normal
479
		case 0:
480
		case 1:
481
			break;
482
		// 2 Mirror image, Normal orientation
483
		case 2:
484
			$source = flopImageGD($source, $sizes);
485
			break;
486
		// 3 Normal image, rotated 180
487
		case 3:
488
			$source = rotateImageGD($source, 180);
489
			break;
490
		// 4 Mirror image, rotated 180
491
		case 4:
492
			$source = flipImageGD($source, $sizes);
493
			break;
494
		// 5 Mirror image, rotated 90 CCW
495
		case 5:
496
			$source = flopImageGD($source, $sizes);
497
			$source = rotateImageGD($source, 90);
498
			break;
499
		// 6 Normal image, rotated 90 CCW
500
		case 6:
501
			$source = rotateImageGD($source, -90);
502
			break;
503
		// 7 Mirror image, rotated 90 CW
504
		case 7:
505
			$source = flopImageGD($source, $sizes);
506
			$source = rotateImageGD($source, -90);
507
			break;
508
		// 8 Normal image, rotated 90 CW
509
		case 8:
510
			$source = rotateImageGD($source, 90);
511
			break;
512
	}
513
514
	// Save the updated image, free resources
515
	imagejpeg($source, $image_name);
516
	imagedestroy($source);
517
518
	return true;
519
}
520
521
/**
522
 * Autorotate an image based on its EXIF Orientation tag.
523
 *
524
 * - ImageMagick only
525
 * - Checks exif data for orientation flag and rotates image so its proper
526
 * - Updates orientation flag if rotation was required
527
 *
528
 * @param object $image_name
529
 */
530
function autoRotateImageWithIM($image_name)
531
{
532
	// Get a new instance of Imagick for use
533
	$image = new Imagick($image_name);
534
535
	// This method should exist if Imagick has been compiled against ImageMagick version
536
	// 6.3.0 or higher which is forever ago, but we check anyway ;)
537
	if (!method_exists($image, 'getImageOrientation'))
538
		return false;
539
540
	$orientation = $image->getImageOrientation();
541
	switch ($orientation)
542
	{
543
		// 0 & 1 Not set or Normal
544
		case Imagick::ORIENTATION_UNDEFINED:
545
		case Imagick::ORIENTATION_TOPLEFT:
546
			break;
547
		// 2 Mirror image, Normal orientation
548
		case Imagick::ORIENTATION_TOPRIGHT:
549
			$image->flopImage();
550
			break;
551
		// 3 Normal image, rotated 180
552
		case Imagick::ORIENTATION_BOTTOMRIGHT:
553
			$image->rotateImage('#000', 180);
554
			break;
555
		// 4 Mirror image, rotated 180
556
		case Imagick::ORIENTATION_BOTTOMLEFT:
557
			$image->flipImage();
558
			break;
559
		// 5 Mirror image, rotated 90 CCW
560
		case Imagick::ORIENTATION_LEFTTOP:
561
			$image->rotateImage('#000', 90);
562
			$image->flopImage();
563
			break;
564
		// 6 Normal image, rotated 90 CCW
565
		case Imagick::ORIENTATION_RIGHTTOP:
566
			$image->rotateImage('#000', 90);
567
			break;
568
		// 7 Mirror image, rotated 90 CW
569
		case Imagick::ORIENTATION_RIGHTBOTTOM:
570
			$image->rotateImage('#000', -90);
571
			$image->flopImage();
572
			break;
573
		// 8 Normal image, rotated 90 CW
574
		case Imagick::ORIENTATION_LEFTBOTTOM:
575
			$image->rotateImage('#000', -90);
576
			break;
577
	}
578
579
	// Now that it's auto-rotated, make sure the EXIF data is correctly updated
580
	if ($orientation >= 2)
581
	{
582
		$image->setImageOrientation(Imagick::ORIENTATION_TOPLEFT);
583
	}
584
585
	// Save the new image in the destination location
586
	$success = $image->writeImage($image_name);
587
588
	// Free resources associated with the Imagick object
589
	$image->clear();
590
591
	return $success;
592
}
593
594
/**
595
 * Rotate an image by X degrees, GD function
596
 *
597
 * @param resource $image
598
 * @param int $degrees
599
 *
600
 * @package Graphics
601
 * @uses GD
602
 * @return resource
603
 */
604
function rotateImageGD($image, $degrees)
605
{
606
	// Kind of need this to do anything
607
	if (function_exists('imagerotate'))
608
	{
609
		// Use positive degrees so GD does not get confused
610
		$degrees -= floor($degrees / 360) * 360;
611
612
		// Rotate away
613
		$background = imagecolorallocatealpha($image, 255, 255, 255, 127);
614
		$image = imagerotate($image, $degrees, $background);
615
	}
616
617
	return $image;
618
}
619
620
/**
621
 * Flop an image using GD functions by copying top to bottom / flop
622
 *
623
 * @param resource $image
624
 * @param array $sizes populated with getimagesize results
625
 *
626
 * @package Graphics
627
 * @uses GD
628
 * @return resource
629
 */
630
function flopImageGD($image, $sizes)
631
{
632
	return flipImageGD($image, $sizes, 'horizontal');
633
}
634
635
/**
636
 * Flip an image using GD function by copying top to bottom / flip vertical
637
 *
638
 * @param resource $image
639
 * @param array $sizes populated with getimagesize results
640
 * @param string $axis vertical for flip about vertical otherwise horizontal flip
641
 *
642
 * @package Graphics
643
 * @uses GD
644
 * @return resource
645
 */
646
function flipImageGD($image, $sizes, $axis = 'vertical')
647
{
648
	// If the built in function (php 5.5) is available, use it
649
	if (function_exists('imageflip'))
650
	{
651
		imageflip($image, $axis === 'vertical' ? IMG_FLIP_VERTICAL : IMG_FLIP_HORIZONTAL);
652
	}
653
	// Pixel mapping then
654
	else
655
	{
656
		$new = imagecreatetruecolor($sizes[0], $sizes[1]);
657
		imagealphablending($new, false);
658
		imagesavealpha($new, true);
659
660
		if ($axis === 'vertical')
661
		{
662
			for ($y = 0; $y < $sizes[1]; $y++)
663
			{
664
				imagecopy($new, $image, 0, $y, 0, $sizes[1] - $y - 1, $sizes[0], 1);
665
			}
666
		}
667
		else
668
		{
669
			for ($x = 0; $x < $sizes[0]; $x++)
670
			{
671
				imagecopy($new, $image, $x, 0, $sizes[0] - $x - 1, 0, 1, $sizes[1]);
672
			}
673
		}
674
675
		$image = $new;
676
		unset($new);
677
	}
678
679
	return $image;
680
}
681
682
/**
683
 * Copy / resize an image using GD bicubic methods
684
 *
685
 * - Used when imagecopyresample() is not available
686
 * - Uses bicubic resizing methods which are lower quality then imagecopyresample
687
 *
688
 * @package Graphics
689
 * @param resource $dst_img
690
 * @param resource $src_img
691
 * @param int $dst_x
692
 * @param int $dst_y
693
 * @param int $src_x
694
 * @param int $src_y
695
 * @param int $dst_w
696
 * @param int $dst_h
697
 * @param int $src_w
698
 * @param int $src_h
699
 */
700
function imagecopyresamplebicubic($dst_img, $src_img, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h)
701
{
702
	$palsize = imagecolorstotal($src_img);
703
	for ($i = 0; $i < $palsize; $i++)
704
	{
705
		$colors = imagecolorsforindex($src_img, $i);
706
		imagecolorallocate($dst_img, $colors['red'], $colors['green'], $colors['blue']);
707
	}
708
709
	$scaleX = ($src_w - 1) / $dst_w;
710
	$scaleY = ($src_h - 1) / $dst_h;
711
712
	$scaleX2 = (int) $scaleX / 2;
713
	$scaleY2 = (int) $scaleY / 2;
714
715
	for ($j = $src_y; $j < $dst_h; $j++)
716
	{
717
		$sY = (int) $j * $scaleY;
718
		$y13 = $sY + $scaleY2;
719
720
		for ($i = $src_x; $i < $dst_w; $i++)
721
		{
722
			$sX = (int) $i * $scaleX;
723
			$x34 = $sX + $scaleX2;
724
725
			$color1 = imagecolorsforindex($src_img, imagecolorat($src_img, $sX, $y13));
726
			$color2 = imagecolorsforindex($src_img, imagecolorat($src_img, $sX, $sY));
727
			$color3 = imagecolorsforindex($src_img, imagecolorat($src_img, $x34, $y13));
728
			$color4 = imagecolorsforindex($src_img, imagecolorat($src_img, $x34, $sY));
729
730
			$red = ($color1['red'] + $color2['red'] + $color3['red'] + $color4['red']) / 4;
731
			$green = ($color1['green'] + $color2['green'] + $color3['green'] + $color4['green']) / 4;
732
			$blue = ($color1['blue'] + $color2['blue'] + $color3['blue'] + $color4['blue']) / 4;
733
734
			$color = imagecolorresolve($dst_img, $red, $green, $blue);
735
			if ($color == -1)
736
			{
737
				if ($palsize++ < 256)
738
					imagecolorallocate($dst_img, $red, $green, $blue);
739
				$color = imagecolorclosest($dst_img, $red, $green, $blue);
740
			}
741
742
			imagesetpixel($dst_img, $i + $dst_x - $src_x, $j + $dst_y - $src_y, $color);
743
		}
744
	}
745
}
746
747
if (!function_exists('imagecreatefrombmp'))
748
{
749
	/**
750
	 * It is set only if it doesn't already exist (for forwards compatiblity.)
751
	 *
752
	 * - It only supports uncompressed bitmaps.
753
	 * - It only supports standard windows bitmaps (no os/2 varients)
754
	 * - Returns an image identifier representing the bitmap image
755
	 * obtained from the given filename.
756
	 *
757
	 * @package Graphics
758
	 * @param string $filename
759
	 * @return resource
760
	 */
761
	function imagecreatefrombmp($filename)
762
	{
763
		global $gd2;
764
765
		$fp = fopen($filename, 'rb');
766
767
		$errors = error_reporting(0);
768
769
		// Unpack the general information about the Bitmap Image File, first 14 Bytes
770
		$header = unpack('vtype/Vsize/Vreserved/Voffset', fread($fp, 14));
771
772
		// Upack the DIB header, it stores detailed information about the bitmap image the pixel format, 40 Bytes long
773
		$info = unpack('Vsize/Vwidth/Vheight/vplanes/vbits/Vcompression/Vimagesize/Vxres/Vyres/Vncolor/Vcolorimportant', fread($fp, 40));
774
775
		// Not a standard bitmap, bail out
776
		if ($header['type'] != 0x4D42)
777
			return false;
778
779
		// Create our image canvas with the given WxH
780
		if ($gd2)
781
			$dst_img = imagecreatetruecolor($info['width'], $info['height']);
782
		else
783
			$dst_img = imagecreate($info['width'], $info['height']);
784
785
		// Color bitCounts 1,4,8 have palette information we use
786
		if ($info['bits'] == 1 || $info['bits'] == 4 || $info['bits'] == 8)
787
		{
788
			$palette_size = $header['offset'] - 54;
789
790
			// Read the palette data
791
			$palettedata = fread($fp, $palette_size);
792
793
			// Create the rgb color array
794
			$palette = array();
795
			$n = 0;
796
			for ($j = 0; $j < $palette_size; $j++)
797
			{
798
				$b = ord($palettedata[$j++]);
799
				$g = ord($palettedata[$j++]);
800
				$r = ord($palettedata[$j++]);
801
802
				$palette[$n++] = imagecolorallocate($dst_img, $r, $g, $b);
803
			}
804
		}
805
806
		$scan_line_size = ($info['bits'] * $info['width'] + 7) >> 3;
807
		$scan_line_align = $scan_line_size & 3 ? 4 - ($scan_line_size & 3) : 0;
808
809
		for ($y = 0, $l = $info['height'] - 1; $y < $info['height']; $y++, $l--)
810
		{
811
			fseek($fp, $header['offset'] + ($scan_line_size + $scan_line_align) * $l);
812
			$scan_line = fread($fp, $scan_line_size);
813
814
			if (strlen($scan_line) < $scan_line_size)
815
				continue;
816
817
			// 32 bits per pixel
818
			if ($info['bits'] == 32)
819
			{
820
				$x = 0;
821
				for ($j = 0; $j < $scan_line_size; $x++)
822
				{
823
					$b = ord($scan_line[$j++]);
824
					$g = ord($scan_line[$j++]);
825
					$r = ord($scan_line[$j++]);
826
					$j++;
827
828
					$color = imagecolorexact($dst_img, $r, $g, $b);
829
					if ($color == -1)
830
					{
831
						$color = imagecolorallocate($dst_img, $r, $g, $b);
832
833
						// Gah!  Out of colors?  Stupid GD 1... try anyhow.
834
						if ($color == -1)
835
							$color = imagecolorclosest($dst_img, $r, $g, $b);
836
					}
837
838
					imagesetpixel($dst_img, $x, $y, $color);
839
				}
840
			}
841
			// 24 bits per pixel
842
			elseif ($info['bits'] == 24)
843
			{
844
				$x = 0;
845
				for ($j = 0; $j < $scan_line_size; $x++)
846
				{
847
					$b = ord($scan_line[$j++]);
848
					$g = ord($scan_line[$j++]);
849
					$r = ord($scan_line[$j++]);
850
851
					$color = imagecolorexact($dst_img, $r, $g, $b);
852
					if ($color == -1)
853
					{
854
						$color = imagecolorallocate($dst_img, $r, $g, $b);
855
856
						// Gah!  Out of colors?  Stupid GD 1... try anyhow.
857
						if ($color == -1)
858
							$color = imagecolorclosest($dst_img, $r, $g, $b);
859
					}
860
861
					imagesetpixel($dst_img, $x, $y, $color);
862
				}
863
			}
864
			// 16 bits per pixel
865
			elseif ($info['bits'] == 16)
866
			{
867
				$x = 0;
868
				for ($j = 0; $j < $scan_line_size; $x++)
869
				{
870
					$b1 = ord($scan_line[$j++]);
871
					$b2 = ord($scan_line[$j++]);
872
873
					$word = $b2 * 256 + $b1;
874
875
					$b = (($word & 31) * 255) / 31;
876
					$g = ((($word >> 5) & 31) * 255) / 31;
877
					$r = ((($word >> 10) & 31) * 255) / 31;
878
879
					// Scale the image colors up properly.
880
					$color = imagecolorexact($dst_img, $r, $g, $b);
881
					if ($color == -1)
882
					{
883
						$color = imagecolorallocate($dst_img, $r, $g, $b);
884
885
						// Gah!  Out of colors?  Stupid GD 1... try anyhow.
886
						if ($color == -1)
887
							$color = imagecolorclosest($dst_img, $r, $g, $b);
888
					}
889
890
					imagesetpixel($dst_img, $x, $y, $color);
891
				}
892
			}
893
			// 8 bits per pixel
894
			elseif ($info['bits'] == 8)
895
			{
896
				$x = 0;
897
				for ($j = 0; $j < $scan_line_size; $x++)
898
					imagesetpixel($dst_img, $x, $y, $palette[ord($scan_line[$j++])]);
0 ignored issues
show
Bug introduced by
The variable $palette does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
899
			}
900
			// 4 bits per pixel
901
			elseif ($info['bits'] == 4)
902
			{
903
				$x = 0;
904
				for ($j = 0; $j < $scan_line_size; $x++)
905
				{
906
					$byte = ord($scan_line[$j++]);
907
908
					imagesetpixel($dst_img, $x, $y, $palette[(int) ($byte / 16)]);
909
					if (++$x < $info['width'])
910
						imagesetpixel($dst_img, $x, $y, $palette[$byte & 15]);
911
				}
912
			}
913
			// 1 bit
914
			elseif ($info['bits'] == 1)
915
			{
916
				$x = 0;
917
				for ($j = 0; $j < $scan_line_size; $x++)
918
				{
919
					$byte = ord($scan_line[$j++]);
920
921
					imagesetpixel($dst_img, $x, $y, $palette[(($byte) & 128) != 0]);
922
					for ($shift = 1; $shift < 8; $shift++)
923
					{
924
						if (++$x < $info['width'])
925
							imagesetpixel($dst_img, $x, $y, $palette[(($byte << $shift) & 128) != 0]);
926
					}
927
				}
928
			}
929
		}
930
931
		fclose($fp);
932
933
		error_reporting($errors);
934
935
		return $dst_img;
936
	}
937
}
938
939
/**
940
 * Show an image containing the visual verification code for registration.
941
 *
942
 * - Requires the GD extension.
943
 * - Uses a random font for each letter from default_theme_dir/fonts.
944
 * - Outputs a png if possible, otherwise a gif.
945
 *
946
 * @package Graphics
947
 * @param string $code
948
 * @return false|null if something goes wrong.
949
 */
950
function showCodeImage($code)
951
{
952
	global $gd2, $settings, $user_info, $modSettings;
953
954
	// What type are we going to be doing?
955
	// Note: The higher the value of visual_verification_type the harder the verification is
956
	// from 0 as disabled through to 4 as "Very hard".
957
	$imageType = $modSettings['visual_verification_type'];
958
959
	// Special case to allow the admin center to show samples.
960
	if ($user_info['is_admin'] && isset($_GET['type']))
961
		$imageType = (int) $_GET['type'];
962
963
	// Some quick references for what we do.
964
	// Do we show no, low or high noise?
965
	$noiseType = $imageType == 3 ? 'low' : ($imageType == 4 ? 'high' : ($imageType == 5 ? 'extreme' : 'none'));
966
	// Can we have more than one font in use?
967
	$varyFonts = $imageType > 1 ? true : false;
968
	// Just a plain white background?
969
	$simpleBGColor = $imageType < 3 ? true : false;
970
	// Plain black foreground?
971
	$simpleFGColor = $imageType == 0 ? true : false;
972
	// High much to rotate each character.
973
	$rotationType = $imageType == 1 ? 'none' : ($imageType > 3 ? 'low' : 'high');
974
	// Do we show some characters inversed?
975
	$showReverseChars = $imageType > 3 ? true : false;
976
	// Special case for not showing any characters.
977
	$disableChars = $imageType == 0 ? true : false;
978
	// What do we do with the font colors. Are they one color, close to one color or random?
979
	$fontColorType = $imageType == 1 ? 'plain' : ($imageType > 3 ? 'random' : 'cyclic');
980
	// Are the fonts random sizes?
981
	$fontSizeRandom = $imageType > 3 ? true : false;
982
	// How much space between characters?
983
	$fontHorSpace = $imageType > 3 ? 'high' : ($imageType == 1 ? 'medium' : 'minus');
984
	// Where do characters sit on the image? (Fixed position or random/very random)
985
	$fontVerPos = $imageType == 1 ? 'fixed' : ($imageType > 3 ? 'vrandom' : 'random');
986
	// Make font semi-transparent?
987
	$fontTrans = $imageType == 2 || $imageType == 3 ? true : false;
988
	// Give the image a border?
989
	$hasBorder = $simpleBGColor;
990
991
	// The amount of pixels inbetween characters.
992
	$character_spacing = 1;
993
994
	// What color is the background - generally white unless we're on "hard".
995
	if ($simpleBGColor)
996
		$background_color = array(255, 255, 255);
997
	else
998
		$background_color = isset($settings['verification_background']) ? $settings['verification_background'] : array(236, 237, 243);
999
1000
	// The color of the characters shown (red, green, blue).
1001
	if ($simpleFGColor)
1002
		$foreground_color = array(0, 0, 0);
1003
	else
1004
	{
1005
		$foreground_color = array(64, 101, 136);
1006
1007
		// Has the theme author requested a custom color?
1008
		if (isset($settings['verification_foreground']))
1009
			$foreground_color = $settings['verification_foreground'];
1010
	}
1011
1012
	if (!is_dir($settings['default_theme_dir'] . '/fonts'))
1013
		return false;
1014
1015
	// Can we use true type fonts?
1016
	$can_do_ttf = function_exists('imagettftext');
1017
1018
	// Get a list of the available fonts.
1019
	$font_dir = dir($settings['default_theme_dir'] . '/fonts');
1020
	$font_list = array();
1021
	$ttfont_list = array();
1022
	while ($entry = $font_dir->read())
1023
	{
1024
		if (preg_match('~^(.+)\.gdf$~', $entry, $matches) === 1)
1025
			$font_list[] = $entry;
1026
		elseif (preg_match('~^(.+)\.ttf$~', $entry, $matches) === 1)
1027
			$ttfont_list[] = $entry;
1028
	}
1029
1030
	if (empty($font_list) && ($can_do_ttf && empty($ttfont_list)))
1031
		return false;
1032
1033
	// For non-hard things don't even change fonts.
1034
	if (!$varyFonts)
1035
	{
1036
		$font_list = !empty($font_list) ? array($font_list[0]) : $font_list;
1037
1038
		// Try use Screenge if we can - it looks good!
1039
		if (in_array('VDS_New.ttf', $ttfont_list))
1040
			$ttfont_list = array('VDS_New.ttf');
1041
		else
1042
			$ttfont_list = empty($ttfont_list) ? array() : array($ttfont_list[0]);
1043
	}
1044
1045
	// Create a list of characters to be shown.
1046
	$characters = array();
1047
	$loaded_fonts = array();
1048
	$str_len = strlen($code);
1049
	for ($i = 0; $i < $str_len; $i++)
1050
	{
1051
		$characters[$i] = array(
1052
			'id' => $code[$i],
1053
			'font' => array_rand($can_do_ttf ? $ttfont_list : $font_list),
1054
		);
1055
1056
		$loaded_fonts[$characters[$i]['font']] = null;
1057
	}
1058
1059
	// Load all fonts and determine the maximum font height.
1060
	if (!$can_do_ttf)
1061
		foreach ($loaded_fonts as $font_index => $dummy)
1062
			$loaded_fonts[$font_index] = imageloadfont($settings['default_theme_dir'] . '/fonts/' . $font_list[$font_index]);
1063
1064
	// Determine the dimensions of each character.
1065
	$total_width = $character_spacing * strlen($code) + 50;
1066
	$max_height = 0;
1067
	foreach ($characters as $char_index => $character)
1068
	{
1069
		if ($can_do_ttf)
1070
		{
1071
			// GD2 handles font size differently.
1072
			if ($fontSizeRandom)
1073
				$font_size = $gd2 ? mt_rand(17, 19) : mt_rand(25, 27);
1074
			else
1075
				$font_size = $gd2 ? 17 : 27;
1076
1077
			$img_box = imagettfbbox($font_size, 0, $settings['default_theme_dir'] . '/fonts/' . $ttfont_list[$character['font']], $character['id']);
1078
1079
			$characters[$char_index]['width'] = abs($img_box[2] - $img_box[0]);
1080
			$characters[$char_index]['height'] = abs($img_box[7] - $img_box[1]);
1081
		}
1082
		else
1083
		{
1084
			$characters[$char_index]['width'] = imagefontwidth($loaded_fonts[$character['font']]);
1085
			$characters[$char_index]['height'] = imagefontheight($loaded_fonts[$character['font']]);
1086
		}
1087
1088
		$max_height = max($characters[$char_index]['height'] + 5, $max_height);
1089
		$total_width += $characters[$char_index]['width'] + 2;
1090
	}
1091
1092
	// Create an image.
1093
	$code_image = $gd2 ? imagecreatetruecolor($total_width, $max_height) : imagecreate($total_width, $max_height);
1094
1095
	// Draw the background.
1096
	$bg_color = imagecolorallocate($code_image, $background_color[0], $background_color[1], $background_color[2]);
1097
	imagefilledrectangle($code_image, 0, 0, $total_width - 1, $max_height - 1, $bg_color);
1098
1099
	// Randomize the foreground color a little.
1100
	for ($i = 0; $i < 3; $i++)
1101
		$foreground_color[$i] = mt_rand(max($foreground_color[$i] - 3, 0), min($foreground_color[$i] + 3, 255));
1102
	$fg_color = imagecolorallocate($code_image, $foreground_color[0], $foreground_color[1], $foreground_color[2]);
1103
1104
	// Color for the noise dots.
1105
	$dotbgcolor = array();
1106
	for ($i = 0; $i < 3; $i++)
1107
		$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);
1108
	$randomness_color = imagecolorallocate($code_image, $dotbgcolor[0], $dotbgcolor[1], $dotbgcolor[2]);
1109
1110
	// Some squares/rectanges for new extreme level
1111
	if ($noiseType == 'extreme')
1112
	{
1113
		for ($i = 0; $i < rand(1, 5); $i++)
1114
		{
1115
			$x1 = rand(0, $total_width / 4);
1116
			$x2 = $x1 + round(rand($total_width / 4, $total_width));
1117
			$y1 = rand(0, $max_height);
1118
			$y2 = $y1 + round(rand(0, $max_height / 3));
1119
			imagefilledrectangle($code_image, $x1, $y1, $x2, $y2, mt_rand(0, 1) ? $fg_color : $randomness_color);
1120
		}
1121
	}
1122
1123
	// Fill in the characters.
1124
	if (!$disableChars)
1125
	{
1126
		$cur_x = 0;
1127
		$last_index = -1;
1128
		foreach ($characters as $char_index => $character)
1129
		{
1130
			// How much rotation will we give?
1131
			if ($rotationType == 'none')
1132
				$angle = 0;
1133
			else
1134
				$angle = mt_rand(-100, 100) / ($rotationType == 'high' ? 6 : 10);
1135
1136
			// What color shall we do it?
1137
			if ($fontColorType == 'cyclic')
1138
			{
1139
				// Here we'll pick from a set of acceptance types.
1140
				$colors = array(
1141
					array(10, 120, 95),
1142
					array(46, 81, 29),
1143
					array(4, 22, 154),
1144
					array(131, 9, 130),
1145
					array(0, 0, 0),
1146
					array(143, 39, 31),
1147
				);
1148
1149
				// Pick a color, but not the same one twice in a row
1150
				$new_index = $last_index;
1151
				while ($last_index == $new_index)
1152
					$new_index = mt_rand(0, count($colors) - 1);
1153
				$char_fg_color = $colors[$new_index];
1154
				$last_index = $new_index;
1155
			}
1156
			elseif ($fontColorType == 'random')
1157
				$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]));
1158
			else
1159
				$char_fg_color = array($foreground_color[0], $foreground_color[1], $foreground_color[2]);
1160
1161
			if (!empty($can_do_ttf))
1162
			{
1163
				// GD2 handles font size differently.
1164
				if ($fontSizeRandom)
1165
					$font_size = $gd2 ? mt_rand(17, 19) : mt_rand(18, 25);
1166
				else
1167
					$font_size = $gd2 ? 18 : 24;
1168
1169
				// Work out the sizes - also fix the character width cause TTF not quite so wide!
1170
				$font_x = $fontHorSpace == 'minus' && $cur_x > 0 ? $cur_x - 3 : $cur_x + 5;
1171
				$font_y = $max_height - ($fontVerPos == 'vrandom' ? mt_rand(2, 8) : ($fontVerPos == 'random' ? mt_rand(3, 5) : 5));
1172
1173
				// What font face?
1174
				if (!empty($ttfont_list))
1175
					$fontface = $settings['default_theme_dir'] . '/fonts/' . $ttfont_list[mt_rand(0, count($ttfont_list) - 1)];
1176
1177
				// What color are we to do it in?
1178
				$is_reverse = $showReverseChars ? mt_rand(0, 1) : false;
1179
				$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]);
1180
1181
				$fontcord = @imagettftext($code_image, $font_size, $angle, $font_x, $font_y, $char_color, $fontface, $character['id']);
0 ignored issues
show
Bug introduced by
The variable $fontface does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1182
				if (empty($fontcord))
1183
					$can_do_ttf = false;
1184
				elseif ($is_reverse)
0 ignored issues
show
Bug Best Practice introduced by
The expression $is_reverse of type integer|false is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null 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...
1185
				{
1186
					imagefilledpolygon($code_image, $fontcord, 4, $fg_color);
1187
1188
					// Put the character back!
1189
					imagettftext($code_image, $font_size, $angle, $font_x, $font_y, $randomness_color, $fontface, $character['id']);
1190
				}
1191
1192
				if ($can_do_ttf)
1193
					$cur_x = max($fontcord[2], $fontcord[4]) + ($angle == 0 ? 0 : 3);
1194
			}
1195
1196
			if (!$can_do_ttf)
1197
			{
1198
				$char_image = $gd2 ? imagecreatetruecolor($character['width'], $character['height']) : imagecreate($character['width'], $character['height']);
1199
				$char_bgcolor = imagecolorallocate($char_image, $background_color[0], $background_color[1], $background_color[2]);
1200
				imagefilledrectangle($char_image, 0, 0, $character['width'] - 1, $character['height'] - 1, $char_bgcolor);
1201
				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]));
1202
				$rotated_char = imagerotate($char_image, mt_rand(-100, 100) / 10, $char_bgcolor);
1203
				imagecopy($code_image, $rotated_char, $cur_x, 0, 0, 0, $character['width'], $character['height']);
1204
				imagedestroy($rotated_char);
1205
				imagedestroy($char_image);
1206
1207
				$cur_x += $character['width'] + $character_spacing;
1208
			}
1209
		}
1210
	}
1211
	// If disabled just show a cross.
1212
	else
1213
	{
1214
		imageline($code_image, 0, 0, $total_width, $max_height, $fg_color);
1215
		imageline($code_image, 0, $max_height, $total_width, 0, $fg_color);
1216
	}
1217
1218
	// Make the background color transparent on the hard image.
1219
	if (!$simpleBGColor)
1220
		imagecolortransparent($code_image, $bg_color);
1221
1222
	if ($hasBorder)
1223
		imagerectangle($code_image, 0, 0, $total_width - 1, $max_height - 1, $fg_color);
1224
1225
	// Add some noise to the background?
1226
	if ($noiseType != 'none')
1227
	{
1228
		for ($i = mt_rand(0, 2); $i < $max_height; $i += mt_rand(1, 2))
1229
			for ($j = mt_rand(0, 10); $j < $total_width; $j += mt_rand(1, 10))
1230
				imagesetpixel($code_image, $j, $i, mt_rand(0, 1) ? $fg_color : $randomness_color);
1231
1232
		// Put in some lines too?
1233
		if ($noiseType != 'extreme')
1234
		{
1235
			$num_lines = $noiseType == 'high' ? mt_rand(3, 7) : mt_rand(2, 5);
1236
			for ($i = 0; $i < $num_lines; $i++)
1237
			{
1238
				if (mt_rand(0, 1))
1239
				{
1240
					$x1 = mt_rand(0, $total_width);
1241
					$x2 = mt_rand(0, $total_width);
1242
					$y1 = 0;
1243
					$y2 = $max_height;
1244
				}
1245
				else
1246
				{
1247
					$y1 = mt_rand(0, $max_height);
1248
					$y2 = mt_rand(0, $max_height);
1249
					$x1 = 0;
1250
					$x2 = $total_width;
1251
				}
1252
				imagesetthickness($code_image, mt_rand(1, 2));
1253
				imageline($code_image, $x1, $y1, $x2, $y2, mt_rand(0, 1) ? $fg_color : $randomness_color);
1254
			}
1255
		}
1256
		else
1257
		{
1258
			// Put in some ellipse
1259
			$num_ellipse = $noiseType == 'extreme' ? mt_rand(6, 12) : mt_rand(2, 6);
1260
			for ($i = 0; $i < $num_ellipse; $i++)
1261
			{
1262
				$x1 = round(rand(($total_width / 4) * -1, $total_width + ($total_width / 4)));
1263
				$x2 = round(rand($total_width / 2, 2 * $total_width));
1264
				$y1 = round(rand(($max_height / 4) * -1, $max_height + ($max_height / 4)));
1265
				$y2 = round(rand($max_height / 2, 2 * $max_height));
1266
				imageellipse($code_image, $x1, $y1, $x2, $y2, mt_rand(0, 1) ? $fg_color : $randomness_color);
1267
			}
1268
		}
1269
	}
1270
1271
	// Show the image.
1272
	if (function_exists('imagepng'))
1273
	{
1274
		header('Content-type: image/png');
1275
		imagepng($code_image);
1276
	}
1277
	else
1278
	{
1279
		header('Content-type: image/gif');
1280
		imagegif($code_image);
1281
	}
1282
1283
	// Bail out.
1284
	imagedestroy($code_image);
1285
	die();
0 ignored issues
show
Coding Style Compatibility introduced by
The function showCodeImage() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
1286
}
1287
1288
/**
1289
 * Show a letter for the visual verification code.
1290
 *
1291
 * - Alternative function for showCodeImage() in case GD is missing.
1292
 * - Includes an image from a random sub directory of default_theme_dir/fonts.
1293
 *
1294
 * @package Graphics
1295
 * @param string $letter
1296
 */
1297
function showLetterImage($letter)
1298
{
1299
	global $settings;
1300
1301
	if (!is_dir($settings['default_theme_dir'] . '/fonts'))
1302
		return false;
1303
1304
	// Get a list of the available font directories.
1305
	$font_dir = dir($settings['default_theme_dir'] . '/fonts');
1306
	$font_list = array();
1307
	while ($entry = $font_dir->read())
1308
		if ($entry[0] !== '.' && is_dir($settings['default_theme_dir'] . '/fonts/' . $entry) && file_exists($settings['default_theme_dir'] . '/fonts/' . $entry . '.gdf'))
1309
			$font_list[] = $entry;
1310
1311
	if (empty($font_list))
1312
		return false;
1313
1314
	// Pick a random font.
1315
	$random_font = $font_list[array_rand($font_list)];
1316
1317
	// Check if the given letter exists.
1318
	if (!file_exists($settings['default_theme_dir'] . '/fonts/' . $random_font . '/' . $letter . '.gif'))
1319
		return false;
1320
1321
	// Include it!
1322
	header('Content-type: image/gif');
1323
	include($settings['default_theme_dir'] . '/fonts/' . $random_font . '/' . $letter . '.gif');
1324
1325
	// Nothing more to come.
1326
	die();
0 ignored issues
show
Coding Style Compatibility introduced by
The function showLetterImage() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
1327
}