Issues (4967)

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.

src/wp-includes/canonical.php (23 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
 * Canonical API to handle WordPress Redirecting
4
 *
5
 * Based on "Permalink Redirect" from Scott Yang and "Enforce www. Preference"
6
 * by Mark Jaquith
7
 *
8
 * @package WordPress
9
 * @since 2.3.0
10
 */
11
12
/**
13
 * Redirects incoming links to the proper URL based on the site url.
14
 *
15
 * Search engines consider www.somedomain.com and somedomain.com to be two
16
 * different URLs when they both go to the same location. This SEO enhancement
17
 * prevents penalty for duplicate content by redirecting all incoming links to
18
 * one or the other.
19
 *
20
 * Prevents redirection for feeds, trackbacks, searches, and
21
 * admin URLs. Does not redirect on non-pretty-permalink-supporting IIS 7+,
22
 * page/post previews, WP admin, Trackbacks, robots.txt, searches, or on POST
23
 * requests.
24
 *
25
 * Will also attempt to find the correct link when a user enters a URL that does
26
 * not exist based on exact WordPress query. Will instead try to parse the URL
27
 * or query in an attempt to figure the correct page to go to.
28
 *
29
 * @since 2.3.0
30
 *
31
 * @global WP_Rewrite $wp_rewrite
32
 * @global bool $is_IIS
33
 * @global WP_Query $wp_query
34
 * @global wpdb $wpdb WordPress database abstraction object.
35
 *
36
 * @param string $requested_url Optional. The URL that was requested, used to
37
 *		figure if redirect is needed.
38
 * @param bool $do_redirect Optional. Redirect to the new URL.
39
 * @return string|void The string of the URL, if redirect needed.
40
 */
41
function redirect_canonical( $requested_url = null, $do_redirect = true ) {
42
	global $wp_rewrite, $is_IIS, $wp_query, $wpdb, $wp;
43
44
	if ( isset( $_SERVER['REQUEST_METHOD'] ) && ! in_array( strtoupper( $_SERVER['REQUEST_METHOD'] ), array( 'GET', 'HEAD' ) ) ) {
45
		return;
46
	}
47
48
	// If we're not in wp-admin and the post has been published and preview nonce
49
	// is non-existent or invalid then no need for preview in query
50
	if ( is_preview() && get_query_var( 'p' ) && 'publish' == get_post_status( get_query_var( 'p' ) ) ) {
51
		if ( ! isset( $_GET['preview_id'] )
52
			|| ! isset( $_GET['preview_nonce'] )
53
			|| ! wp_verify_nonce( $_GET['preview_nonce'], 'post_preview_' . (int) $_GET['preview_id'] ) ) {
54
			$wp_query->is_preview = false;
55
		}
56
	}
57
58
	if ( is_trackback() || is_search() || is_admin() || is_preview() || is_robots() || ( $is_IIS && !iis7_supports_permalinks() ) ) {
59
		return;
60
	}
61
62
	if ( ! $requested_url && isset( $_SERVER['HTTP_HOST'] ) ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $requested_url of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
63
		// build the URL in the address bar
64
		$requested_url  = is_ssl() ? 'https://' : 'http://';
65
		$requested_url .= $_SERVER['HTTP_HOST'];
66
		$requested_url .= $_SERVER['REQUEST_URI'];
67
	}
68
69
	$original = @parse_url($requested_url);
70
	if ( false === $original ) {
71
		return;
72
	}
73
74
	$redirect = $original;
75
	$redirect_url = false;
76
77
	// Notice fixing
78
	if ( !isset($redirect['path']) )
79
		$redirect['path'] = '';
80
	if ( !isset($redirect['query']) )
81
		$redirect['query'] = '';
82
83
	// If the original URL ended with non-breaking spaces, they were almost
84
	// certainly inserted by accident. Let's remove them, so the reader doesn't
85
	// see a 404 error with no obvious cause.
86
	$redirect['path'] = preg_replace( '|(%C2%A0)+$|i', '', $redirect['path'] );
87
88
	// It's not a preview, so remove it from URL
89
	if ( get_query_var( 'preview' ) ) {
90
		$redirect['query'] = remove_query_arg( 'preview', $redirect['query'] );
91
	}
92
93
	if ( is_feed() && ( $id = get_query_var( 'p' ) ) ) {
94
		if ( $redirect_url = get_post_comments_feed_link( $id, get_query_var( 'feed' ) ) ) {
95
			$redirect['query'] = _remove_qs_args_if_not_in_url( $redirect['query'], array( 'p', 'page_id', 'attachment_id', 'pagename', 'name', 'post_type', 'feed'), $redirect_url );
96
			$redirect['path'] = parse_url( $redirect_url, PHP_URL_PATH );
97
		}
98
	}
99
100
	if ( is_singular() && 1 > $wp_query->post_count && ($id = get_query_var('p')) ) {
101
102
		$vars = $wpdb->get_results( $wpdb->prepare("SELECT post_type, post_parent FROM $wpdb->posts WHERE ID = %d", $id) );
103
104
		if ( isset($vars[0]) && $vars = $vars[0] ) {
105
			if ( 'revision' == $vars->post_type && $vars->post_parent > 0 )
106
				$id = $vars->post_parent;
107
108 View Code Duplication
			if ( $redirect_url = get_permalink($id) )
109
				$redirect['query'] = _remove_qs_args_if_not_in_url( $redirect['query'], array( 'p', 'page_id', 'attachment_id', 'pagename', 'name', 'post_type' ), $redirect_url );
110
		}
111
	}
112
113
	// These tests give us a WP-generated permalink
114
	if ( is_404() ) {
115
116
		// Redirect ?page_id, ?p=, ?attachment_id= to their respective url's
117
		$id = max( get_query_var('p'), get_query_var('page_id'), get_query_var('attachment_id') );
118
		if ( $id && $redirect_post = get_post($id) ) {
119
			$post_type_obj = get_post_type_object($redirect_post->post_type);
120
			if ( $post_type_obj->public && 'auto-draft' != $redirect_post->post_status ) {
121
				$redirect_url = get_permalink($redirect_post);
122
				$redirect['query'] = _remove_qs_args_if_not_in_url( $redirect['query'], array( 'p', 'page_id', 'attachment_id', 'pagename', 'name', 'post_type' ), $redirect_url );
0 ignored issues
show
It seems like $redirect_url defined by get_permalink($redirect_post) on line 121 can also be of type false; however, _remove_qs_args_if_not_in_url() does only seem to accept string, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
123
			}
124
		}
125
126
		if ( get_query_var( 'day' ) && get_query_var( 'monthnum' ) && get_query_var( 'year' ) ) {
127
			$year  = get_query_var( 'year' );
128
			$month = get_query_var( 'monthnum' );
129
			$day   = get_query_var( 'day' );
130
			$date  = sprintf( '%04d-%02d-%02d', $year, $month, $day );
131
			if ( ! wp_checkdate( $month, $day, $year, $date ) ) {
132
				$redirect_url = get_month_link( $year, $month );
133
				$redirect['query'] = _remove_qs_args_if_not_in_url( $redirect['query'], array( 'year', 'monthnum', 'day' ), $redirect_url );
134
			}
135
		} elseif ( get_query_var( 'monthnum' ) && get_query_var( 'year' ) && 12 < get_query_var( 'monthnum' ) ) {
136
			$redirect_url = get_year_link( get_query_var( 'year' ) );
137
			$redirect['query'] = _remove_qs_args_if_not_in_url( $redirect['query'], array( 'year', 'monthnum' ), $redirect_url );
138
		}
139
140
		if ( ! $redirect_url ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $redirect_url of type string|false is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
141 View Code Duplication
			if ( $redirect_url = redirect_guess_404_permalink() ) {
142
				$redirect['query'] = _remove_qs_args_if_not_in_url( $redirect['query'], array( 'page', 'feed', 'p', 'page_id', 'attachment_id', 'pagename', 'name', 'post_type' ), $redirect_url );
143
			}
144
		}
145
146
		if ( get_query_var( 'page' ) && $wp_query->post &&
147
			false !== strpos( $wp_query->post->post_content, '<!--nextpage-->' ) ) {
148
			$redirect['path'] = rtrim( $redirect['path'], (int) get_query_var( 'page' ) . '/' );
149
			$redirect['query'] = remove_query_arg( 'page', $redirect['query'] );
150
			$redirect_url = get_permalink( $wp_query->post->ID );
151
		}
152
153
	} elseif ( is_object($wp_rewrite) && $wp_rewrite->using_permalinks() ) {
154
		// rewriting of old ?p=X, ?m=2004, ?m=200401, ?m=20040101
155
		if ( is_attachment() &&
156
			! array_diff( array_keys( $wp->query_vars ), array( 'attachment', 'attachment_id' ) ) &&
157
			! $redirect_url ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $redirect_url of type string|false is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
158
			if ( ! empty( $_GET['attachment_id'] ) ) {
159
				$redirect_url = get_attachment_link( get_query_var( 'attachment_id' ) );
160
				if ( $redirect_url ) {
161
					$redirect['query'] = remove_query_arg( 'attachment_id', $redirect['query'] );
162
				}
163
			} else {
164
				$redirect_url = get_attachment_link();
165
			}
166 View Code Duplication
		} elseif ( is_single() && !empty($_GET['p']) && ! $redirect_url ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $redirect_url of type string|false is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
167
			if ( $redirect_url = get_permalink(get_query_var('p')) )
168
				$redirect['query'] = remove_query_arg(array('p', 'post_type'), $redirect['query']);
169
		} elseif ( is_single() && !empty($_GET['name'])  && ! $redirect_url ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $redirect_url of type string|false is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
170
			if ( $redirect_url = get_permalink( $wp_query->get_queried_object_id() ) )
171
				$redirect['query'] = remove_query_arg('name', $redirect['query']);
172 View Code Duplication
		} elseif ( is_page() && !empty($_GET['page_id']) && ! $redirect_url ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $redirect_url of type string|false is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
173
			if ( $redirect_url = get_permalink(get_query_var('page_id')) )
174
				$redirect['query'] = remove_query_arg('page_id', $redirect['query']);
175
		} elseif ( is_page() && !is_feed() && 'page' == get_option('show_on_front') && get_queried_object_id() == get_option('page_on_front')  && ! $redirect_url ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $redirect_url of type string|false is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
176
			$redirect_url = home_url('/');
177
		} elseif ( is_home() && !empty($_GET['page_id']) && 'page' == get_option('show_on_front') && get_query_var('page_id') == get_option('page_for_posts')  && ! $redirect_url ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $redirect_url of type string|false is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
178
			if ( $redirect_url = get_permalink(get_option('page_for_posts')) )
179
				$redirect['query'] = remove_query_arg('page_id', $redirect['query']);
180
		} elseif ( !empty($_GET['m']) && ( is_year() || is_month() || is_day() ) ) {
181
			$m = get_query_var('m');
182
			switch ( strlen($m) ) {
183
				case 4: // Yearly
184
					$redirect_url = get_year_link($m);
185
					break;
186
				case 6: // Monthly
187
					$redirect_url = get_month_link( substr($m, 0, 4), substr($m, 4, 2) );
188
					break;
189
				case 8: // Daily
190
					$redirect_url = get_day_link(substr($m, 0, 4), substr($m, 4, 2), substr($m, 6, 2));
191
					break;
192
			}
193
			if ( $redirect_url )
0 ignored issues
show
Bug Best Practice introduced by
The expression $redirect_url of type string|false is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
194
				$redirect['query'] = remove_query_arg('m', $redirect['query']);
195
		// now moving on to non ?m=X year/month/day links
196
		} elseif ( is_day() && get_query_var('year') && get_query_var('monthnum') && !empty($_GET['day']) ) {
197 View Code Duplication
			if ( $redirect_url = get_day_link(get_query_var('year'), get_query_var('monthnum'), get_query_var('day')) )
198
				$redirect['query'] = remove_query_arg(array('year', 'monthnum', 'day'), $redirect['query']);
199
		} elseif ( is_month() && get_query_var('year') && !empty($_GET['monthnum']) ) {
200 View Code Duplication
			if ( $redirect_url = get_month_link(get_query_var('year'), get_query_var('monthnum')) )
201
				$redirect['query'] = remove_query_arg(array('year', 'monthnum'), $redirect['query']);
202 View Code Duplication
		} elseif ( is_year() && !empty($_GET['year']) ) {
203
			if ( $redirect_url = get_year_link(get_query_var('year')) )
204
				$redirect['query'] = remove_query_arg('year', $redirect['query']);
205
		} elseif ( is_author() && !empty($_GET['author']) && preg_match( '|^[0-9]+$|', $_GET['author'] ) ) {
206
			$author = get_userdata(get_query_var('author'));
207
			if ( ( false !== $author ) && $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE $wpdb->posts.post_author = %d AND $wpdb->posts.post_status = 'publish' LIMIT 1", $author->ID ) ) ) {
208
				if ( $redirect_url = get_author_posts_url($author->ID, $author->user_nicename) )
209
					$redirect['query'] = remove_query_arg('author', $redirect['query']);
210
			}
211
		} elseif ( is_category() || is_tag() || is_tax() ) { // Terms (Tags/categories)
212
213
			$term_count = 0;
214
			foreach ( $wp_query->tax_query->queried_terms as $tax_query )
215
				$term_count += count( $tax_query['terms'] );
216
217
			$obj = $wp_query->get_queried_object();
218
			if ( $term_count <= 1 && !empty($obj->term_id) && ( $tax_url = get_term_link((int)$obj->term_id, $obj->taxonomy) ) && !is_wp_error($tax_url) ) {
219
				if ( !empty($redirect['query']) ) {
220
					// Strip taxonomy query vars off the url.
221
					$qv_remove = array( 'term', 'taxonomy');
222
					if ( is_category() ) {
223
						$qv_remove[] = 'category_name';
224
						$qv_remove[] = 'cat';
225
					} elseif ( is_tag() ) {
226
						$qv_remove[] = 'tag';
227
						$qv_remove[] = 'tag_id';
228
					} else { // Custom taxonomies will have a custom query var, remove those too:
229
						$tax_obj = get_taxonomy( $obj->taxonomy );
230
						if ( false !== $tax_obj->query_var )
231
							$qv_remove[] = $tax_obj->query_var;
232
					}
233
234
					$rewrite_vars = array_diff( array_keys($wp_query->query), array_keys($_GET) );
235
236
					if ( !array_diff($rewrite_vars, array_keys($_GET))  ) { // Check to see if all the Query vars are coming from the rewrite, none are set via $_GET
237
						$redirect['query'] = remove_query_arg($qv_remove, $redirect['query']); //Remove all of the per-tax qv's
238
239
						// Create the destination url for this taxonomy
240
						$tax_url = parse_url($tax_url);
241
						if ( ! empty($tax_url['query']) ) { // Taxonomy accessible via ?taxonomy=..&term=.. or any custom qv..
242
							parse_str($tax_url['query'], $query_vars);
243
							$redirect['query'] = add_query_arg($query_vars, $redirect['query']);
244
						} else { // Taxonomy is accessible via a "pretty-URL"
245
							$redirect['path'] = $tax_url['path'];
246
						}
247
248
					} else { // Some query vars are set via $_GET. Unset those from $_GET that exist via the rewrite
249
						foreach ( $qv_remove as $_qv ) {
250
							if ( isset($rewrite_vars[$_qv]) )
251
								$redirect['query'] = remove_query_arg($_qv, $redirect['query']);
252
						}
253
					}
254
				}
255
256
			}
257
		} elseif ( is_single() && strpos($wp_rewrite->permalink_structure, '%category%') !== false && $cat = get_query_var( 'category_name' ) ) {
258
			$category = get_category_by_path( $cat );
259
			if ( ( ! $category || is_wp_error( $category ) ) || ! has_term( $category->term_id, 'category', $wp_query->get_queried_object_id() ) ) {
260
				$redirect_url = get_permalink($wp_query->get_queried_object_id());
261
			}
262
		}
263
264
		// Post Paging
265
		if ( is_singular() && get_query_var('page') ) {
266
			if ( !$redirect_url )
0 ignored issues
show
Bug Best Practice introduced by
The expression $redirect_url of type string|false is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
267
				$redirect_url = get_permalink( get_queried_object_id() );
268
269
			$page = get_query_var( 'page' );
270
			if ( $page > 1 ) {
271
				if ( is_front_page() ) {
272
					$redirect_url = trailingslashit( $redirect_url ) . user_trailingslashit( "$wp_rewrite->pagination_base/$page", 'paged' );
0 ignored issues
show
It seems like $redirect_url can also be of type false; however, trailingslashit() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
273
				} else {
274
					$redirect_url = trailingslashit( $redirect_url ) . user_trailingslashit( $page, 'single_paged' );
0 ignored issues
show
It seems like $redirect_url can also be of type false; however, trailingslashit() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
275
				}
276
			}
277
			$redirect['query'] = remove_query_arg( 'page', $redirect['query'] );
278
		}
279
280
		// paging and feeds
281
		if ( get_query_var('paged') || is_feed() || get_query_var('cpage') ) {
282
			while ( preg_match( "#/$wp_rewrite->pagination_base/?[0-9]+?(/+)?$#", $redirect['path'] ) || preg_match( '#/(comments/?)?(feed|rss|rdf|atom|rss2)(/+)?$#', $redirect['path'] ) || preg_match( "#/{$wp_rewrite->comments_pagination_base}-[0-9]+(/+)?$#", $redirect['path'] ) ) {
283
				// Strip off paging and feed
284
				$redirect['path'] = preg_replace("#/$wp_rewrite->pagination_base/?[0-9]+?(/+)?$#", '/', $redirect['path']); // strip off any existing paging
285
				$redirect['path'] = preg_replace('#/(comments/?)?(feed|rss2?|rdf|atom)(/+|$)#', '/', $redirect['path']); // strip off feed endings
286
				$redirect['path'] = preg_replace("#/{$wp_rewrite->comments_pagination_base}-[0-9]+?(/+)?$#", '/', $redirect['path']); // strip off any existing comment paging
287
			}
288
289
			$addl_path = '';
290
			if ( is_feed() && in_array( get_query_var('feed'), $wp_rewrite->feeds ) ) {
291
				$addl_path = !empty( $addl_path ) ? trailingslashit($addl_path) : '';
292
				if ( !is_singular() && get_query_var( 'withcomments' ) )
293
					$addl_path .= 'comments/';
294
				if ( ( 'rss' == get_default_feed() && 'feed' == get_query_var('feed') ) || 'rss' == get_query_var('feed') )
295
					$addl_path .= user_trailingslashit( 'feed/' . ( ( get_default_feed() == 'rss2' ) ? '' : 'rss2' ), 'feed' );
296
				else
297
					$addl_path .= user_trailingslashit( 'feed/' . ( ( get_default_feed() ==  get_query_var('feed') || 'feed' == get_query_var('feed') ) ? '' : get_query_var('feed') ), 'feed' );
298
				$redirect['query'] = remove_query_arg( 'feed', $redirect['query'] );
299
			} elseif ( is_feed() && 'old' == get_query_var('feed') ) {
300
				$old_feed_files = array(
301
					'wp-atom.php'         => 'atom',
302
					'wp-commentsrss2.php' => 'comments_rss2',
303
					'wp-feed.php'         => get_default_feed(),
304
					'wp-rdf.php'          => 'rdf',
305
					'wp-rss.php'          => 'rss2',
306
					'wp-rss2.php'         => 'rss2',
307
				);
308
				if ( isset( $old_feed_files[ basename( $redirect['path'] ) ] ) ) {
309
					$redirect_url = get_feed_link( $old_feed_files[ basename( $redirect['path'] ) ] );
310
					wp_redirect( $redirect_url, 301 );
311
					die();
0 ignored issues
show
Coding Style Compatibility introduced by
The function redirect_canonical() contains an exit expression.

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

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

Loading history...
312
				}
313
			}
314
315
			if ( get_query_var('paged') > 0 ) {
316
				$paged = get_query_var('paged');
317
				$redirect['query'] = remove_query_arg( 'paged', $redirect['query'] );
318
				if ( !is_feed() ) {
319
					if ( $paged > 1 && !is_single() ) {
320
						$addl_path = ( !empty( $addl_path ) ? trailingslashit($addl_path) : '' ) . user_trailingslashit("$wp_rewrite->pagination_base/$paged", 'paged');
321
					} elseif ( !is_single() ) {
322
						$addl_path = !empty( $addl_path ) ? trailingslashit($addl_path) : '';
323
					}
324
				} elseif ( $paged > 1 ) {
325
					$redirect['query'] = add_query_arg( 'paged', $paged, $redirect['query'] );
326
				}
327
			}
328
329
			if ( get_option( 'page_comments' ) && (
330
				( 'newest' == get_option( 'default_comments_page' ) && get_query_var( 'cpage' ) > 0 ) ||
331
				( 'newest' != get_option( 'default_comments_page' ) && get_query_var( 'cpage' ) > 1 )
332
			) ) {
333
				$addl_path = ( !empty( $addl_path ) ? trailingslashit($addl_path) : '' ) . user_trailingslashit( $wp_rewrite->comments_pagination_base . '-' . get_query_var('cpage'), 'commentpaged' );
334
				$redirect['query'] = remove_query_arg( 'cpage', $redirect['query'] );
335
			}
336
337
			$redirect['path'] = user_trailingslashit( preg_replace('|/' . preg_quote( $wp_rewrite->index, '|' ) . '/?$|', '/', $redirect['path']) ); // strip off trailing /index.php/
338
			if ( !empty( $addl_path ) && $wp_rewrite->using_index_permalinks() && strpos($redirect['path'], '/' . $wp_rewrite->index . '/') === false )
339
				$redirect['path'] = trailingslashit($redirect['path']) . $wp_rewrite->index . '/';
340
			if ( !empty( $addl_path ) )
341
				$redirect['path'] = trailingslashit($redirect['path']) . $addl_path;
342
			$redirect_url = $redirect['scheme'] . '://' . $redirect['host'] . $redirect['path'];
343
		}
344
345
		if ( 'wp-register.php' == basename( $redirect['path'] ) ) {
346
			if ( is_multisite() ) {
347
				/** This filter is documented in wp-login.php */
348
				$redirect_url = apply_filters( 'wp_signup_location', network_site_url( 'wp-signup.php' ) );
349
			} else {
350
				$redirect_url = wp_registration_url();
351
			}
352
353
			wp_redirect( $redirect_url, 301 );
354
			die();
0 ignored issues
show
Coding Style Compatibility introduced by
The function redirect_canonical() contains an exit expression.

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

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

Loading history...
355
		}
356
	}
357
358
	// tack on any additional query vars
359
	$redirect['query'] = preg_replace( '#^\??&*?#', '', $redirect['query'] );
360
	if ( $redirect_url && !empty($redirect['query']) ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $redirect_url of type string|false is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
361
		parse_str( $redirect['query'], $_parsed_query );
362
		$redirect = @parse_url($redirect_url);
363
364
		if ( ! empty( $_parsed_query['name'] ) && ! empty( $redirect['query'] ) ) {
365
			parse_str( $redirect['query'], $_parsed_redirect_query );
366
367
			if ( empty( $_parsed_redirect_query['name'] ) )
368
				unset( $_parsed_query['name'] );
369
		}
370
371
		$_parsed_query = rawurlencode_deep( $_parsed_query );
372
		$redirect_url = add_query_arg( $_parsed_query, $redirect_url );
373
	}
374
375
	if ( $redirect_url )
0 ignored issues
show
Bug Best Practice introduced by
The expression $redirect_url of type string|false is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
376
		$redirect = @parse_url($redirect_url);
377
378
	// www.example.com vs example.com
379
	$user_home = @parse_url(home_url());
380
	if ( !empty($user_home['host']) )
381
		$redirect['host'] = $user_home['host'];
382
	if ( empty($user_home['path']) )
383
		$user_home['path'] = '/';
384
385
	// Handle ports
386
	if ( !empty($user_home['port']) )
387
		$redirect['port'] = $user_home['port'];
388
	else
389
		unset($redirect['port']);
390
391
	// trailing /index.php
392
	$redirect['path'] = preg_replace('|/' . preg_quote( $wp_rewrite->index, '|' ) . '/*?$|', '/', $redirect['path']);
393
394
	// Remove trailing spaces from the path
395
	$redirect['path'] = preg_replace( '#(%20| )+$#', '', $redirect['path'] );
396
397
	if ( !empty( $redirect['query'] ) ) {
398
		// Remove trailing spaces from certain terminating query string args
399
		$redirect['query'] = preg_replace( '#((p|page_id|cat|tag)=[^&]*?)(%20| )+$#', '$1', $redirect['query'] );
400
401
		// Clean up empty query strings
402
		$redirect['query'] = trim(preg_replace( '#(^|&)(p|page_id|cat|tag)=?(&|$)#', '&', $redirect['query']), '&');
403
404
		// Redirect obsolete feeds
405
		$redirect['query'] = preg_replace( '#(^|&)feed=rss(&|$)#', '$1feed=rss2$2', $redirect['query'] );
406
407
		// Remove redundant leading ampersands
408
		$redirect['query'] = preg_replace( '#^\??&*?#', '', $redirect['query'] );
409
	}
410
411
	// strip /index.php/ when we're not using PATHINFO permalinks
412
	if ( !$wp_rewrite->using_index_permalinks() )
413
		$redirect['path'] = str_replace( '/' . $wp_rewrite->index . '/', '/', $redirect['path'] );
414
415
	// trailing slashes
416
	if ( is_object($wp_rewrite) && $wp_rewrite->using_permalinks() && !is_404() && (!is_front_page() || ( is_front_page() && (get_query_var('paged') > 1) ) ) ) {
417
		$user_ts_type = '';
418
		if ( get_query_var('paged') > 0 ) {
419
			$user_ts_type = 'paged';
420
		} else {
421
			foreach ( array('single', 'category', 'page', 'day', 'month', 'year', 'home') as $type ) {
422
				$func = 'is_' . $type;
423
				if ( call_user_func($func) ) {
424
					$user_ts_type = $type;
425
					break;
426
				}
427
			}
428
		}
429
		$redirect['path'] = user_trailingslashit($redirect['path'], $user_ts_type);
430
	} elseif ( is_front_page() ) {
431
		$redirect['path'] = trailingslashit($redirect['path']);
432
	}
433
434
	// Strip multiple slashes out of the URL
435
	if ( strpos($redirect['path'], '//') > -1 )
436
		$redirect['path'] = preg_replace('|/+|', '/', $redirect['path']);
437
438
	// Always trailing slash the Front Page URL
439
	if ( trailingslashit( $redirect['path'] ) == trailingslashit( $user_home['path'] ) )
440
		$redirect['path'] = trailingslashit($redirect['path']);
441
442
	// Ignore differences in host capitalization, as this can lead to infinite redirects
443
	// Only redirect no-www <=> yes-www
444
	if ( strtolower($original['host']) == strtolower($redirect['host']) ||
445
		( strtolower($original['host']) != 'www.' . strtolower($redirect['host']) && 'www.' . strtolower($original['host']) != strtolower($redirect['host']) ) )
446
		$redirect['host'] = $original['host'];
447
448
	$compare_original = array( $original['host'], $original['path'] );
449
450
	if ( !empty( $original['port'] ) )
451
		$compare_original[] = $original['port'];
452
453
	if ( !empty( $original['query'] ) )
454
		$compare_original[] = $original['query'];
455
456
	$compare_redirect = array( $redirect['host'], $redirect['path'] );
457
458
	if ( !empty( $redirect['port'] ) )
459
		$compare_redirect[] = $redirect['port'];
460
461
	if ( !empty( $redirect['query'] ) )
462
		$compare_redirect[] = $redirect['query'];
463
464 View Code Duplication
	if ( $compare_original !== $compare_redirect ) {
465
		$redirect_url = $redirect['scheme'] . '://' . $redirect['host'];
466
		if ( !empty($redirect['port']) )
467
			$redirect_url .= ':' . $redirect['port'];
468
		$redirect_url .= $redirect['path'];
469
		if ( !empty($redirect['query']) )
470
			$redirect_url .= '?' . $redirect['query'];
471
	}
472
473
	if ( ! $redirect_url || $redirect_url == $requested_url ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $redirect_url of type string|false is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
474
		return;
475
	}
476
477
	// Hex encoded octets are case-insensitive.
478
	if ( false !== strpos($requested_url, '%') ) {
479
		if ( !function_exists('lowercase_octets') ) {
480
			/**
481
			 * Converts the first hex-encoded octet match to lowercase.
482
			 *
483
			 * @since 3.1.0
484
			 * @ignore
485
			 *
486
			 * @param array $matches Hex-encoded octet matches for the requested URL.
487
			 * @return string Lowercased version of the first match.
488
			 */
489
			function lowercase_octets($matches) {
490
				return strtolower( $matches[0] );
491
			}
492
		}
493
		$requested_url = preg_replace_callback('|%[a-fA-F0-9][a-fA-F0-9]|', 'lowercase_octets', $requested_url);
494
	}
495
496
	/**
497
	 * Filters the canonical redirect URL.
498
	 *
499
	 * Returning false to this filter will cancel the redirect.
500
	 *
501
	 * @since 2.3.0
502
	 *
503
	 * @param string $redirect_url  The redirect URL.
504
	 * @param string $requested_url The requested URL.
505
	 */
506
	$redirect_url = apply_filters( 'redirect_canonical', $redirect_url, $requested_url );
507
508
	// yes, again -- in case the filter aborted the request
509
	if ( ! $redirect_url || strip_fragment_from_url( $redirect_url ) == strip_fragment_from_url( $requested_url ) ) {
510
		return;
511
	}
512
513
	if ( $do_redirect ) {
514
		// protect against chained redirects
515
		if ( !redirect_canonical($redirect_url, false) ) {
516
			wp_redirect($redirect_url, 301);
517
			exit();
0 ignored issues
show
Coding Style Compatibility introduced by
The function redirect_canonical() contains an exit expression.

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

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

Loading history...
518
		} else {
519
			// Debug
520
			// die("1: $redirect_url<br />2: " . redirect_canonical( $redirect_url, false ) );
521
			return;
522
		}
523
	} else {
524
		return $redirect_url;
525
	}
526
}
527
528
/**
529
 * Removes arguments from a query string if they are not present in a URL
530
 * DO NOT use this in plugin code.
531
 *
532
 * @since 3.4.0
533
 * @access private
534
 *
535
 * @param string $query_string
536
 * @param array $args_to_check
537
 * @param string $url
538
 * @return string The altered query 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...
539
 */
540
function _remove_qs_args_if_not_in_url( $query_string, Array $args_to_check, $url ) {
541
	$parsed_url = @parse_url( $url );
542
	if ( ! empty( $parsed_url['query'] ) ) {
543
		parse_str( $parsed_url['query'], $parsed_query );
544
		foreach ( $args_to_check as $qv ) {
545
			if ( !isset( $parsed_query[$qv] ) )
546
				$query_string = remove_query_arg( $qv, $query_string );
547
		}
548
	} else {
549
		$query_string = remove_query_arg( $args_to_check, $query_string );
550
	}
551
	return $query_string;
552
}
553
554
/**
555
 * Strips the #fragment from a URL, if one is present.
556
 *
557
 * @since 4.4.0
558
 *
559
 * @param string $url The URL to strip.
560
 * @return string The altered URL.
561
 */
562
function strip_fragment_from_url( $url ) {
563
	$parsed_url = @parse_url( $url );
564 View Code Duplication
	if ( ! empty( $parsed_url['host'] ) ) {
565
		// This mirrors code in redirect_canonical(). It does not handle every case.
566
		$url = $parsed_url['scheme'] . '://' . $parsed_url['host'];
567
		if ( ! empty( $parsed_url['port'] ) ) {
568
			$url .= ':' . $parsed_url['port'];
569
		}
570
		$url .= $parsed_url['path'];
571
		if ( ! empty( $parsed_url['query'] ) ) {
572
			$url .= '?' . $parsed_url['query'];
573
		}
574
	}
575
576
	return $url;
577
}
578
579
/**
580
 * Attempts to guess the correct URL based on query vars
581
 *
582
 * @since 2.3.0
583
 *
584
 * @global wpdb $wpdb WordPress database abstraction object.
585
 *
586
 * @return false|string The correct URL if one is found. False on failure.
587
 */
588
function redirect_guess_404_permalink() {
589
	global $wpdb;
590
591
	if ( get_query_var('name') ) {
592
		$where = $wpdb->prepare("post_name LIKE %s", $wpdb->esc_like( get_query_var('name') ) . '%');
593
594
		// if any of post_type, year, monthnum, or day are set, use them to refine the query
595
		if ( get_query_var('post_type') )
596
			$where .= $wpdb->prepare(" AND post_type = %s", get_query_var('post_type'));
597
		else
598
			$where .= " AND post_type IN ('" . implode( "', '", get_post_types( array( 'public' => true ) ) ) . "')";
599
600
		if ( get_query_var('year') )
601
			$where .= $wpdb->prepare(" AND YEAR(post_date) = %d", get_query_var('year'));
602
		if ( get_query_var('monthnum') )
603
			$where .= $wpdb->prepare(" AND MONTH(post_date) = %d", get_query_var('monthnum'));
604
		if ( get_query_var('day') )
605
			$where .= $wpdb->prepare(" AND DAYOFMONTH(post_date) = %d", get_query_var('day'));
606
607
		$post_id = $wpdb->get_var("SELECT ID FROM $wpdb->posts WHERE $where AND post_status = 'publish'");
608
		if ( ! $post_id )
609
			return false;
610
		if ( get_query_var( 'feed' ) )
611
			return get_post_comments_feed_link( $post_id, get_query_var( 'feed' ) );
612
		elseif ( get_query_var( 'page' ) && 1 < get_query_var( 'page' ) )
613
			return trailingslashit( get_permalink( $post_id ) ) . user_trailingslashit( get_query_var( 'page' ), 'single_paged' );
0 ignored issues
show
It seems like get_permalink($post_id) targeting get_permalink() can also be of type false; however, trailingslashit() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
614
		else
615
			return get_permalink( $post_id );
616
	}
617
618
	return false;
619
}
620
621
/**
622
 * Redirects a variety of shorthand URLs to the admin.
623
 *
624
 * If a user visits example.com/admin, they'll be redirected to /wp-admin.
625
 * Visiting /login redirects to /wp-login.php, and so on.
626
 *
627
 * @since 3.4.0
628
 *
629
 * @global WP_Rewrite $wp_rewrite
630
 */
631
function wp_redirect_admin_locations() {
632
	global $wp_rewrite;
633
	if ( ! ( is_404() && $wp_rewrite->using_permalinks() ) )
634
		return;
635
636
	$admins = array(
637
		home_url( 'wp-admin', 'relative' ),
638
		home_url( 'dashboard', 'relative' ),
639
		home_url( 'admin', 'relative' ),
640
		site_url( 'dashboard', 'relative' ),
641
		site_url( 'admin', 'relative' ),
642
	);
643
	if ( in_array( untrailingslashit( $_SERVER['REQUEST_URI'] ), $admins ) ) {
644
		wp_redirect( admin_url() );
645
		exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The function wp_redirect_admin_locations() contains an exit expression.

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

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

Loading history...
646
	}
647
648
	$logins = array(
649
		home_url( 'wp-login.php', 'relative' ),
650
		home_url( 'login', 'relative' ),
651
		site_url( 'login', 'relative' ),
652
	);
653
	if ( in_array( untrailingslashit( $_SERVER['REQUEST_URI'] ), $logins ) ) {
654
		wp_redirect( wp_login_url() );
655
		exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The function wp_redirect_admin_locations() contains an exit expression.

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

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

Loading history...
656
	}
657
}
658