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/http.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
 * Core HTTP Request API
4
 *
5
 * Standardizes the HTTP requests for WordPress. Handles cookies, gzip encoding and decoding, chunk
6
 * decoding, if HTTP 1.1 and various other difficult HTTP protocol implementations.
7
 *
8
 * @package WordPress
9
 * @subpackage HTTP
10
 */
11
12
/**
13
 * Returns the initialized WP_Http Object
14
 *
15
 * @since 2.7.0
16
 * @access private
17
 *
18
 * @staticvar WP_Http $http
19
 *
20
 * @return WP_Http HTTP Transport object.
21
 */
22
function _wp_http_get_object() {
23
	static $http = null;
24
25
	if ( is_null( $http ) ) {
26
		$http = new WP_Http();
27
	}
28
	return $http;
29
}
30
31
/**
32
 * Retrieve the raw response from a safe HTTP request.
33
 *
34
 * This function is ideal when the HTTP request is being made to an arbitrary
35
 * URL. The URL is validated to avoid redirection and request forgery attacks.
36
 *
37
 * @since 3.6.0
38
 *
39
 * @see wp_remote_request() For more information on the response array format.
40
 * @see WP_Http::request() For default arguments information.
41
 *
42
 * @param string $url  Site URL to retrieve.
43
 * @param array  $args Optional. Request arguments. Default empty array.
44
 * @return WP_Error|array The response or WP_Error on failure.
45
 */
46
function wp_safe_remote_request( $url, $args = array() ) {
47
	$args['reject_unsafe_urls'] = true;
48
	$http = _wp_http_get_object();
49
	return $http->request( $url, $args );
50
}
51
52
/**
53
 * Retrieve the raw response from a safe HTTP request using the GET method.
54
 *
55
 * This function is ideal when the HTTP request is being made to an arbitrary
56
 * URL. The URL is validated to avoid redirection and request forgery attacks.
57
 *
58
 * @since 3.6.0
59
 *
60
 * @see wp_remote_request() For more information on the response array format.
61
 * @see WP_Http::request() For default arguments information.
62
 *
63
 * @param string $url  Site URL to retrieve.
64
 * @param array  $args Optional. Request arguments. Default empty array.
65
 * @return WP_Error|array The response or WP_Error on failure.
66
 */
67
function wp_safe_remote_get( $url, $args = array() ) {
68
	$args['reject_unsafe_urls'] = true;
69
	$http = _wp_http_get_object();
70
	return $http->get( $url, $args );
71
}
72
73
/**
74
 * Retrieve the raw response from a safe HTTP request using the POST method.
75
 *
76
 * This function is ideal when the HTTP request is being made to an arbitrary
77
 * URL. The URL is validated to avoid redirection and request forgery attacks.
78
 *
79
 * @since 3.6.0
80
 *
81
 * @see wp_remote_request() For more information on the response array format.
82
 * @see WP_Http::request() For default arguments information.
83
 *
84
 * @param string $url  Site URL to retrieve.
85
 * @param array  $args Optional. Request arguments. Default empty array.
86
 * @return WP_Error|array The response or WP_Error on failure.
87
 */
88
function wp_safe_remote_post( $url, $args = array() ) {
89
	$args['reject_unsafe_urls'] = true;
90
	$http = _wp_http_get_object();
91
	return $http->post( $url, $args );
92
}
93
94
/**
95
 * Retrieve the raw response from a safe HTTP request using the HEAD method.
96
 *
97
 * This function is ideal when the HTTP request is being made to an arbitrary
98
 * URL. The URL is validated to avoid redirection and request forgery attacks.
99
 *
100
 * @since 3.6.0
101
 *
102
 * @see wp_remote_request() For more information on the response array format.
103
 * @see WP_Http::request() For default arguments information.
104
 *
105
 * @param string $url Site URL to retrieve.
106
 * @param array $args Optional. Request arguments. Default empty array.
107
 * @return WP_Error|array The response or WP_Error on failure.
108
 */
