Issues (311)

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.

lib/timber-image.php (13 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
2
3
/**
4
 * If TimberPost is the class you're going to spend the most time, TimberImage is the class you're going to have the most fun with.
5
 * @example
6
 * ```php
7
 * $context = Timber::get_context();
8
 * $post = new TimberPost();
9
 * $context['post'] = $post;
10
 *
11
 * // lets say you have an alternate large 'cover image' for your post stored in a custom field which returns an image ID
12
 * $cover_image_id = $post->cover_image;
13
 * $context['cover_image'] = new TimberImage($cover_image_id);
14
 * Timber::render('single.twig', $context);
15
 * ```
16
 *
17
 * ```twig
18
 * <article>
19
 * 	<img src="{{cover_image.src}}" class="cover-image" />
20
 * 	<h1 class="headline">{{post.title}}</h1>
21
 * 	<div class="body">
22
 * 		{{post.content}}
23
 * 	</div>
24
 *
25
 * 	<img src="{{ Image(post.custom_field_with_image_id).src }}" alt="Another way to initialize images as TimberImages, but within Twig" />
26
 * </article>
27
 * ```
28
 *
29
 * ```html
30
 * <article>
31
 * 	<img src="http://example.org/wp-content/uploads/2015/06/nevermind.jpg" class="cover-image" />
32
 * 	<h1 class="headline">Now you've done it!</h1>
33
 * 	<div class="body">
34
 * 		Whatever whatever
35
 * 	</div>
36
 * 	<img src="http://example.org/wp-content/uploads/2015/06/kurt.jpg" alt="Another way to initialize images as TimberImages, but within Twig" />
37
 * </article>
38
 * ```
39
 */
40
class TimberImage extends TimberPost implements TimberCoreInterface {
41
42
	protected $_can_edit;
43
	protected $_dimensions;
44
	public $abs_url;
45
	/**
46
	 * @var string $object_type what does this class represent in WordPress terms?
47
	 */
48
	public $object_type = 'image';
49
	/**
50
	 * @var string $representation what does this class represent in WordPress terms?
51
	 */
52
	public static $representation = 'image';
53
	/**
54
	 * @var array of supported relative file types
55
	 */
56
	private $file_types = array('jpg', 'jpeg', 'png', 'svg', 'bmp', 'ico', 'gif', 'tiff', 'pdf');
57
	/**
58
	 * @api
59
	 * @var string $file_loc the location of the image file in the filesystem (ex: `/var/www/htdocs/wp-content/uploads/2015/08/my-pic.jpg`)
60
	 */
61
	public $file_loc;
62
	public $file;
63
	/**
64
	 * @api
65
	 * @var integer the ID of the image (which is a WP_Post)
66
	 */
67
	public $id;
68
	public $sizes = array();
69
	/**
70
	 * @api
71
	 * @var string $caption the string stored in the WordPress database
72
	 */
73
	public $caption;
74
	/**
75
	 * @var $_wp_attached_file the file as stored in the WordPress database
76
	 */
77
	protected $_wp_attached_file;
78
79
	/**
80
	 * Creates a new TimberImage object
81
	 * @example
82
	 * ```php
83
	 * // You can pass it an ID number
84
	 * $myImage = new TimberImage(552);
85
	 *
86
	 * //Or send it a URL to an image
87
	 * $myImage = new TimberImage('http://google.com/logo.jpg');
88
	 * ```
89
	 * @param int|string $iid
90
	 */
91
	public function __construct($iid) {
92
		$this->init($iid);
93
	}
94
95
	/**
96
	 * @return string the src of the file
0 ignored issues
show
Should the return type not be boolean|string?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
97
	 */
98
	public function __toString() {
99
		if ( $this->get_src() ) {
100
			return $this->get_src();
101
		}
102
		return '';
103
	}
104
105
	/**
106
	 * Get a PHP array with pathinfo() info from the file
107
	 * @return array
108
	 */
109
	function get_pathinfo() {
110
		return pathinfo($this->file);
111
	}
112
113
	/**
114
	 * @internal
115
	 * @param string $dim
0 ignored issues
show
Should the type for parameter $dim not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
116
	 * @return array|int
117
	 */
118
	protected function get_dimensions($dim = null) {
119
		if ( isset($this->_dimensions) ) {
120
			return $this->get_dimensions_loaded($dim);
121
		}
122
		if ( file_exists($this->file_loc) && filesize($this->file_loc) ) {
123
			list($width, $height) = getimagesize($this->file_loc);
124
			$this->_dimensions = array();
125
			$this->_dimensions[0] = $width;
126
			$this->_dimensions[1] = $height;
127
			return $this->get_dimensions_loaded($dim);
128
		}
129
	}
130
131
	/**
132
	 * @internal
133
	 * @param string|null $dim
134
	 * @return array|int
135
	 */
136
	protected function get_dimensions_loaded($dim) {
137
		if ( $dim === null ) {
138
			return $this->_dimensions;
139
		}
140
		if ( $dim == 'w' || $dim == 'width' ) {
141
			return $this->_dimensions[0];
142
		}
143
		if ( $dim == 'h' || $dim == 'height' ) {
144
			return $this->_dimensions[1];
145
		}
146
		return null;
147
	}
148
149
	/**
150
	 * @internal
151
	 * @param  int $iid the id number of the image in the WP database
152
	 */
153
	protected function get_image_info( $iid ) {
154
		$image_info = $iid;
155
		if (is_numeric($iid)) {
156
			$image_info = wp_get_attachment_metadata($iid);
157
			if (!is_array($image_info)) {
158
				$image_info = array();
159
			}
160
			$image_custom = get_post_custom($iid);
161
			$basic = get_post($iid);
162
			if ($basic) {
163
				if (isset($basic->post_excerpt)) {
164
					$this->caption = $basic->post_excerpt;
165
				}
166
				$image_custom = array_merge($image_custom, get_object_vars($basic));
167
			}
168
			return array_merge($image_info, $image_custom);
169
		}
170
		if (is_array($image_info) && isset($image_info['image'])) {
171
			return $image_info['image'];
172
		}
173
		if (is_object($image_info)) {
174
		   return get_object_vars($image_info);
175
		}
176
		return $iid;
177
	}
178
179
	/**
180
	 * @internal
181
	 * @param  string $url for evaluation
182
	 * @return string with http/https corrected depending on what's appropriate for server
183
	 */
184
	protected static function _maybe_secure_url($url) {
185
		if ( is_ssl() && strpos($url, 'https') !== 0 && strpos($url, 'http') === 0 ) {
186
			$url = 'https' . substr($url, strlen('http'));
187
		}
188
		return $url;
189
	}
190
191
	public static function wp_upload_dir() {
192
		static $wp_upload_dir = false;
193
194
		if ( !$wp_upload_dir ) {
195
			$wp_upload_dir = wp_upload_dir();
196
		}
197
198
		return $wp_upload_dir;
199
	}
200
201
	/**
202
	 * @internal
203
	 * @param int $iid
0 ignored issues
show
Should the type for parameter $iid not be false|integer?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
204
	 */
205
	function init( $iid = false ) {
206
		if ( !is_numeric( $iid ) && is_string( $iid ) ) {
207
			if (strstr($iid, '://')) {
208
				$this->init_with_url($iid);
209
				return;
210
			}
211
			if ( strstr($iid, ABSPATH) ) {
212
				$this->init_with_file_path($iid);
213
				return;
214
			}
215
216
			$relative = false;
217
			$iid_lower = strtolower($iid);
218
			foreach( $this->file_types as $type ) { if( strstr( $iid_lower, $type ) ) { $relative = true; break; } };
219
			if ( $relative ) {
220
				$this->init_with_relative_path( $iid );
221
				return;
222
			}
223
		} else if ( $iid instanceof WP_Post ) {
224
			$ref = new ReflectionClass($this);
225
			$post = $ref->getParentClass()->newInstance($iid->ID);
226
			if (isset($post->_thumbnail_id) && $post->_thumbnail_id) {
227
				return $this->init((int) $post->_thumbnail_id);
228
			}
229
			return $this->init($iid->ID);
230
		} else if ( $iid instanceof TimberPost ) {
231
			/**
232
			 * This will catch TimberPost and any post classes that extend TimberPost,
233
			 * see http://php.net/manual/en/internals2.opcodes.instanceof.php#109108
234
			 * and https://github.com/jarednova/timber/wiki/Extending-Timber
235
			 */
236
			$iid = (int) $iid->_thumbnail_id;
237
		}
238
239
		$image_info = $this->get_image_info($iid);
240
241
		$this->import($image_info);
242
		$basedir = self::wp_upload_dir();
243
		$basedir = $basedir['basedir'];
244
		if ( isset($this->file) ) {
245
			$this->file_loc = $basedir . DIRECTORY_SEPARATOR . $this->file;
246
		} else if ( isset($this->_wp_attached_file) ) {
247
			$this->file = reset($this->_wp_attached_file);
248
			$this->file_loc = $basedir . DIRECTORY_SEPARATOR . $this->file;
249
		}
250
		if ( isset($image_info['id']) ) {
251
			$this->ID = $image_info['id'];
252
		} else if ( is_numeric($iid) ) {
253
			$this->ID = $iid;
0 ignored issues
show
Documentation Bug introduced by
It seems like $iid can also be of type integer or double. However, the property $ID is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
254
		}
255
		if ( isset($this->ID) ) {
256
			$custom = get_post_custom($this->ID);
257
			foreach ($custom as $key => $value) {
258
				$this->$key = $value[0];
259
			}
260
			$this->id = $this->ID;
261
		} else {
262
			if ( is_array($iid) || is_object($iid) ) {
263
				TimberHelper::error_log('Not able to init in TimberImage with iid=');
264
				TimberHelper::error_log($iid);
265
			} else {
266
				TimberHelper::error_log('Not able to init in TimberImage with iid=' . $iid);
267
			}
268
		}
269
	}
270
271
	/**
272
	 * @internal
273
	 * @param string $relative_path
274
	 */
275
	protected function init_with_relative_path( $relative_path ) {
276
		$this->abs_url = home_url( $relative_path );
277
		$file_path = TimberURLHelper::get_full_path( $relative_path );
278
		$this->file_loc = $file_path;
279
		$this->file = $file_path;
280
	}
281
282
	/**
283
	 * @internal
284
	 * @param string $file_path
285
	 */
286
	protected function init_with_file_path( $file_path ) {
287
		$url = TimberURLHelper::file_system_to_url( $file_path );
288
		$this->abs_url = $url;
289
		$this->file_loc = $file_path;
290
		$this->file = $file_path;
291
	}
292
293
	/**
294
	 * @internal
295
	 * @param string $url
296
	 */
297
	protected function init_with_url($url) {
298
		$this->abs_url = $url;
299
		if ( TimberURLHelper::is_local($url) ) {
300
			$this->file = ABSPATH . TimberURLHelper::get_rel_url($url);
301
			$this->file_loc = ABSPATH . TimberURLHelper::get_rel_url($url);
302
		}
303
	}
304
305
	/**
306
	 * @api
307
	 * @example
308
	 * ```twig
309
	 * <img src="{{ image.src }}" alt="{{ image.alt }}" />
310
	 * ```
311
	 * ```html
312
	 * <img src="http://example.org/wp-content/uploads/2015/08/pic.jpg" alt="W3 Checker told me to add alt text, so I am" />
313
	 * ```
314
	 * @return string alt text stored in WordPress
315
	 */
316
	public function alt() {
317
		$alt = trim(strip_tags(get_post_meta($this->ID, '_wp_attachment_image_alt', true)));
318
		return $alt;
319
	}
320
321
	/**
322
	 * @api
323
	 * @example
324
	 * ```twig
325
	 * {% if post.thumbnail.aspect < 1 %}
326
	 *     {# handle vertical image #}
327
	 *     <img src="{{ post.thumbnail.src|resize(300, 500) }}" alt="A basketball player" />
328
	 * {% else %}
329
	 * 	   <img src="{{ post.thumbnail.src|resize(500) }}" alt="A sumo wrestler" />
330
	 * {% endif %}
331
	 * ```
332
	 * @return float
0 ignored issues
show
Should the return type not be integer?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
333
	 */
334
	public function aspect() {
335
		$w = intval($this->width());
336
		$h = intval($this->height());
337
		return $w / $h;
338
	}
339
340
	/**
341
	 * @api
342
	 * @example
343
	 * ```twig
344
	 * <img src="{{ image.src }}" height="{{ image.height }}" />
345
	 * ```
346
	 * ```html
347
	 * <img src="http://example.org/wp-content/uploads/2015/08/pic.jpg" height="900" />
348
	 * ```
349
	 * @return int
0 ignored issues
show
Should the return type not be array|integer?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
350
	 */
351
	public function height() {
352
		return $this->get_dimensions('height');
353
	}
354
355
	/**
356
	 * Returns the link to an image attachment's Permalink page (NOT the link for the image itself!!)
357
	 * @api
358
	 * @example
359
	 * ```twig
360
	 * <a href="{{ image.link }}"><img src="{{ image.src }} "/></a>
361
	 * ```
362
	 * ```html
363
	 * <a href="http://example.org/my-cool-picture"><img src="http://example.org/wp-content/uploads/2015/whatever.jpg"/></a>
364
	 * ```
365
	 */
366
	public function link() {
367
		if ( strlen($this->abs_url) ) {
368
			return $this->abs_url;
369
		}
370
		return get_permalink($this->ID);
371
	}
372
373
	/**
374
	 * @api
375
	 * @return bool|TimberPost
0 ignored issues
show
Should the return type not be false|object?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
376
	 */
377
	public function parent() {
378
		if ( !$this->post_parent ) {
379
			return false;
380
		}
381
		return new $this->PostClass($this->post_parent);
382
	}
383
384
	/**
385
	 * @api
386
	 * @example
387
	 * ```twig
388
	 * <img src="{{ image.path }}" />
389
	 * ```
390
	 * ```html
391
	 * <img src="/wp-content/uploads/2015/08/pic.jpg" />
392
	 * ```
393
	 * @return  string the /relative/path/to/the/file
394
	 */
395
	public function path() {
396
		return TimberURLHelper::get_rel_path($this->src());
397
	}
398
399
	/**
400
	 * @param string $size a size known to WordPress (like "medium")
401
	 * @api
402
	 * @example
403
	 * ```twig
404
	 * <h1>{{post.title}}</h1>
405
	 * <img src="{{post.thumbnail.src}}" />
406
	 * ```
407
	 * ```html
408
	 * <img src="http://example.org/wp-content/uploads/2015/08/pic.jpg" />
409
	 * ```
410
	 * @return bool|string
411
	 */
412
	public function src($size = '') {
413
		if ( isset($this->abs_url) ) {
414
			return $this->_maybe_secure_url($this->abs_url);
415
		}
416
417
		if ( $size && is_string($size) && isset($this->sizes[$size]) ) {
418
			$image = image_downsize($this->ID, $size);
419
			return $this->_maybe_secure_url(reset($image));
420
		}
421
422
		if ( !isset($this->file) && isset($this->_wp_attached_file) ) {
423
			$this->file = $this->_wp_attached_file;
424
		}
425
426
		if ( !isset($this->file) ) {
427
			return false;
428
		}
429
430
		$dir = self::wp_upload_dir();
431
		$base = $dir['baseurl'];
432
433
		$src = trailingslashit($this->_maybe_secure_url($base)) . $this->file;
434
		$src = apply_filters('timber/image/src', $src, $this->ID);
435
		return apply_filters('timber_image_src', $src, $this->ID);
436
	}
437
438
	/**
439
	 * @deprecated use src() instead
440
	 * @return string
0 ignored issues
show
Should the return type not be boolean|string?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
441
	 */
442
	function url() {
443
		return $this->get_src();
444
	}
445
446
	/**
447
	 * @api
448
	 * @example
449
	 * ```twig
450
	 * <img src="{{ image.src }}" width="{{ image.width }}" />
451
	 * ```
452
	 * ```html
453
	 * <img src="http://example.org/wp-content/uploads/2015/08/pic.jpg" width="1600" />
454
	 * ```
455
	 * @return int
0 ignored issues
show
Should the return type not be array|integer?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
456
	 */
457
	public function width() {
458
		return $this->get_dimensions('width');
459
	}
460
461
462
	/**
463
	 * @deprecated 0.21.9 use TimberImage::width() instead
464
	 * @internal
465
	 * @return int
0 ignored issues
show
Should the return type not be array|integer?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
466
	 */
467
	function get_width() {
468
		return $this->width();
469
	}
470
471
	/**
472
	 * @deprecated 0.21.9 use TimberImage::height() instead
473
	 * @internal
474
	 * @return int
0 ignored issues
show
Should the return type not be array|integer?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
475
	 */
476
	function get_height() {
477
		return $this->height();
478
	}
479
480
	/**
481
	 * @deprecated 0.21.9 use TimberImage::src
482
	 * @internal
483
	 * @param string $size
484
	 * @return bool|string
485
	 */
486
	function get_src( $size = '' ) {
487
		return $this->src( $size );
488
	}
489
490
	/**
491
	 * @deprecated 0.21.9 use TimberImage::path()
492
	 * @internal
493
	 * @return string
494
	 */
495
	function get_path() {
496
		return $this->link();
497
	}
498
499
	/**
500
	 * @deprecated use src() instead
501
	 * @return string
0 ignored issues
show
Should the return type not be boolean|string?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
502
	 */
503
	function get_url() {
504
		return $this->get_src();
505
	}
506
507
	/**
508
	 * @internal
509
	 * @deprecated 0.21.8
510
	 * @return bool|TimberPost
0 ignored issues
show
Should the return type not be false|object?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
511
	 */
512
	function get_parent() {
513
		return $this->parent();
514
	}
515
516
	/**
517
	 * @internal
518
	 * @deprecated 0.21.9
519
	 * @see TimberImage::alt
520
	 * @return string
521
	 */
522
	function get_alt() {
523
		return $this->alt();
524
	}
525
526
}
527