Issues (2010)

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.

wp-includes/class-wp.php (8 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
 * WordPress environment setup class.
4
 *
5
 * @package WordPress
6
 * @since 2.0.0
7
 */
8
class WP {
9
	/**
10
	 * Public query variables.
11
	 *
12
	 * Long list of public query variables.
13
	 *
14
	 * @since 2.0.0
15
	 * @access public
16
	 * @var array
17
	 */
18
	public $public_query_vars = array('m', 'p', 'posts', 'w', 'cat', 'withcomments', 'withoutcomments', 's', 'search', 'exact', 'sentence', 'calendar', 'page', 'paged', 'more', 'tb', 'pb', 'author', 'order', 'orderby', 'year', 'monthnum', 'day', 'hour', 'minute', 'second', 'name', 'category_name', 'tag', 'feed', 'author_name', 'static', 'pagename', 'page_id', 'error', 'attachment', 'attachment_id', 'subpost', 'subpost_id', 'preview', 'robots', 'taxonomy', 'term', 'cpage', 'post_type', 'embed' );
19
20
	/**
21
	 * Private query variables.
22
	 *
23
	 * Long list of private query variables.
24
	 *
25
	 * @since 2.0.0
26
	 * @access public
27
	 * @var array
28
	 */
29
	public $private_query_vars = array( 'offset', 'posts_per_page', 'posts_per_archive_page', 'showposts', 'nopaging', 'post_type', 'post_status', 'category__in', 'category__not_in', 'category__and', 'tag__in', 'tag__not_in', 'tag__and', 'tag_slug__in', 'tag_slug__and', 'tag_id', 'post_mime_type', 'perm', 'comments_per_page', 'post__in', 'post__not_in', 'post_parent', 'post_parent__in', 'post_parent__not_in', 'title' );
30
31
	/**
32
	 * Extra query variables set by the user.
33
	 *
34
	 * @since 2.1.0
35
	 * @access public
36
	 * @var array
37
	 */
38
	public $extra_query_vars = array();
39
40
	/**
41
	 * Query variables for setting up the WordPress Query Loop.
42
	 *
43
	 * @since 2.0.0
44
	 * @access public
45
	 * @var array
46
	 */
47
	public $query_vars;
48
49
	/**
50
	 * String parsed to set the query variables.
51
	 *
52
	 * @since 2.0.0
53
	 * @access public
54
	 * @var string
55
	 */
56
	public $query_string;
57
58
	/**
59
	 * The request path, e.g. 2015/05/06.
60
	 *
61
	 * @since 2.0.0
62
	 * @access public
63
	 * @var string
64
	 */
65
	public $request;
66
67
	/**
68
	 * Rewrite rule the request matched.
69
	 *
70
	 * @since 2.0.0
71
	 * @access public
72
	 * @var string
73
	 */
74
	public $matched_rule;
75
76
	/**
77
	 * Rewrite query the request matched.
78
	 *
79
	 * @since 2.0.0
80
	 * @access public
81
	 * @var string
82
	 */
83
	public $matched_query;
84
85
	/**
86
	 * Whether already did the permalink.
87
	 *
88
	 * @since 2.0.0
89
	 * @access public
90
	 * @var bool
91
	 */
92
	public $did_permalink = false;
93
94
	/**
95
	 * Add name to list of public query variables.
96
	 *
97
	 * @since 2.1.0
98
	 * @access public
99
	 *
100
	 * @param string $qv Query variable name.
101
	 */
102
	public function add_query_var($qv) {
103
		if ( !in_array($qv, $this->public_query_vars) )
104
			$this->public_query_vars[] = $qv;
105
	}
106
107
	/**
108
	 * Removes a query variable from a list of public query variables.
109
	 *
110
	 * @since 4.5.0
111
	 * @access public
112
	 *
113
	 * @param string $name Query variable name.
114
	 */
115
	public function remove_query_var( $name ) {
116
		$this->public_query_vars = array_diff( $this->public_query_vars, array( $name ) );
117
	}
118
119
	/**
120
	 * Set the value of a query variable.
121
	 *
122
	 * @since 2.3.0
123
	 * @access public
124
	 *
125
	 * @param string $key Query variable name.
126
	 * @param mixed $value Query variable value.
127
	 */
128
	public function set_query_var($key, $value) {
129
		$this->query_vars[$key] = $value;
130
	}
131
132
	/**
133
	 * Parse request to find correct WordPress query.
134
	 *
135
	 * Sets up the query variables based on the request. There are also many
136
	 * filters and actions that can be used to further manipulate the result.
137
	 *
138
	 * @since 2.0.0
139
	 * @access public
140
	 *
141
	 * @global WP_Rewrite $wp_rewrite
142
	 *
143
	 * @param array|string $extra_query_vars Set the extra query variables.
144
	 */
145
	public function parse_request($extra_query_vars = '') {
146
		global $wp_rewrite;
147
148
		/**
149
		 * Filters whether to parse the request.
150
		 *
151
		 * @since 3.5.0
152
		 *
153
		 * @param bool         $bool             Whether or not to parse the request. Default true.
154
		 * @param WP           $this             Current WordPress environment instance.
155
		 * @param array|string $extra_query_vars Extra passed query variables.
156
		 */
157
		if ( ! apply_filters( 'do_parse_request', true, $this, $extra_query_vars ) )
158
			return;
159
160
		$this->query_vars = array();
161
		$post_type_query_vars = array();
162
163
		if ( is_array( $extra_query_vars ) ) {
164
			$this->extra_query_vars = & $extra_query_vars;
165
		} elseif ( ! empty( $extra_query_vars ) ) {
166
			parse_str( $extra_query_vars, $this->extra_query_vars );
167
		}
168
		// Process PATH_INFO, REQUEST_URI, and 404 for permalinks.
169
170
		// Fetch the rewrite rules.
171
		$rewrite = $wp_rewrite->wp_rewrite_rules();
172
173
		if ( ! empty($rewrite) ) {
174
			// If we match a rewrite rule, this will be cleared.
175
			$error = '404';
176
			$this->did_permalink = true;
177
178
			$pathinfo = isset( $_SERVER['PATH_INFO'] ) ? $_SERVER['PATH_INFO'] : '';
179
			list( $pathinfo ) = explode( '?', $pathinfo );
180
			$pathinfo = str_replace( "%", "%25", $pathinfo );
181
182
			list( $req_uri ) = explode( '?', $_SERVER['REQUEST_URI'] );
183
			$self = $_SERVER['PHP_SELF'];
184
			$home_path = trim( parse_url( home_url(), PHP_URL_PATH ), '/' );
185
			$home_path_regex = sprintf( '|^%s|i', preg_quote( $home_path, '|' ) );
186
187
			// Trim path info from the end and the leading home path from the
188
			// front. For path info requests, this leaves us with the requesting
189
			// filename, if any. For 404 requests, this leaves us with the
190
			// requested permalink.
191
			$req_uri = str_replace($pathinfo, '', $req_uri);
192
			$req_uri = trim($req_uri, '/');
193
			$req_uri = preg_replace( $home_path_regex, '', $req_uri );
194
			$req_uri = trim($req_uri, '/');
195
			$pathinfo = trim($pathinfo, '/');
196
			$pathinfo = preg_replace( $home_path_regex, '', $pathinfo );
197
			$pathinfo = trim($pathinfo, '/');
198
			$self = trim($self, '/');
199
			$self = preg_replace( $home_path_regex, '', $self );
200
			$self = trim($self, '/');
201
202
			// The requested permalink is in $pathinfo for path info requests and
203
			//  $req_uri for other requests.
204
			if ( ! empty($pathinfo) && !preg_match('|^.*' . $wp_rewrite->index . '$|', $pathinfo) ) {
205
				$requested_path = $pathinfo;
206
			} else {
207
				// If the request uri is the index, blank it out so that we don't try to match it against a rule.
208
				if ( $req_uri == $wp_rewrite->index )
209
					$req_uri = '';
210
				$requested_path = $req_uri;
211
			}
212
			$requested_file = $req_uri;
213
214
			$this->request = $requested_path;
215
216
			// Look for matches.
217
			$request_match = $requested_path;
218
			if ( empty( $request_match ) ) {
219
				// An empty request could only match against ^$ regex
220
				if ( isset( $rewrite['$'] ) ) {
221
					$this->matched_rule = '$';
222
					$query = $rewrite['$'];
223
					$matches = array('');
224
				}
225
			} else {
226
				foreach ( (array) $rewrite as $match => $query ) {
227
					// If the requested file is the anchor of the match, prepend it to the path info.
228 View Code Duplication
					if ( ! empty($requested_file) && strpos($match, $requested_file) === 0 && $requested_file != $requested_path )
229
						$request_match = $requested_file . '/' . $requested_path;
230
231
					if ( preg_match("#^$match#", $request_match, $matches) ||
232
						preg_match("#^$match#", urldecode($request_match), $matches) ) {
233
234 View Code Duplication
						if ( $wp_rewrite->use_verbose_page_rules && preg_match( '/pagename=\$matches\[([0-9]+)\]/', $query, $varmatch ) ) {
235
							// This is a verbose page match, let's check to be sure about it.
236
							$page = get_page_by_path( $matches[ $varmatch[1] ] );
237
							if ( ! $page ) {
238
						 		continue;
239
							}
240
241
							$post_status_obj = get_post_status_object( $page->post_status );
242
							if ( ! $post_status_obj->public && ! $post_status_obj->protected
243
								&& ! $post_status_obj->private && $post_status_obj->exclude_from_search ) {
244
								continue;
245
							}
246
						}
247
248
						// Got a match.
249
						$this->matched_rule = $match;
0 ignored issues
show
Documentation Bug introduced by
It seems like $match can also be of type integer. However, the property $matched_rule 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...
250
						break;
251
					}
252
				}
253
			}
254
255
			if ( isset( $this->matched_rule ) ) {
256
				// Trim the query of everything up to the '?'.
257
				$query = preg_replace("!^.+\?!", '', $query);
0 ignored issues
show
The variable $query 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...
258
259
				// Substitute the substring matches into the query.
260
				$query = addslashes(WP_MatchesMapRegex::apply($query, $matches));
0 ignored issues
show
The variable $matches 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...
261
262
				$this->matched_query = $query;
263
264
				// Parse the query.
265
				parse_str($query, $perma_query_vars);
266
267
				// If we're processing a 404 request, clear the error var since we found something.
268
				if ( '404' == $error )
269
					unset( $error, $_GET['error'] );
270
			}
271
272
			// If req_uri is empty or if it is a request for ourself, unset error.
273
			if ( empty($requested_path) || $requested_file == $self || strpos($_SERVER['PHP_SELF'], 'wp-admin/') !== false ) {
274
				unset( $error, $_GET['error'] );
275
276
				if ( isset($perma_query_vars) && strpos($_SERVER['PHP_SELF'], 'wp-admin/') !== false )
277
					unset( $perma_query_vars );
278
279
				$this->did_permalink = false;
280
			}
281
		}
282
283
		/**
284
		 * Filters the query variables whitelist before processing.
285
		 *
286
		 * Allows (publicly allowed) query vars to be added, removed, or changed prior
287
		 * to executing the query. Needed to allow custom rewrite rules using your own arguments
288
		 * to work, or any other custom query variables you want to be publicly available.
289
		 *
290
		 * @since 1.5.0
291
		 *
292
		 * @param array $public_query_vars The array of whitelisted query variables.
293
		 */
294
		$this->public_query_vars = apply_filters( 'query_vars', $this->public_query_vars );
0 ignored issues
show
Documentation Bug introduced by
It seems like apply_filters('query_var...his->public_query_vars) of type * is incompatible with the declared type array of property $public_query_vars.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
295
296 View Code Duplication
		foreach ( get_post_types( array(), 'objects' ) as $post_type => $t ) {
297
			if ( is_post_type_viewable( $t ) && $t->query_var ) {
298
				$post_type_query_vars[$t->query_var] = $post_type;
299
			}
300
		}
301
302
		foreach ( $this->public_query_vars as $wpvar ) {
303
			if ( isset( $this->extra_query_vars[$wpvar] ) )
304
				$this->query_vars[$wpvar] = $this->extra_query_vars[$wpvar];
305
			elseif ( isset( $_POST[$wpvar] ) )
306
				$this->query_vars[$wpvar] = $_POST[$wpvar];
307
			elseif ( isset( $_GET[$wpvar] ) )
308
				$this->query_vars[$wpvar] = $_GET[$wpvar];
309
			elseif ( isset( $perma_query_vars[$wpvar] ) )
310
				$this->query_vars[$wpvar] = $perma_query_vars[$wpvar];
311
312
			if ( !empty( $this->query_vars[$wpvar] ) ) {
313
				if ( ! is_array( $this->query_vars[$wpvar] ) ) {
314
					$this->query_vars[$wpvar] = (string) $this->query_vars[$wpvar];
315
				} else {
316
					foreach ( $this->query_vars[$wpvar] as $vkey => $v ) {
317
						if ( !is_object( $v ) ) {
318
							$this->query_vars[$wpvar][$vkey] = (string) $v;
319
						}
320
					}
321
				}
322
323
				if ( isset($post_type_query_vars[$wpvar] ) ) {
324
					$this->query_vars['post_type'] = $post_type_query_vars[$wpvar];
325
					$this->query_vars['name'] = $this->query_vars[$wpvar];
326
				}
327
			}
328
		}
329
330
		// Convert urldecoded spaces back into +
331
		foreach ( get_taxonomies( array() , 'objects' ) as $taxonomy => $t )
332
			if ( $t->query_var && isset( $this->query_vars[$t->query_var] ) )
333
				$this->query_vars[$t->query_var] = str_replace( ' ', '+', $this->query_vars[$t->query_var] );
334
335
		// Don't allow non-publicly queryable taxonomies to be queried from the front end.
336
		if ( ! is_admin() ) {
337
			foreach ( get_taxonomies( array( 'publicly_queryable' => false ), 'objects' ) as $taxonomy => $t ) {
338
				/*
339
				 * Disallow when set to the 'taxonomy' query var.
340
				 * Non-publicly queryable taxonomies cannot register custom query vars. See register_taxonomy().
341
				 */
342
				if ( isset( $this->query_vars['taxonomy'] ) && $taxonomy === $this->query_vars['taxonomy'] ) {
343
					unset( $this->query_vars['taxonomy'], $this->query_vars['term'] );
344
				}
345
			}
346
		}
347
348
		// Limit publicly queried post_types to those that are publicly_queryable
349
		if ( isset( $this->query_vars['post_type']) ) {
350
			$queryable_post_types = get_post_types( array('publicly_queryable' => true) );
351
			if ( ! is_array( $this->query_vars['post_type'] ) ) {
352
				if ( ! in_array( $this->query_vars['post_type'], $queryable_post_types ) )
353
					unset( $this->query_vars['post_type'] );
354
			} else {
355
				$this->query_vars['post_type'] = array_intersect( $this->query_vars['post_type'], $queryable_post_types );
356
			}
357
		}
358
359
		// Resolve conflicts between posts with numeric slugs and date archive queries.
360
		$this->query_vars = wp_resolve_numeric_slug_conflicts( $this->query_vars );
361
362
		foreach ( (array) $this->private_query_vars as $var) {
363
			if ( isset($this->extra_query_vars[$var]) )
364
				$this->query_vars[$var] = $this->extra_query_vars[$var];
365
		}
366
367
		if ( isset($error) )
368
			$this->query_vars['error'] = $error;
369
370
		/**
371
		 * Filters the array of parsed query variables.
372
		 *
373
		 * @since 2.1.0
374
		 *
375
		 * @param array $query_vars The array of requested query variables.
376
		 */
377
		$this->query_vars = apply_filters( 'request', $this->query_vars );
0 ignored issues
show
Documentation Bug introduced by
It seems like apply_filters('request', $this->query_vars) of type * is incompatible with the declared type array of property $query_vars.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
378
379
		/**
380
		 * Fires once all query variables for the current request have been parsed.
381
		 *
382
		 * @since 2.1.0
383
		 *
384
		 * @param WP &$this Current WordPress environment instance (passed by reference).
385
		 */
386
		do_action_ref_array( 'parse_request', array( &$this ) );
387
	}
388
389
	/**
390
	 * Sends additional HTTP headers for caching, content type, etc.
391
	 *
392
	 * Sets the Content-Type header. Sets the 'error' status (if passed) and optionally exits.
393
	 * If showing a feed, it will also send Last-Modified, ETag, and 304 status if needed.
394
	 *
395
	 * @since 2.0.0
396
	 * @since 4.4.0 `X-Pingback` header is added conditionally after posts have been queried in handle_404().
397
	 * @access public
398
	 */
399
	public function send_headers() {
400
		$headers = array();
401
		$status = null;
402
		$exit_required = false;
403
404
		if ( is_user_logged_in() )
405
			$headers = array_merge($headers, wp_get_nocache_headers());
406
		if ( ! empty( $this->query_vars['error'] ) ) {
407
			$status = (int) $this->query_vars['error'];
408
			if ( 404 === $status ) {
409
				if ( ! is_user_logged_in() )
410
					$headers = array_merge($headers, wp_get_nocache_headers());
411
				$headers['Content-Type'] = get_option('html_type') . '; charset=' . get_option('blog_charset');
412
			} elseif ( in_array( $status, array( 403, 500, 502, 503 ) ) ) {
413
				$exit_required = true;
414
			}
415
		} elseif ( empty( $this->query_vars['feed'] ) ) {
416
			$headers['Content-Type'] = get_option('html_type') . '; charset=' . get_option('blog_charset');
417
		} else {
418
			// Set the correct content type for feeds
419
			$type = $this->query_vars['feed'];
420
			if ( 'feed' == $this->query_vars['feed'] ) {
421
				$type = get_default_feed();
422
			}
423
			$headers['Content-Type'] = feed_content_type( $type ) . '; charset=' . get_option( 'blog_charset' );
424
425
			// We're showing a feed, so WP is indeed the only thing that last changed
426
			if ( !empty($this->query_vars['withcomments'])
427
				|| false !== strpos( $this->query_vars['feed'], 'comments-' )
428
				|| ( empty($this->query_vars['withoutcomments'])
429
					&& ( !empty($this->query_vars['p'])
430
						|| !empty($this->query_vars['name'])
431
						|| !empty($this->query_vars['page_id'])
432
						|| !empty($this->query_vars['pagename'])
433
						|| !empty($this->query_vars['attachment'])
434
						|| !empty($this->query_vars['attachment_id'])
435
					)
436
				)
437
			)
438
				$wp_last_modified = mysql2date('D, d M Y H:i:s', get_lastcommentmodified('GMT'), 0).' GMT';
0 ignored issues
show
0 is of type integer, but the function expects a boolean.

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...
439
			else
440
				$wp_last_modified = mysql2date('D, d M Y H:i:s', get_lastpostmodified('GMT'), 0).' GMT';
0 ignored issues
show
0 is of type integer, but the function expects a boolean.

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...
441
			$wp_etag = '"' . md5($wp_last_modified) . '"';
442
			$headers['Last-Modified'] = $wp_last_modified;
443
			$headers['ETag'] = $wp_etag;
444
445
			// Support for Conditional GET
446
			if (isset($_SERVER['HTTP_IF_NONE_MATCH']))
447
				$client_etag = wp_unslash( $_SERVER['HTTP_IF_NONE_MATCH'] );
448
			else $client_etag = false;
449
450
			$client_last_modified = empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? '' : trim($_SERVER['HTTP_IF_MODIFIED_SINCE']);
451
			// If string is empty, return 0. If not, attempt to parse into a timestamp
452
			$client_modified_timestamp = $client_last_modified ? strtotime($client_last_modified) : 0;
453
454
			// Make a timestamp for our most recent modification...
455
			$wp_modified_timestamp = strtotime($wp_last_modified);
456
457
			if ( ($client_last_modified && $client_etag) ?
458
					 (($client_modified_timestamp >= $wp_modified_timestamp) && ($client_etag == $wp_etag)) :
459
					 (($client_modified_timestamp >= $wp_modified_timestamp) || ($client_etag == $wp_etag)) ) {
460
				$status = 304;
461
				$exit_required = true;
462
			}
463
		}
464
465
		/**
466
		 * Filters the HTTP headers before they're sent to the browser.
467
		 *
468
		 * @since 2.8.0
469
		 *
470
		 * @param array $headers The list of headers to be sent.
471
		 * @param WP    $this    Current WordPress environment instance.
472
		 */
473
		$headers = apply_filters( 'wp_headers', $headers, $this );
474
475
		if ( ! empty( $status ) )
476
			status_header( $status );
477
478
		// If Last-Modified is set to false, it should not be sent (no-cache situation).
479
		if ( isset( $headers['Last-Modified'] ) && false === $headers['Last-Modified'] ) {
480
			unset( $headers['Last-Modified'] );
481
482
			// In PHP 5.3+, make sure we are not sending a Last-Modified header.
483 View Code Duplication
			if ( function_exists( 'header_remove' ) ) {
484
				@header_remove( 'Last-Modified' );
485
			} else {
486
				// In PHP 5.2, send an empty Last-Modified header, but only as a
487
				// last resort to override a header already sent. #WP23021
488
				foreach ( headers_list() as $header ) {
489
					if ( 0 === stripos( $header, 'Last-Modified' ) ) {
490
						$headers['Last-Modified'] = '';
491
						break;
492
					}
493
				}
494
			}
495
		}
496
497
		foreach ( (array) $headers as $name => $field_value )
498
			@header("{$name}: {$field_value}");
499
500
		if ( $exit_required )
501
			exit();
502
503
		/**
504
		 * Fires once the requested HTTP headers for caching, content type, etc. have been sent.
505
		 *
506
		 * @since 2.1.0
507
		 *
508
		 * @param WP &$this Current WordPress environment instance (passed by reference).
509
		 */
510
		do_action_ref_array( 'send_headers', array( &$this ) );
511
	}
512
513
	/**
514
	 * Sets the query string property based off of the query variable property.
515
	 *
516
	 * The {@see 'query_string'} filter is deprecated, but still works. Plugins should
517
	 * use the {@see 'request'} filter instead.
518
	 *
519
	 * @since 2.0.0
520
	 * @access public
521
	 */
522
	public function build_query_string() {
523
		$this->query_string = '';
524
		foreach ( (array) array_keys($this->query_vars) as $wpvar) {
525
			if ( '' != $this->query_vars[$wpvar] ) {
526
				$this->query_string .= (strlen($this->query_string) < 1) ? '' : '&';
527
				if ( !is_scalar($this->query_vars[$wpvar]) ) // Discard non-scalars.
528
					continue;
529
				$this->query_string .= $wpvar . '=' . rawurlencode($this->query_vars[$wpvar]);
530
			}
531
		}
532
533
		if ( has_filter( 'query_string' ) ) {  // Don't bother filtering and parsing if no plugins are hooked in.
534
			/**
535
			 * Filters the query string before parsing.
536
			 *
537
			 * @since 1.5.0
538
			 * @deprecated 2.1.0 Use 'query_vars' or 'request' filters instead.
539
			 *
540
			 * @param string $query_string The query string to modify.
541
			 */
542
			$this->query_string = apply_filters( 'query_string', $this->query_string );
543
			parse_str($this->query_string, $this->query_vars);
544
		}
545
	}
546
547
	/**
548
	 * Set up the WordPress Globals.
549
	 *
550
	 * The query_vars property will be extracted to the GLOBALS. So care should
551
	 * be taken when naming global variables that might interfere with the
552
	 * WordPress environment.
553
	 *
554
	 * @since 2.0.0
555
	 * @access public
556
	 *
557
	 * @global WP_Query     $wp_query
558
	 * @global string       $query_string Query string for the loop.
559
	 * @global array        $posts The found posts.
560
	 * @global WP_Post|null $post The current post, if available.
561
	 * @global string       $request The SQL statement for the request.
562
	 * @global int          $more Only set, if single page or post.
563
	 * @global int          $single If single page or post. Only set, if single page or post.
564
	 * @global WP_User      $authordata Only set, if author archive.
565
	 */
566
	public function register_globals() {
567
		global $wp_query;
568
569
		// Extract updated query vars back into global namespace.
570
		foreach ( (array) $wp_query->query_vars as $key => $value ) {
571
			$GLOBALS[ $key ] = $value;
572
		}
573
574
		$GLOBALS['query_string'] = $this->query_string;
575
		$GLOBALS['posts'] = & $wp_query->posts;
576
		$GLOBALS['post'] = isset( $wp_query->post ) ? $wp_query->post : null;
577
		$GLOBALS['request'] = $wp_query->request;
578
579
		if ( $wp_query->is_single() || $wp_query->is_page() ) {
580
			$GLOBALS['more']   = 1;
581
			$GLOBALS['single'] = 1;
582
		}
583
584
		if ( $wp_query->is_author() && isset( $wp_query->post ) )
585
			$GLOBALS['authordata'] = get_userdata( $wp_query->post->post_author );
586
	}
587
588
	/**
589
	 * Set up the current user.
590
	 *
591
	 * @since 2.0.0
592
	 * @access public
593
	 */
594
	public function init() {
595
		wp_get_current_user();
596
	}
597
598
	/**
599
	 * Set up the Loop based on the query variables.
600
	 *
601
	 * @since 2.0.0
602
	 * @access public
603
	 *
604
	 * @global WP_Query $wp_the_query
605
	 */
606
	public function query_posts() {
607
		global $wp_the_query;
608
		$this->build_query_string();
609
		$wp_the_query->query($this->query_vars);
610
 	}
611
612
 	/**
0 ignored issues
show
There is some trailing whitespace on this line which should be avoided as per coding-style.
Loading history...
613
	 * Set the Headers for 404, if nothing is found for requested URL.
614
	 *
615
	 * Issue a 404 if a request doesn't match any posts and doesn't match
616
	 * any object (e.g. an existing-but-empty category, tag, author) and a 404 was not already
617
	 * issued, and if the request was not a search or the homepage.
618
	 *
619
	 * Otherwise, issue a 200.
620
	 *
621
	 * This sets headers after posts have been queried. handle_404() really means "handle status."
622
	 * By inspecting the result of querying posts, seemingly successful requests can be switched to
623
	 * a 404 so that canonical redirection logic can kick in.
624
	 *
625
	 * @since 2.0.0
626
     * @access public
627
	 *
628
	 * @global WP_Query $wp_query
629
 	 */
630
	public function handle_404() {
631
		global $wp_query;
632
633
		/**
634
		 * Filters whether to short-circuit default header status handling.
635
		 *
636
		 * Returning a non-false value from the filter will short-circuit the handling
637
		 * and return early.
638
		 *
639
		 * @since 4.5.0
640
		 *
641
		 * @param bool     $preempt  Whether to short-circuit default header status handling. Default false.
642
		 * @param WP_Query $wp_query WordPress Query object.
643
		 */
644
		if ( false !== apply_filters( 'pre_handle_404', false, $wp_query ) ) {
645
			return;
646
		}
647
648
		// If we've already issued a 404, bail.
649
		if ( is_404() )
650
			return;
651
652
		// Never 404 for the admin, robots, or if we found posts.
653
		if ( is_admin() || is_robots() || $wp_query->posts ) {
654
655
			$success = true;
656
			if ( is_singular() ) {
657
				$p = false;
658
659
				if ( $wp_query->post instanceof WP_Post ) {
660
					$p = clone $wp_query->post;
661
				}
662
663
				// Only set X-Pingback for single posts that allow pings.
664
				if ( $p && pings_open( $p ) ) {
665
					@header( 'X-Pingback: ' . get_bloginfo( 'pingback_url' ) );
666
				}
667
668
				// check for paged content that exceeds the max number of pages
669
				$next = '<!--nextpage-->';
670
				if ( $p && false !== strpos( $p->post_content, $next ) && ! empty( $this->query_vars['page'] ) ) {
671
					$page = trim( $this->query_vars['page'], '/' );
672
					$success = (int) $page <= ( substr_count( $p->post_content, $next ) + 1 );
673
				}
674
			}
675
676
			if ( $success ) {
677
				status_header( 200 );
678
				return;
679
			}
680
		}
681
682
		// We will 404 for paged queries, as no posts were found.
683
		if ( ! is_paged() ) {
684
685
			// Don't 404 for authors without posts as long as they matched an author on this site.
686
			$author = get_query_var( 'author' );
687
			if ( is_author() && is_numeric( $author ) && $author > 0 && is_user_member_of_blog( $author ) ) {
688
				status_header( 200 );
689
				return;
690
			}
691
692
			// Don't 404 for these queries if they matched an object.
693
			if ( ( is_tag() || is_category() || is_tax() || is_post_type_archive() ) && get_queried_object() ) {
694
				status_header( 200 );
695
				return;
696
			}
697
698
			// Don't 404 for these queries either.
699
			if ( is_home() || is_search() || is_feed() ) {
700
				status_header( 200 );
701
				return;
702
			}
703
		}
704
705
		// Guess it's time to 404.
706
		$wp_query->set_404();
707
		status_header( 404 );
708
		nocache_headers();
709
	}
710
711
	/**
712
	 * Sets up all of the variables required by the WordPress environment.
713
	 *
714
	 * The action {@see 'wp'} has one parameter that references the WP object. It
715
	 * allows for accessing the properties and methods to further manipulate the
716
	 * object.
717
	 *
718
	 * @since 2.0.0
719
	 * @access public
720
	 *
721
	 * @param string|array $query_args Passed to parse_request().
722
	 */
723
	public function main($query_args = '') {
724
		$this->init();
725
		$this->parse_request($query_args);
726
		$this->send_headers();
727
		$this->query_posts();
728
		$this->handle_404();
729
		$this->register_globals();
730
731
		/**
732
		 * Fires once the WordPress environment has been set up.
733
		 *
734
		 * @since 2.1.0
735
		 *
736
		 * @param WP &$this Current WordPress environment instance (passed by reference).
737
		 */
738
		do_action_ref_array( 'wp', array( &$this ) );
739
	}
740
}
741
742
/**
743
 * Helper class to remove the need to use eval to replace $matches[] in query strings.
744
 *
745
 * @since 2.9.0
746
 */
747
class WP_MatchesMapRegex {
748
	/**
749
	 * store for matches
750
	 *
751
	 * @access private
752
	 * @var array
753
	 */
754
	private $_matches;
755
756
	/**
757
	 * store for mapping result
758
	 *
759
	 * @access public
760
	 * @var string
761
	 */
762
	public $output;
763
764
	/**
765
	 * subject to perform mapping on (query string containing $matches[] references
766
	 *
767
	 * @access private
768
	 * @var string
769
	 */
770
	private $_subject;
771
772
	/**
773
	 * regexp pattern to match $matches[] references
774
	 *
775
	 * @var string
776
	 */
777
	public $_pattern = '(\$matches\[[1-9]+[0-9]*\])'; // magic number
778
779
	/**
780
	 * constructor
781
	 *
782
	 * @param string $subject subject if regex
783
	 * @param array  $matches data to use in map
784
	 */
785
	public function __construct($subject, $matches) {
786
		$this->_subject = $subject;
787
		$this->_matches = $matches;
788
		$this->output = $this->_map();
789
	}
790
791
	/**
792
	 * Substitute substring matches in subject.
793
	 *
794
	 * static helper function to ease use
795
	 *
796
	 * @static
797
	 * @access public
798
	 *
799
	 * @param string $subject subject
800
	 * @param array  $matches data used for substitution
801
	 * @return string
802
	 */
803
	public static function apply($subject, $matches) {
804
		$oSelf = new WP_MatchesMapRegex($subject, $matches);
805
		return $oSelf->output;
806
	}
807
808
	/**
809
	 * do the actual mapping
810
	 *
811
	 * @access private
812
	 * @return string
813
	 */
814
	private function _map() {
815
		$callback = array($this, 'callback');
816
		return preg_replace_callback($this->_pattern, $callback, $this->_subject);
817
	}
818
819
	/**
820
	 * preg_replace_callback hook
821
	 *
822
	 * @access public
823
	 * @param  array $matches preg_replace regexp matches
824
	 * @return string
825
	 */
826
	public function callback($matches) {
827
		$index = intval(substr($matches[0], 9, -1));
828
		return ( isset( $this->_matches[$index] ) ? urlencode($this->_matches[$index]) : '' );
829
	}
830
}
831