109
function wp_safe_remote_head( $url, $args = array() ) {
110
	$args['reject_unsafe_urls'] = true;
111
	$http = _wp_http_get_object();
112
	return $http->head( $url, $args );
113
}
114
115
/**
116
 * Retrieve the raw response from the HTTP request.
117
 *
118
 * The array structure is a little complex:
119
 *
120
 *     $res = array(
121
 *         'headers'  => array(),
122
 *         'response' => array(
123
 *             'code'    => int,
124
 *             'message' => string
125
 *         )
126
 *     );
127
 *
128
 * All of the headers in $res['headers'] are with the name as the key and the
129
 * value as the value. So to get the User-Agent, you would do the following.
130
 *
131
 *     $user_agent = $res['headers']['user-agent'];
132
 *
133
 * The body is the raw response content and can be retrieved from $res['body'].
134
 *
135
 * This function is called first to make the request and there are other API
136
 * functions to abstract out the above convoluted setup.
137
 *
138
 * Request method defaults for helper functions:
139
 *  - Default 'GET'  for wp_remote_get()
140
 *  - Default 'POST' for wp_remote_post()
141
 *  - Default 'HEAD' for wp_remote_head()
142
 *
143
 * @since 2.7.0
144
 *
145
 * @see WP_Http::request() For additional information on default arguments.
146
 *
147
 * @param string $url  Site URL to retrieve.
148
 * @param array  $args Optional. Request arguments. Default empty array.
149
 * @return WP_Error|array The response or WP_Error on failure.
150
 */
151
function wp_remote_request($url, $args = array()) {
152
	$http = _wp_http_get_object();
153
	return $http->request( $url, $args );
154
}
155
156
/**
157
 * Retrieve the raw response from the HTTP request using the GET method.
158
 *
159
 * @since 2.7.0
160
 *
161
 * @see wp_remote_request() For more information on the response array format.
162
 * @see WP_Http::request() For default arguments information.
163
 *
164
 * @param string $url  Site URL to retrieve.
165
 * @param array  $args Optional. Request arguments. Default empty array.
166
 * @return WP_Error|array The response or WP_Error on failure.
167
 */
168
function wp_remote_get($url, $args = array()) {
169
	$http = _wp_http_get_object();
170
	return $http->get( $url, $args );
171
}
172
173
/**
174
 * Retrieve the raw response from the HTTP request using the POST method.
175
 *
176
 * @since 2.7.0
177
 *
178
 * @see wp_remote_request() For more information on the response array format.
179
 * @see WP_Http::request() For default arguments information.
180
 *
181
 * @param string $url  Site URL to retrieve.
182
 * @param array  $args Optional. Request arguments. Default empty array.
183
 * @return WP_Error|array The response or WP_Error on failure.
184
 */
185
function wp_remote_post($url, $args = array()) {
186
	$http = _wp_http_get_object();
187
	return $http->post( $url, $args );
188
}
189
190
/**
191
 * Retrieve the raw response from the HTTP request using the HEAD method.
192
 *
193
 * @since 2.7.0
194
 *
195
 * @see wp_remote_request() For more information on the response array format.
196
 * @see WP_Http::request() For default arguments information.
197
 *
198
 * @param string $url  Site URL to retrieve.
199
 * @param array  $args Optional. Request arguments. Default empty array.
200
 * @return WP_Error|array The response or WP_Error on failure.
201
 */
202
function wp_remote_head($url, $args = array()) {
203
	$http = _wp_http_get_object();
204
	return $http->head( $url, $args );
205
}
206
207
/**
208
 * Retrieve only the headers from the raw response.
209
 *
210
 * @since 2.7.0
211
 * @since 4.6.0 Return value changed from an array to an Requests_Utility_CaseInsensitiveDictionary instance.
212
 *
213
 * @see \Requests_Utility_CaseInsensitiveDictionary
214
 *
215
 * @param array $response HTTP response.
216
 * @return array|\Requests_Utility_CaseInsensitiveDictionary The headers of the response. Empty array if incorrect parameter given.
217
 */
