GitHub Access Token became invalid

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

Issues (423)

Security Analysis    not enabled

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

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

system/libraries/Image_lib.php (15 issues)

Upgrade to new PHP Analysis Engine

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

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

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

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

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

Loading history...
2
/**
3
 * CodeIgniter
4
 *
5
 * An open source application development framework for PHP
6
 *
7
 * This content is released under the MIT License (MIT)
8
 *
9
 * Copyright (c) 2014 - 2015, British Columbia Institute of Technology
10
 *
11
 * Permission is hereby granted, free of charge, to any person obtaining a copy
12
 * of this software and associated documentation files (the "Software"), to deal
13
 * in the Software without restriction, including without limitation the rights
14
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
 * copies of the Software, and to permit persons to whom the Software is
16
 * furnished to do so, subject to the following conditions:
17
 *
18
 * The above copyright notice and this permission notice shall be included in
19
 * all copies or substantial portions of the Software.
20
 *
21
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27
 * THE SOFTWARE.
28
 *
29
 * @package	CodeIgniter
30
 * @author	EllisLab Dev Team
31
 * @copyright	Copyright (c) 2008 - 2014, EllisLab, Inc. (http://ellislab.com/)
32
 * @copyright	Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/)
33
 * @license	http://opensource.org/licenses/MIT	MIT License
34
 * @link	http://codeigniter.com
35
 * @since	Version 1.0.0
36
 * @filesource
37
 */
38
defined('BASEPATH') OR exit('No direct script access allowed');
39
40
/**
41
 * Image Manipulation class
42
 *
43
 * @package		CodeIgniter
44
 * @subpackage	Libraries
45
 * @category	Image_lib
46
 * @author		EllisLab Dev Team
47
 * @link		http://codeigniter.com/user_guide/libraries/image_lib.html
48
 */
