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/pluggable.php (6 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
 * These functions can be replaced via plugins. If plugins do not redefine these
4
 * functions, then these will be used instead.
5
 *
6
 * @package WordPress
7
 */
8
9
if ( !function_exists('wp_set_current_user') ) :
10
/**
11
 * Changes the current user by ID or name.
12
 *
13
 * Set $id to null and specify a name if you do not know a user's ID.
14
 *
15
 * Some WordPress functionality is based on the current user and not based on
16
 * the signed in user. Therefore, it opens the ability to edit and perform
17
 * actions on users who aren't signed in.
18
 *
19
 * @since 2.0.3
20
 * @global WP_User $current_user The current user object which holds the user data.
21
 *
22
 * @param int    $id   User ID
23
 * @param string $name User's username
24
 * @return WP_User Current user User object
25
 */
26
function wp_set_current_user($id, $name = '') {
27
	global $current_user;
28
29
	// If `$id` matches the user who's already current, there's nothing to do.
30
	if ( isset( $current_user )
31
		&& ( $current_user instanceof WP_User )
32
		&& ( $id == $current_user->ID )
33
		&& ( null !== $id )
34
	) {
35
		return $current_user;
36
	}
37
38
	$current_user = new WP_User( $id, $name );
39
40
	setup_userdata( $current_user->ID );
41
42
	/**
43
	 * Fires after the current user is set.
44
	 *
45
	 * @since 2.0.1
46
	 */
47
	do_action( 'set_current_user' );
48
49
	return $current_user;
50
}
51
endif;
52
53
if ( !function_exists('wp_get_current_user') ) :
54
/**
55
 * Retrieve the current user object.
56
 *
57
 * Will set the current user, if the current user is not set. The current user
58
 * will be set to the logged-in person. If no user is logged-in, then it will
59
 * set the current user to 0, which is invalid and won't have any permissions.
60
 *
61
 * @since 2.0.3
62
 *
63
 * @see _wp_get_current_user()
64
 * @global WP_User $current_user Checks if the current user is set.
65
 *
66
 * @return WP_User Current WP_User instance.
67
 */
68
function wp_get_current_user() {
69
	return _wp_get_current_user();
70
}
71
endif;
72
73
if ( !function_exists('get_userdata') ) :
74
/**
75
 * Retrieve user info by user ID.
76
 *
77
 * @since 0.71
78
 *
79
 * @param int $user_id User ID
80
 * @return WP_User|false WP_User object on success, false on failure.
81
 */
82
function get_userdata( $user_id ) {
83
	return get_user_by( 'id', $user_id );
84
}
85
endif;
86
87
if ( !function_exists('get_user_by') ) :
88
/**
89
 * Retrieve user info by a given field
90
 *
91
 * @since 2.8.0
92
 * @since 4.4.0 Added 'ID' as an alias of 'id' for the `$field` parameter.
93
 *
94
 * @param string     $field The field to retrieve the user with. id | ID | slug | email | login.
95
 * @param int|string $value A value for $field. A user ID, slug, email address, or login name.
96
 * @return WP_User|false WP_User object on success, false on failure.
97
 */
98
function get_user_by( $field, $value ) {
99
	$userdata = WP_User::get_data_by( $field, $value );
100
101
	if ( !$userdata )
102
		return false;
103
104
	$user = new WP_User;
105
	$user->init( $userdata );
106
107
	return $user;
108
}
109
endif;
110
111
if ( !function_exists('cache_users') ) :
112
/**
113
 * Retrieve info for user lists to prevent multiple queries by get_userdata()
114
 *
115
 * @since 3.0.0
116
 *
117
 * @global wpdb $wpdb WordPress database abstraction object.
118
 *
119
 * @param array $user_ids User ID numbers list
120
 */
121
function cache_users( $user_ids ) {
122
	global $wpdb;
123
124
	$clean = _get_non_cached_ids( $user_ids, 'users' );
125
126
	if ( empty( $clean ) )
127
		return;
128
129
	$list = implode( ',', $clean );
130
131
	$users = $wpdb->get_results( "SELECT * FROM $wpdb->users WHERE ID IN ($list)" );
132
133
	$ids = array();
134
	foreach ( $users as $user ) {
135
		update_user_caches( $user );
136
		$ids[] = $user->ID;
137
	}
138
	update_meta_cache( 'user', $ids );
139
}
140
endif;
141
142
if ( !function_exists( 'wp_mail' ) ) :
143
/**
144
 * Send mail, similar to PHP's mail
145
 *
146
 * A true return value does not automatically mean that the user received the
147
 * email successfully. It just only means that the method used was able to
148
 * process the request without any errors.
149
 *
150
 * Using the two 'wp_mail_from' and 'wp_mail_from_name' hooks allow from
151
 * creating a from address like 'Name <[email protected]>' when both are set. If
152
 * just 'wp_mail_from' is set, then just the email address will be used with no
153
 * name.
154
 *
155
 * The default content type is 'text/plain' which does not allow using HTML.
156
 * However, you can set the content type of the email by using the
157
 * {@see 'wp_mail_content_type'} filter.
158
 *
159
 * The default charset is based on the charset used on the blog. The charset can
160
 * be set using the {@see 'wp_mail_charset'} filter.
161
 *
162
 * @since 1.2.1
163
 *
164
 * @global PHPMailer $phpmailer
165
 *
166
 * @param string|array $to          Array or comma-separated list of email addresses to send message.
167
 * @param string       $subject     Email subject
168
 * @param string       $message     Message contents
169
 * @param string|array $headers     Optional. Additional headers.
170
 * @param string|array $attachments Optional. Files to attach.
171
 * @return bool Whether the email contents were sent successfully.
172
 */
173
function wp_mail( $to, $subject, $message, $headers = '', $attachments = array() ) {
174
	// Compact the input, apply the filters, and extract them back out
175
176
	/**
177
	 * Filters the wp_mail() arguments.
178
	 *
179
	 * @since 2.2.0
180
	 *
181
	 * @param array $args A compacted array of wp_mail() arguments, including the "to" email,
182
	 *                    subject, message, headers, and attachments values.
183
	 */
184
	$atts = apply_filters( 'wp_mail', compact( 'to', 'subject', 'message', 'headers', 'attachments' ) );
185
186
	if ( isset( $atts['to'] ) ) {
187
		$to = $atts['to'];
188
	}
189
190
	if ( isset( $atts['subject'] ) ) {
191
		$subject = $atts['subject'];
192
	}
193
194
	if ( isset( $atts['message'] ) ) {
195
		$message = $atts['message'];
196
	}
197
198
	if ( isset( $atts['headers'] ) ) {
199
		$headers = $atts['headers'];
200
	}
201
202
	if ( isset( $atts['attachments'] ) ) {
203
		$attachments = $atts['attachments'];
204
	}
205
206
	if ( ! is_array( $attachments ) ) {
207
		$attachments = explode( "\n", str_replace( "\r\n", "\n", $attachments ) );
208
	}
209
	global $phpmailer;
210
211
	// (Re)create it, if it's gone missing
212
	if ( ! ( $phpmailer instanceof PHPMailer ) ) {
213
		require_once ABSPATH . WPINC . '/class-phpmailer.php';
214
		require_once ABSPATH . WPINC . '/class-smtp.php';
215
		$phpmailer = new PHPMailer( true );
216
	}
217
218
	// Headers
219
	$cc = $bcc = $reply_to = array();
220
221
	if ( empty( $headers ) ) {
222
		$headers = array();
223
	} else {
224
		if ( !is_array( $headers ) ) {
225
			// Explode the headers out, so this function can take both
226
			// string headers and an array of headers.
227
			$tempheaders = explode( "\n", str_replace( "\r\n", "\n", $headers ) );
228
		} else {
229
			$tempheaders = $headers;
230
		}
231
		$headers = array();
232
233
		// If it's actually got contents
234
		if ( !empty( $tempheaders ) ) {
235
			// Iterate through the raw headers
236
			foreach ( (array) $tempheaders as $header ) {
237
				if ( strpos($header, ':') === false ) {
238
					if ( false !== stripos( $header, 'boundary=' ) ) {
239
						$parts = preg_split('/boundary=/i', trim( $header ) );
240
						$boundary = trim( str_replace( array( "'", '"' ), '', $parts[1] ) );
241
					}
242
					continue;
243
				}
244
				// Explode them out
245
				list( $name, $content ) = explode( ':', trim( $header ), 2 );
246
247
				// Cleanup crew
248
				$name    = trim( $name    );
249
				$content = trim( $content );
250
251
				switch ( strtolower( $name ) ) {
252
					// Mainly for legacy -- process a From: header if it's there
253
					case 'from':
254
						$bracket_pos = strpos( $content, '<' );
255
						if ( $bracket_pos !== false ) {
256
							// Text before the bracketed email is the "From" name.
257
							if ( $bracket_pos > 0 ) {
258
								$from_name = substr( $content, 0, $bracket_pos - 1 );
259
								$from_name = str_replace( '"', '', $from_name );
260
								$from_name = trim( $from_name );
261
							}
262
263
							$from_email = substr( $content, $bracket_pos + 1 );
264
							$from_email = str_replace( '>', '', $from_email );
265
							$from_email = trim( $from_email );
266
267
						// Avoid setting an empty $from_email.
268
						} elseif ( '' !== trim( $content ) ) {
269
							$from_email = trim( $content );
270
						}
271
						break;
272
					case 'content-type':
273
						if ( strpos( $content, ';' ) !== false ) {
274
							list( $type, $charset_content ) = explode( ';', $content );
275
							$content_type = trim( $type );
276
							if ( false !== stripos( $charset_content, 'charset=' ) ) {
277
								$charset = trim( str_replace( array( 'charset=', '"' ), '', $charset_content ) );
278
							} elseif ( false !== stripos( $charset_content, 'boundary=' ) ) {
279
								$boundary = trim( str_replace( array( 'BOUNDARY=', 'boundary=', '"' ), '', $charset_content ) );
280
								$charset = '';
281
							}
282
283
						// Avoid setting an empty $content_type.
284
						} elseif ( '' !== trim( $content ) ) {
285
							$content_type = trim( $content );
286
						}
287
						break;
288
					case 'cc':
289
						$cc = array_merge( (array) $cc, explode( ',', $content ) );
290
						break;
291
					case 'bcc':
292
						$bcc = array_merge( (array) $bcc, explode( ',', $content ) );
293
						break;
294
					case 'reply-to':
295
						$reply_to = array_merge( (array) $reply_to, explode( ',', $content ) );
296
						break;
297
					default:
298
						// Add it to our grand headers array
299
						$headers[trim( $name )] = trim( $content );
300
						break;
301
				}
302
			}
303
		}
304
	}
305
306
	// Empty out the values that may be set
307
	$phpmailer->ClearAllRecipients();
308
	$phpmailer->ClearAttachments();
309
	$phpmailer->ClearCustomHeaders();
310
	$phpmailer->ClearReplyTos();
311
312
	// From email and name
313
	// If we don't have a name from the input headers
314
	if ( !isset( $from_name ) )
315
		$from_name = 'WordPress';
316
317
	/* If we don't have an email from the input headers default to wordpress@$sitename
318
	 * Some hosts will block outgoing mail from this address if it doesn't exist but
319
	 * there's no easy alternative. Defaulting to admin_email might appear to be another
320
	 * option but some hosts may refuse to relay mail from an unknown domain. See
321
	 * https://core.trac.wordpress.org/ticket/5007.
322
	 */
323
324
	if ( !isset( $from_email ) ) {
325
		// Get the site domain and get rid of www.
326
		$sitename = strtolower( $_SERVER['SERVER_NAME'] );
327
		if ( substr( $sitename, 0, 4 ) == 'www.' ) {
328
			$sitename = substr( $sitename, 4 );
329
		}
330
331
		$from_email = 'wordpress@' . $sitename;
332
	}
333
334
	/**
335
	 * Filters the email address to send from.
336
	 *
337
	 * @since 2.2.0
338
	 *
339
	 * @param string $from_email Email address to send from.
340
	 */
341
	$from_email = apply_filters( 'wp_mail_from', $from_email );
342
343
	/**
344
	 * Filters the name to associate with the "from" email address.
345
	 *
346
	 * @since 2.3.0
347
	 *
348
	 * @param string $from_name Name associated with the "from" email address.
349
	 */
350
	$from_name = apply_filters( 'wp_mail_from_name', $from_name );
351
352
	$phpmailer->setFrom( $from_email, $from_name, false );
353
354
	// Set destination addresses
355
	if ( !is_array( $to ) )
356
		$to = explode( ',', $to );
357
358
	// Set mail's subject and body
359
	$phpmailer->Subject = $subject;
360
	$phpmailer->Body    = $message;
361
362
	// Use appropriate methods for handling addresses, rather than treating them as generic headers
363
	$address_headers = compact( 'to', 'cc', 'bcc', 'reply_to' );
364
365
	foreach ( $address_headers as $address_header => $addresses ) {
366
		if ( empty( $addresses ) ) {
367
			continue;
368
		}
369
370
		foreach ( (array) $addresses as $address ) {
371
			try {
372
				// Break $recipient into name and address parts if in the format "Foo <[email protected]>"
373
				$recipient_name = '';
374
375
				if ( preg_match( '/(.*)<(.+)>/', $address, $matches ) ) {
376
					if ( count( $matches ) == 3 ) {
377
						$recipient_name = $matches[1];
378
						$address        = $matches[2];
379
					}
380
				}
381
382
				switch ( $address_header ) {
383
					case 'to':
384
						$phpmailer->addAddress( $address, $recipient_name );
385
						break;
386
					case 'cc':
387
						$phpmailer->addCc( $address, $recipient_name );
388
						break;
389
					case 'bcc':
390
						$phpmailer->addBcc( $address, $recipient_name );
391
						break;
392
					case 'reply_to':
393
						$phpmailer->addReplyTo( $address, $recipient_name );
394
						break;
395
				}
396
			} catch ( phpmailerException $e ) {
397
				continue;
398
			}
399
		}
400
	}
401
402
	// Set to use PHP's mail()
403
	$phpmailer->IsMail();
404
405
	// Set Content-Type and charset
406
	// If we don't have a content-type from the input headers
407
	if ( !isset( $content_type ) )
408
		$content_type = 'text/plain';
409
410
	/**
411
	 * Filters the wp_mail() content type.
412
	 *
413
	 * @since 2.3.0
414
	 *
415
	 * @param string $content_type Default wp_mail() content type.
416
	 */
417
	$content_type = apply_filters( 'wp_mail_content_type', $content_type );
418
419
	$phpmailer->ContentType = $content_type;
420
421
	// Set whether it's plaintext, depending on $content_type
422
	if ( 'text/html' == $content_type )
423
		$phpmailer->IsHTML( true );
424
425
	// If we don't have a charset from the input headers
426
	if ( !isset( $charset ) )
427
		$charset = get_bloginfo( 'charset' );
428
429
	// Set the content-type and charset
430
431
	/**
432
	 * Filters the default wp_mail() charset.
433
	 *
434
	 * @since 2.3.0
435
	 *
436
	 * @param string $charset Default email charset.
437
	 */
438
	$phpmailer->CharSet = apply_filters( 'wp_mail_charset', $charset );
439
440
	// Set custom headers
441
	if ( !empty( $headers ) ) {
442
		foreach ( (array) $headers as $name => $content ) {
443
			$phpmailer->AddCustomHeader( sprintf( '%1$s: %2$s', $name, $content ) );
444
		}
445
446
		if ( false !== stripos( $content_type, 'multipart' ) && ! empty($boundary) )
447
			$phpmailer->AddCustomHeader( sprintf( "Content-Type: %s;\n\t boundary=\"%s\"", $content_type, $boundary ) );
448
	}
449
450
	if ( !empty( $attachments ) ) {
451
		foreach ( $attachments as $attachment ) {
452
			try {
453
				$phpmailer->AddAttachment($attachment);
454
			} catch ( phpmailerException $e ) {
455
				continue;
456
			}
457
		}
458
	}
459
460
	/**
461
	 * Fires after PHPMailer is initialized.
462
	 *
463
	 * @since 2.2.0
464
	 *
465
	 * @param PHPMailer &$phpmailer The PHPMailer instance, passed by reference.
466
	 */
467
	do_action_ref_array( 'phpmailer_init', array( &$phpmailer ) );
468
469
	// Send!
470
	try {
471
		return $phpmailer->Send();
472
	} catch ( phpmailerException $e ) {
473
474
		$mail_error_data = compact( 'to', 'subject', 'message', 'headers', 'attachments' );
475
476
		/**
477
		 * Fires after a phpmailerException is caught.
478
		 *
479
		 * @since 4.4.0
480
		 *
481
		 * @param WP_Error $error A WP_Error object with the phpmailerException code, message, and an array
482
		 *                        containing the mail recipient, subject, message, headers, and attachments.
483
		 */
484
 		do_action( 'wp_mail_failed', new WP_Error( $e->getCode(), $e->getMessage(), $mail_error_data ) );
485
486
		return false;
487
	}
488
}
489
endif;
490
491
if ( !function_exists('wp_authenticate') ) :
492
/**
493
 * Authenticate a user, confirming the login credentials are valid.
494
 *
495
 * @since 2.5.0
496
 * @since 4.5.0 `$username` now accepts an email address.
497
 *
498
 * @param string $username User's username or email address.
499
 * @param string $password User's password.
500
 * @return WP_User|WP_Error WP_User object if the credentials are valid,
501
 *                          otherwise WP_Error.
502
 */
503
function wp_authenticate($username, $password) {
504
	$username = sanitize_user($username);
505
	$password = trim($password);
506
507
	/**
508
	 * Filters whether a set of user login credentials are valid.
509
	 *
510
	 * A WP_User object is returned if the credentials authenticate a user.
511
	 * WP_Error or null otherwise.
512
	 *
513
	 * @since 2.8.0
514
	 * @since 4.5.0 `$username` now accepts an email address.
515
	 *
516
	 * @param null|WP_User|WP_Error $user     WP_User if the user is authenticated.
517
	 *                                        WP_Error or null otherwise.
518
	 * @param string                $username Username or email address.
519
	 * @param string                $password User password
520
	 */
521
	$user = apply_filters( 'authenticate', null, $username, $password );
522
523
	if ( $user == null ) {
524
		// TODO what should the error message be? (Or would these even happen?)
525
		// Only needed if all authentication handlers fail to return anything.
526
		$user = new WP_Error( 'authentication_failed', __( '<strong>ERROR</strong>: Invalid username, email address or incorrect password.' ) );
527
	}
528
529
	$ignore_codes = array('empty_username', 'empty_password');
530
531
	if (is_wp_error($user) && !in_array($user->get_error_code(), $ignore_codes) ) {
532
		/**
533
		 * Fires after a user login has failed.
534
		 *
535
		 * @since 2.5.0
536
		 * @since 4.5.0 The value of `$username` can now be an email address.
537
		 *
538
		 * @param string $username Username or email address.
539
		 */
540
		do_action( 'wp_login_failed', $username );
541
	}
542
543
	return $user;
544
}
545
endif;
546
547
if ( !function_exists('wp_logout') ) :
548
/**
549
 * Log the current user out.
550
 *
551
 * @since 2.5.0
552
 */
553
function wp_logout() {
554
	wp_destroy_current_session();
555
	wp_clear_auth_cookie();
556
557
	/**
558
	 * Fires after a user is logged-out.
559
	 *
560
	 * @since 1.5.0
561
	 */
562
	do_action( 'wp_logout' );
563
}
564
endif;
565
566
if ( !function_exists('wp_validate_auth_cookie') ) :
567
/**
568
 * Validates authentication cookie.
569
 *
570
 * The checks include making sure that the authentication cookie is set and
571
 * pulling in the contents (if $cookie is not used).
572
 *
573
 * Makes sure the cookie is not expired. Verifies the hash in cookie is what is
574
 * should be and compares the two.
575
 *
576
 * @since 2.5.0
577
 *
578
 * @global int $login_grace_period
579
 *
580
 * @param string $cookie Optional. If used, will validate contents instead of cookie's
581
 * @param string $scheme Optional. The cookie scheme to use: auth, secure_auth, or logged_in
582
 * @return false|int False if invalid cookie, User ID if valid.
583
 */
584
function wp_validate_auth_cookie($cookie = '', $scheme = '') {
585
	if ( ! $cookie_elements = wp_parse_auth_cookie($cookie, $scheme) ) {
586
		/**
587
		 * Fires if an authentication cookie is malformed.
588
		 *
589
		 * @since 2.7.0
590
		 *
591
		 * @param string $cookie Malformed auth cookie.
592
		 * @param string $scheme Authentication scheme. Values include 'auth', 'secure_auth',
593
		 *                       or 'logged_in'.
594
		 */
595
		do_action( 'auth_cookie_malformed', $cookie, $scheme );
596
		return false;
597
	}
598
599
	$scheme = $cookie_elements['scheme'];
600
	$username = $cookie_elements['username'];
601
	$hmac = $cookie_elements['hmac'];
602
	$token = $cookie_elements['token'];
603
	$expired = $expiration = $cookie_elements['expiration'];
604
605
	// Allow a grace period for POST and Ajax requests
606
	if ( defined('DOING_AJAX') || 'POST' == $_SERVER['REQUEST_METHOD'] ) {
607
		$expired += HOUR_IN_SECONDS;
608
	}
609
610
	// Quick check to see if an honest cookie has expired
611
	if ( $expired < time() ) {
612
		/**
613
		 * Fires once an authentication cookie has expired.
614
		 *
615
		 * @since 2.7.0
616
		 *
617
		 * @param array $cookie_elements An array of data for the authentication cookie.
618
		 */
619
		do_action( 'auth_cookie_expired', $cookie_elements );
620
		return false;
621
	}
622
623
	$user = get_user_by('login', $username);
624
	if ( ! $user ) {
625
		/**
626
		 * Fires if a bad username is entered in the user authentication process.
627
		 *
628
		 * @since 2.7.0
629
		 *
630
		 * @param array $cookie_elements An array of data for the authentication cookie.
631
		 */
632
		do_action( 'auth_cookie_bad_username', $cookie_elements );
633
		return false;
634
	}
635
636
	$pass_frag = substr($user->user_pass, 8, 4);
637
638
	$key = wp_hash( $username . '|' . $pass_frag . '|' . $expiration . '|' . $token, $scheme );
639
640
	// If ext/hash is not present, compat.php's hash_hmac() does not support sha256.
641
	$algo = function_exists( 'hash' ) ? 'sha256' : 'sha1';
642
	$hash = hash_hmac( $algo, $username . '|' . $expiration . '|' . $token, $key );
0 ignored issues
show
It seems like $key defined by wp_hash($username . '|' ... '|' . $token, $scheme) on line 638 can also be of type false; however, hash_hmac() 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...
643
644
	if ( ! hash_equals( $hash, $hmac ) ) {
0 ignored issues
show
It seems like $hash defined by hash_hmac($algo, $userna...n . '|' . $token, $key) on line 642 can also be of type false; however, hash_equals() 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...
645
		/**
646
		 * Fires if a bad authentication cookie hash is encountered.
647
		 *
648
		 * @since 2.7.0
649
		 *
650
		 * @param array $cookie_elements An array of data for the authentication cookie.
651
		 */
652
		do_action( 'auth_cookie_bad_hash', $cookie_elements );
653
		return false;
654
	}
655
656
	$manager = WP_Session_Tokens::get_instance( $user->ID );
657
	if ( ! $manager->verify( $token ) ) {
658
		do_action( 'auth_cookie_bad_session_token', $cookie_elements );
659
		return false;
660
	}
661
662
	// Ajax/POST grace period set above
663
	if ( $expiration < time() ) {
664
		$GLOBALS['login_grace_period'] = 1;
665
	}
666
667
	/**
668
	 * Fires once an authentication cookie has been validated.
669
	 *
670
	 * @since 2.7.0
671
	 *
672
	 * @param array   $cookie_elements An array of data for the authentication cookie.
673
	 * @param WP_User $user            User object.
674
	 */
675
	do_action( 'auth_cookie_valid', $cookie_elements, $user );
676
677
	return $user->ID;
678
}
679
endif;
680
681
if ( !function_exists('wp_generate_auth_cookie') ) :
682
/**
683
 * Generate authentication cookie contents.
684
 *
685
 * @since 2.5.0
686
 *
687
 * @param int    $user_id    User ID
688
 * @param int    $expiration The time the cookie expires as a UNIX timestamp.
689
 * @param string $scheme     Optional. The cookie scheme to use: auth, secure_auth, or logged_in
690
 * @param string $token      User's session token to use for this cookie
691
 * @return string Authentication cookie contents. Empty string if user does not exist.
692
 */
693
function wp_generate_auth_cookie( $user_id, $expiration, $scheme = 'auth', $token = '' ) {
694
	$user = get_userdata($user_id);
695
	if ( ! $user ) {
696
		return '';
697
	}
698
699
	if ( ! $token ) {
700
		$manager = WP_Session_Tokens::get_instance( $user_id );
701
		$token = $manager->create( $expiration );
702
	}
703
704
	$pass_frag = substr($user->user_pass, 8, 4);
705
706
	$key = wp_hash( $user->user_login . '|' . $pass_frag . '|' . $expiration . '|' . $token, $scheme );
707
708
	// If ext/hash is not present, compat.php's hash_hmac() does not support sha256.
709
	$algo = function_exists( 'hash' ) ? 'sha256' : 'sha1';
710
	$hash = hash_hmac( $algo, $user->user_login . '|' . $expiration . '|' . $token, $key );
0 ignored issues
show
It seems like $key defined by wp_hash($user->user_logi... '|' . $token, $scheme) on line 706 can also be of type false; however, hash_hmac() 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...
711
712
	$cookie = $user->user_login . '|' . $expiration . '|' . $token . '|' . $hash;
713
714
	/**
715
	 * Filters the authentication cookie.
716
	 *
717
	 * @since 2.5.0
718
	 *
719
	 * @param string $cookie     Authentication cookie.
720
	 * @param int    $user_id    User ID.
721
	 * @param int    $expiration The time the cookie expires as a UNIX timestamp.
722
	 * @param string $scheme     Cookie scheme used. Accepts 'auth', 'secure_auth', or 'logged_in'.
723
	 * @param string $token      User's session token used.
724
	 */
725
	return apply_filters( 'auth_cookie', $cookie, $user_id, $expiration, $scheme, $token );
726
}
727
endif;
728
729
if ( !function_exists('wp_parse_auth_cookie') ) :
730
/**
731
 * Parse a cookie into its components
732
 *
733
 * @since 2.7.0
734
 *
735
 * @param string $cookie
736
 * @param string $scheme Optional. The cookie scheme to use: auth, secure_auth, or logged_in
737
 * @return array|false Authentication cookie components
738
 */
739
function wp_parse_auth_cookie($cookie = '', $scheme = '') {
740
	if ( empty($cookie) ) {
741
		switch ($scheme){
742
			case 'auth':
743
				$cookie_name = AUTH_COOKIE;
744
				break;
745
			case 'secure_auth':
746
				$cookie_name = SECURE_AUTH_COOKIE;
747
				break;
748
			case "logged_in":
749
				$cookie_name = LOGGED_IN_COOKIE;
750
				break;
751
			default:
752
				if ( is_ssl() ) {
753
					$cookie_name = SECURE_AUTH_COOKIE;
754
					$scheme = 'secure_auth';
755
				} else {
756
					$cookie_name = AUTH_COOKIE;
757
					$scheme = 'auth';
758
				}
759
	    }
760
761
		if ( empty($_COOKIE[$cookie_name]) )
762
			return false;
763
		$cookie = $_COOKIE[$cookie_name];
764
	}
765
766
	$cookie_elements = explode('|', $cookie);
767
	if ( count( $cookie_elements ) !== 4 ) {
768
		return false;
769
	}
770
771
	list( $username, $expiration, $token, $hmac ) = $cookie_elements;
772
773
	return compact( 'username', 'expiration', 'token', 'hmac', 'scheme' );
774
}
775
endif;
776
777
if ( !function_exists('wp_set_auth_cookie') ) :
778
/**
779
 * Log in a user by setting authentication cookies.
780
 *
781
 * The $remember parameter increases the time that the cookie will be kept. The
782
 * default the cookie is kept without remembering is two days. When $remember is
783
 * set, the cookies will be kept for 14 days or two weeks.
784
 *
785
 * @since 2.5.0
786
 * @since 4.3.0 Added the `$token` parameter.
787
 *
788
 * @param int    $user_id  User ID
789
 * @param bool   $remember Whether to remember the user
790
 * @param mixed  $secure   Whether the admin cookies should only be sent over HTTPS.
791
 *                         Default is_ssl().
792
 * @param string $token    Optional. User's session token to use for this cookie.
793
 */
794
function wp_set_auth_cookie( $user_id, $remember = false, $secure = '', $token = '' ) {
795
	if ( $remember ) {
796
		/**
797
		 * Filters the duration of the authentication cookie expiration period.
798
		 *
799
		 * @since 2.8.0
800
		 *
801
		 * @param int  $length   Duration of the expiration period in seconds.
802
		 * @param int  $user_id  User ID.
803
		 * @param bool $remember Whether to remember the user login. Default false.
804
		 */
805
		$expiration = time() + apply_filters( 'auth_cookie_expiration', 14 * DAY_IN_SECONDS, $user_id, $remember );
806
807
		/*
808
		 * Ensure the browser will continue to send the cookie after the expiration time is reached.
809
		 * Needed for the login grace period in wp_validate_auth_cookie().
810
		 */
811
		$expire = $expiration + ( 12 * HOUR_IN_SECONDS );
812
	} else {
813
		/** This filter is documented in wp-includes/pluggable.php */
814
		$expiration = time() + apply_filters( 'auth_cookie_expiration', 2 * DAY_IN_SECONDS, $user_id, $remember );
815
		$expire = 0;
816
	}
817
818
	if ( '' === $secure ) {
819
		$secure = is_ssl();
820
	}
821
822
	// Front-end cookie is secure when the auth cookie is secure and the site's home URL is forced HTTPS.
823
	$secure_logged_in_cookie = $secure && 'https' === parse_url( get_option( 'home' ), PHP_URL_SCHEME );
824
825
	/**
826
	 * Filters whether the connection is secure.
827
	 *
828
	 * @since 3.1.0
829
	 *
830
	 * @param bool $secure  Whether the connection is secure.
831
	 * @param int  $user_id User ID.
832
	 */
833
	$secure = apply_filters( 'secure_auth_cookie', $secure, $user_id );
834
835
	/**
836
	 * Filters whether to use a secure cookie when logged-in.
837
	 *
838
	 * @since 3.1.0
839
	 *
840
	 * @param bool $secure_logged_in_cookie Whether to use a secure cookie when logged-in.
841
	 * @param int  $user_id                 User ID.
842
	 * @param bool $secure                  Whether the connection is secure.
843
	 */
844
	$secure_logged_in_cookie = apply_filters( 'secure_logged_in_cookie', $secure_logged_in_cookie, $user_id, $secure );
845
846
	if ( $secure ) {
847
		$auth_cookie_name = SECURE_AUTH_COOKIE;
848
		$scheme = 'secure_auth';
849
	} else {
850
		$auth_cookie_name = AUTH_COOKIE;
851
		$scheme = 'auth';
852
	}
853
854
	if ( '' === $token ) {
855
		$manager = WP_Session_Tokens::get_instance( $user_id );
856
		$token   = $manager->create( $expiration );
857
	}
858
859
	$auth_cookie = wp_generate_auth_cookie( $user_id, $expiration, $scheme, $token );
860
	$logged_in_cookie = wp_generate_auth_cookie( $user_id, $expiration, 'logged_in', $token );
861
862
	/**
863
	 * Fires immediately before the authentication cookie is set.
864
	 *
865
	 * @since 2.5.0
866
	 *
867
	 * @param string $auth_cookie Authentication cookie.
868
	 * @param int    $expire      The time the login grace period expires as a UNIX timestamp.
869
	 *                            Default is 12 hours past the cookie's expiration time.
870
	 * @param int    $expiration  The time when the authentication cookie expires as a UNIX timestamp.
871
	 *                            Default is 14 days from now.
872
	 * @param int    $user_id     User ID.
873
	 * @param string $scheme      Authentication scheme. Values include 'auth', 'secure_auth', or 'logged_in'.
874
	 */
875
	do_action( 'set_auth_cookie', $auth_cookie, $expire, $expiration, $user_id, $scheme );
876
877
	/**
878
	 * Fires immediately before the logged-in authentication cookie is set.
879
	 *
880
	 * @since 2.6.0
881
	 *
882
	 * @param string $logged_in_cookie The logged-in cookie.
883
	 * @param int    $expire           The time the login grace period expires as a UNIX timestamp.
884
	 *                                 Default is 12 hours past the cookie's expiration time.
885
	 * @param int    $expiration       The time when the logged-in authentication cookie expires as a UNIX timestamp.
886
	 *                                 Default is 14 days from now.
887
	 * @param int    $user_id          User ID.
888
	 * @param string $scheme           Authentication scheme. Default 'logged_in'.
889
	 */
890
	do_action( 'set_logged_in_cookie', $logged_in_cookie, $expire, $expiration, $user_id, 'logged_in' );
891
892
	setcookie($auth_cookie_name, $auth_cookie, $expire, PLUGINS_COOKIE_PATH, COOKIE_DOMAIN, $secure, true);
893
	setcookie($auth_cookie_name, $auth_cookie, $expire, ADMIN_COOKIE_PATH, COOKIE_DOMAIN, $secure, true);
894
	setcookie(LOGGED_IN_COOKIE, $logged_in_cookie, $expire, COOKIEPATH, COOKIE_DOMAIN, $secure_logged_in_cookie, true);
895
	if ( COOKIEPATH != SITECOOKIEPATH )
896
		setcookie(LOGGED_IN_COOKIE, $logged_in_cookie, $expire, SITECOOKIEPATH, COOKIE_DOMAIN, $secure_logged_in_cookie, true);
897
}
898
endif;
899
900
if ( !function_exists('wp_clear_auth_cookie') ) :
901
/**
902
 * Removes all of the cookies associated with authentication.
903
 *
904
 * @since 2.5.0
905
 */
906
function wp_clear_auth_cookie() {
907
	/**
908
	 * Fires just before the authentication cookies are cleared.
909
	 *
910
	 * @since 2.7.0
911
	 */
912
	do_action( 'clear_auth_cookie' );
913
914
	setcookie( AUTH_COOKIE,        ' ', time() - YEAR_IN_SECONDS, ADMIN_COOKIE_PATH,   COOKIE_DOMAIN );
915
	setcookie( SECURE_AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, ADMIN_COOKIE_PATH,   COOKIE_DOMAIN );
916
	setcookie( AUTH_COOKIE,        ' ', time() - YEAR_IN_SECONDS, PLUGINS_COOKIE_PATH, COOKIE_DOMAIN );
917
	setcookie( SECURE_AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, PLUGINS_COOKIE_PATH, COOKIE_DOMAIN );
918
	setcookie( LOGGED_IN_COOKIE,   ' ', time() - YEAR_IN_SECONDS, COOKIEPATH,          COOKIE_DOMAIN );
919
	setcookie( LOGGED_IN_COOKIE,   ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH,      COOKIE_DOMAIN );
920
921
	// Old cookies
922
	setcookie( AUTH_COOKIE,        ' ', time() - YEAR_IN_SECONDS, COOKIEPATH,     COOKIE_DOMAIN );
923
	setcookie( AUTH_COOKIE,        ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH, COOKIE_DOMAIN );
924
	setcookie( SECURE_AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, COOKIEPATH,     COOKIE_DOMAIN );
925
	setcookie( SECURE_AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH, COOKIE_DOMAIN );
926
927
	// Even older cookies
928
	setcookie( USER_COOKIE, ' ', time() - YEAR_IN_SECONDS, COOKIEPATH,     COOKIE_DOMAIN );
929
	setcookie( PASS_COOKIE, ' ', time() - YEAR_IN_SECONDS, COOKIEPATH,     COOKIE_DOMAIN );
930
	setcookie( USER_COOKIE, ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH, COOKIE_DOMAIN );
931
	setcookie( PASS_COOKIE, ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH, COOKIE_DOMAIN );
932
}
933
endif;
934
935
if ( !function_exists('is_user_logged_in') ) :
936
/**
937
 * Checks if the current visitor is a logged in user.
938
 *
939
 * @since 2.0.0
940
 *
941
 * @return bool True if user is logged in, false if not logged in.
942
 */
943
function is_user_logged_in() {
944
	$user = wp_get_current_user();
945
946
	return $user->exists();
947
}
948
endif;
949
950
if ( !function_exists('auth_redirect') ) :
951
/**
952
 * Checks if a user is logged in, if not it redirects them to the login page.
953
 *
954
 * @since 1.5.0
955
 */
956
function auth_redirect() {
957
	// Checks if a user is logged in, if not redirects them to the login page
958
959
	$secure = ( is_ssl() || force_ssl_admin() );
960
961
	/**
962
	 * Filters whether to use a secure authentication redirect.
963
	 *
964
	 * @since 3.1.0
965
	 *
966
	 * @param bool $secure Whether to use a secure authentication redirect. Default false.
967
	 */
968
	$secure = apply_filters( 'secure_auth_redirect', $secure );
969
970
	// If https is required and request is http, redirect
971 View Code Duplication
	if ( $secure && !is_ssl() && false !== strpos($_SERVER['REQUEST_URI'], 'wp-admin') ) {
972
		if ( 0 === strpos( $_SERVER['REQUEST_URI'], 'http' ) ) {
973
			wp_redirect( set_url_scheme( $_SERVER['REQUEST_URI'], 'https' ) );
974
			exit();
975
		} else {
976
			wp_redirect( 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
977
			exit();
978
		}
979
	}
980
981
	/**
982
	 * Filters the authentication redirect scheme.
983
	 *
984
	 * @since 2.9.0
985
	 *
986
	 * @param string $scheme Authentication redirect scheme. Default empty.
987
	 */
988
	$scheme = apply_filters( 'auth_redirect_scheme', '' );
989
990
	if ( $user_id = wp_validate_auth_cookie( '',  $scheme) ) {
991
		/**
992
		 * Fires before the authentication redirect.
993
		 *
994
		 * @since 2.8.0
995
		 *
996
		 * @param int $user_id User ID.
997
		 */
998
		do_action( 'auth_redirect', $user_id );
999
1000
		// If the user wants ssl but the session is not ssl, redirect.
1001 View Code Duplication
		if ( !$secure && get_user_option('use_ssl', $user_id) && false !== strpos($_SERVER['REQUEST_URI'], 'wp-admin') ) {
1002
			if ( 0 === strpos( $_SERVER['REQUEST_URI'], 'http' ) ) {
1003
				wp_redirect( set_url_scheme( $_SERVER['REQUEST_URI'], 'https' ) );
1004
				exit();
1005
			} else {
1006
				wp_redirect( 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
1007
				exit();
1008
			}
1009
		}
1010
1011
		return;  // The cookie is good so we're done
1012
	}
1013
1014
	// The cookie is no good so force login
1015
	nocache_headers();
1016
1017
	$redirect = ( strpos( $_SERVER['REQUEST_URI'], '/options.php' ) && wp_get_referer() ) ? wp_get_referer() : set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
1018
1019
	$login_url = wp_login_url($redirect, true);
1020
1021
	wp_redirect($login_url);
1022
	exit();
1023
}
1024
endif;
1025
1026
if ( !function_exists('check_admin_referer') ) :
1027
/**
1028
 * Makes sure that a user was referred from another admin page.
1029
 *
1030
 * To avoid security exploits.
1031
 *
1032
 * @since 1.2.0
1033
 *
1034
 * @param int|string $action    Action nonce.
1035
 * @param string     $query_arg Optional. Key to check for nonce in `$_REQUEST` (since 2.5).
1036
 *                              Default '_wpnonce'.
1037
 * @return false|int False if the nonce is invalid, 1 if the nonce is valid and generated between
1038
 *                   0-12 hours ago, 2 if the nonce is valid and generated between 12-24 hours ago.
1039
 */
1040
function check_admin_referer( $action = -1, $query_arg = '_wpnonce' ) {
1041
	if ( -1 == $action )
1042
		_doing_it_wrong( __FUNCTION__, __( 'You should specify a nonce action to be verified by using the first parameter.' ), '3.2.0' );
1043
1044
	$adminurl = strtolower(admin_url());
1045
	$referer = strtolower(wp_get_referer());
1046
	$result = isset($_REQUEST[$query_arg]) ? wp_verify_nonce($_REQUEST[$query_arg], $action) : false;
1047
1048
	/**
1049
	 * Fires once the admin request has been validated or not.
1050
	 *
1051
	 * @since 1.5.1
1052
	 *
1053
	 * @param string    $action The nonce action.
1054
	 * @param false|int $result False if the nonce is invalid, 1 if the nonce is valid and generated between
1055
	 *                          0-12 hours ago, 2 if the nonce is valid and generated between 12-24 hours ago.
1056
	 */
1057
	do_action( 'check_admin_referer', $action, $result );
1058
1059
	if ( ! $result && ! ( -1 == $action && strpos( $referer, $adminurl ) === 0 ) ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $result of type integer|false is loosely compared to false; this is ambiguous if the integer can be zero. 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 integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
1060
		wp_nonce_ays( $action );
1061
		die();
1062
	}
1063
1064
	return $result;
1065
}
1066
endif;
1067
1068
if ( !function_exists('check_ajax_referer') ) :
1069
/**
1070
 * Verifies the Ajax request to prevent processing requests external of the blog.
1071
 *
1072
 * @since 2.0.3
1073
 *
1074
 * @param int|string   $action    Action nonce.
1075
 * @param false|string $query_arg Optional. Key to check for the nonce in `$_REQUEST` (since 2.5). If false,
1076
 *                                `$_REQUEST` values will be evaluated for '_ajax_nonce', and '_wpnonce'
1077
 *                                (in that order). Default false.
1078
 * @param bool         $die       Optional. Whether to die early when the nonce cannot be verified.
1079
 *                                Default true.
1080
 * @return false|int False if the nonce is invalid, 1 if the nonce is valid and generated between
1081
 *                   0-12 hours ago, 2 if the nonce is valid and generated between 12-24 hours ago.
1082
 */
1083
function check_ajax_referer( $action = -1, $query_arg = false, $die = true ) {
1084
	$nonce = '';
1085
1086
	if ( $query_arg && isset( $_REQUEST[ $query_arg ] ) )
1087
		$nonce = $_REQUEST[ $query_arg ];
1088
	elseif ( isset( $_REQUEST['_ajax_nonce'] ) )
1089
		$nonce = $_REQUEST['_ajax_nonce'];
1090
	elseif ( isset( $_REQUEST['_wpnonce'] ) )
1091
		$nonce = $_REQUEST['_wpnonce'];
1092
1093
	$result = wp_verify_nonce( $nonce, $action );
1094
1095
	/**
1096
	 * Fires once the Ajax request has been validated or not.
1097
	 *
1098
	 * @since 2.1.0
1099
	 *
1100
	 * @param string    $action The Ajax nonce action.
1101
	 * @param false|int $result False if the nonce is invalid, 1 if the nonce is valid and generated between
1102
	 *                          0-12 hours ago, 2 if the nonce is valid and generated between 12-24 hours ago.
1103
	 */
1104
	do_action( 'check_ajax_referer', $action, $result );
1105
1106
	if ( $die && false === $result ) {
1107
		if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
1108
			wp_die( -1 );
1109
		} else {
1110
			die( '-1' );
1111
		}
1112
	}
1113
1114
	return $result;
1115
}
1116
endif;
1117
1118
if ( !function_exists('wp_redirect') ) :
1119
/**
1120
 * Redirects to another page.
1121
 *
1122
 * Note: wp_redirect() does not exit automatically, and should almost always be
1123
 * followed by a call to `exit;`:
1124
 *
1125
 *     wp_redirect( $url );
1126
 *     exit;
1127
 *
1128
 * Exiting can also be selectively manipulated by using wp_redirect() as a conditional
1129
 * in conjunction with the {@see 'wp_redirect'} and {@see 'wp_redirect_location'} hooks:
1130
 *
1131
 *     if ( wp_redirect( $url ) {
1132
 *         exit;
1133
 *     }
1134
 *
1135
 * @since 1.5.1
1136
 *
1137
 * @global bool $is_IIS
1138
 *
1139
 * @param string $location The path to redirect to.
1140
 * @param int    $status   Status code to use.
1141
 * @return bool False if $location is not provided, true otherwise.
1142
 */
1143
function wp_redirect($location, $status = 302) {
1144
	global $is_IIS;
1145
1146
	/**
1147
	 * Filters the redirect location.
1148
	 *
1149
	 * @since 2.1.0
1150
	 *
1151
	 * @param string $location The path to redirect to.
1152
	 * @param int    $status   Status code to use.
1153
	 */
1154
	$location = apply_filters( 'wp_redirect', $location, $status );
1155
1156
	/**
1157
	 * Filters the redirect status code.
1158
	 *
1159
	 * @since 2.3.0
1160
	 *
1161
	 * @param int    $status   Status code to use.
1162
	 * @param string $location The path to redirect to.
1163
	 */
1164
	$status = apply_filters( 'wp_redirect_status', $status, $location );
1165
1166
	if ( ! $location )
1167
		return false;
1168
1169
	$location = wp_sanitize_redirect($location);
1170
1171
	if ( !$is_IIS && PHP_SAPI != 'cgi-fcgi' )
1172
		status_header($status); // This causes problems on IIS and some FastCGI setups
1173
1174
	header("Location: $location", true, $status);
1175
1176
	return true;
1177
}
1178
endif;
1179
1180
if ( !function_exists('wp_sanitize_redirect') ) :
1181
/**
1182
 * Sanitizes a URL for use in a redirect.
1183
 *
1184
 * @since 2.3.0
1185
 *
1186
 * @param string $location The path to redirect to.
1187
 * @return string Redirect-sanitized URL.
1188
 **/
1189
function wp_sanitize_redirect($location) {
1190
	$regex = '/
1191
		(
1192
			(?: [\xC2-\xDF][\x80-\xBF]        # double-byte sequences   110xxxxx 10xxxxxx
1193
			|   \xE0[\xA0-\xBF][\x80-\xBF]    # triple-byte sequences   1110xxxx 10xxxxxx * 2
1194
			|   [\xE1-\xEC][\x80-\xBF]{2}
1195
			|   \xED[\x80-\x9F][\x80-\xBF]
1196
			|   [\xEE-\xEF][\x80-\xBF]{2}
1197
			|   \xF0[\x90-\xBF][\x80-\xBF]{2} # four-byte sequences   11110xxx 10xxxxxx * 3
1198
			|   [\xF1-\xF3][\x80-\xBF]{3}
1199
			|   \xF4[\x80-\x8F][\x80-\xBF]{2}
1200
		){1,40}                              # ...one or more times
1201
		)/x';
1202
	$location = preg_replace_callback( $regex, '_wp_sanitize_utf8_in_redirect', $location );
1203
	$location = preg_replace('|[^a-z0-9-~+_.?#=&;,/:%!*\[\]()@]|i', '', $location);
1204
	$location = wp_kses_no_null($location);
1205
1206
	// remove %0d and %0a from location
1207
	$strip = array('%0d', '%0a', '%0D', '%0A');
1208
	return _deep_replace( $strip, $location );
1209
}
1210
1211
/**
1212
 * URL encode UTF-8 characters in a URL.
1213
 *
1214
 * @ignore
1215
 * @since 4.2.0
1216
 * @access private
1217
 *
1218
 * @see wp_sanitize_redirect()
1219
 *
1220
 * @param array $matches RegEx matches against the redirect location.
1221
 * @return string URL-encoded version of the first RegEx match.
1222
 */
1223
function _wp_sanitize_utf8_in_redirect( $matches ) {
1224
	return urlencode( $matches[0] );
1225
}
1226
endif;
1227
1228
if ( !function_exists('wp_safe_redirect') ) :
1229
/**
1230
 * Performs a safe (local) redirect, using wp_redirect().
1231
 *
1232
 * Checks whether the $location is using an allowed host, if it has an absolute
1233
 * path. A plugin can therefore set or remove allowed host(s) to or from the
1234
 * list.
1235
 *
1236
 * If the host is not allowed, then the redirect defaults to wp-admin on the siteurl
1237
 * instead. This prevents malicious redirects which redirect to another host,
1238
 * but only used in a few places.
1239
 *
1240
 * @since 2.3.0
1241
 *
1242
 * @param string $location The path to redirect to.
1243
 * @param int    $status   Status code to use.
1244
 */
1245
function wp_safe_redirect($location, $status = 302) {
1246
1247
	// Need to look at the URL the way it will end up in wp_redirect()
1248
	$location = wp_sanitize_redirect($location);
1249
1250
	/**
1251
	 * Filters the redirect fallback URL for when the provided redirect is not safe (local).
1252
	 *
1253
	 * @since 4.3.0
1254
	 *
1255
	 * @param string $fallback_url The fallback URL to use by default.
1256
	 * @param int    $status       The redirect status.
1257
	 */
1258
	$location = wp_validate_redirect( $location, apply_filters( 'wp_safe_redirect_fallback', admin_url(), $status ) );
1259
1260
	wp_redirect($location, $status);
1261
}
1262
endif;
1263
1264
if ( !function_exists('wp_validate_redirect') ) :
1265
/**
1266
 * Validates a URL for use in a redirect.
1267
 *
1268
 * Checks whether the $location is using an allowed host, if it has an absolute
1269
 * path. A plugin can therefore set or remove allowed host(s) to or from the
1270
 * list.
1271
 *
1272
 * If the host is not allowed, then the redirect is to $default supplied
1273
 *
1274
 * @since 2.8.1
1275
 *
1276
 * @param string $location The redirect to validate
1277
 * @param string $default  The value to return if $location is not allowed
1278
 * @return string redirect-sanitized URL
1279
 **/
1280
function wp_validate_redirect($location, $default = '') {
1281
	$location = trim( $location );
1282
	// browsers will assume 'http' is your protocol, and will obey a redirect to a URL starting with '//'
1283
	if ( substr($location, 0, 2) == '//' )
1284
		$location = 'http:' . $location;
1285
1286
	// In php 5 parse_url may fail if the URL query part contains http://, bug #38143
1287
	$test = ( $cut = strpos($location, '?') ) ? substr( $location, 0, $cut ) : $location;
1288
1289
	// @-operator is used to prevent possible warnings in PHP < 5.3.3.
1290
	$lp = @parse_url($test);
1291
1292
	// Give up if malformed URL
1293
	if ( false === $lp )
1294
		return $default;
1295
1296
	// Allow only http and https schemes. No data:, etc.
1297
	if ( isset($lp['scheme']) && !('http' == $lp['scheme'] || 'https' == $lp['scheme']) )
1298
		return $default;
1299
1300
	// Reject if certain components are set but host is not. This catches urls like https:host.com for which parse_url does not set the host field.
1301
	if ( ! isset( $lp['host'] ) && ( isset( $lp['scheme'] ) || isset( $lp['user'] ) || isset( $lp['pass'] ) || isset( $lp['port'] ) ) ) {
1302
		return $default;
1303
	}
1304
1305
	// Reject malformed components parse_url() can return on odd inputs.
1306
	foreach ( array( 'user', 'pass', 'host' ) as $component ) {
1307
		if ( isset( $lp[ $component ] ) && strpbrk( $lp[ $component ], ':/?#@' ) ) {
1308
			return $default;
1309
		}
1310
	}
1311
1312
	$wpp = parse_url(home_url());
1313
1314
	/**
1315
	 * Filters the whitelist of hosts to redirect to.
1316
	 *
1317
	 * @since 2.3.0
1318
	 *
1319
	 * @param array       $hosts An array of allowed hosts.
1320
	 * @param bool|string $host  The parsed host; empty if not isset.
1321
	 */
1322
	$allowed_hosts = (array) apply_filters( 'allowed_redirect_hosts', array($wpp['host']), isset($lp['host']) ? $lp['host'] : '' );
1323
1324
	if ( isset($lp['host']) && ( !in_array($lp['host'], $allowed_hosts) && $lp['host'] != strtolower($wpp['host'])) )
1325
		$location = $default;
1326
1327
	return $location;
1328
}
1329
endif;
1330
1331
if ( ! function_exists('wp_notify_postauthor') ) :
1332
/**
1333
 * Notify an author (and/or others) of a comment/trackback/pingback on a post.
1334
 *
1335
 * @since 1.0.0
1336
 *
1337
 * @param int|WP_Comment  $comment_id Comment ID or WP_Comment object.
1338
 * @param string          $deprecated Not used
1339
 * @return bool True on completion. False if no email addresses were specified.
1340
 */
1341
function wp_notify_postauthor( $comment_id, $deprecated = null ) {
1342
	if ( null !== $deprecated ) {
1343
		_deprecated_argument( __FUNCTION__, '3.8.0' );
1344
	}
1345
1346
	$comment = get_comment( $comment_id );
1347
	if ( empty( $comment ) || empty( $comment->comment_post_ID ) )
1348
		return false;
1349
1350
	$post    = get_post( $comment->comment_post_ID );
1351
	$author  = get_userdata( $post->post_author );
1352
1353
	// Who to notify? By default, just the post author, but others can be added.
1354
	$emails = array();
1355
	if ( $author ) {
1356
		$emails[] = $author->user_email;
1357
	}
1358
1359
	/**
1360
	 * Filters the list of email addresses to receive a comment notification.
1361
	 *
1362
	 * By default, only post authors are notified of comments. This filter allows
1363
	 * others to be added.
1364
	 *
1365
	 * @since 3.7.0
1366
	 *
1367
	 * @param array $emails     An array of email addresses to receive a comment notification.
1368
	 * @param int   $comment_id The comment ID.
1369
	 */
1370
	$emails = apply_filters( 'comment_notification_recipients', $emails, $comment->comment_ID );
1371
	$emails = array_filter( $emails );
1372
1373
	// If there are no addresses to send the comment to, bail.
1374
	if ( ! count( $emails ) ) {
1375
		return false;
1376
	}
1377
1378
	// Facilitate unsetting below without knowing the keys.
1379
	$emails = array_flip( $emails );
1380
1381
	/**
1382
	 * Filters whether to notify comment authors of their comments on their own posts.
1383
	 *
1384
	 * By default, comment authors aren't notified of their comments on their own
1385
	 * posts. This filter allows you to override that.
1386
	 *
1387
	 * @since 3.8.0
1388
	 *
1389
	 * @param bool $notify     Whether to notify the post author of their own comment.
1390
	 *                         Default false.
1391
	 * @param int  $comment_id The comment ID.
1392
	 */
1393
	$notify_author = apply_filters( 'comment_notification_notify_author', false, $comment->comment_ID );
1394
1395
	// The comment was left by the author
1396
	if ( $author && ! $notify_author && $comment->user_id == $post->post_author ) {
1397
		unset( $emails[ $author->user_email ] );
1398
	}
1399
1400
	// The author moderated a comment on their own post
1401
	if ( $author && ! $notify_author && $post->post_author == get_current_user_id() ) {
1402
		unset( $emails[ $author->user_email ] );
1403
	}
1404
1405
	// The post author is no longer a member of the blog
1406
	if ( $author && ! $notify_author && ! user_can( $post->post_author, 'read_post', $post->ID ) ) {
1407
		unset( $emails[ $author->user_email ] );
1408
	}
1409
1410
	// If there's no email to send the comment to, bail, otherwise flip array back around for use below
1411
	if ( ! count( $emails ) ) {
1412
		return false;
1413
	} else {
1414
		$emails = array_flip( $emails );
1415
	}
1416
1417
	$comment_author_domain = @gethostbyaddr($comment->comment_author_IP);
1418
1419
	// The blogname option is escaped with esc_html on the way into the database in sanitize_option
1420
	// we want to reverse this for the plain text arena of emails.
1421
	$blogname = wp_specialchars_decode(get_option('blogname'), ENT_QUOTES);
1422
	$comment_content = wp_specialchars_decode( $comment->comment_content );
1423
1424
	switch ( $comment->comment_type ) {
1425 View Code Duplication
		case 'trackback':
1426
			$notify_message  = sprintf( __( 'New trackback on your post "%s"' ), $post->post_title ) . "\r\n";
1427
			/* translators: 1: website name, 2: website IP, 3: website hostname */
1428
			$notify_message .= sprintf( __('Website: %1$s (IP: %2$s, %3$s)'), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
1429
			$notify_message .= sprintf( __( 'URL: %s' ), $comment->comment_author_url ) . "\r\n";
1430
			$notify_message .= sprintf( __( 'Comment: %s' ), "\r\n" . $comment_content ) . "\r\n\r\n";
1431
			$notify_message .= __( 'You can see all trackbacks on this post here:' ) . "\r\n";
1432
			/* translators: 1: blog name, 2: post title */
1433
			$subject = sprintf( __('[%1$s] Trackback: "%2$s"'), $blogname, $post->post_title );
1434
			break;
1435 View Code Duplication
		case 'pingback':
1436
			$notify_message  = sprintf( __( 'New pingback on your post "%s"' ), $post->post_title ) . "\r\n";
1437
			/* translators: 1: website name, 2: website IP, 3: website hostname */
1438
			$notify_message .= sprintf( __('Website: %1$s (IP: %2$s, %3$s)'), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
1439
			$notify_message .= sprintf( __( 'URL: %s' ), $comment->comment_author_url ) . "\r\n";
1440
			$notify_message .= sprintf( __( 'Comment: %s' ), "\r\n" . $comment_content ) . "\r\n\r\n";
1441
			$notify_message .= __( 'You can see all pingbacks on this post here:' ) . "\r\n";
1442
			/* translators: 1: blog name, 2: post title */
1443
			$subject = sprintf( __('[%1$s] Pingback: "%2$s"'), $blogname, $post->post_title );
1444
			break;
1445
		default: // Comments
1446
			$notify_message  = sprintf( __( 'New comment on your post "%s"' ), $post->post_title ) . "\r\n";
1447
			/* translators: 1: comment author, 2: author IP, 3: author domain */
1448
			$notify_message .= sprintf( __( 'Author: %1$s (IP: %2$s, %3$s)' ), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
1449
			$notify_message .= sprintf( __( 'Email: %s' ), $comment->comment_author_email ) . "\r\n";
1450
			$notify_message .= sprintf( __( 'URL: %s' ), $comment->comment_author_url ) . "\r\n";
1451
			$notify_message .= sprintf( __('Comment: %s' ), "\r\n" . $comment_content ) . "\r\n\r\n";
1452
			$notify_message .= __( 'You can see all comments on this post here:' ) . "\r\n";
1453
			/* translators: 1: blog name, 2: post title */
1454
			$subject = sprintf( __('[%1$s] Comment: "%2$s"'), $blogname, $post->post_title );
1455
			break;
1456
	}
1457
	$notify_message .= get_permalink($comment->comment_post_ID) . "#comments\r\n\r\n";
1458
	$notify_message .= sprintf( __('Permalink: %s'), get_comment_link( $comment ) ) . "\r\n";
1459
1460
	if ( user_can( $post->post_author, 'edit_comment', $comment->comment_ID ) ) {
1461 View Code Duplication
		if ( EMPTY_TRASH_DAYS ) {
1462
			$notify_message .= sprintf( __( 'Trash it: %s' ), admin_url( "comment.php?action=trash&c={$comment->comment_ID}#wpbody-content" ) ) . "\r\n";
1463
		} else {
1464
			$notify_message .= sprintf( __( 'Delete it: %s' ), admin_url( "comment.php?action=delete&c={$comment->comment_ID}#wpbody-content" ) ) . "\r\n";
1465
		}
1466
		$notify_message .= sprintf( __( 'Spam it: %s' ), admin_url( "comment.php?action=spam&c={$comment->comment_ID}#wpbody-content" ) ) . "\r\n";
1467
	}
1468
1469
	$wp_email = 'wordpress@' . preg_replace('#^www\.#', '', strtolower($_SERVER['SERVER_NAME']));
1470
1471
	if ( '' == $comment->comment_author ) {
1472
		$from = "From: \"$blogname\" <$wp_email>";
1473
		if ( '' != $comment->comment_author_email )
1474
			$reply_to = "Reply-To: $comment->comment_author_email";
1475
	} else {
1476
		$from = "From: \"$comment->comment_author\" <$wp_email>";
1477
		if ( '' != $comment->comment_author_email )
1478
			$reply_to = "Reply-To: \"$comment->comment_author_email\" <$comment->comment_author_email>";
1479
	}
1480
1481
	$message_headers = "$from\n"
1482
		. "Content-Type: text/plain; charset=\"" . get_option('blog_charset') . "\"\n";
1483
1484
	if ( isset($reply_to) )
1485
		$message_headers .= $reply_to . "\n";
1486
1487
	/**
1488
	 * Filters the comment notification email text.
1489
	 *
1490
	 * @since 1.5.2
1491
	 *
1492
	 * @param string $notify_message The comment notification email text.
1493
	 * @param int    $comment_id     Comment ID.
1494
	 */
1495
	$notify_message = apply_filters( 'comment_notification_text', $notify_message, $comment->comment_ID );
1496
1497
	/**
1498
	 * Filters the comment notification email subject.
1499
	 *
1500
	 * @since 1.5.2
1501
	 *
1502
	 * @param string $subject    The comment notification email subject.
1503
	 * @param int    $comment_id Comment ID.
1504
	 */
1505
	$subject = apply_filters( 'comment_notification_subject', $subject, $comment->comment_ID );
1506
1507
	/**
1508
	 * Filters the comment notification email headers.
1509
	 *
1510
	 * @since 1.5.2
1511
	 *
1512
	 * @param string $message_headers Headers for the comment notification email.
1513
	 * @param int    $comment_id      Comment ID.
1514
	 */
1515
	$message_headers = apply_filters( 'comment_notification_headers', $message_headers, $comment->comment_ID );
1516
1517
	foreach ( $emails as $email ) {
1518
		@wp_mail( $email, wp_specialchars_decode( $subject ), $notify_message, $message_headers );
1519
	}
1520
1521
	return true;
1522
}
1523
endif;
1524
1525
if ( !function_exists('wp_notify_moderator') ) :
1526
/**
1527
 * Notifies the moderator of the site about a new comment that is awaiting approval.
1528
 *
1529
 * @since 1.0.0
1530
 *
1531
 * @global wpdb $wpdb WordPress database abstraction object.
1532
 *
1533
 * Uses the {@see 'notify_moderator'} filter to determine whether the site moderator
1534
 * should be notified, overriding the site setting.
1535
 *
1536
 * @param int $comment_id Comment ID.
1537
 * @return true Always returns true.
1538
 */
1539
function wp_notify_moderator($comment_id) {
1540
	global $wpdb;
1541
1542
	$maybe_notify = get_option( 'moderation_notify' );
1543
1544
	/**
1545
	 * Filters whether to send the site moderator email notifications, overriding the site setting.
1546
	 *
1547
	 * @since 4.4.0
1548
	 *
1549
	 * @param bool $maybe_notify Whether to notify blog moderator.
1550
	 * @param int  $comment_ID   The id of the comment for the notification.
1551
	 */
1552
	$maybe_notify = apply_filters( 'notify_moderator', $maybe_notify, $comment_id );
1553
1554
	if ( ! $maybe_notify ) {
1555
		return true;
1556
	}
1557
1558
	$comment = get_comment($comment_id);
1559
	$post = get_post($comment->comment_post_ID);
1560
	$user = get_userdata( $post->post_author );
1561
	// Send to the administration and to the post author if the author can modify the comment.
1562
	$emails = array( get_option( 'admin_email' ) );
1563
	if ( $user && user_can( $user->ID, 'edit_comment', $comment_id ) && ! empty( $user->user_email ) ) {
1564
		if ( 0 !== strcasecmp( $user->user_email, get_option( 'admin_email' ) ) )
1565
			$emails[] = $user->user_email;
1566
	}
1567
1568
	$comment_author_domain = @gethostbyaddr($comment->comment_author_IP);
1569
	$comments_waiting = $wpdb->get_var("SELECT count(comment_ID) FROM $wpdb->comments WHERE comment_approved = '0'");
1570
1571
	// The blogname option is escaped with esc_html on the way into the database in sanitize_option
1572
	// we want to reverse this for the plain text arena of emails.
1573
	$blogname = wp_specialchars_decode(get_option('blogname'), ENT_QUOTES);
1574
	$comment_content = wp_specialchars_decode( $comment->comment_content );
1575
1576
	switch ( $comment->comment_type ) {
1577 View Code Duplication
		case 'trackback':
1578
			$notify_message  = sprintf( __('A new trackback on the post "%s" is waiting for your approval'), $post->post_title ) . "\r\n";
1579
			$notify_message .= get_permalink($comment->comment_post_ID) . "\r\n\r\n";
1580
			/* translators: 1: website name, 2: website IP, 3: website hostname */
1581
			$notify_message .= sprintf( __( 'Website: %1$s (IP: %2$s, %3$s)' ), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
1582
			$notify_message .= sprintf( __( 'URL: %s' ), $comment->comment_author_url ) . "\r\n";
1583
			$notify_message .= __('Trackback excerpt: ') . "\r\n" . $comment_content . "\r\n\r\n";
1584
			break;
1585 View Code Duplication
		case 'pingback':
1586
			$notify_message  = sprintf( __('A new pingback on the post "%s" is waiting for your approval'), $post->post_title ) . "\r\n";
1587
			$notify_message .= get_permalink($comment->comment_post_ID) . "\r\n\r\n";
1588
			/* translators: 1: website name, 2: website IP, 3: website hostname */
1589
			$notify_message .= sprintf( __( 'Website: %1$s (IP: %2$s, %3$s)' ), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
1590
			$notify_message .= sprintf( __( 'URL: %s' ), $comment->comment_author_url ) . "\r\n";
1591
			$notify_message .= __('Pingback excerpt: ') . "\r\n" . $comment_content . "\r\n\r\n";
1592
			break;
1593 View Code Duplication
		default: // Comments
1594
			$notify_message  = sprintf( __('A new comment on the post "%s" is waiting for your approval'), $post->post_title ) . "\r\n";
1595
			$notify_message .= get_permalink($comment->comment_post_ID) . "\r\n\r\n";
1596
			$notify_message .= sprintf( __( 'Author: %1$s (IP: %2$s, %3$s)' ), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
1597
			$notify_message .= sprintf( __( 'Email: %s' ), $comment->comment_author_email ) . "\r\n";
1598
			$notify_message .= sprintf( __( 'URL: %s' ), $comment->comment_author_url ) . "\r\n";
1599
			$notify_message .= sprintf( __( 'Comment: %s' ), "\r\n" . $comment_content ) . "\r\n\r\n";
1600
			break;
1601
	}
1602
1603
	$notify_message .= sprintf( __( 'Approve it: %s' ), admin_url( "comment.php?action=approve&c={$comment_id}#wpbody-content" ) ) . "\r\n";
1604
1605 View Code Duplication
	if ( EMPTY_TRASH_DAYS )
1606
		$notify_message .= sprintf( __( 'Trash it: %s' ), admin_url( "comment.php?action=trash&c={$comment_id}#wpbody-content" ) ) . "\r\n";
1607
	else
1608
		$notify_message .= sprintf( __( 'Delete it: %s' ), admin_url( "comment.php?action=delete&c={$comment_id}#wpbody-content" ) ) . "\r\n";
1609
1610
	$notify_message .= sprintf( __( 'Spam it: %s' ), admin_url( "comment.php?action=spam&c={$comment_id}#wpbody-content" ) ) . "\r\n";
1611
1612
	$notify_message .= sprintf( _n('Currently %s comment is waiting for approval. Please visit the moderation panel:',
1613
 		'Currently %s comments are waiting for approval. Please visit the moderation panel:', $comments_waiting), number_format_i18n($comments_waiting) ) . "\r\n";
1614
	$notify_message .= admin_url( "edit-comments.php?comment_status=moderated#wpbody-content" ) . "\r\n";
1615
1616
	$subject = sprintf( __('[%1$s] Please moderate: "%2$s"'), $blogname, $post->post_title );
1617
	$message_headers = '';
1618
1619
	/**
1620
	 * Filters the list of recipients for comment moderation emails.
1621
	 *
1622
	 * @since 3.7.0
1623
	 *
1624
	 * @param array $emails     List of email addresses to notify for comment moderation.
1625
	 * @param int   $comment_id Comment ID.
1626
	 */
1627
	$emails = apply_filters( 'comment_moderation_recipients', $emails, $comment_id );
1628
1629
	/**
1630
	 * Filters the comment moderation email text.
1631
	 *
1632
	 * @since 1.5.2
1633
	 *
1634
	 * @param string $notify_message Text of the comment moderation email.
1635
	 * @param int    $comment_id     Comment ID.
1636
	 */
1637
	$notify_message = apply_filters( 'comment_moderation_text', $notify_message, $comment_id );
1638
1639
	/**
1640
	 * Filters the comment moderation email subject.
1641
	 *
1642
	 * @since 1.5.2
1643
	 *
1644
	 * @param string $subject    Subject of the comment moderation email.
1645
	 * @param int    $comment_id Comment ID.
1646
	 */
1647
	$subject = apply_filters( 'comment_moderation_subject', $subject, $comment_id );
1648
1649
	/**
1650
	 * Filters the comment moderation email headers.
1651
	 *
1652
	 * @since 2.8.0
1653
	 *
1654
	 * @param string $message_headers Headers for the comment moderation email.
1655
	 * @param int    $comment_id      Comment ID.
1656
	 */
1657
	$message_headers = apply_filters( 'comment_moderation_headers', $message_headers, $comment_id );
1658
1659
	foreach ( $emails as $email ) {
1660
		@wp_mail( $email, wp_specialchars_decode( $subject ), $notify_message, $message_headers );
1661
	}
1662
1663
	return true;
1664
}
1665
endif;
1666
1667
if ( !function_exists('wp_password_change_notification') ) :
1668
/**
1669
 * Notify the blog admin of a user changing password, normally via email.
1670
 *
1671
 * @since 2.7.0
1672
 *
1673
 * @param WP_User $user User object.
1674
 */
1675
function wp_password_change_notification( $user ) {
1676
	// send a copy of password change notification to the admin
1677
	// but check to see if it's the admin whose password we're changing, and skip this
1678
	if ( 0 !== strcasecmp( $user->user_email, get_option( 'admin_email' ) ) ) {
1679
		/* translators: %s: user name */
1680
		$message = sprintf( __( 'Password changed for user: %s' ), $user->user_login ) . "\r\n";
1681
		// The blogname option is escaped with esc_html on the way into the database in sanitize_option
1682
		// we want to reverse this for the plain text arena of emails.
1683
		$blogname = wp_specialchars_decode(get_option('blogname'), ENT_QUOTES);
1684
		/* translators: %s: site title */
1685
		wp_mail( get_option( 'admin_email' ), sprintf( __( '[%s] Password Changed' ), $blogname ), $message );
1686
	}
1687
}
1688
endif;
1689
1690
if ( !function_exists('wp_new_user_notification') ) :
1691
/**
1692
 * Email login credentials to a newly-registered user.
1693
 *
1694
 * A new user registration notification is also sent to admin email.
1695
 *
1696
 * @since 2.0.0
1697
 * @since 4.3.0 The `$plaintext_pass` parameter was changed to `$notify`.
1698
 * @since 4.3.1 The `$plaintext_pass` parameter was deprecated. `$notify` added as a third parameter.
1699
 * @since 4.6.0 The `$notify` parameter accepts 'user' for sending notification only to the user created.
1700
 *
1701
 * @global wpdb         $wpdb      WordPress database object for queries.
1702
 * @global PasswordHash $wp_hasher Portable PHP password hashing framework instance.
1703
 *
1704
 * @param int    $user_id    User ID.
1705
 * @param null   $deprecated Not used (argument deprecated).
1706
 * @param string $notify     Optional. Type of notification that should happen. Accepts 'admin' or an empty
1707
 *                           string (admin only), 'user', or 'both' (admin and user). Default empty.
1708
 */
1709
function wp_new_user_notification( $user_id, $deprecated = null, $notify = '' ) {
1710
	if ( $deprecated !== null ) {
1711
		_deprecated_argument( __FUNCTION__, '4.3.1' );
1712
	}
1713
1714
	global $wpdb, $wp_hasher;
1715
	$user = get_userdata( $user_id );
1716
1717
	// The blogname option is escaped with esc_html on the way into the database in sanitize_option
1718
	// we want to reverse this for the plain text arena of emails.
1719
	$blogname = wp_specialchars_decode(get_option('blogname'), ENT_QUOTES);
1720
1721
	if ( 'user' !== $notify ) {
1722
		$message  = sprintf( __( 'New user registration on your site %s:' ), $blogname ) . "\r\n\r\n";
1723
		$message .= sprintf( __( 'Username: %s' ), $user->user_login ) . "\r\n\r\n";
1724
		$message .= sprintf( __( 'Email: %s' ), $user->user_email ) . "\r\n";
1725
1726
		@wp_mail( get_option( 'admin_email' ), sprintf( __( '[%s] New User Registration' ), $blogname ), $message );
1727
	}
1728
1729
	// `$deprecated was pre-4.3 `$plaintext_pass`. An empty `$plaintext_pass` didn't sent a user notifcation.
1730
	if ( 'admin' === $notify || ( empty( $deprecated ) && empty( $notify ) ) ) {
1731
		return;
1732
	}
1733
1734
	// Generate something random for a password reset key.
1735
	$key = wp_generate_password( 20, false );
1736
1737
	/** This action is documented in wp-login.php */
1738
	do_action( 'retrieve_password_key', $user->user_login, $key );
1739
1740
	// Now insert the key, hashed, into the DB.
1741 View Code Duplication
	if ( empty( $wp_hasher ) ) {
1742
		require_once ABSPATH . WPINC . '/class-phpass.php';
1743
		$wp_hasher = new PasswordHash( 8, true );
1744
	}
1745
	$hashed = time() . ':' . $wp_hasher->HashPassword( $key );
1746
	$wpdb->update( $wpdb->users, array( 'user_activation_key' => $hashed ), array( 'user_login' => $user->user_login ) );
1747
1748
	$message = sprintf(__('Username: %s'), $user->user_login) . "\r\n\r\n";
1749
	$message .= __('To set your password, visit the following address:') . "\r\n\r\n";
1750
	$message .= '<' . network_site_url("wp-login.php?action=rp&key=$key&login=" . rawurlencode($user->user_login), 'login') . ">\r\n\r\n";
1751
1752
	$message .= wp_login_url() . "\r\n";
1753
1754
	wp_mail($user->user_email, sprintf(__('[%s] Your username and password info'), $blogname), $message);
1755
}
1756
endif;
1757
1758
if ( !function_exists('wp_nonce_tick') ) :
1759
/**
1760
 * Get the time-dependent variable for nonce creation.
1761
 *
1762
 * A nonce has a lifespan of two ticks. Nonces in their second tick may be
1763
 * updated, e.g. by autosave.
1764
 *
1765
 * @since 2.5.0
1766
 *
1767
 * @return float Float value rounded up to the next highest integer.
1768
 */
1769
function wp_nonce_tick() {
1770
	/**
1771
	 * Filters the lifespan of nonces in seconds.
1772
	 *
1773
	 * @since 2.5.0
1774
	 *
1775
	 * @param int $lifespan Lifespan of nonces in seconds. Default 86,400 seconds, or one day.
1776
	 */
1777
	$nonce_life = apply_filters( 'nonce_life', DAY_IN_SECONDS );
1778
1779
	return ceil(time() / ( $nonce_life / 2 ));
1780
}
1781
endif;
1782
1783
if ( !function_exists('wp_verify_nonce') ) :
1784
/**
1785
 * Verify that correct nonce was used with time limit.
1786
 *
1787
 * The user is given an amount of time to use the token, so therefore, since the
1788
 * UID and $action remain the same, the independent variable is the time.
1789
 *
1790
 * @since 2.0.3
1791
 *
1792
 * @param string     $nonce  Nonce that was used in the form to verify
1793
 * @param string|int $action Should give context to what is taking place and be the same when nonce was created.
1794
 * @return false|int False if the nonce is invalid, 1 if the nonce is valid and generated between
1795
 *                   0-12 hours ago, 2 if the nonce is valid and generated between 12-24 hours ago.
1796
 */
1797
function wp_verify_nonce( $nonce, $action = -1 ) {
1798
	$nonce = (string) $nonce;
1799
	$user = wp_get_current_user();
1800
	$uid = (int) $user->ID;
1801
	if ( ! $uid ) {
1802
		/**
1803
		 * Filters whether the user who generated the nonce is logged out.
1804
		 *
1805
		 * @since 3.5.0
1806
		 *
1807
		 * @param int    $uid    ID of the nonce-owning user.
1808
		 * @param string $action The nonce action.
1809
		 */
1810
		$uid = apply_filters( 'nonce_user_logged_out', $uid, $action );
1811
	}
1812
1813
	if ( empty( $nonce ) ) {
1814
		return false;
1815
	}
1816
1817
	$token = wp_get_session_token();
1818
	$i = wp_nonce_tick();
1819
1820
	// Nonce generated 0-12 hours ago
1821
	$expected = substr( wp_hash( $i . '|' . $action . '|' . $uid . '|' . $token, 'nonce'), -12, 10 );
1822
	if ( hash_equals( $expected, $nonce ) ) {
1823
		return 1;
1824
	}
1825
1826
	// Nonce generated 12-24 hours ago
1827
	$expected = substr( wp_hash( ( $i - 1 ) . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );
1828
	if ( hash_equals( $expected, $nonce ) ) {
1829
		return 2;
1830
	}
1831
1832
	/**
1833
	 * Fires when nonce verification fails.
1834
	 *
1835
	 * @since 4.4.0
1836
	 *
1837
	 * @param string     $nonce  The invalid nonce.
1838
	 * @param string|int $action The nonce action.
1839
	 * @param WP_User    $user   The current user object.
1840
	 * @param string     $token  The user's session token.
1841
	 */
1842
	do_action( 'wp_verify_nonce_failed', $nonce, $action, $user, $token );
1843
1844
	// Invalid nonce
1845
	return false;
1846
}
1847
endif;
1848
1849
if ( !function_exists('wp_create_nonce') ) :
1850
/**
1851
 * Creates a cryptographic token tied to a specific action, user, user session,
1852
 * and window of time.
1853
 *
1854
 * @since 2.0.3
1855
 * @since 4.0.0 Session tokens were integrated with nonce creation
1856
 *
1857
 * @param string|int $action Scalar value to add context to the nonce.
1858
 * @return string The token.
1859
 */
1860
function wp_create_nonce($action = -1) {
1861
	$user = wp_get_current_user();
1862
	$uid = (int) $user->ID;
1863
	if ( ! $uid ) {
1864
		/** This filter is documented in wp-includes/pluggable.php */
1865
		$uid = apply_filters( 'nonce_user_logged_out', $uid, $action );
1866
	}
1867
1868
	$token = wp_get_session_token();
1869
	$i = wp_nonce_tick();
1870
1871
	return substr( wp_hash( $i . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );
1872
}
1873
endif;
1874
1875
if ( !function_exists('wp_salt') ) :
1876
/**
1877
 * Get salt to add to hashes.
1878
 *
1879
 * Salts are created using secret keys. Secret keys are located in two places:
1880
 * in the database and in the wp-config.php file. The secret key in the database
1881
 * is randomly generated and will be appended to the secret keys in wp-config.php.
1882
 *
1883
 * The secret keys in wp-config.php should be updated to strong, random keys to maximize
1884
 * security. Below is an example of how the secret key constants are defined.
1885
 * Do not paste this example directly into wp-config.php. Instead, have a
1886
 * {@link https://api.wordpress.org/secret-key/1.1/salt/ secret key created} just
1887
 * for you.
1888
 *
1889
 *     define('AUTH_KEY',         ' Xakm<o xQy rw4EMsLKM-?!T+,PFF})H4lzcW57AF0U@N@< >M%G4Yt>f`z]MON');
1890
 *     define('SECURE_AUTH_KEY',  'LzJ}op]mr|6+![P}Ak:uNdJCJZd>(Hx.-Mh#Tz)pCIU#uGEnfFz|f ;;eU%/U^O~');
1891
 *     define('LOGGED_IN_KEY',    '|i|Ux`9<p-h$aFf(qnT:sDO:D1P^wZ$$/Ra@miTJi9G;ddp_<q}6H1)o|a +&JCM');
1892
 *     define('NONCE_KEY',        '%:R{[P|,s.KuMltH5}cI;/k<Gx~j!f0I)m_sIyu+&NJZ)-iO>z7X>QYR0Z_XnZ@|');
1893
 *     define('AUTH_SALT',        'eZyT)-Naw]F8CwA*VaW#q*|.)g@o}||wf~@C-YSt}(dh_r6EbI#A,y|nU2{B#JBW');
1894
 *     define('SECURE_AUTH_SALT', '!=oLUTXh,QW=H `}`L|9/^4-3 STz},T(w}W<I`.JjPi)<Bmf1v,HpGe}T1:Xt7n');
1895
 *     define('LOGGED_IN_SALT',   '+XSqHc;@Q*K_b|Z?NC[3H!!EONbh.n<+=uKR:>*c(u`g~EJBf#8u#R{mUEZrozmm');
1896
 *     define('NONCE_SALT',       'h`GXHhD>SLWVfg1(1(N{;.V!MoE(SfbA_ksP@&`+AycHcAV$+?@3q+rxV{%^VyKT');
1897
 *
1898
 * Salting passwords helps against tools which has stored hashed values of
1899
 * common dictionary strings. The added values makes it harder to crack.
1900
 *
1901
 * @since 2.5.0
1902
 *
1903
 * @link https://api.wordpress.org/secret-key/1.1/salt/ Create secrets for wp-config.php
1904
 *
1905
 * @staticvar array $cached_salts
1906
 * @staticvar array $duplicated_keys
1907
 *
1908
 * @param string $scheme Authentication scheme (auth, secure_auth, logged_in, nonce)
1909
 * @return string Salt value
1910
 */
1911
function wp_salt( $scheme = 'auth' ) {
1912
	static $cached_salts = array();
1913
	if ( isset( $cached_salts[ $scheme ] ) ) {
1914
		/**
1915
		 * Filters the WordPress salt.
1916
		 *
1917
		 * @since 2.5.0
1918
		 *
1919
		 * @param string $cached_salt Cached salt for the given scheme.
1920
		 * @param string $scheme      Authentication scheme. Values include 'auth',
1921
		 *                            'secure_auth', 'logged_in', and 'nonce'.
1922
		 */
1923
		return apply_filters( 'salt', $cached_salts[ $scheme ], $scheme );
1924
	}
1925
1926
	static $duplicated_keys;
1927
	if ( null === $duplicated_keys ) {
1928
		$duplicated_keys = array( 'put your unique phrase here' => true );
1929
		foreach ( array( 'AUTH', 'SECURE_AUTH', 'LOGGED_IN', 'NONCE', 'SECRET' ) as $first ) {
1930
			foreach ( array( 'KEY', 'SALT' ) as $second ) {
1931
				if ( ! defined( "{$first}_{$second}" ) ) {
1932
					continue;
1933
				}
1934
				$value = constant( "{$first}_{$second}" );
1935
				$duplicated_keys[ $value ] = isset( $duplicated_keys[ $value ] );
1936
			}
1937
		}
1938
	}
1939
1940
	$values = array(
1941
		'key' => '',
1942
		'salt' => ''
1943
	);
1944
	if ( defined( 'SECRET_KEY' ) && SECRET_KEY && empty( $duplicated_keys[ SECRET_KEY ] ) ) {
1945
		$values['key'] = SECRET_KEY;
1946
	}
1947
	if ( 'auth' == $scheme && defined( 'SECRET_SALT' ) && SECRET_SALT && empty( $duplicated_keys[ SECRET_SALT ] ) ) {
1948
		$values['salt'] = SECRET_SALT;
1949
	}
1950
1951
	if ( in_array( $scheme, array( 'auth', 'secure_auth', 'logged_in', 'nonce' ) ) ) {
1952
		foreach ( array( 'key', 'salt' ) as $type ) {
1953
			$const = strtoupper( "{$scheme}_{$type}" );
1954
			if ( defined( $const ) && constant( $const ) && empty( $duplicated_keys[ constant( $const ) ] ) ) {
1955
				$values[ $type ] = constant( $const );
1956
			} elseif ( ! $values[ $type ] ) {
1957
				$values[ $type ] = get_site_option( "{$scheme}_{$type}" );
1958
				if ( ! $values[ $type ] ) {
1959
					$values[ $type ] = wp_generate_password( 64, true, true );
1960
					update_site_option( "{$scheme}_{$type}", $values[ $type ] );
1961
				}
1962
			}
1963
		}
1964
	} else {
1965
		if ( ! $values['key'] ) {
1966
			$values['key'] = get_site_option( 'secret_key' );
1967
			if ( ! $values['key'] ) {
1968
				$values['key'] = wp_generate_password( 64, true, true );
1969
				update_site_option( 'secret_key', $values['key'] );
1970
			}
1971
		}
1972
		$values['salt'] = hash_hmac( 'md5', $scheme, $values['key'] );
1973
	}
1974
1975
	$cached_salts[ $scheme ] = $values['key'] . $values['salt'];
1976
1977
	/** This filter is documented in wp-includes/pluggable.php */
1978
	return apply_filters( 'salt', $cached_salts[ $scheme ], $scheme );
1979
}
1980
endif;
1981
1982
if ( !function_exists('wp_hash') ) :
1983
/**
1984
 * Get hash of given string.
1985
 *
1986
 * @since 2.0.3
1987
 *
1988
 * @param string $data   Plain text to hash
1989
 * @param string $scheme Authentication scheme (auth, secure_auth, logged_in, nonce)
1990
 * @return string Hash of $data
1991
 */
1992
function wp_hash($data, $scheme = 'auth') {
1993
	$salt = wp_salt($scheme);
1994
1995
	return hash_hmac('md5', $data, $salt);
1996
}
1997
endif;
1998
1999
if ( !function_exists('wp_hash_password') ) :
2000
/**
2001
 * Create a hash (encrypt) of a plain text password.
2002
 *
2003
 * For integration with other applications, this function can be overwritten to
2004
 * instead use the other package password checking algorithm.
2005
 *
2006
 * @since 2.5.0
2007
 *
2008
 * @global PasswordHash $wp_hasher PHPass object
2009
 *
2010
 * @param string $password Plain text user password to hash
2011
 * @return string The hash string of the password
2012
 */
2013
function wp_hash_password($password) {
2014
	global $wp_hasher;
2015
2016 View Code Duplication
	if ( empty($wp_hasher) ) {
2017
		require_once( ABSPATH . WPINC . '/class-phpass.php');
2018
		// By default, use the portable hash from phpass
2019
		$wp_hasher = new PasswordHash(8, true);
2020
	}
2021
2022
	return $wp_hasher->HashPassword( trim( $password ) );
2023
}
2024
endif;
2025
2026
if ( !function_exists('wp_check_password') ) :
2027
/**
2028
 * Checks the plaintext password against the encrypted Password.
2029
 *
2030
 * Maintains compatibility between old version and the new cookie authentication
2031
 * protocol using PHPass library. The $hash parameter is the encrypted password
2032
 * and the function compares the plain text password when encrypted similarly
2033
 * against the already encrypted password to see if they match.
2034
 *
2035
 * For integration with other applications, this function can be overwritten to
2036
 * instead use the other package password checking algorithm.
2037
 *
2038
 * @since 2.5.0
2039
 *
2040
 * @global PasswordHash $wp_hasher PHPass object used for checking the password
2041
 *	against the $hash + $password
2042
 * @uses PasswordHash::CheckPassword
2043
 *
2044
 * @param string     $password Plaintext user's password
2045
 * @param string     $hash     Hash of the user's password to check against.
2046
 * @param string|int $user_id  Optional. User ID.
2047
 * @return bool False, if the $password does not match the hashed password
2048
 */
2049
function wp_check_password($password, $hash, $user_id = '') {
2050
	global $wp_hasher;
2051
2052
	// If the hash is still md5...
2053
	if ( strlen($hash) <= 32 ) {
2054
		$check = hash_equals( $hash, md5( $password ) );
2055
		if ( $check && $user_id ) {
2056
			// Rehash using new hash.
2057
			wp_set_password($password, $user_id);
2058
			$hash = wp_hash_password($password);
2059
		}
2060
2061
		/**
2062
		 * Filters whether the plaintext password matches the encrypted password.
2063
		 *
2064
		 * @since 2.5.0
2065
		 *
2066
		 * @param bool       $check    Whether the passwords match.
2067
		 * @param string     $password The plaintext password.
2068
		 * @param string     $hash     The hashed password.
2069
		 * @param string|int $user_id  User ID. Can be empty.
2070
		 */
2071
		return apply_filters( 'check_password', $check, $password, $hash, $user_id );
2072
	}
2073
2074
	// If the stored hash is longer than an MD5, presume the
2075
	// new style phpass portable hash.
2076 View Code Duplication
	if ( empty($wp_hasher) ) {
2077
		require_once( ABSPATH . WPINC . '/class-phpass.php');
2078
		// By default, use the portable hash from phpass
2079
		$wp_hasher = new PasswordHash(8, true);
2080
	}
2081
2082
	$check = $wp_hasher->CheckPassword($password, $hash);
2083
2084
	/** This filter is documented in wp-includes/pluggable.php */
2085
	return apply_filters( 'check_password', $check, $password, $hash, $user_id );
2086
}
2087
endif;
2088
2089
if ( !function_exists('wp_generate_password') ) :
2090
/**
2091
 * Generates a random password drawn from the defined set of characters.
2092
 *
2093
 * @since 2.5.0
2094
 *
2095
 * @param int  $length              Optional. The length of password to generate. Default 12.
2096
 * @param bool $special_chars       Optional. Whether to include standard special characters.
2097
 *                                  Default true.
2098
 * @param bool $extra_special_chars Optional. Whether to include other special characters.
2099
 *                                  Used when generating secret keys and salts. Default false.
2100
 * @return string The random password.
2101
 */
2102
function wp_generate_password( $length = 12, $special_chars = true, $extra_special_chars = false ) {
2103
	$chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
2104
	if ( $special_chars )
2105
		$chars .= '!@#$%^&*()';
2106
	if ( $extra_special_chars )
2107
		$chars .= '-_ []{}<>~`+=,.;:/?|';
2108
2109
	$password = '';
2110
	for ( $i = 0; $i < $length; $i++ ) {
2111
		$password .= substr($chars, wp_rand(0, strlen($chars) - 1), 1);
2112
	}
2113
2114
	/**
2115
	 * Filters the randomly-generated password.
2116
	 *
2117
	 * @since 3.0.0
2118
	 *
2119
	 * @param string $password The generated password.
2120
	 */
2121
	return apply_filters( 'random_password', $password );
2122
}
2123
endif;
2124
2125
if ( !function_exists('wp_rand') ) :
2126
/**
2127
 * Generates a random number
2128
 *
2129
 * @since 2.6.2
2130
 * @since 4.4.0 Uses PHP7 random_int() or the random_compat library if available.
2131
 *
2132
 * @global string $rnd_value
2133
 * @staticvar string $seed
2134
 * @staticvar bool $external_rand_source_available
2135
 *
2136
 * @param int $min Lower limit for the generated number
2137
 * @param int $max Upper limit for the generated number
2138
 * @return int A random number between min and max
2139
 */
2140
function wp_rand( $min = 0, $max = 0 ) {
2141
	global $rnd_value;
2142
2143
	// Some misconfigured 32bit environments (Entropy PHP, for example) truncate integers larger than PHP_INT_MAX to PHP_INT_MAX rather than overflowing them to floats.
2144
	$max_random_number = 3000000000 === 2147483647 ? (float) "4294967295" : 4294967295; // 4294967295 = 0xffffffff
2145
2146
	// We only handle Ints, floats are truncated to their integer value.
2147
	$min = (int) $min;
2148
	$max = (int) $max;
2149
2150
	// Use PHP's CSPRNG, or a compatible method
2151
	static $use_random_int_functionality = true;
2152
	if ( $use_random_int_functionality ) {
2153
		try {
2154
			$_max = ( 0 != $max ) ? $max : $max_random_number;
2155
			// wp_rand() can accept arguments in either order, PHP cannot.
2156
			$_max = max( $min, $_max );
2157
			$_min = min( $min, $_max );
2158
			$val = random_int( $_min, $_max );
2159
			if ( false !== $val ) {
2160
				return absint( $val );
2161
			} else {
2162
				$use_random_int_functionality = false;
2163
			}
2164
		} catch ( Error $e ) {
0 ignored issues
show
The class Error does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
2165
			$use_random_int_functionality = false;
2166
		} catch ( Exception $e ) {
2167
			$use_random_int_functionality = false;
2168
		}
2169
	}
2170
2171
	// Reset $rnd_value after 14 uses
2172
	// 32(md5) + 40(sha1) + 40(sha1) / 8 = 14 random numbers from $rnd_value
2173
	if ( strlen($rnd_value) < 8 ) {
2174
		if ( defined( 'WP_SETUP_CONFIG' ) )
2175
			static $seed = '';
2176
		else
2177
			$seed = get_transient('random_seed');
2178
		$rnd_value = md5( uniqid(microtime() . mt_rand(), true ) . $seed );
2179
		$rnd_value .= sha1($rnd_value);
2180
		$rnd_value .= sha1($rnd_value . $seed);
2181
		$seed = md5($seed . $rnd_value);
2182
		if ( ! defined( 'WP_SETUP_CONFIG' ) && ! defined( 'WP_INSTALLING' ) ) {
2183
			set_transient( 'random_seed', $seed );
2184
		}
2185
	}
2186
2187
	// Take the first 8 digits for our value
2188
	$value = substr($rnd_value, 0, 8);
2189
2190
	// Strip the first eight, leaving the remainder for the next call to wp_rand().
2191
	$rnd_value = substr($rnd_value, 8);
2192
2193
	$value = abs(hexdec($value));
2194
2195
	// Reduce the value to be within the min - max range
2196
	if ( $max != 0 )
2197
		$value = $min + ( $max - $min + 1 ) * $value / ( $max_random_number + 1 );
2198
2199
	return abs(intval($value));
2200
}
2201
endif;
2202
2203
if ( !function_exists('wp_set_password') ) :
2204
/**
2205
 * Updates the user's password with a new encrypted one.
2206
 *
2207
 * For integration with other applications, this function can be overwritten to
2208
 * instead use the other package password checking algorithm.
2209
 *
2210
 * Please note: This function should be used sparingly and is really only meant for single-time
2211
 * application. Leveraging this improperly in a plugin or theme could result in an endless loop
2212
 * of password resets if precautions are not taken to ensure it does not execute on every page load.
2213
 *
2214
 * @since 2.5.0
2215
 *
2216
 * @global wpdb $wpdb WordPress database abstraction object.
2217
 *
2218
 * @param string $password The plaintext new user password
2219
 * @param int    $user_id  User ID
2220
 */
2221
function wp_set_password( $password, $user_id ) {
2222
	global $wpdb;
2223
2224
	$hash = wp_hash_password( $password );
2225
	$wpdb->update($wpdb->users, array('user_pass' => $hash, 'user_activation_key' => ''), array('ID' => $user_id) );
2226
2227
	wp_cache_delete($user_id, 'users');
2228
}
2229
endif;
2230
2231
if ( !function_exists( 'get_avatar' ) ) :
2232
/**
2233
 * Retrieve the avatar `<img>` tag for a user, email address, MD5 hash, comment, or post.
2234
 *
2235
 * @since 2.5.0
2236
 * @since 4.2.0 Optional `$args` parameter added.
2237
 *
2238
 * @param mixed $id_or_email The Gravatar to retrieve. Accepts a user_id, gravatar md5 hash,
2239
 *                           user email, WP_User object, WP_Post object, or WP_Comment object.
2240
 * @param int    $size       Optional. Height and width of the avatar image file in pixels. Default 96.
2241
 * @param string $default    Optional. URL for the default image or a default type. Accepts '404'
2242
 *                           (return a 404 instead of a default image), 'retro' (8bit), 'monsterid'
2243
 *                           (monster), 'wavatar' (cartoon face), 'indenticon' (the "quilt"),
2244
 *                           'mystery', 'mm', or 'mysteryman' (The Oyster Man), 'blank' (transparent GIF),
2245
 *                           or 'gravatar_default' (the Gravatar logo). Default is the value of the
2246
 *                           'avatar_default' option, with a fallback of 'mystery'.
2247
 * @param string $alt        Optional. Alternative text to use in &lt;img&gt; tag. Default empty.
2248
 * @param array  $args       {
2249
 *     Optional. Extra arguments to retrieve the avatar.
2250
 *
2251
 *     @type int          $height        Display height of the avatar in pixels. Defaults to $size.
2252
 *     @type int          $width         Display width of the avatar in pixels. Defaults to $size.
2253
 *     @type bool         $force_default Whether to always show the default image, never the Gravatar. Default false.
2254
 *     @type string       $rating        What rating to display avatars up to. Accepts 'G', 'PG', 'R', 'X', and are
2255
 *                                       judged in that order. Default is the value of the 'avatar_rating' option.
2256
 *     @type string       $scheme        URL scheme to use. See set_url_scheme() for accepted values.
2257
 *                                       Default null.
2258
 *     @type array|string $class         Array or string of additional classes to add to the &lt;img&gt; element.
2259
 *                                       Default null.
2260
 *     @type bool         $force_display Whether to always show the avatar - ignores the show_avatars option.
2261
 *                                       Default false.
2262
 *     @type string       $extra_attr    HTML attributes to insert in the IMG element. Is not sanitized. Default empty.
2263
 * }
2264
 * @return false|string `<img>` tag for the user's avatar. False on failure.
2265
 */
2266
function get_avatar( $id_or_email, $size = 96, $default = '', $alt = '', $args = null ) {
2267
	$defaults = array(
2268
		// get_avatar_data() args.
2269
		'size'          => 96,
2270
		'height'        => null,
2271
		'width'         => null,
2272
		'default'       => get_option( 'avatar_default', 'mystery' ),
2273
		'force_default' => false,
2274
		'rating'        => get_option( 'avatar_rating' ),
2275
		'scheme'        => null,
2276
		'alt'           => '',
2277
		'class'         => null,
2278
		'force_display' => false,
2279
		'extra_attr'    => '',
2280
	);
2281
2282
	if ( empty( $args ) ) {
2283
		$args = array();
2284
	}
2285
2286
	$args['size']    = (int) $size;
2287
	$args['default'] = $default;
2288
	$args['alt']     = $alt;
2289
2290
	$args = wp_parse_args( $args, $defaults );
2291
2292
	if ( empty( $args['height'] ) ) {
2293
		$args['height'] = $args['size'];
2294
	}
2295
	if ( empty( $args['width'] ) ) {
2296
		$args['width'] = $args['size'];
2297
	}
2298
2299
	if ( is_object( $id_or_email ) && isset( $id_or_email->comment_ID ) ) {
2300
		$id_or_email = get_comment( $id_or_email );
2301
	}
2302
2303
	/**
2304
	 * Filters whether to retrieve the avatar URL early.
2305
	 *
2306
	 * Passing a non-null value will effectively short-circuit get_avatar(), passing
2307
	 * the value through the {@see 'get_avatar'} filter and returning early.
2308
	 *
2309
	 * @since 4.2.0
2310
	 *
2311
	 * @param string $avatar      HTML for the user's avatar. Default null.
2312
	 * @param mixed  $id_or_email The Gravatar to retrieve. Accepts a user_id, gravatar md5 hash,
2313
	 *                            user email, WP_User object, WP_Post object, or WP_Comment object.
2314
	 * @param array  $args        Arguments passed to get_avatar_url(), after processing.
2315
	 */
2316
	$avatar = apply_filters( 'pre_get_avatar', null, $id_or_email, $args );
2317
2318
	if ( ! is_null( $avatar ) ) {
2319
		/** This filter is documented in wp-includes/pluggable.php */
2320
		return apply_filters( 'get_avatar', $avatar, $id_or_email, $args['size'], $args['default'], $args['alt'], $args );
2321
	}
2322
2323
	if ( ! $args['force_display'] && ! get_option( 'show_avatars' ) ) {
2324
		return false;
2325
	}
2326
2327
	$url2x = get_avatar_url( $id_or_email, array_merge( $args, array( 'size' => $args['size'] * 2 ) ) );
2328
2329
	$args = get_avatar_data( $id_or_email, $args );
2330
2331
	$url = $args['url'];
2332
2333
	if ( ! $url || is_wp_error( $url ) ) {
2334
		return false;
2335
	}
2336
2337
	$class = array( 'avatar', 'avatar-' . (int) $args['size'], 'photo' );
2338
2339
	if ( ! $args['found_avatar'] || $args['force_default'] ) {
2340
		$class[] = 'avatar-default';
2341
	}
2342
2343
	if ( $args['class'] ) {
2344
		if ( is_array( $args['class'] ) ) {
2345
			$class = array_merge( $class, $args['class'] );
2346
		} else {
2347
			$class[] = $args['class'];
2348
		}
2349
	}
2350
2351
	$avatar = sprintf(
2352
		"<img alt='%s' src='%s' srcset='%s' class='%s' height='%d' width='%d' %s/>",
2353
		esc_attr( $args['alt'] ),
2354
		esc_url( $url ),
2355
		esc_attr( "$url2x 2x" ),
2356
		esc_attr( join( ' ', $class ) ),
2357
		(int) $args['height'],
2358
		(int) $args['width'],
2359
		$args['extra_attr']
2360
	);
2361
2362
	/**
2363
	 * Filters the avatar to retrieve.
2364
	 *
2365
	 * @since 2.5.0
2366
	 * @since 4.2.0 The `$args` parameter was added.
2367
	 *
2368
	 * @param string $avatar      &lt;img&gt; tag for the user's avatar.
2369
	 * @param mixed  $id_or_email The Gravatar to retrieve. Accepts a user_id, gravatar md5 hash,
2370
	 *                            user email, WP_User object, WP_Post object, or WP_Comment object.
2371
	 * @param int    $size        Square avatar width and height in pixels to retrieve.
2372
	 * @param string $alt         Alternative text to use in the avatar image tag.
2373
	 *                                       Default empty.
2374
	 * @param array  $args        Arguments passed to get_avatar_data(), after processing.
2375
	 */
2376
	return apply_filters( 'get_avatar', $avatar, $id_or_email, $args['size'], $args['default'], $args['alt'], $args );
2377
}
2378
endif;
2379
2380
if ( !function_exists( 'wp_text_diff' ) ) :
2381
/**
2382
 * Displays a human readable HTML representation of the difference between two strings.
2383
 *
2384
 * The Diff is available for getting the changes between versions. The output is
2385
 * HTML, so the primary use is for displaying the changes. If the two strings
2386
 * are equivalent, then an empty string will be returned.
2387
 *
2388
 * The arguments supported and can be changed are listed below.
2389
 *
2390
 * 'title' : Default is an empty string. Titles the diff in a manner compatible
2391
 *		with the output.
2392
 * 'title_left' : Default is an empty string. Change the HTML to the left of the
2393
 *		title.
2394
 * 'title_right' : Default is an empty string. Change the HTML to the right of
2395
 *		the title.
2396
 *
2397
 * @since 2.6.0
2398
 *
2399
 * @see wp_parse_args() Used to change defaults to user defined settings.
2400
 * @uses Text_Diff
2401
 * @uses WP_Text_Diff_Renderer_Table
2402
 *
2403
 * @param string       $left_string  "old" (left) version of string
2404
 * @param string       $right_string "new" (right) version of string
2405
 * @param string|array $args         Optional. Change 'title', 'title_left', and 'title_right' defaults.
2406
 * @return string Empty string if strings are equivalent or HTML with differences.
2407
 */
2408
function wp_text_diff( $left_string, $right_string, $args = null ) {
2409
	$defaults = array( 'title' => '', 'title_left' => '', 'title_right' => '' );
2410
	$args = wp_parse_args( $args, $defaults );
0 ignored issues
show
It seems like $args can also be of type null; however, wp_parse_args() does only seem to accept string|array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
2411
2412
	if ( ! class_exists( 'WP_Text_Diff_Renderer_Table', false ) )
2413
		require( ABSPATH . WPINC . '/wp-diff.php' );
2414
2415
	$left_string  = normalize_whitespace($left_string);
2416
	$right_string = normalize_whitespace($right_string);
2417
2418
	$left_lines  = explode("\n", $left_string);
2419
	$right_lines = explode("\n", $right_string);
2420
	$text_diff = new Text_Diff($left_lines, $right_lines);
2421
	$renderer  = new WP_Text_Diff_Renderer_Table( $args );
2422
	$diff = $renderer->render($text_diff);
2423
2424
	if ( !$diff )
2425
		return '';
2426
2427
	$r  = "<table class='diff'>\n";
2428
2429
	if ( ! empty( $args[ 'show_split_view' ] ) ) {
2430
		$r .= "<col class='content diffsplit left' /><col class='content diffsplit middle' /><col class='content diffsplit right' />";
2431
	} else {
2432
		$r .= "<col class='content' />";
2433
	}
2434
2435
	if ( $args['title'] || $args['title_left'] || $args['title_right'] )
2436
		$r .= "<thead>";
2437
	if ( $args['title'] )
2438
		$r .= "<tr class='diff-title'><th colspan='4'>$args[title]</th></tr>\n";
2439
	if ( $args['title_left'] || $args['title_right'] ) {
2440
		$r .= "<tr class='diff-sub-title'>\n";
2441
		$r .= "\t<td></td><th>$args[title_left]</th>\n";
2442
		$r .= "\t<td></td><th>$args[title_right]</th>\n";
2443
		$r .= "</tr>\n";
2444
	}
2445
	if ( $args['title'] || $args['title_left'] || $args['title_right'] )
2446
		$r .= "</thead>\n";
2447
2448
	$r .= "<tbody>\n$diff\n</tbody>\n";
2449
	$r .= "</table>";
2450
2451
	return $r;
2452
}
2453
endif;
2454
2455