218
function wp_remote_retrieve_headers( $response ) {
219
	if ( is_wp_error( $response ) || ! isset( $response['headers'] ) ) {
220
		return array();
221
	}
222
223
	return $response['headers'];
224
}
225
226
/**
227
 * Retrieve a single header by name from the raw response.
228
 *
229
 * @since 2.7.0
230
 *
231
 * @param array  $response
232
 * @param string $header Header name to retrieve value from.
233
 * @return string The header value. Empty string on if incorrect parameter given, or if the header doesn't exist.
234
 */
235
function wp_remote_retrieve_header( $response, $header ) {
236
	if ( is_wp_error( $response ) || ! isset( $response['headers'] ) ) {
237
		return '';
238
	}
239
240
	if ( isset( $response['headers'][ $header ] ) ) {
241
		return $response['headers'][$header];
242
	}
243
244
	return '';
245
}
246
247
/**
248
 * Retrieve only the response code from the raw response.
249
 *
250
 * Will return an empty array if incorrect parameter value is given.
251
 *
252
 * @since 2.7.0
253
 *
254
 * @param array $response HTTP response.
255
 * @return int|string The response code as an integer. Empty string on incorrect parameter given.
256
 */
257
function wp_remote_retrieve_response_code( $response ) {
258 View Code Duplication
	if ( is_wp_error($response) || ! isset($response['response']) || ! is_array($response['response']))
259
		return '';
260
261
	return $response['response']['code'];
262
}
263
264
/**
265
 * Retrieve only the response message from the raw response.
266
 *
267
 * Will return an empty array if incorrect parameter value is given.
268
 *
269
 * @since 2.7.0
270
 *
271
 * @param array $response HTTP response.
272
 * @return string The response message. Empty string on incorrect parameter given.
273
 */
274
function wp_remote_retrieve_response_message( $response ) {
275 View Code Duplication
	if ( is_wp_error($response) || ! isset($response['response']) || ! is_array($response['response']))
276
		return '';
277
278
	return $response['response']['message'];
279
}
280
281
/**
282
 * Retrieve only the body from the raw response.
283
 *
284
 * @since 2.7.0
285
 *
286
 * @param array $response HTTP response.
287
 * @return string The body of the response. Empty string if no body or incorrect parameter given.
288
 */
289
function wp_remote_retrieve_body( $response ) {
290
	if ( is_wp_error($response) || ! isset($response['body']) )
291
		return '';
292
293
	return $response['body'];
294
}
295
296
/**
297
 * Retrieve only the cookies from the raw response.
298
 *
299
 * @since 4.4.0
300
 *
301
 * @param array $response HTTP response.
302
 * @return array An array of `WP_Http_Cookie` objects from the response. Empty array if there are none, or the response is a WP_Error.
303
 */
304
function wp_remote_retrieve_cookies( $response ) {
305
	if ( is_wp_error( $response ) || empty( $response['cookies'] ) ) {
306
		return array();
307
	}
308
309
	return $response['cookies'];
310
}
311
312
/**
313
 * Retrieve a single cookie by name from the raw response.
314
 *
315
 * @since 4.4.0
316
 *
317
 * @param array  $response HTTP response.
318
 * @param string $name     The name of the cookie to retrieve.
319
 * @return WP_Http_Cookie|string The `WP_Http_Cookie` object. Empty string if the cookie isn't present in the response.
320
 */
321
function wp_remote_retrieve_cookie( $response, $name ) {
322
	$cookies = wp_remote_retrieve_cookies( $response );
323
324
	if ( empty( $cookies ) ) {
325
		return '';
326
	}
327
328
	foreach ( $cookies as $cookie ) {
329
		if ( $cookie->name === $name ) {
330
			return $cookie;
331
		}
332
	}
333
334
	return '';
335
}
336
337
/**
338
 * Retrieve a single cookie's value by name from the raw response.
339
 *
340
 * @since 4.4.0
341
 *
342
 * @param array  $response HTTP response.
343
 * @param string $name     The name of the cookie to retrieve.
344
 * @return string The value of the cookie. Empty string if the cookie isn't present in the response.
345
 */