49
class CI_Image_lib {
50
51
	/**
52
	 * PHP extension/library to use for image manipulation
53
	 * Can be: imagemagick, netpbm, gd, gd2
54
	 *
55
	 * @var string
56
	 */
57
	public $image_library		= 'gd2';
58
59
	/**
60
	 * Path to the graphic library (if applicable)
61
	 *
62
	 * @var string
63
	 */
64
	public $library_path		= '';
65
66
	/**
67
	 * Whether to send to browser or write to disk
68
	 *
69
	 * @var bool
70
	 */
71
	public $dynamic_output		= FALSE;
72
73
	/**
74
	 * Path to original image
75
	 *
76
	 * @var string
77
	 */
78
	public $source_image		= '';
79
80
	/**
81
	 * Path to the modified image
82
	 *
83
	 * @var string
84
	 */
85
	public $new_image		= '';
86
87
	/**
88
	 * Image width
89
	 *
90
	 * @var int
91
	 */
92
	public $width			= '';
93
94
	/**
95
	 * Image height
96
	 *
97
	 * @var int
98
	 */
99
	public $height			= '';
100
101
	/**
102
	 * Quality percentage of new image
103
	 *
104
	 * @var int
105
	 */
106
	public $quality			= 90;
107
108
	/**
109
	 * Whether to create a thumbnail
110
	 *
111
	 * @var bool
112
	 */
113
	public $create_thumb		= FALSE;
114
115
	/**
116
	 * String to add to thumbnail version of image
117
	 *
118
	 * @var string
119
	 */
120
	public $thumb_marker		= '_thumb';
121
122
	/**
123
	 * Whether to maintain aspect ratio when resizing or use hard values
124
	 *
125
	 * @var bool
126
	 */
127
	public $maintain_ratio		= TRUE;
128
129
	/**
130
	 * auto, height, or width.  Determines what to use as the master dimension
131
	 *
132
	 * @var string
133
	 */
134
	public $master_dim		= 'auto';
135
136
	/**
137
	 * Angle at to rotate image
138
	 *
139
	 * @var string
140
	 */
141
	public $rotation_angle		= '';
142
143
	/**
144
	 * X Coordinate for manipulation of the current image
145
	 *
146
	 * @var int
147
	 */
148
	public $x_axis			= '';
149
150
	/**
151
	 * Y Coordinate for manipulation of the current image
152
	 *
153
	 * @var int
154
	 */
155
	public $y_axis			= '';
156
157
	// --------------------------------------------------------------------------
158
	// Watermark Vars
159
	// --------------------------------------------------------------------------
160
161
	/**
162
	 * Watermark text if graphic is not used
163
	 *
164
	 * @var string
165
	 */
166
	public $wm_text			= '';
167
168
	/**
169
	 * Type of watermarking.  Options:  text/overlay
170
	 *
171
	 * @var string
172
	 */
173
	public $wm_type			= 'text';
174
175
	/**
176
	 * Default transparency for watermark
177
	 *
178
	 * @var int
179
	 */
180
	public $wm_x_transp		= 4;
181
182
	/**
183
	 * Default transparency for watermark
184
	 *
185
	 * @var int
186
	 */
187
	public $wm_y_transp		= 4;
188
189
	/**
190
	 * Watermark image path
191
	 *
192
	 * @var string
193
	 */
194
	public $wm_overlay_path		= '';
195
196
	/**
197
	 * TT font
198
	 *
199
	 * @var string
200
	 */
201
	public $wm_font_path		= '';
202
203
	/**
204
	 * Font size (different versions of GD will either use points or pixels)
205
	 *
206
	 * @var int
207
	 */
208
	public $wm_font_size		= 17;
209
210
	/**
211
	 * Vertical alignment:   T M B
212
	 *
213
	 * @var string
214
	 */
215
	public $wm_vrt_alignment	= 'B';
216
217
	/**
218
	 * Horizontal alignment: L R C
219
	 *
220
	 * @var string
221
	 */
222
	public $wm_hor_alignment	= 'C';
223
224
	/**
225
	 * Padding around text
226
	 *
227
	 * @var int
228
	 */
229
	public $wm_padding			= 0;
230
231
	/**
232
	 * Lets you push text to the right
233
	 *
234
	 * @var int
235
	 */
236
	public $wm_hor_offset		= 0;
237
238
	/**
239
	 * Lets you push text down
240
	 *
241
	 * @var int
242
	 */
243
	public $wm_vrt_offset		= 0;
244
245
	/**
246
	 * Text color
247
	 *
248
	 * @var string
249
	 */
250
	protected $wm_font_color	= '#ffffff';
251
252
	/**
253
	 * Dropshadow color
254
	 *
255
	 * @var string
256
	 */
257
	protected $wm_shadow_color	= '';
258
259
	/**
260
	 * Dropshadow distance
261
	 *
262
	 * @var int
263
	 */
264
	public $wm_shadow_distance	= 2;
265
266
	/**
267
	 * Image opacity: 1 - 100  Only works with image
268
	 *
269
	 * @var int
270
	 */
271
	public $wm_opacity		= 50;
272
273
	// --------------------------------------------------------------------------
274
	// Private Vars
275
	// --------------------------------------------------------------------------
276
277
	/**
278
	 * Source image folder
279
	 *
280
	 * @var string
281
	 */
282
	public $source_folder		= '';
283
284
	/**
285
	 * Destination image folder
286
	 *
287
	 * @var string
288
	 */
289
	public $dest_folder		= '';
290
291
	/**
292
	 * Image mime-type
293
	 *
294
	 * @var string
295
	 */
296
	public $mime_type		= '';
297
298
	/**
299
	 * Original image width
300
	 *
301
	 * @var int
302
	 */
303
	public $orig_width		= '';
304
305
	/**
306
	 * Original image height
307
	 *
308
	 * @var int
309
	 */
310
	public $orig_height		= '';
311
312
	/**
313
	 * Image format
314
	 *
315
	 * @var string
316
	 */
317
	public $image_type		= '';
318
319
	/**
320
	 * Size of current image
321
	 *
322
	 * @var string
323
	 */
324
	public $size_str		= '';
325
326
	/**
327
	 * Full path to source image
328
	 *
329
	 * @var string
330
	 */
331
	public $full_src_path		= '';
332
333
	/**
334
	 * Full path to destination image
335
	 *
336
	 * @var string
337
	 */
338
	public $full_dst_path		= '';
339
340
	/**
341
	 * File permissions
342
	 *
343
	 * @var	int
344
	 */
345
	public $file_permissions = 0644;
346
347
	/**
348
	 * Name of function to create image
349
	 *
350
	 * @var string
351
	 */
352
	public $create_fnc		= 'imagecreatetruecolor';
353
354
	/**
355
	 * Name of function to copy image
356
	 *
357
	 * @var string
358
	 */
359
	public $copy_fnc		= 'imagecopyresampled';
360
361
	/**
362
	 * Error messages
363
	 *
364
	 * @var array
365
	 */
366
	public $error_msg		= array();
367
368
	/**
369
	 * Whether to have a drop shadow on watermark
370
	 *
371
	 * @var bool
372
	 */
373
	protected $wm_use_drop_shadow	= FALSE;
374
375
	/**
376
	 * Whether to use truetype fonts
377
	 *
378
	 * @var bool
379
	 */
380
	public $wm_use_truetype	= FALSE;
381
382
	/**
383
	 * Initialize Image Library
384
	 *
385
	 * @param	array	$props
386
	 * @return	void
387
	 */
388
	public function __construct($props = array())
389
	{
390
		if (count($props) > 0)
391
		{
392
			$this->initialize($props);
393
		}
394
395
		log_message('info', 'Image Lib Class Initialized');
396
	}
397
398
	// --------------------------------------------------------------------
399
400
	/**
401
	 * Initialize image properties
402
	 *
403
	 * Resets values in case this class is used in a loop
404
	 *
405
	 * @return	void
406
	 */
407
	public function clear()
408
	{
409
		$props = array('thumb_marker', 'library_path', 'source_image', 'new_image', 'width', 'height', 'rotation_angle', 'x_axis', 'y_axis', 'wm_text', 'wm_overlay_path', 'wm_font_path', 'wm_shadow_color', 'source_folder', 'dest_folder', 'mime_type', 'orig_width', 'orig_height', 'image_type', 'size_str', 'full_src_path', 'full_dst_path');
410
411
		foreach ($props as $val)
412
		{
413
			$this->$val = '';
414
		}
415
416
		$this->image_library 		= 'gd2';
417
		$this->dynamic_output 		= FALSE;
418
		$this->quality 				= 90;
419
		$this->create_thumb 		= FALSE;
420
		$this->thumb_marker 		= '_thumb';
421
		$this->maintain_ratio 		= TRUE;
422
		$this->master_dim 			= 'auto';
423
		$this->wm_type 				= 'text';
424
		$this->wm_x_transp 			= 4;
425
		$this->wm_y_transp 			= 4;
426
		$this->wm_font_size 		= 17;
427
		$this->wm_vrt_alignment 	= 'B';
428
		$this->wm_hor_alignment 	= 'C';
429
		$this->wm_padding 			= 0;
430
		$this->wm_hor_offset 		= 0;
431
		$this->wm_vrt_offset 		= 0;
432
		$this->wm_font_color		= '#ffffff';
433
		$this->wm_shadow_distance 	= 2;
434
		$this->wm_opacity 			= 50;
435
		$this->create_fnc 			= 'imagecreatetruecolor';
436
		$this->copy_fnc 			= 'imagecopyresampled';
437
		$this->error_msg 			= array();
438
		$this->wm_use_drop_shadow 	= FALSE;
439
		$this->wm_use_truetype 		= FALSE;
440
	}
441
442
	// --------------------------------------------------------------------
443
444
	/**
445
	 * initialize image preferences
446
	 *
447
	 * @param	array
448
	 * @return	bool
449
	 */
450
	public function initialize($props = array())
451
	{
452
		// Convert array elements into class variables
453
		if (count($props) > 0)
454
		{
455
			foreach ($props as $key => $val)
456
			{
457
				if (property_exists($this, $key))
458
				{
459
					if (in_array($key, array('wm_font_color', 'wm_shadow_color')))
460
					{
461
						if (preg_match('/^#?([0-9a-f]{3}|[0-9a-f]{6})$/i', $val, $matches))
462
						{
463
							/* $matches[1] contains our hex color value, but it might be
464
							 * both in the full 6-length format or the shortened 3-length
465
							 * value.
466
							 * We'll later need the full version, so we keep it if it's
467
							 * already there and if not - we'll convert to it. We can
468
							 * access string characters by their index as in an array,
469
							 * so we'll do that and use concatenation to form the final
470
							 * value:
471
							 */
472
							$val = (strlen($matches[1]) === 6)
473
								? '#'.$matches[1]
474
								: '#'.$matches[1][0].$matches[1][0].$matches[1][1].$matches[1][1].$matches[1][2].$matches[1][2];
475
						}
476
						else
477
						{
478
							continue;
479
						}
480
					}
481
482
					$this->$key = $val;
483
				}
484
			}
485
		}
486
487
		// Is there a source image? If not, there's no reason to continue
488
		if ($this->source_image === '')
489
		{
490
			$this->set_error('imglib_source_image_required');
491
			return FALSE;
492
		}
493
494
		/* Is getimagesize() available?
495
		 *
496
		 * We use it to determine the image properties (width/height).
497
		 * Note: We need to figure out how to determine image
498
		 * properties using ImageMagick and NetPBM
499
		 */
500
		if ( ! function_exists('getimagesize'))
501
		{
502
			$this->set_error('imglib_gd_required_for_props');
503
			return FALSE;
504
		}
505
506
		$this->image_library = strtolower($this->image_library);
507
508
		/* Set the full server path
509
		 *
510
		 * The source image may or may not contain a path.
511
		 * Either way, we'll try use realpath to generate the
512
		 * full server path in order to more reliably read it.
513
		 */
514
		if (($full_source_path = realpath($this->source_image)) !== FALSE)
515
		{
516
			$full_source_path = str_replace('\\', '/', $full_source_path);
517
		}
518
		else
519
		{
520
			$full_source_path = $this->source_image;
521
		}
522
523
		$x = explode('/', $full_source_path);
524
		$this->source_image = end($x);
525
		$this->source_folder = str_replace($this->source_image, '', $full_source_path);
526
527
		// Set the Image Properties
528
		if ( ! $this->get_image_properties($this->source_folder.$this->source_image))
529
		{
530
			return FALSE;
531
		}
532
533
		/*
534
		 * Assign the "new" image name/path
535
		 *
536
		 * If the user has set a "new_image" name it means
537
		 * we are making a copy of the source image. If not
538
		 * it means we are altering the original. We'll
539
		 * set the destination filename and path accordingly.
540
		 */
541
		if ($this->new_image === '')
542
		{
543
			$this->dest_image = $this->source_image;
544
			$this->dest_folder = $this->source_folder;
545
		}
546
		elseif (strpos($this->new_image, '/') === FALSE)
547
		{
548
			$this->dest_folder = $this->source_folder;
549
			$this->dest_image = $this->new_image;
550
		}
551
		else
552
		{
553
			if (strpos($this->new_image, '/') === FALSE && strpos($this->new_image, '\\') === FALSE)
554
			{
555
				$full_dest_path = str_replace('\\', '/', realpath($this->new_image));
556
			}
557
			else
558
			{
559
				$full_dest_path = $this->new_image;
560
			}
561
562
			// Is there a file name?
563
			if ( ! preg_match('#\.(jpg|jpeg|gif|png)$#i', $full_dest_path))
564
			{
565
				$this->dest_folder = $full_dest_path.'/';
566
				$this->dest_image = $this->source_image;
567
			}
568
			else
569
			{
570
				$x = explode('/', $full_dest_path);
571
				$this->dest_image = end($x);
572
				$this->dest_folder = str_replace($this->dest_image, '', $full_dest_path);
573
			}
574
		}
575
576
		/* Compile the finalized filenames/paths
577
		 *
578
		 * We'll create two master strings containing the
579
		 * full server path to the source image and the
580
		 * full server path to the destination image.
581
		 * We'll also split the destination image name
582
		 * so we can insert the thumbnail marker if needed.
583
		 */
584
		if ($this->create_thumb === FALSE OR $this->thumb_marker === '')
585
		{
586
			$this->thumb_marker = '';
587
		}
588
589
		$xp = $this->explode_name($this->dest_image);
590
591
		$filename = $xp['name'];
592
		$file_ext = $xp['ext'];
593
594
		$this->full_src_path = $this->source_folder.$this->source_image;
595
		$this->full_dst_path = $this->dest_folder.$filename.$this->thumb_marker.$file_ext;
596
597
		/* Should we maintain image proportions?
598
		 *
599
		 * When creating thumbs or copies, the target width/height
600
		 * might not be in correct proportion with the source
601
		 * image's width/height. We'll recalculate it here.
602
		 */
603
		if ($this->maintain_ratio === TRUE && ($this->width !== 0 OR $this->height !== 0))
604
		{
605
			$this->image_reproportion();
606
		}
607
608
		/* Was a width and height specified?
609
		 *
610
		 * If the destination width/height was not submitted we
611
		 * will use the values from the actual file
612
		 */
613
		if ($this->width === '')
614
		{
615
			$this->width = $this->orig_width;
616
		}
617
618
		if ($this->height === '')
619
		{
620
			$this->height = $this->orig_height;
621
		}
622
623
		// Set the quality
624
		$this->quality = trim(str_replace('%', '', $this->quality));
625
626
		if ($this->quality === '' OR $this->quality === 0 OR ! ctype_digit($this->quality))
0 ignored issues
show
Unused Code Bug introduced by
The strict comparison === seems to always evaluate to false as the types of $this->quality (string) and 0 (integer) can never be identical. Maybe you want to use a loose comparison == instead?
Loading history...
627
		{
628
			$this->quality = 90;
629
		}
630
631
		// Set the x/y coordinates
632
		is_numeric($this->x_axis) OR $this->x_axis = 0;
633
		is_numeric($this->y_axis) OR $this->y_axis = 0;
634
635
		// Watermark-related Stuff...
636
		if ($this->wm_overlay_path !== '')
637
		{
638
			$this->wm_overlay_path = str_replace('\\', '/', realpath($this->wm_overlay_path));
639
		}
640
641
		if ($this->wm_shadow_color !== '')
642
		{
643
			$this->wm_use_drop_shadow = TRUE;
644
		}
645
		elseif ($this->wm_use_drop_shadow === TRUE && $this->wm_shadow_color === '')
646
		{
647
			$this->wm_use_drop_shadow = FALSE;
648
		}
649
650
		if ($this->wm_font_path !== '')
651
		{
652
			$this->wm_use_truetype = TRUE;
653
		}
654
655
		return TRUE;
656
	}
657
658
	// --------------------------------------------------------------------
659
660
	/**
661
	 * Image Resize
662
	 *
663
	 * This is a wrapper function that chooses the proper
664
	 * resize function based on the protocol specified
665
	 *
666
	 * @return	bool
667
	 */
668
	public function resize()
669
	{
670
		$protocol = ($this->image_library === 'gd2') ? 'image_process_gd' : 'image_process_'.$this->image_library;
671
		return $this->$protocol('resize');
672
	}
673
674
	// --------------------------------------------------------------------
675
676
	/**
677
	 * Image Crop
678
	 *
679
	 * This is a wrapper function that chooses the proper
680
	 * cropping function based on the protocol specified
681
	 *
682
	 * @return	bool
683
	 */
684
	public function crop()
685
	{
686
		$protocol = ($this->image_library === 'gd2') ? 'image_process_gd' : 'image_process_'.$this->image_library;
687
		return $this->$protocol('crop');
688
	}
689
690
	// --------------------------------------------------------------------
691
692
	/**
693
	 * Image Rotate
694
	 *
695
	 * This is a wrapper function that chooses the proper
696
	 * rotation function based on the protocol specified
697
	 *
698
	 * @return	bool
699
	 */
700
	public function rotate()
701
	{
702
		// Allowed rotation values
703
		$degs = array(90, 180, 270, 'vrt', 'hor');
704
705
		if ($this->rotation_angle === '' OR ! in_array($this->rotation_angle, $degs))
706
		{
707
			$this->set_error('imglib_rotation_angle_required');
708
			return FALSE;
709
		}
710
711
		// Reassign the width and height
712
		if ($this->rotation_angle === 90 OR $this->rotation_angle === 270)
0 ignored issues
show
Unused Code Bug introduced by
The strict comparison === seems to always evaluate to false as the types of $this->rotation_angle (string) and 90 (integer) can never be identical. Maybe you want to use a loose comparison == instead?
Loading history...
713
		{
714
			$this->width	= $this->orig_height;
715
			$this->height	= $this->orig_width;
716
		}
717
		else
718
		{
719
			$this->width	= $this->orig_width;
720
			$this->height	= $this->orig_height;
721
		}
722
723
		// Choose resizing function
724
		if ($this->image_library === 'imagemagick' OR $this->image_library === 'netpbm')
725
		{
726
			$protocol = 'image_process_'.$this->image_library;
727
			return $this->$protocol('rotate');
728
		}
729
730
		return ($this->rotation_angle === 'hor' OR $this->rotation_angle === 'vrt')
731
			? $this->image_mirror_gd()
732
			: $this->image_rotate_gd();
733
	}
734
735
	// --------------------------------------------------------------------
736
737
	/**
738
	 * Image Process Using GD/GD2
739
	 *
740
	 * This function will resize or crop
741
	 *
742
	 * @param	string
743
	 * @return	bool
744
	 */
745
	public function image_process_gd($action = 'resize')
746
	{
747
		$v2_override = FALSE;
748
749
		// If the target width/height match the source, AND if the new file name is not equal to the old file name
750
		// we'll simply make a copy of the original with the new name... assuming dynamic rendering is off.
751
		if ($this->dynamic_output === FALSE && $this->orig_width === $this->width && $this->orig_height === $this->height)
752
		{
753
			if ($this->source_image !== $this->new_image && @copy($this->full_src_path, $this->full_dst_path))
754
			{
755
				chmod($this->full_dst_path, $this->file_permissions);
756
			}
757
758
			return TRUE;
759
		}
760
761
		// Let's set up our values based on the action
762
		if ($action === 'crop')
763
		{
764
			// Reassign the source width/height if cropping
765
			$this->orig_width  = $this->width;
766
			$this->orig_height = $this->height;
767
768
			// GD 2.0 has a cropping bug so we'll test for it
769
			if ($this->gd_version() !== FALSE)
770
			{
771
				$gd_version = str_replace('0', '', $this->gd_version());
772
				$v2_override = ($gd_version == 2);
773
			}
774
		}
775
		else
776
		{
777
			// If resizing the x/y axis must be zero
778
			$this->x_axis = 0;
779
			$this->y_axis = 0;
780
		}
781
782
		// Create the image handle
783
		if ( ! ($src_img = $this->image_create_gd()))
784
		{
785
			return FALSE;
786
		}
787
788
		/* Create the image
789
		 *
790
		 * Old conditional which users report cause problems with shared GD libs who report themselves as "2.0 or greater"
791
		 * it appears that this is no longer the issue that it was in 2004, so we've removed it, retaining it in the comment
792
		 * below should that ever prove inaccurate.
793
		 *
794
		 * if ($this->image_library === 'gd2' && function_exists('imagecreatetruecolor') && $v2_override === FALSE)
795
		 */
796
		if ($this->image_library === 'gd2' && function_exists('imagecreatetruecolor'))
797
		{
798
			$create	= 'imagecreatetruecolor';
799
			$copy	= 'imagecopyresampled';
800
		}
801
		else
802
		{
803
			$create	= 'imagecreate';
804
			$copy	= 'imagecopyresized';
805
		}
806
807
		$dst_img = $create($this->width, $this->height);
808
809
		if ($this->image_type === 3) // png we can actually preserve transparency
0 ignored issues
show
Unused Code Bug introduced by
The strict comparison === seems to always evaluate to false as the types of $this->image_type (string) and 3 (integer) can never be identical. Maybe you want to use a loose comparison == instead?
Loading history...
810
		{
811
			imagealphablending($dst_img, FALSE);
812
			imagesavealpha($dst_img, TRUE);
813
		}
814
815
		$copy($dst_img, $src_img, 0, 0, $this->x_axis, $this->y_axis, $this->width, $this->height, $this->orig_width, $this->orig_height);
816
817
		// Show the image
818 View Code Duplication
		if ($this->dynamic_output === TRUE)
819
		{
820
			$this->image_display_gd($dst_img);
821
		}
822
		elseif ( ! $this->image_save_gd($dst_img)) // Or save it
823
		{
824
			return FALSE;
825
		}
826
827
		// Kill the file handles
828
		imagedestroy($dst_img);
829
		imagedestroy($src_img);
830
831
		chmod($this->full_dst_path, $this->file_permissions);
832
833
		return TRUE;
834
	}
835
836
	// --------------------------------------------------------------------
837
838
	/**
839
	 * Image Process Using ImageMagick
840
	 *
841
	 * This function will resize, crop or rotate
842
	 *
843
	 * @param	string
844
	 * @return	bool
845
	 */
846
	public function image_process_imagemagick($action = 'resize')
847
	{
848
		// Do we have a vaild library path?
849
		if ($this->library_path === '')
850
		{
851
			$this->set_error('imglib_libpath_invalid');
852
			return FALSE;
853
		}
854
855
		if ( ! preg_match('/convert$/i', $this->library_path))
856
		{
857
			$this->library_path = rtrim($this->library_path, '/').'/convert';
858
		}
859
860
		// Execute the command
861
		$cmd = $this->library_path.' -quality '.$this->quality;
862
863
		if ($action === 'crop')
864
		{
865
			$cmd .= ' -crop '.$this->width.'x'.$this->height.'+'.$this->x_axis.'+'.$this->y_axis.' "'.$this->full_src_path.'" "'.$this->full_dst_path .'" 2>&1';
866
		}
867
		elseif ($action === 'rotate')
868
		{
869
			$angle = ($this->rotation_angle === 'hor' OR $this->rotation_angle === 'vrt')
870
					? '-flop' : '-rotate '.$this->rotation_angle;
871
872
			$cmd .= ' '.$angle.' "'.$this->full_src_path.'" "'.$this->full_dst_path.'" 2>&1';
873
		}
874
		else // Resize
875
		{
876
			if($this->maintain_ratio === TRUE)
877
			{
878
				$cmd .= ' -resize '.$this->width.'x'.$this->height.' "'.$this->full_src_path.'" "'.$this->full_dst_path.'" 2>&1';
879
			}
880
			else
881
			{
882
				$cmd .= ' -resize '.$this->width.'x'.$this->height.'\! "'.$this->full_src_path.'" "'.$this->full_dst_path.'" 2>&1';
883
			}
884
		}
885
886
		$retval = 1;
887
		// exec() might be disabled
888
		if (function_usable('exec'))
889
		{
890
			@exec($cmd, $output, $retval);
891
		}
892
893
		// Did it work?
894
		if ($retval > 0)
895
		{
896
			$this->set_error('imglib_image_process_failed');
897
			return FALSE;
898
		}
899
900
		chmod($this->full_dst_path, $this->file_permissions);
901
902
		return TRUE;
903
	}
904
905
	// --------------------------------------------------------------------
906
907
	/**
908
	 * Image Process Using NetPBM
909
	 *
910
	 * This function will resize, crop or rotate
911
	 *
912
	 * @param	string
913
	 * @return	bool
914
	 */
915
	public function image_process_netpbm($action = 'resize')
916
	{
917
		if ($this->library_path === '')
918
		{
919
			$this->set_error('imglib_libpath_invalid');
920
			return FALSE;
921
		}
922
923
		// Build the resizing command
924
		switch ($this->image_type)
925
		{
926
			case 1 :
927
				$cmd_in		= 'giftopnm';
928
				$cmd_out	= 'ppmtogif';
929
				break;
930
			case 2 :
931
				$cmd_in		= 'jpegtopnm';
932
				$cmd_out	= 'ppmtojpeg';
933
				break;
934
			case 3 :
935
				$cmd_in		= 'pngtopnm';
936
				$cmd_out	= 'ppmtopng';
937
				break;
938
		}
939
940
		if ($action === 'crop')
941
		{
942
			$cmd_inner = 'pnmcut -left '.$this->x_axis.' -top '.$this->y_axis.' -width '.$this->width.' -height '.$this->height;
943
		}
944
		elseif ($action === 'rotate')
945
		{
946
			switch ($this->rotation_angle)
947
			{
948
				case 90:	$angle = 'r270';
0 ignored issues
show
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
949
					break;
950
				case 180:	$angle = 'r180';
0 ignored issues
show
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
951
					break;
952
				case 270:	$angle = 'r90';
0 ignored issues
show
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
953
					break;
954
				case 'vrt':	$angle = 'tb';
0 ignored issues
show
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
955
					break;
956
				case 'hor':	$angle = 'lr';
0 ignored issues
show
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
957
					break;
958
			}
959
960
			$cmd_inner = 'pnmflip -'.$angle.' ';
961
		}
962
		else // Resize
963
		{
964
			$cmd_inner = 'pnmscale -xysize '.$this->width.' '.$this->height;
965
		}
966
967
		$cmd = $this->library_path.$cmd_in.' '.$this->full_src_path.' | '.$cmd_inner.' | '.$cmd_out.' > '.$this->dest_folder.'netpbm.tmp';
968
969
		$retval = 1;
970
		// exec() might be disabled
971
		if (function_usable('exec'))
972
		{
973
			@exec($cmd, $output, $retval);
974
		}
975
976
		// Did it work?
977
		if ($retval > 0)
978
		{
979
			$this->set_error('imglib_image_process_failed');
980
			return FALSE;
981
		}
982
983
		// With NetPBM we have to create a temporary image.
984
		// If you try manipulating the original it fails so
985
		// we have to rename the temp file.
986
		copy($this->dest_folder.'netpbm.tmp', $this->full_dst_path);
987
		unlink($this->dest_folder.'netpbm.tmp');
988
		chmod($this->full_dst_path, $this->file_permissions);
989
990
		return TRUE;
991
	}
992
993
	// --------------------------------------------------------------------
994
995
	/**
996
	 * Image Rotate Using GD
997
	 *
998
	 * @return	bool
999
	 */
1000
	public function image_rotate_gd()
1001
	{
1002
		// Create the image handle
1003
		if ( ! ($src_img = $this->image_create_gd()))
1004
		{
1005
			return FALSE;
1006
		}
1007
1008
		// Set the background color
1009
		// This won't work with transparent PNG files so we are
1010
		// going to have to figure out how to determine the color
1011
		// of the alpha channel in a future release.
1012
1013
		$white = imagecolorallocate($src_img, 255, 255, 255);
1014
1015
		// Rotate it!
1016
		$dst_img = imagerotate($src_img, $this->rotation_angle, $white);
1017
1018
		// Show the image
1019 View Code Duplication
		if ($this->dynamic_output === TRUE)
1020
		{
1021
			$this->image_display_gd($dst_img);
1022
		}
1023
		elseif ( ! $this->image_save_gd($dst_img)) // ... or save it
1024
		{
1025
			return FALSE;
1026
		}
1027
1028
		// Kill the file handles
1029
		imagedestroy($dst_img);
1030
		imagedestroy($src_img);
1031
1032
		chmod($this->full_dst_path, $this->file_permissions);
1033
1034
		return TRUE;
1035
	}
1036
1037
	// --------------------------------------------------------------------
1038
1039
	/**
1040
	 * Create Mirror Image using GD
1041
	 *
1042
	 * This function will flip horizontal or vertical
1043
	 *
1044
	 * @return	bool
1045
	 */
1046
	public function image_mirror_gd()
1047
	{
1048
		if ( ! $src_img = $this->image_create_gd())
1049
		{
1050
			return FALSE;
1051
		}
1052
1053
		$width  = $this->orig_width;
1054
		$height = $this->orig_height;
1055
1056
		if ($this->rotation_angle === 'hor')
1057
		{
1058 View Code Duplication
			for ($i = 0; $i < $height; $i++)
1059
			{
1060
				$left = 0;
1061
				$right = $width - 1;
1062
1063
				while ($left < $right)
1064
				{
1065
					$cl = imagecolorat($src_img, $left, $i);
1066
					$cr = imagecolorat($src_img, $right, $i);
1067
1068
					imagesetpixel($src_img, $left, $i, $cr);
1069
					imagesetpixel($src_img, $right, $i, $cl);
1070
1071
					$left++;
1072
					$right--;
1073
				}
1074
			}
1075
		}
1076
		else
1077
		{
1078 View Code Duplication
			for ($i = 0; $i < $width; $i++)
1079
			{
1080
				$top = 0;
1081
				$bottom = $height - 1;
1082
1083
				while ($top < $bottom)
1084
				{
1085
					$ct = imagecolorat($src_img, $i, $top);
1086
					$cb = imagecolorat($src_img, $i, $bottom);
1087
1088
					imagesetpixel($src_img, $i, $top, $cb);
1089
					imagesetpixel($src_img, $i, $bottom, $ct);
1090
1091
					$top++;
1092
					$bottom--;
1093
				}
1094
			}
1095
		}
1096
1097
		// Show the image
1098 View Code Duplication
		if ($this->dynamic_output === TRUE)
1099
		{
1100
			$this->image_display_gd($src_img);
1101
		}
1102
		elseif ( ! $this->image_save_gd($src_img)) // ... or save it
1103
		{
1104
			return FALSE;
1105
		}
1106
1107
		// Kill the file handles
1108
		imagedestroy($src_img);
1109
1110
		chmod($this->full_dst_path, $this->file_permissions);
1111
1112
		return TRUE;
1113
	}
1114
1115
	// --------------------------------------------------------------------
1116
1117
	/**
1118
	 * Image Watermark
1119
	 *
1120
	 * This is a wrapper function that chooses the type
1121
	 * of watermarking based on the specified preference.
1122
	 *
1123
	 * @return	bool
1124
	 */
1125
	public function watermark()
1126
	{
1127
		return ($this->wm_type === 'overlay') ? $this->overlay_watermark() : $this->text_watermark();
1128
	}
1129
1130
	// --------------------------------------------------------------------
1131
1132
	/**
1133
	 * Watermark - Graphic Version
1134
	 *
1135
	 * @return	bool
1136
	 */
1137
	public function overlay_watermark()
1138
	{
1139
		if ( ! function_exists('imagecolortransparent'))
1140
		{
1141
			$this->set_error('imglib_gd_required');
1142
			return FALSE;
1143
		}
1144
1145
		// Fetch source image properties
1146
		$this->get_image_properties();
1147
1148
		// Fetch watermark image properties
1149
		$props		= $this->get_image_properties($this->wm_overlay_path, TRUE);
1150
		$wm_img_type	= $props['image_type'];
1151
		$wm_width	= $props['width'];
1152
		$wm_height	= $props['height'];
1153
1154
		// Create two image resources
1155
		$wm_img  = $this->image_create_gd($this->wm_overlay_path, $wm_img_type);
1156
		$src_img = $this->image_create_gd($this->full_src_path);
1157
1158
		// Reverse the offset if necessary
1159
		// When the image is positioned at the bottom
1160
		// we don't want the vertical offset to push it
1161
		// further down. We want the reverse, so we'll
1162
		// invert the offset. Same with the horizontal
1163
		// offset when the image is at the right
1164
1165
		$this->wm_vrt_alignment = strtoupper($this->wm_vrt_alignment[0]);
1166
		$this->wm_hor_alignment = strtoupper($this->wm_hor_alignment[0]);
1167
1168
		if ($this->wm_vrt_alignment === 'B')
1169
			$this->wm_vrt_offset = $this->wm_vrt_offset * -1;
1170
1171
		if ($this->wm_hor_alignment === 'R')
1172
			$this->wm_hor_offset = $this->wm_hor_offset * -1;
1173
1174
		// Set the base x and y axis values
1175
		$x_axis = $this->wm_hor_offset + $this->wm_padding;
1176
		$y_axis = $this->wm_vrt_offset + $this->wm_padding;
1177
1178
		// Set the vertical position
1179 View Code Duplication
		if ($this->wm_vrt_alignment === 'M')
1180
		{
1181
			$y_axis += ($this->orig_height / 2) - ($wm_height / 2);
1182
		}
1183
		elseif ($this->wm_vrt_alignment === 'B')
1184
		{
1185
			$y_axis += $this->orig_height - $wm_height;
1186
		}
1187
1188
		// Set the horizontal position
1189
		if ($this->wm_hor_alignment === 'C')
1190
		{
1191
			$x_axis += ($this->orig_width / 2) - ($wm_width / 2);
1192
		}
1193
		elseif ($this->wm_hor_alignment === 'R')
1194
		{
1195
			$x_axis += $this->orig_width - $wm_width;
1196
		}
1197
1198
		// Build the finalized image
1199
		if ($wm_img_type === 3 && function_exists('imagealphablending'))
1200
		{
1201
			@imagealphablending($src_img, TRUE);
1202
		}
1203
1204
		// Set RGB values for text and shadow
1205
		$rgba = imagecolorat($wm_img, $this->wm_x_transp, $this->wm_y_transp);
1206
		$alpha = ($rgba & 0x7F000000) >> 24;
1207
1208
		// make a best guess as to whether we're dealing with an image with alpha transparency or no/binary transparency
1209
		if ($alpha > 0)
1210
		{
1211
			// copy the image directly, the image's alpha transparency being the sole determinant of blending
1212
			imagecopy($src_img, $wm_img, $x_axis, $y_axis, 0, 0, $wm_width, $wm_height);
1213
		}
1214
		else
1215
		{
1216
			// set our RGB value from above to be transparent and merge the images with the specified opacity
1217
			imagecolortransparent($wm_img, imagecolorat($wm_img, $this->wm_x_transp, $this->wm_y_transp));
1218
			imagecopymerge($src_img, $wm_img, $x_axis, $y_axis, 0, 0, $wm_width, $wm_height, $this->wm_opacity);
1219
		}
1220
1221
		// We can preserve transparency for PNG images
1222
		if ($this->image_type === 3)
0 ignored issues
show
Unused Code Bug introduced by
The strict comparison === seems to always evaluate to false as the types of $this->image_type (string) and 3 (integer) can never be identical. Maybe you want to use a loose comparison == instead?
Loading history...
1223
		{
1224
			imagealphablending($src_img, FALSE);
1225
			imagesavealpha($src_img, TRUE);
1226
		}
1227
1228
		// Output the image
1229 View Code Duplication
		if ($this->dynamic_output === TRUE)
1230
		{
1231
			$this->image_display_gd($src_img);
1232
		}
1233
		elseif ( ! $this->image_save_gd($src_img)) // ... or save it
1234
		{
1235
			return FALSE;
1236
		}
1237
1238
		imagedestroy($src_img);
1239
		imagedestroy($wm_img);
1240
1241
		return TRUE;
1242
	}
1243
1244
	// --------------------------------------------------------------------
1245
1246
	/**
1247
	 * Watermark - Text Version
1248
	 *
1249
	 * @return	bool
1250
	 */
1251
	public function text_watermark()
1252
	{
1253
		if ( ! ($src_img = $this->image_create_gd()))
1254
		{
1255
			return FALSE;
1256
		}
1257
1258
		if ($this->wm_use_truetype === TRUE && ! file_exists($this->wm_font_path))
1259
		{
1260
			$this->set_error('imglib_missing_font');
1261
			return FALSE;
1262
		}
1263
1264
		// Fetch source image properties
1265
		$this->get_image_properties();
1266
1267
		// Reverse the vertical offset
1268
		// When the image is positioned at the bottom
1269
		// we don't want the vertical offset to push it
1270
		// further down. We want the reverse, so we'll
1271
		// invert the offset. Note: The horizontal
1272
		// offset flips itself automatically
1273
1274
		if ($this->wm_vrt_alignment === 'B')
1275
		{
1276
			$this->wm_vrt_offset = $this->wm_vrt_offset * -1;
1277
		}
1278
1279
		if ($this->wm_hor_alignment === 'R')
1280
		{
1281
			$this->wm_hor_offset = $this->wm_hor_offset * -1;
1282
		}
1283
1284
		// Set font width and height
1285
		// These are calculated differently depending on
1286
		// whether we are using the true type font or not
1287
		if ($this->wm_use_truetype === TRUE)
1288
		{
1289
			if (empty($this->wm_font_size))
1290
			{
1291
				$this->wm_font_size = 17;
1292
			}
1293
1294
			if (function_exists('imagettfbbox'))
1295
			{
1296
				$temp = imagettfbbox($this->wm_font_size, 0, $this->wm_font_path, $this->wm_text);
1297
				$temp = $temp[2] - $temp[0];
1298
1299
				$fontwidth = $temp / strlen($this->wm_text);
1300
			}
1301
			else
1302
			{
1303
				$fontwidth = $this->wm_font_size - ($this->wm_font_size / 4);
1304
			}
1305
1306
			$fontheight = $this->wm_font_size;
1307
			$this->wm_vrt_offset += $this->wm_font_size;
1308
		}
1309
		else
1310
		{
1311
			$fontwidth  = imagefontwidth($this->wm_font_size);
1312
			$fontheight = imagefontheight($this->wm_font_size);
1313
		}
1314
1315
		// Set base X and Y axis values
1316
		$x_axis = $this->wm_hor_offset + $this->wm_padding;
1317
		$y_axis = $this->wm_vrt_offset + $this->wm_padding;
1318
1319
		if ($this->wm_use_drop_shadow === FALSE)
1320
		{
1321
			$this->wm_shadow_distance = 0;
1322
		}
1323
1324
		$this->wm_vrt_alignment = strtoupper($this->wm_vrt_alignment[0]);
1325
		$this->wm_hor_alignment = strtoupper($this->wm_hor_alignment[0]);
1326
1327
		// Set vertical alignment
1328 View Code Duplication
		if ($this->wm_vrt_alignment === 'M')
1329
		{
1330
			$y_axis += ($this->orig_height / 2) + ($fontheight / 2);
1331
		}
1332
		elseif ($this->wm_vrt_alignment === 'B')
1333
		{
1334
			$y_axis += $this->orig_height - $fontheight - $this->wm_shadow_distance - ($fontheight / 2);
1335
		}
1336
1337
		// Set horizontal alignment
1338
		if ($this->wm_hor_alignment === 'R')
1339
		{
1340
			$x_axis += $this->orig_width - ($fontwidth * strlen($this->wm_text)) - $this->wm_shadow_distance;
1341
		}
1342
		elseif ($this->wm_hor_alignment === 'C')
1343
		{
1344
			$x_axis += floor(($this->orig_width - ($fontwidth * strlen($this->wm_text))) / 2);
1345
		}
1346
1347
		if ($this->wm_use_drop_shadow)
1348
		{
1349
			// Offset from text
1350
			$x_shad = $x_axis + $this->wm_shadow_distance;
1351
			$y_shad = $y_axis + $this->wm_shadow_distance;
1352
1353
			/* Set RGB values for shadow
1354
			 *
1355
			 * First character is #, so we don't really need it.
1356
			 * Get the rest of the string and split it into 2-length
1357
			 * hex values:
1358
			 */
1359
			$drp_color = str_split(substr($this->wm_shadow_color, 1, 6), 2);
1360
			$drp_color = imagecolorclosest($src_img, hexdec($drp_color[0]), hexdec($drp_color[1]), hexdec($drp_color[2]));
1361
1362
			// Add the shadow to the source image
1363 View Code Duplication
			if ($this->wm_use_truetype)
1364
			{
1365
				imagettftext($src_img, $this->wm_font_size, 0, $x_shad, $y_shad, $drp_color, $this->wm_font_path, $this->wm_text);
1366
			}
1367
			else
1368
			{
1369
				imagestring($src_img, $this->wm_font_size, $x_shad, $y_shad, $this->wm_text, $drp_color);
1370
			}
1371
		}
1372
1373
		/* Set RGB values for text
1374
		 *
1375
		 * First character is #, so we don't really need it.
1376
		 * Get the rest of the string and split it into 2-length
1377
		 * hex values:
1378
		 */
1379
		$txt_color = str_split(substr($this->wm_font_color, 1, 6), 2);
1380
		$txt_color = imagecolorclosest($src_img, hexdec($txt_color[0]), hexdec($txt_color[1]), hexdec($txt_color[2]));
1381
1382
		// Add the text to the source image
1383 View Code Duplication
		if ($this->wm_use_truetype)
1384
		{
1385
			imagettftext($src_img, $this->wm_font_size, 0, $x_axis, $y_axis, $txt_color, $this->wm_font_path, $this->wm_text);
1386
		}
1387
		else
1388
		{
1389
			imagestring($src_img, $this->wm_font_size, $x_axis, $y_axis, $this->wm_text, $txt_color);
1390
		}
1391
1392
		// We can preserve transparency for PNG images
1393
		if ($this->image_type === 3)
0 ignored issues
show
Unused Code Bug introduced by
The strict comparison === seems to always evaluate to false as the types of $this->image_type (string) and 3 (integer) can never be identical. Maybe you want to use a loose comparison == instead?
Loading history...
1394
		{
1395
			imagealphablending($src_img, FALSE);
1396
			imagesavealpha($src_img, TRUE);
1397
		}
1398
1399
		// Output the final image
1400
		if ($this->dynamic_output === TRUE)
1401
		{
1402
			$this->image_display_gd($src_img);
1403
		}
1404
		else
1405
		{
1406
			$this->image_save_gd($src_img);
1407
		}
1408
1409
		imagedestroy($src_img);
1410
1411
		return TRUE;
1412
	}
1413
1414
	// --------------------------------------------------------------------
1415
1416
	/**
1417
	 * Create Image - GD
1418
	 *
1419
	 * This simply creates an image resource handle
1420
	 * based on the type of image being processed
1421
	 *
1422
	 * @param	string
1423
	 * @param	string
1424
	 * @return	resource
1425
	 */
1426
	public function image_create_gd($path = '', $image_type = '')
1427
	{
1428
		if ($path === '')
1429
		{
1430
			$path = $this->full_src_path;
1431
		}
1432
1433
		if ($image_type === '')
1434
		{
1435
			$image_type = $this->image_type;
1436
		}
1437
1438
		switch ($image_type)
1439
		{
1440 View Code Duplication
			case 1:
1441
				if ( ! function_exists('imagecreatefromgif'))
1442
				{
1443
					$this->set_error(array('imglib_unsupported_imagecreate', 'imglib_gif_not_supported'));
1444
					return FALSE;
1445
				}
1446
1447
				return imagecreatefromgif($path);
1448 View Code Duplication
			case 2:
1449
				if ( ! function_exists('imagecreatefromjpeg'))
1450
				{
1451
					$this->set_error(array('imglib_unsupported_imagecreate', 'imglib_jpg_not_supported'));
1452
					return FALSE;
1453
				}
1454
1455
				return imagecreatefromjpeg($path);
1456 View Code Duplication
			case 3:
1457
				if ( ! function_exists('imagecreatefrompng'))
1458
				{
1459
					$this->set_error(array('imglib_unsupported_imagecreate', 'imglib_png_not_supported'));
1460
					return FALSE;
1461
				}
1462
1463
				return imagecreatefrompng($path);
1464
			default:
1465
				$this->set_error(array('imglib_unsupported_imagecreate'));
1466
				return FALSE;
1467
		}
1468
	}
1469
1470
	// --------------------------------------------------------------------
1471
1472
	/**
1473
	 * Write image file to disk - GD
1474
	 *
1475
	 * Takes an image resource as input and writes the file
1476
	 * to the specified destination
1477
	 *
1478
	 * @param	resource
1479
	 * @return	bool
1480
	 */
1481
	public function image_save_gd($resource)
1482
	{
1483
		switch ($this->image_type)
1484
		{
1485 View Code Duplication
			case 1:
1486
				if ( ! function_exists('imagegif'))
1487
				{
1488
					$this->set_error(array('imglib_unsupported_imagecreate', 'imglib_gif_not_supported'));
1489
					return FALSE;
1490
				}
1491
1492
				if ( ! @imagegif($resource, $this->full_dst_path))
1493
				{
1494
					$this->set_error('imglib_save_failed');
1495
					return FALSE;
1496
				}
1497
			break;
1498 View Code Duplication
			case 2:
1499
				if ( ! function_exists('imagejpeg'))
1500
				{
1501
					$this->set_error(array('imglib_unsupported_imagecreate', 'imglib_jpg_not_supported'));
1502
					return FALSE;
1503
				}
1504
1505
				if ( ! @imagejpeg($resource, $this->full_dst_path, $this->quality))
1506
				{
1507
					$this->set_error('imglib_save_failed');
1508
					return FALSE;
1509
				}
1510
			break;
1511 View Code Duplication
			case 3:
1512
				if ( ! function_exists('imagepng'))
1513
				{
1514
					$this->set_error(array('imglib_unsupported_imagecreate', 'imglib_png_not_supported'));
1515
					return FALSE;
1516
				}
1517
1518
				if ( ! @imagepng($resource, $this->full_dst_path))
1519
				{
1520
					$this->set_error('imglib_save_failed');
1521
					return FALSE;
1522
				}
1523
			break;
1524
			default:
1525
				$this->set_error(array('imglib_unsupported_imagecreate'));
1526
				return FALSE;
1527
			break;
1528
		}
1529
1530
		return TRUE;
1531
	}
1532
1533
	// --------------------------------------------------------------------
1534
1535
	/**
1536
	 * Dynamically outputs an image
1537
	 *
1538
	 * @param	resource
1539
	 * @return	void
1540
	 */
1541
	public function image_display_gd($resource)
1542
	{
1543
		header('Content-Disposition: filename='.$this->source_image.';');
1544
		header('Content-Type: '.$this->mime_type);
1545
		header('Content-Transfer-Encoding: binary');
1546
		header('Last-Modified: '.gmdate('D, d M Y H:i:s', time()).' GMT');
1547
1548
		switch ($this->image_type)
1549
		{
1550
			case 1	:	imagegif($resource);
0 ignored issues
show
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
1551
				break;
1552
			case 2	:	imagejpeg($resource, NULL, $this->quality);
0 ignored issues
show
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
1553
				break;
1554
			case 3	:	imagepng($resource);
0 ignored issues
show
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
1555
				break;
1556
			default:	echo 'Unable to display the image';
0 ignored issues
show
The default body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a default statement must start on the line immediately following the statement.

switch ($expr) {
    default:
        doSomething(); //right
        break;
}


switch ($expr) {
    default:

        doSomething(); //wrong
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
1557
				break;
1558
		}
1559
	}
1560
1561
	// --------------------------------------------------------------------
1562
1563
	/**
1564
	 * Re-proportion Image Width/Height
1565
	 *
1566
	 * When creating thumbs, the desired width/height
1567
	 * can end up warping the image due to an incorrect
1568
	 * ratio between the full-sized image and the thumb.
1569
	 *
1570
	 * This function lets us re-proportion the width/height
1571
	 * if users choose to maintain the aspect ratio when resizing.
1572
	 *
1573
	 * @return	void
1574
	 */
1575
	public function image_reproportion()
1576
	{
1577
		if (($this->width === 0 && $this->height === 0) OR $this->orig_width === 0 OR $this->orig_height === 0
1578
			OR ( ! ctype_digit((string) $this->width) && ! ctype_digit((string) $this->height))
1579
			OR ! ctype_digit((string) $this->orig_width) OR ! ctype_digit((string) $this->orig_height))
1580
		{
1581
			return;
1582
		}
1583
1584
		// Sanitize
1585
		$this->width = (int) $this->width;
1586
		$this->height = (int) $this->height;
1587
1588
		if ($this->master_dim !== 'width' && $this->master_dim !== 'height')
1589
		{
1590
			if ($this->width > 0 && $this->height > 0)
1591
			{
1592
				$this->master_dim = ((($this->orig_height/$this->orig_width) - ($this->height/$this->width)) < 0)
1593
							? 'width' : 'height';
1594
			}
1595
			else
1596
			{
1597
				$this->master_dim = ($this->height === 0) ? 'width' : 'height';
1598
			}
1599
		}
1600
		elseif (($this->master_dim === 'width' && $this->width === 0)
1601
			OR ($this->master_dim === 'height' && $this->height === 0))
1602
		{
1603
			return;
1604
		}
1605
1606
		if ($this->master_dim === 'width')
1607
		{
1608
			$this->height = (int) ceil($this->width*$this->orig_height/$this->orig_width);
1609
		}
1610
		else
1611
		{
1612
			$this->width = (int) ceil($this->orig_width*$this->height/$this->orig_height);
1613
		}
1614
	}
1615
1616
	// --------------------------------------------------------------------
1617
1618
	/**
1619
	 * Get image properties
1620
	 *
1621
	 * A helper function that gets info about the file
1622
	 *
1623
	 * @param	string
1624
	 * @param	bool
1625
	 * @return	mixed
1626
	 */
1627
	public function get_image_properties($path = '', $return = FALSE)
1628
	{
1629
		// For now we require GD but we should
1630
		// find a way to determine this using IM or NetPBM
1631
1632
		if ($path === '')
1633
		{
1634
			$path = $this->full_src_path;
1635
		}
1636
1637
		if ( ! file_exists($path))
1638
		{
1639
			$this->set_error('imglib_invalid_path');
1640
			return FALSE;
1641
		}
1642
1643
		$vals = getimagesize($path);
1644
		$types = array(1 => 'gif', 2 => 'jpeg', 3 => 'png');
1645
		$mime = (isset($types[$vals[2]])) ? 'image/'.$types[$vals[2]] : 'image/jpg';
1646
1647
		if ($return === TRUE)
1648
		{
1649
			return array(
1650
					'width' =>	$vals[0],
1651
					'height' =>	$vals[1],
1652
					'image_type' =>	$vals[2],
1653
					'size_str' =>	$vals[3],
1654
					'mime_type' =>	$mime
1655
				);
1656
		}
1657
1658
		$this->orig_width	= $vals[0];
1659
		$this->orig_height	= $vals[1];
1660
		$this->image_type	= $vals[2];
1661
		$this->size_str		= $vals[3];
1662
		$this->mime_type	= $mime;
1663
1664
		return TRUE;
1665
	}
1666
1667
	// --------------------------------------------------------------------
1668
1669
	/**
1670
	 * Size calculator
1671
	 *
1672
	 * This function takes a known width x height and
1673
	 * recalculates it to a new size. Only one
1674
	 * new variable needs to be known
1675
	 *
1676
	 *	$props = array(
1677
	 *			'width'		=> $width,
1678
	 *			'height'	=> $height,
1679
	 *			'new_width'	=> 40,
1680
	 *			'new_height'	=> ''
1681
	 *		);
1682
	 *
1683
	 * @param	array
1684
	 * @return	array
1685
	 */
1686
	public function size_calculator($vals)
1687
	{
1688
		if ( ! is_array($vals))
1689
		{
1690
			return;
1691
		}
1692
1693
		$allowed = array('new_width', 'new_height', 'width', 'height');
1694
1695
		foreach ($allowed as $item)
1696
		{
1697
			if (empty($vals[$item]))
1698
			{
1699
				$vals[$item] = 0;
1700
			}
1701
		}
1702
1703
		if ($vals['width'] === 0 OR $vals['height'] === 0)
1704
		{
1705
			return $vals;
1706
		}
1707
1708
		if ($vals['new_width'] === 0)
1709
		{
1710
			$vals['new_width'] = ceil($vals['width']*$vals['new_height']/$vals['height']);
1711
		}
1712
		elseif ($vals['new_height'] === 0)
1713
		{
1714
			$vals['new_height'] = ceil($vals['new_width']*$vals['height']/$vals['width']);
1715
		}
1716
1717
		return $vals;
1718
	}
1719
1720
	// --------------------------------------------------------------------
1721
1722
	/**
1723
	 * Explode source_image
1724
	 *
1725
	 * This is a helper function that extracts the extension
1726
	 * from the source_image.  This function lets us deal with
1727
	 * source_images with multiple periods, like: my.cool.jpg
1728
	 * It returns an associative array with two elements:
1729
	 * $array['ext']  = '.jpg';
1730
	 * $array['name'] = 'my.cool';
1731
	 *
1732
	 * @param	array
1733
	 * @return	array
1734
	 */
1735
	public function explode_name($source_image)
1736
	{
1737
		$ext = strrchr($source_image, '.');
1738
		$name = ($ext === FALSE) ? $source_image : substr($source_image, 0, -strlen($ext));
1739
1740
		return array('ext' => $ext, 'name' => $name);
1741
	}
1742
1743
	// --------------------------------------------------------------------
1744
1745
	/**
1746
	 * Is GD Installed?
1747
	 *
1748
	 * @return	bool
1749
	 */
1750
	public function gd_loaded()
1751
	{
1752
		if ( ! extension_loaded('gd'))
1753
		{
1754
			/* As it is stated in the PHP manual, dl() is not always available
1755
			 * and even if so - it could generate an E_WARNING message on failure
1756
			 */
1757
			return (function_exists('dl') && @dl('gd.so'));
1758
		}
1759
1760
		return TRUE;
1761
	}
1762
1763
	// --------------------------------------------------------------------
1764
1765
	/**
1766
	 * Get GD version
1767
	 *
1768
	 * @return	mixed
1769
	 */
1770
	public function gd_version()
1771
	{
1772
		if (function_exists('gd_info'))
1773
		{
1774
			$gd_version = @gd_info();
1775
			return preg_replace('/\D/', '', $gd_version['GD Version']);
1776
		}
1777
1778
		return FALSE;
1779
	}
1780
1781
	// --------------------------------------------------------------------
1782
1783
	/**
1784
	 * Set error message
1785
	 *
1786
	 * @param	string
1787
	 * @return	void
1788
	 */
1789
	public function set_error($msg)
1790
	{
1791
		$CI =& get_instance();
1792
		$CI->lang->load('imglib');
1793
1794
		if (is_array($msg))
1795
		{
1796
			foreach ($msg as $val)
1797
			{
1798
				$msg = ($CI->lang->line($val) === FALSE) ? $val : $CI->lang->line($val);
1799
				$this->error_msg[] = $msg;
1800
				log_message('error', $msg);
1801
			}
1802
		}
1803
		else
1804
		{
1805
			$msg = ($CI->lang->line($msg) === FALSE) ? $msg : $CI->lang->line($msg);
1806
			$this->error_msg[] = $msg;
1807
			log_message('error', $msg);
1808
		}
1809
	}
1810
1811
	// --------------------------------------------------------------------
1812
1813
	/**
1814
	 * Show error messages
1815
	 *
1816
	 * @param	string
1817
	 * @param	string
1818
	 * @return	string
1819
	 */
1820
	public function display_errors($open = '<p>', $close = '</p>')
1821
	{
1822
		return (count($this->error_msg) > 0) ? $open.implode($close.$open, $this->error_msg).$close : '';
1823
	}
1824
1825
}
1826