346
function wp_remote_retrieve_cookie_value( $response, $name ) {
347
	$cookie = wp_remote_retrieve_cookie( $response, $name );
348
349
	if ( ! is_a( $cookie, 'WP_Http_Cookie' ) ) {
350
		return '';
351
	}
352
353
	return $cookie->value;
354
}
355
356
/**
357
 * Determines if there is an HTTP Transport that can process this request.
358
 *
359
 * @since 3.2.0
360
 *
361
 * @param array  $capabilities Array of capabilities to test or a wp_remote_request() $args array.
362
 * @param string $url          Optional. If given, will check if the URL requires SSL and adds
363
 *                             that requirement to the capabilities array.
364
 *
365
 * @return bool
366
 */
367
function wp_http_supports( $capabilities = array(), $url = null ) {
368
	$http = _wp_http_get_object();
369
370
	$capabilities = wp_parse_args( $capabilities );
371
372
	$count = count( $capabilities );
373
374
	// If we have a numeric $capabilities array, spoof a wp_remote_request() associative $args array
375
	if ( $count && count( array_filter( array_keys( $capabilities ), 'is_numeric' ) ) == $count ) {
376
		$capabilities = array_combine( array_values( $capabilities ), array_fill( 0, $count, true ) );
377
	}
378
379
	if ( $url && !isset( $capabilities['ssl'] ) ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $url of type string|null is loosely compared to true; 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...
380
		$scheme = parse_url( $url, PHP_URL_SCHEME );
381
		if ( 'https' == $scheme || 'ssl' == $scheme ) {
382
			$capabilities['ssl'] = true;
383
		}
384
	}
385
386
	return (bool) $http->_get_first_available_transport( $capabilities );
387
}
388
389
/**
390
 * Get the HTTP Origin of the current request.
391
 *
392
 * @since 3.4.0
393
 *
394
 * @return string URL of the origin. Empty string if no origin.
395
 */
396
function get_http_origin() {
397
	$origin = '';
398
	if ( ! empty ( $_SERVER[ 'HTTP_ORIGIN' ] ) )
399
		$origin = $_SERVER[ 'HTTP_ORIGIN' ];
400
401
	/**
402
	 * Change the origin of an HTTP request.
403
	 *
404
	 * @since 3.4.0
405
	 *
406
	 * @param string $origin The original origin for the request.
407
	 */
408
	return apply_filters( 'http_origin', $origin );
409
}
410
411
/**
412
 * Retrieve list of allowed HTTP origins.
413
 *
414
 * @since 3.4.0
415
 *
416
 * @return array Array of origin URLs.
417
 */
418
function get_allowed_http_origins() {
419
	$admin_origin = parse_url( admin_url() );
420
	$home_origin = parse_url( home_url() );
421
422
	// @todo preserve port?
423
	$allowed_origins = array_unique( array(
424
		'http://' . $admin_origin[ 'host' ],
425
		'https://' . $admin_origin[ 'host' ],
426
		'http://' . $home_origin[ 'host' ],
427
		'https://' . $home_origin[ 'host' ],
428
	) );
429
430
	/**
431
	 * Change the origin types allowed for HTTP requests.
432
	 *
433
	 * @since 3.4.0
434
	 *
435
	 * @param array $allowed_origins {
436
	 *     Default allowed HTTP origins.
437
	 *     @type string Non-secure URL for admin origin.
438
	 *     @type string Secure URL for admin origin.
439
	 *     @type string Non-secure URL for home origin.
440
	 *     @type string Secure URL for home origin.
441
	 * }
442
	 */
443
	return apply_filters( 'allowed_http_origins' , $allowed_origins );
444
}
445
446
/**
447
 * Determines if the HTTP origin is an authorized one.
448
 *
449
 * @since 3.4.0
450
 *
451
 * @param null|string $origin Origin URL. If not provided, the value of get_http_origin() is used.
452
 * @return string Origin URL if allowed, empty string if not.
453
 */
454
function is_allowed_http_origin( $origin = null ) {
455
	$origin_arg = $origin;
456
457
	if ( null === $origin )
458
		$origin = get_http_origin();
459
460
	if ( $origin && ! in_array( $origin, get_allowed_http_origins() ) )
461
		$origin = '';
462
463
	/**
464
	 * Change the allowed HTTP origin result.
465
	 *
466
	 * @since 3.4.0
467
	 *
468
	 * @param string $origin     Origin URL if allowed, empty string if not.
469
	 * @param string $origin_arg Original origin string passed into is_allowed_http_origin function.
470
	 */
471
	return apply_filters( 'allowed_http_origin', $origin, $origin_arg );
472
}
473
474
/**
475
 * Send Access-Control-Allow-Origin and related headers if the current request
476
 * is from an allowed origin.
477
 *
478
 * If the request is an OPTIONS request, the script exits with either access
479
 * control headers sent, or a 403 response if the origin is not allowed. For
480
 * other request methods, you will receive a return value.
481
 *
482
 * @since 3.4.0
483
 *
484
 * @return string|false Returns the origin URL if headers are sent. Returns false
0 ignored issues
show
Should the return type not be null|string|false?

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...
485
 *                      if headers are not sent.
486
 */
487
function send_origin_headers() {
488
	$origin = get_http_origin();
489
490
	if ( is_allowed_http_origin( $origin ) ) {
491
		@header( 'Access-Control-Allow-Origin: ' .  $origin );
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
492
		@header( 'Access-Control-Allow-Credentials: true' );
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
493
		if ( 'OPTIONS' === $_SERVER['REQUEST_METHOD'] )
494
			exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The function send_origin_headers() 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...
495
		return $origin;
496
	}
497
498
	if ( 'OPTIONS' === $_SERVER['REQUEST_METHOD'] ) {
499
		status_header( 403 );
500
		exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The function send_origin_headers() 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...
501
	}
502
503
	return false;
504
}
505
506
/**
507
 * Validate a URL for safe use in the HTTP API.
508
 *
509
 * @since 3.5.2
510
 *
511
 * @param string $url
512
 * @return false|string URL or false on failure.
513
 */
514
function wp_http_validate_url( $url ) {
515
	$original_url = $url;
516
	$url = wp_kses_bad_protocol( $url, array( 'http', 'https' ) );
517
	if ( ! $url || strtolower( $url ) !== strtolower( $original_url ) )
518
		return false;
519
520
	$parsed_url = @parse_url( $url );
521
	if ( ! $parsed_url || empty( $parsed_url['host'] ) )
522
		return false;
523
524
	if ( isset( $parsed_url['user'] ) || isset( $parsed_url['pass'] ) )
525
		return false;
526
527
	if ( false !== strpbrk( $parsed_url['host'], ':#?[]' ) )
528
		return false;
529
530
	$parsed_home = @parse_url( get_option( 'home' ) );
531
532
	if ( isset( $parsed_home['host'] ) ) {
533
		$same_host = ( strtolower( $parsed_home['host'] ) === strtolower( $parsed_url['host'] ) || 'localhost' === strtolower( $parsed_url['host'] ) );
534
	} else {
535
		$same_host = false;
536
	}
537
538
	if ( ! $same_host ) {
539
		$host = trim( $parsed_url['host'], '.' );
540
		if ( preg_match( '#^(([1-9]?\d|1\d\d|25[0-5]|2[0-4]\d)\.){3}([1-9]?\d|1\d\d|25[0-5]|2[0-4]\d)$#', $host ) ) {
541
			$ip = $host;
542
		} else {
543
			$ip = gethostbyname( $host );
544
			if ( $ip === $host ) // Error condition for gethostbyname()
545
				$ip = false;
546
		}
547
		if ( $ip ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $ip of type false|string 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...
548
			$parts = array_map( 'intval', explode( '.', $ip ) );
549
			if ( 127 === $parts[0] || 10 === $parts[0] || 0 === $parts[0]
550
				|| ( 172 === $parts[0] && 16 <= $parts[1] && 31 >= $parts[1] )
551
				|| ( 192 === $parts[0] && 168 === $parts[1] )
552
			) {
553
				// If host appears local, reject unless specifically allowed.
554
				/**
555
				 * Check if HTTP request is external or not.
556
				 *
557
				 * Allows to change and allow external requests for the HTTP request.
558
				 *
559
				 * @since 3.6.0
560
				 *
561
				 * @param bool   false Whether HTTP request is external or not.
562
				 * @param string $host IP of the requested host.
563
				 * @param string $url  URL of the requested host.
564
				 */
565
				if ( ! apply_filters( 'http_request_host_is_external', false, $host, $url ) )
566
					return false;
567
			}
568
		}
569
	}
570
571
	if ( empty( $parsed_url['port'] ) )
572
		return $url;
573
574
	$port = $parsed_url['port'];
575
	if ( 80 === $port || 443 === $port || 8080 === $port )
576
		return $url;
577
578
	if ( $parsed_home && $same_host && isset( $parsed_home['port'] ) && $parsed_home['port'] === $port )
579
		return $url;
580
581
	return false;
582
}
583
584
/**
585
 * Whitelists allowed redirect hosts for safe HTTP requests as well.
586
 *
587
 * Attached to the {@see 'http_request_host_is_external'} filter.
588
 *
589
 * @since 3.6.0
590
 *
591
 * @param bool   $is_external
592
 * @param string $host
593
 * @return bool
594
 */
595
function allowed_http_request_hosts( $is_external, $host ) {
596
	if ( ! $is_external && wp_validate_redirect( 'http://' . $host ) )
597
		$is_external = true;
598
	return $is_external;
599
}
600
601
/**
602
 * Whitelists any domain in a multisite installation for safe HTTP requests.
603
 *
604
 * Attached to the {@see 'http_request_host_is_external'} filter.
605
 *
606
 * @since 3.6.0
607
 *
608
 * @global wpdb $wpdb WordPress database abstraction object.
609
 * @staticvar array $queried
610
 *
611
 * @param bool   $is_external
612
 * @param string $host
613
 * @return bool
614
 */
615
function ms_allowed_http_request_hosts( $is_external, $host ) {
616
	global $wpdb;
617
	static $queried = array();
618
	if ( $is_external )
619
		return $is_external;
620
	if ( $host === get_network()->domain )
621
		return true;
622
	if ( isset( $queried[ $host ] ) )
623
		return $queried[ $host ];
624
	$queried[ $host ] = (bool) $wpdb->get_var( $wpdb->prepare( "SELECT domain FROM $wpdb->blogs WHERE domain = %s LIMIT 1", $host ) );
625
	return $queried[ $host ];
626
}
627
628
/**
629
 * A wrapper for PHP's parse_url() function that handles consistency in the return
630
 * values across PHP versions.
631
 *
632
 * PHP 5.4.7 expanded parse_url()'s ability to handle non-absolute url's, including
633
 * schemeless and relative url's with :// in the path. This function works around
634
 * those limitations providing a standard output on PHP 5.2~5.4+.
635
 *
636
 * Secondly, across various PHP versions, schemeless URLs starting containing a ":"
637
 * in the query are being handled inconsistently. This function works around those
638
 * differences as well.
639
 *
640
 * Error suppression is used as prior to PHP 5.3.3, an E_WARNING would be generated
641
 * when URL parsing failed.
642
 *
643
 * @since 4.4.0
644
 * @since 4.7.0 The $component parameter was added for parity with PHP's parse_url().
645
 *
646
 * @param string $url       The URL to parse.
647
 * @param int    $component The specific component to retrieve. Use one of the PHP
648
 *                          predefined constants to specify which one.
649
 *                          Defaults to -1 (= return all parts as an array).
650
 *                          @see http://php.net/manual/en/function.parse-url.php
651
 * @return mixed False on parse failure; Array of URL components on success;
652
 *               When a specific component has been requested: null if the component
653
 *               doesn't exist in the given URL; a string or - in the case of
654
 *               PHP_URL_PORT - integer when it does. See parse_url()'s return values.
655
 */
656
function wp_parse_url( $url, $component = -1 ) {
657
	$to_unset = array();
658
	$url = strval( $url );
659
660
	if ( '//' === substr( $url, 0, 2 ) ) {
661
		$to_unset[] = 'scheme';
662
		$url = 'placeholder:' . $url;
663
	} elseif ( '/' === substr( $url, 0, 1 ) ) {
664
		$to_unset[] = 'scheme';
665
		$to_unset[] = 'host';
666
		$url = 'placeholder://placeholder' . $url;
667
	}
668
669
	$parts = @parse_url( $url );
670
671
	if ( false === $parts ) {
672
		// Parsing failure.
673
		return $parts;
674
	}
675
676
	// Remove the placeholder values.
677
	foreach ( $to_unset as $key ) {
678
		unset( $parts[ $key ] );
679
	}
680
681
	return _get_component_from_parsed_url_array( $parts, $component );
682
}
683
684
/**
685
 * Retrieve a specific component from a parsed URL array.
686
 *
687
 * @internal
688
 *
689
 * @since 4.7.0
690
 *
691
 * @param array|false $url_parts The parsed URL. Can be false if the URL failed to parse.
692
 * @param int    $component The specific component to retrieve. Use one of the PHP
693
 *                          predefined constants to specify which one.
694
 *                          Defaults to -1 (= return all parts as an array).
695
 *                          @see http://php.net/manual/en/function.parse-url.php
696
 * @return mixed False on parse failure; Array of URL components on success;
697
 *               When a specific component has been requested: null if the component
698
 *               doesn't exist in the given URL; a string or - in the case of
699
 *               PHP_URL_PORT - integer when it does. See parse_url()'s return values.
700
 */
701
function _get_component_from_parsed_url_array( $url_parts, $component = -1 ) {
702
	if ( -1 === $component ) {
703
		return $url_parts;
704
	}
705
706
	$key = _wp_translate_php_url_constant_to_key( $component );
707
	if ( false !== $key && is_array( $url_parts ) && isset( $url_parts[ $key ] ) ) {
708
		return $url_parts[ $key ];
709
	} else {
710
		return null;
711
	}
712
}
713
714
/**
715
 * Translate a PHP_URL_* constant to the named array keys PHP uses.
716
 *
717
 * @internal
718
 *
719
 * @since 4.7.0
720
 *
721
 * @see   http://php.net/manual/en/url.constants.php
722
 *
723
 * @param int $constant PHP_URL_* constant.
724
 * @return string|bool The named key or false.
0 ignored issues
show
Consider making the return type a bit more specific; maybe use string|false.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
725
 */
726
function _wp_translate_php_url_constant_to_key( $constant ) {
727
	$translation = array(
728
		PHP_URL_SCHEME   => 'scheme',
729
		PHP_URL_HOST     => 'host',
730
		PHP_URL_PORT     => 'port',
731
		PHP_URL_USER     => 'user',
732
		PHP_URL_PASS     => 'pass',
733
		PHP_URL_PATH     => 'path',
734
		PHP_URL_QUERY    => 'query',
735
		PHP_URL_FRAGMENT => 'fragment',
736
	);
737
738
	if ( isset( $translation[ $constant ] ) ) {
739
		return $translation[ $constant ];
740
	} else {
741
		return false;
742
	}
743
}
744