Make WordPress Core

Ticket #57553: load.php

File load.php, 49.9 KB (added by mahbubmr500, 4 years ago)

Ticket track: https://core.trac.wordpress.org/ticket/57553

Line 
1<?php
2/**
3 * These functions are needed to load WordPress.
4 *
5 * @package WordPress
6 */
7
8/**
9 * Return the HTTP protocol sent by the server.
10 *
11 * @since 4.4.0
12 *
13 * @return string The HTTP protocol. Default: HTTP/1.0.
14 */
15function wp_get_server_protocol() {
16 $protocol = isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : '';
17 if ( ! in_array( $protocol, array( 'HTTP/1.1', 'HTTP/2', 'HTTP/2.0', 'HTTP/3' ), true ) ) {
18 $protocol = 'HTTP/1.0';
19 }
20 return $protocol;
21}
22
23/**
24 * Fix `$_SERVER` variables for various setups.
25 *
26 * @since 3.0.0
27 * @access private
28 *
29 * @global string $PHP_SELF The filename of the currently executing script,
30 * relative to the document root.
31 */
32function wp_fix_server_vars() {
33 global $PHP_SELF;
34
35 $default_server_values = array(
36 'SERVER_SOFTWARE' => '',
37 'REQUEST_URI' => '',
38 );
39
40 $_SERVER = array_merge( $default_server_values, $_SERVER );
41
42 // Fix for IIS when running with PHP ISAPI.
43 if ( empty( $_SERVER['REQUEST_URI'] ) || ( 'cgi-fcgi' !== PHP_SAPI && preg_match( '/^Microsoft-IIS\//', $_SERVER['SERVER_SOFTWARE'] ) ) ) {
44
45 if ( isset( $_SERVER['HTTP_X_ORIGINAL_URL'] ) ) {
46 // IIS Mod-Rewrite.
47 $_SERVER['REQUEST_URI'] = $_SERVER['HTTP_X_ORIGINAL_URL'];
48 } elseif ( isset( $_SERVER['HTTP_X_REWRITE_URL'] ) ) {
49 // IIS Isapi_Rewrite.
50 $_SERVER['REQUEST_URI'] = $_SERVER['HTTP_X_REWRITE_URL'];
51 } else {
52 // Use ORIG_PATH_INFO if there is no PATH_INFO.
53 if ( ! isset( $_SERVER['PATH_INFO'] ) && isset( $_SERVER['ORIG_PATH_INFO'] ) ) {
54 $_SERVER['PATH_INFO'] = $_SERVER['ORIG_PATH_INFO'];
55 }
56
57 // Some IIS + PHP configurations put the script-name in the path-info (no need to append it twice).
58 if ( isset( $_SERVER['PATH_INFO'] ) ) {
59 if ( $_SERVER['PATH_INFO'] == $_SERVER['SCRIPT_NAME'] ) {
60 $_SERVER['REQUEST_URI'] = $_SERVER['PATH_INFO'];
61 } else {
62 $_SERVER['REQUEST_URI'] = $_SERVER['SCRIPT_NAME'] . $_SERVER['PATH_INFO'];
63 }
64 }
65
66 // Append the query string if it exists and isn't null.
67 if ( ! empty( $_SERVER['QUERY_STRING'] ) ) {
68 $_SERVER['REQUEST_URI'] .= '?' . $_SERVER['QUERY_STRING'];
69 }
70 }
71 }
72
73 // Fix for PHP as CGI hosts that set SCRIPT_FILENAME to something ending in php.cgi for all requests.
74 if ( isset( $_SERVER['SCRIPT_FILENAME'] ) && ( strpos( $_SERVER['SCRIPT_FILENAME'], 'php.cgi' ) == strlen( $_SERVER['SCRIPT_FILENAME'] ) - 7 ) ) {
75 $_SERVER['SCRIPT_FILENAME'] = $_SERVER['PATH_TRANSLATED'];
76 }
77
78 // Fix for Dreamhost and other PHP as CGI hosts.
79 if ( isset( $_SERVER['SCRIPT_NAME'] ) && ( strpos( $_SERVER['SCRIPT_NAME'], 'php.cgi' ) !== false ) ) {
80 unset( $_SERVER['PATH_INFO'] );
81 }
82
83 // Fix empty PHP_SELF.
84 $PHP_SELF = $_SERVER['PHP_SELF'];
85 if ( empty( $PHP_SELF ) ) {
86 $_SERVER['PHP_SELF'] = preg_replace( '/(\?.*)?$/', '', $_SERVER['REQUEST_URI'] );
87 $PHP_SELF = $_SERVER['PHP_SELF'];
88 }
89
90 wp_populate_basic_auth_from_authorization_header();
91}
92
93/**
94 * Populates the Basic Auth server details from the Authorization header.
95 *
96 * Some servers running in CGI or FastCGI mode don't pass the Authorization
97 * header on to WordPress. If it's been rewritten to the `HTTP_AUTHORIZATION` header,
98 * fill in the proper $_SERVER variables instead.
99 *
100 * @since 5.6.0
101 */
102function wp_populate_basic_auth_from_authorization_header() {
103 // If we don't have anything to pull from, return early.
104 if ( ! isset( $_SERVER['HTTP_AUTHORIZATION'] ) && ! isset( $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] ) ) {
105 return;
106 }
107
108 // If either PHP_AUTH key is already set, do nothing.
109 if ( isset( $_SERVER['PHP_AUTH_USER'] ) || isset( $_SERVER['PHP_AUTH_PW'] ) ) {
110 return;
111 }
112
113 // From our prior conditional, one of these must be set.
114 $header = isset( $_SERVER['HTTP_AUTHORIZATION'] ) ? $_SERVER['HTTP_AUTHORIZATION'] : $_SERVER['REDIRECT_HTTP_AUTHORIZATION'];
115
116 // Test to make sure the pattern matches expected.
117 if ( ! preg_match( '%^Basic [a-z\d/+]*={0,2}$%i', $header ) ) {
118 return;
119 }
120
121 // Removing `Basic ` the token would start six characters in.
122 $token = substr( $header, 6 );
123 $userpass = base64_decode( $token );
124
125 list( $user, $pass ) = explode( ':', $userpass );
126
127 // Now shove them in the proper keys where we're expecting later on.
128 $_SERVER['PHP_AUTH_USER'] = $user;
129 $_SERVER['PHP_AUTH_PW'] = $pass;
130}
131
132/**
133 * Check for the required PHP version, and the MySQL extension or
134 * a database drop-in.
135 *
136 * Dies if requirements are not met.
137 *
138 * @since 3.0.0
139 * @access private
140 *
141 * @global string $required_php_version The required PHP version string.
142 * @global string $wp_version The WordPress version string.
143 */
144function wp_check_php_mysql_versions() {
145 global $required_php_version, $wp_version;
146 $php_version = PHP_VERSION;
147
148 if ( version_compare( $required_php_version, $php_version, '>' ) ) {
149 $protocol = wp_get_server_protocol();
150 header( sprintf( '%s 500 Internal Server Error', $protocol ), true, 500 );
151 header( 'Content-Type: text/html; charset=utf-8' );
152 printf( 'Your server is running PHP version %1$s but WordPress %2$s requires at least %3$s.', $php_version, $wp_version, $required_php_version );
153 exit( 1 );
154 }
155
156 if ( ! extension_loaded( 'mysql' ) && ! extension_loaded( 'mysqli' ) && ! extension_loaded( 'mysqlnd' )
157 // This runs before default constants are defined, so we can't assume WP_CONTENT_DIR is set yet.
158 && ( defined( 'WP_CONTENT_DIR' ) && ! file_exists( WP_CONTENT_DIR . '/db.php' )
159 || ! file_exists( ABSPATH . 'wp-content/db.php' ) )
160 ) {
161 require_once ABSPATH . WPINC . '/functions.php';
162 wp_load_translations_early();
163 $args = array(
164 'exit' => false,
165 'code' => 'mysql_not_found',
166 );
167 wp_die(
168 __( 'Your PHP installation appears to be missing the MySQL extension which is required by WordPress.' ),
169 __( 'Requirements Not Met' ),
170 $args
171 );
172 exit( 1 );
173 }
174}
175
176/**
177 * Retrieves the current environment type.
178 *
179 * The type can be set via the `WP_ENVIRONMENT_TYPE` global system variable,
180 * or a constant of the same name.
181 *
182 * Possible values are 'local', 'development', 'staging', and 'production'.
183 * If not set, the type defaults to 'production'.
184 *
185 * @since 5.5.0
186 * @since 5.5.1 Added the 'local' type.
187 * @since 5.5.1 Removed the ability to alter the list of types.
188 *
189 * @return string The current environment type.
190 */
191function wp_get_environment_type() {
192 static $current_env = '';
193
194 if ( ! defined( 'WP_RUN_CORE_TESTS' ) && $current_env ) {
195 return $current_env;
196 }
197
198 $wp_environments = array(
199 'local',
200 'development',
201 'staging',
202 'production',
203 );
204
205 // Add a note about the deprecated WP_ENVIRONMENT_TYPES constant.
206 if ( defined( 'WP_ENVIRONMENT_TYPES' ) && function_exists( '_deprecated_argument' ) ) {
207 if ( function_exists( '__' ) ) {
208 /* translators: %s: WP_ENVIRONMENT_TYPES */
209 $message = sprintf( __( 'The %s constant is no longer supported.' ), 'WP_ENVIRONMENT_TYPES' );
210 } else {
211 $message = sprintf( 'The %s constant is no longer supported.', 'WP_ENVIRONMENT_TYPES' );
212 }
213
214 _deprecated_argument(
215 'define()',
216 '5.5.1',
217 $message
218 );
219 }
220
221 // Check if the environment variable has been set, if `getenv` is available on the system.
222 if ( function_exists( 'getenv' ) ) {
223 $has_env = getenv( 'WP_ENVIRONMENT_TYPE' );
224 if ( false !== $has_env ) {
225 $current_env = $has_env;
226 }
227 }
228
229 // Fetch the environment from a constant, this overrides the global system variable.
230 if ( defined( 'WP_ENVIRONMENT_TYPE' ) && WP_ENVIRONMENT_TYPE ) {
231 $current_env = WP_ENVIRONMENT_TYPE;
232 }
233
234 // Make sure the environment is an allowed one, and not accidentally set to an invalid value.
235 if ( ! in_array( $current_env, $wp_environments, true ) ) {
236 $current_env = 'production';
237 }
238
239 return $current_env;
240}
241
242/**
243 * Don't load all of WordPress when handling a favicon.ico request.
244 *
245 * Instead, send the headers for a zero-length favicon and bail.
246 *
247 * @since 3.0.0
248 * @deprecated 5.4.0 Deprecated in favor of do_favicon().
249 */
250function wp_favicon_request() {
251 if ( '/favicon.ico' === $_SERVER['REQUEST_URI'] ) {
252 header( 'Content-Type: image/vnd.microsoft.icon' );
253 exit;
254 }
255}
256
257/**
258 * Die with a maintenance message when conditions are met.
259 *
260 * The default message can be replaced by using a drop-in (maintenance.php in
261 * the wp-content directory).
262 *
263 * @since 3.0.0
264 * @access private
265 */
266function wp_maintenance() {
267 // Return if maintenance mode is disabled.
268 if ( ! wp_is_maintenance_mode() ) {
269 return;
270 }
271
272 if ( file_exists( WP_CONTENT_DIR . '/maintenance.php' ) ) {
273 require_once WP_CONTENT_DIR . '/maintenance.php';
274 die();
275 }
276
277 require_once ABSPATH . WPINC . '/functions.php';
278 wp_load_translations_early();
279
280 header( 'Retry-After: 600' );
281
282 wp_die(
283 __( 'Briefly unavailable for scheduled maintenance. Check back in a minute.' ),
284 __( 'Maintenance' ),
285 503
286 );
287}
288
289/**
290 * Check if maintenance mode is enabled.
291 *
292 * Checks for a file in the WordPress root directory named ".maintenance".
293 * This file will contain the variable $upgrading, set to the time the file
294 * was created. If the file was created less than 10 minutes ago, WordPress
295 * is in maintenance mode.
296 *
297 * @since 5.5.0
298 *
299 * @global int $upgrading The Unix timestamp marking when upgrading WordPress began.
300 *
301 * @return bool True if maintenance mode is enabled, false otherwise.
302 */
303function wp_is_maintenance_mode() {
304 global $upgrading;
305
306 if ( ! file_exists( ABSPATH . '.maintenance' ) || wp_installing() ) {
307 return false;
308 }
309
310 require ABSPATH . '.maintenance';
311 // If the $upgrading timestamp is older than 10 minutes, consider maintenance over.
312 if ( ( time() - $upgrading ) >= 10 * MINUTE_IN_SECONDS ) {
313 return false;
314 }
315
316 /**
317 * Filters whether to enable maintenance mode.
318 *
319 * This filter runs before it can be used by plugins. It is designed for
320 * non-web runtimes. If this filter returns true, maintenance mode will be
321 * active and the request will end. If false, the request will be allowed to
322 * continue processing even if maintenance mode should be active.
323 *
324 * @since 4.6.0
325 *
326 * @param bool $enable_checks Whether to enable maintenance mode. Default true.
327 * @param int $upgrading The timestamp set in the .maintenance file.
328 */
329 if ( ! apply_filters( 'enable_maintenance_mode', true, $upgrading ) ) {
330 return false;
331 }
332
333 return true;
334}
335
336/**
337 * Get the time elapsed so far during this PHP script.
338 *
339 * Uses REQUEST_TIME_FLOAT that appeared in PHP 5.4.0.
340 *
341 * @since 5.8.0
342 *
343 * @return float Seconds since the PHP script started.
344 */
345function timer_float() {
346 return microtime( true ) - $_SERVER['REQUEST_TIME_FLOAT'];
347}
348
349/**
350 * Start the WordPress micro-timer.
351 *
352 * @since 0.71
353 * @access private
354 *
355 * @global float $timestart Unix timestamp set at the beginning of the page load.
356 * @see timer_stop()
357 *
358 * @return bool Always returns true.
359 */
360function timer_start() {
361 global $timestart;
362 $timestart = microtime( true );
363 return true;
364}
365
366/**
367 * Retrieve or display the time from the page start to when function is called.
368 *
369 * @since 0.71
370 *
371 * @global float $timestart Seconds from when timer_start() is called.
372 * @global float $timeend Seconds from when function is called.
373 *
374 * @param int|bool $display Whether to echo or return the results. Accepts 0|false for return,
375 * 1|true for echo. Default 0|false.
376 * @param int $precision The number of digits from the right of the decimal to display.
377 * Default 3.
378 * @return string The "second.microsecond" finished time calculation. The number is formatted
379 * for human consumption, both localized and rounded.
380 */
381function timer_stop( $display = 0, $precision = 3 ) {
382 global $timestart, $timeend;
383 $timeend = microtime( true );
384 $timetotal = $timeend - $timestart;
385 $r = ( function_exists( 'number_format_i18n' ) ) ? number_format_i18n( $timetotal, $precision ) : number_format( $timetotal, $precision );
386 if ( $display ) {
387 echo $r;
388 }
389 return $r;
390}
391
392/**
393 * Set PHP error reporting based on WordPress debug settings.
394 *
395 * Uses three constants: `WP_DEBUG`, `WP_DEBUG_DISPLAY`, and `WP_DEBUG_LOG`.
396 * All three can be defined in wp-config.php. By default, `WP_DEBUG` and
397 * `WP_DEBUG_LOG` are set to false, and `WP_DEBUG_DISPLAY` is set to true.
398 *
399 * When `WP_DEBUG` is true, all PHP notices are reported. WordPress will also
400 * display internal notices: when a deprecated WordPress function, function
401 * argument, or file is used. Deprecated code may be removed from a later
402 * version.
403 *
404 * It is strongly recommended that plugin and theme developers use `WP_DEBUG`
405 * in their development environments.
406 *
407 * `WP_DEBUG_DISPLAY` and `WP_DEBUG_LOG` perform no function unless `WP_DEBUG`
408 * is true.
409 *
410 * When `WP_DEBUG_DISPLAY` is true, WordPress will force errors to be displayed.
411 * `WP_DEBUG_DISPLAY` defaults to true. Defining it as null prevents WordPress
412 * from changing the global configuration setting. Defining `WP_DEBUG_DISPLAY`
413 * as false will force errors to be hidden.
414 *
415 * When `WP_DEBUG_LOG` is true, errors will be logged to `wp-content/debug.log`.
416 * When `WP_DEBUG_LOG` is a valid path, errors will be logged to the specified file.
417 *
418 * Errors are never displayed for XML-RPC, REST, `ms-files.php`, and Ajax requests.
419 *
420 * @since 3.0.0
421 * @since 5.1.0 `WP_DEBUG_LOG` can be a file path.
422 * @access private
423 */
424function wp_debug_mode() {
425 /**
426 * Filters whether to allow the debug mode check to occur.
427 *
428 * This filter runs before it can be used by plugins. It is designed for
429 * non-web runtimes. Returning false causes the `WP_DEBUG` and related
430 * constants to not be checked and the default PHP values for errors
431 * will be used unless you take care to update them yourself.
432 *
433 * To use this filter you must define a `$wp_filter` global before
434 * WordPress loads, usually in `wp-config.php`.
435 *
436 * Example:
437 *
438 * $GLOBALS['wp_filter'] = array(
439 * 'enable_wp_debug_mode_checks' => array(
440 * 10 => array(
441 * array(
442 * 'accepted_args' => 0,
443 * 'function' => function() {
444 * return false;
445 * },
446 * ),
447 * ),
448 * ),
449 * );
450 *
451 * @since 4.6.0
452 *
453 * @param bool $enable_debug_mode Whether to enable debug mode checks to occur. Default true.
454 */
455 if ( ! apply_filters( 'enable_wp_debug_mode_checks', true ) ) {
456 return;
457 }
458
459 if ( WP_DEBUG ) {
460 error_reporting( E_ALL );
461
462 if ( WP_DEBUG_DISPLAY ) {
463 ini_set( 'display_errors', 1 );
464 } elseif ( null !== WP_DEBUG_DISPLAY ) {
465 ini_set( 'display_errors', 0 );
466 }
467
468 if ( in_array( strtolower( (string) WP_DEBUG_LOG ), array( 'true', '1' ), true ) ) {
469 $log_path = WP_CONTENT_DIR . '/debug.log';
470 } elseif ( is_string( WP_DEBUG_LOG ) ) {
471 $log_path = WP_DEBUG_LOG;
472 } else {
473 $log_path = false;
474 }
475
476 if ( $log_path ) {
477 ini_set( 'log_errors', 1 );
478 ini_set( 'error_log', $log_path );
479 }
480 } else {
481 error_reporting( E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_ERROR | E_WARNING | E_PARSE | E_USER_ERROR | E_USER_WARNING | E_RECOVERABLE_ERROR );
482 }
483
484 if (
485 defined( 'XMLRPC_REQUEST' ) || defined( 'REST_REQUEST' ) || defined( 'MS_FILES_REQUEST' ) ||
486 ( defined( 'WP_INSTALLING' ) && WP_INSTALLING ) ||
487 wp_doing_ajax() || wp_is_json_request() ) {
488
489 if ( WP_DEBUG && WP_DEBUG_DISPLAY ) {
490 ini_set( 'display_errors', 1 );
491 }
492 else{
493 ini_set( 'display_errors', 0 );
494 }
495 }
496}
497
498/**
499 * Set the location of the language directory.
500 *
501 * To set directory manually, define the `WP_LANG_DIR` constant
502 * in wp-config.php.
503 *
504 * If the language directory exists within `WP_CONTENT_DIR`, it
505 * is used. Otherwise the language directory is assumed to live
506 * in `WPINC`.
507 *
508 * @since 3.0.0
509 * @access private
510 */
511function wp_set_lang_dir() {
512 if ( ! defined( 'WP_LANG_DIR' ) ) {
513 if ( file_exists( WP_CONTENT_DIR . '/languages' ) && @is_dir( WP_CONTENT_DIR . '/languages' ) || ! @is_dir( ABSPATH . WPINC . '/languages' ) ) {
514 /**
515 * Server path of the language directory.
516 *
517 * No leading slash, no trailing slash, full path, not relative to ABSPATH
518 *
519 * @since 2.1.0
520 */
521 define( 'WP_LANG_DIR', WP_CONTENT_DIR . '/languages' );
522 if ( ! defined( 'LANGDIR' ) ) {
523 // Old static relative path maintained for limited backward compatibility - won't work in some cases.
524 define( 'LANGDIR', 'wp-content/languages' );
525 }
526 } else {
527 /**
528 * Server path of the language directory.
529 *
530 * No leading slash, no trailing slash, full path, not relative to `ABSPATH`.
531 *
532 * @since 2.1.0
533 */
534 define( 'WP_LANG_DIR', ABSPATH . WPINC . '/languages' );
535 if ( ! defined( 'LANGDIR' ) ) {
536 // Old relative path maintained for backward compatibility.
537 define( 'LANGDIR', WPINC . '/languages' );
538 }
539 }
540 }
541}
542
543/**
544 * Load the database class file and instantiate the `$wpdb` global.
545 *
546 * @since 2.5.0
547 *
548 * @global wpdb $wpdb WordPress database abstraction object.
549 */
550function require_wp_db() {
551 global $wpdb;
552
553 require_once ABSPATH . WPINC . '/class-wpdb.php';
554
555 if ( file_exists( WP_CONTENT_DIR . '/db.php' ) ) {
556 require_once WP_CONTENT_DIR . '/db.php';
557 }
558
559 if ( isset( $wpdb ) ) {
560 return;
561 }
562
563 $dbuser = defined( 'DB_USER' ) ? DB_USER : '';
564 $dbpassword = defined( 'DB_PASSWORD' ) ? DB_PASSWORD : '';
565 $dbname = defined( 'DB_NAME' ) ? DB_NAME : '';
566 $dbhost = defined( 'DB_HOST' ) ? DB_HOST : '';
567
568 $wpdb = new wpdb( $dbuser, $dbpassword, $dbname, $dbhost );
569}
570
571/**
572 * Set the database table prefix and the format specifiers for database
573 * table columns.
574 *
575 * Columns not listed here default to `%s`.
576 *
577 * @since 3.0.0
578 * @access private
579 *
580 * @global wpdb $wpdb WordPress database abstraction object.
581 * @global string $table_prefix The database table prefix.
582 */
583function wp_set_wpdb_vars() {
584 global $wpdb, $table_prefix;
585 if ( ! empty( $wpdb->error ) ) {
586 dead_db();
587 }
588
589 $wpdb->field_types = array(
590 'post_author' => '%d',
591 'post_parent' => '%d',
592 'menu_order' => '%d',
593 'term_id' => '%d',
594 'term_group' => '%d',
595 'term_taxonomy_id' => '%d',
596 'parent' => '%d',
597 'count' => '%d',
598 'object_id' => '%d',
599 'term_order' => '%d',
600 'ID' => '%d',
601 'comment_ID' => '%d',
602 'comment_post_ID' => '%d',
603 'comment_parent' => '%d',
604 'user_id' => '%d',
605 'link_id' => '%d',
606 'link_owner' => '%d',
607 'link_rating' => '%d',
608 'option_id' => '%d',
609 'blog_id' => '%d',
610 'meta_id' => '%d',
611 'post_id' => '%d',
612 'user_status' => '%d',
613 'umeta_id' => '%d',
614 'comment_karma' => '%d',
615 'comment_count' => '%d',
616 // Multisite:
617 'active' => '%d',
618 'cat_id' => '%d',
619 'deleted' => '%d',
620 'lang_id' => '%d',
621 'mature' => '%d',
622 'public' => '%d',
623 'site_id' => '%d',
624 'spam' => '%d',
625 );
626
627 $prefix = $wpdb->set_prefix( $table_prefix );
628
629 if ( is_wp_error( $prefix ) ) {
630 wp_load_translations_early();
631 wp_die(
632 sprintf(
633 /* translators: 1: $table_prefix, 2: wp-config.php */
634 __( '<strong>Error:</strong> %1$s in %2$s can only contain numbers, letters, and underscores.' ),
635 '<code>$table_prefix</code>',
636 '<code>wp-config.php</code>'
637 )
638 );
639 }
640}
641
642/**
643 * Toggle `$_wp_using_ext_object_cache` on and off without directly
644 * touching global.
645 *
646 * @since 3.7.0
647 *
648 * @global bool $_wp_using_ext_object_cache
649 *
650 * @param bool $using Whether external object cache is being used.
651 * @return bool The current 'using' setting.
652 */
653function wp_using_ext_object_cache( $using = null ) {
654 global $_wp_using_ext_object_cache;
655 $current_using = $_wp_using_ext_object_cache;
656 if ( null !== $using ) {
657 $_wp_using_ext_object_cache = $using;
658 }
659 return $current_using;
660}
661
662/**
663 * Start the WordPress object cache.
664 *
665 * If an object-cache.php file exists in the wp-content directory,
666 * it uses that drop-in as an external object cache.
667 *
668 * @since 3.0.0
669 * @access private
670 *
671 * @global array $wp_filter Stores all of the filters.
672 */
673function wp_start_object_cache() {
674 global $wp_filter;
675 static $first_init = true;
676
677 // Only perform the following checks once.
678
679 /**
680 * Filters whether to enable loading of the object-cache.php drop-in.
681 *
682 * This filter runs before it can be used by plugins. It is designed for non-web
683 * runtimes. If false is returned, object-cache.php will never be loaded.
684 *
685 * @since 5.8.0
686 *
687 * @param bool $enable_object_cache Whether to enable loading object-cache.php (if present).
688 * Default true.
689 */
690 if ( $first_init && apply_filters( 'enable_loading_object_cache_dropin', true ) ) {
691 if ( ! function_exists( 'wp_cache_init' ) ) {
692 /*
693 * This is the normal situation. First-run of this function. No
694 * caching backend has been loaded.
695 *
696 * We try to load a custom caching backend, and then, if it
697 * results in a wp_cache_init() function existing, we note
698 * that an external object cache is being used.
699 */
700 if ( file_exists( WP_CONTENT_DIR . '/object-cache.php' ) ) {
701 require_once WP_CONTENT_DIR . '/object-cache.php';
702 if ( function_exists( 'wp_cache_init' ) ) {
703 wp_using_ext_object_cache( true );
704 }
705
706 // Re-initialize any hooks added manually by object-cache.php.
707 if ( $wp_filter ) {
708 $wp_filter = WP_Hook::build_preinitialized_hooks( $wp_filter );
709 }
710 }
711 } elseif ( ! wp_using_ext_object_cache() && file_exists( WP_CONTENT_DIR . '/object-cache.php' ) ) {
712 /*
713 * Sometimes advanced-cache.php can load object-cache.php before
714 * this function is run. This breaks the function_exists() check
715 * above and can result in wp_using_ext_object_cache() returning
716 * false when actually an external cache is in use.
717 */
718 wp_using_ext_object_cache( true );
719 }
720 }
721
722 if ( ! wp_using_ext_object_cache() ) {
723 require_once ABSPATH . WPINC . '/cache.php';
724 }
725
726 require_once ABSPATH . WPINC . '/cache-compat.php';
727
728 /*
729 * If cache supports reset, reset instead of init if already
730 * initialized. Reset signals to the cache that global IDs
731 * have changed and it may need to update keys and cleanup caches.
732 */
733 if ( ! $first_init && function_exists( 'wp_cache_switch_to_blog' ) ) {
734 wp_cache_switch_to_blog( get_current_blog_id() );
735 } elseif ( function_exists( 'wp_cache_init' ) ) {
736 wp_cache_init();
737 }
738
739 if ( function_exists( 'wp_cache_add_global_groups' ) ) {
740 wp_cache_add_global_groups(
741 array(
742 'blog-details',
743 'blog-id-cache',
744 'blog-lookup',
745 'blog_meta',
746 'global-posts',
747 'networks',
748 'sites',
749 'site-details',
750 'site-options',
751 'site-transient',
752 'rss',
753 'users',
754 'useremail',
755 'userlogins',
756 'usermeta',
757 'user_meta',
758 'userslugs',
759 )
760 );
761
762 wp_cache_add_non_persistent_groups( array( 'counts', 'plugins' ) );
763 }
764
765 $first_init = false;
766}
767
768/**
769 * Redirect to the installer if WordPress is not installed.
770 *
771 * Dies with an error message when Multisite is enabled.
772 *
773 * @since 3.0.0
774 * @access private
775 */
776function wp_not_installed() {
777 if ( is_blog_installed() || wp_installing() ) {
778 return;
779 }
780
781 nocache_headers();
782
783 if ( is_multisite() ) {
784 wp_die( __( 'The site you have requested is not installed properly. Please contact the system administrator.' ) );
785 }
786
787 require ABSPATH . WPINC . '/kses.php';
788 require ABSPATH . WPINC . '/pluggable.php';
789
790 $link = wp_guess_url() . '/wp-admin/install.php';
791
792 wp_redirect( $link );
793 die();
794}
795
796/**
797 * Retrieve an array of must-use plugin files.
798 *
799 * The default directory is wp-content/mu-plugins. To change the default
800 * directory manually, define `WPMU_PLUGIN_DIR` and `WPMU_PLUGIN_URL`
801 * in wp-config.php.
802 *
803 * @since 3.0.0
804 * @access private
805 *
806 * @return string[] Array of absolute paths of files to include.
807 */
808function wp_get_mu_plugins() {
809 $mu_plugins = array();
810 if ( ! is_dir( WPMU_PLUGIN_DIR ) ) {
811 return $mu_plugins;
812 }
813 $dh = opendir( WPMU_PLUGIN_DIR );
814 if ( ! $dh ) {
815 return $mu_plugins;
816 }
817 while ( ( $plugin = readdir( $dh ) ) !== false ) {
818 if ( '.php' === substr( $plugin, -4 ) ) {
819 $mu_plugins[] = WPMU_PLUGIN_DIR . '/' . $plugin;
820 }
821 }
822 closedir( $dh );
823 sort( $mu_plugins );
824
825 return $mu_plugins;
826}
827
828/**
829 * Retrieve an array of active and valid plugin files.
830 *
831 * While upgrading or installing WordPress, no plugins are returned.
832 *
833 * The default directory is `wp-content/plugins`. To change the default
834 * directory manually, define `WP_PLUGIN_DIR` and `WP_PLUGIN_URL`
835 * in `wp-config.php`.
836 *
837 * @since 3.0.0
838 * @access private
839 *
840 * @return string[] Array of paths to plugin files relative to the plugins directory.
841 */
842function wp_get_active_and_valid_plugins() {
843 $plugins = array();
844 $active_plugins = (array) get_option( 'active_plugins', array() );
845
846 // Check for hacks file if the option is enabled.
847 if ( get_option( 'hack_file' ) && file_exists( ABSPATH . 'my-hacks.php' ) ) {
848 _deprecated_file( 'my-hacks.php', '1.5.0' );
849 array_unshift( $plugins, ABSPATH . 'my-hacks.php' );
850 }
851
852 if ( empty( $active_plugins ) || wp_installing() ) {
853 return $plugins;
854 }
855
856 $network_plugins = is_multisite() ? wp_get_active_network_plugins() : false;
857
858 foreach ( $active_plugins as $plugin ) {
859 if ( ! validate_file( $plugin ) // $plugin must validate as file.
860 && '.php' === substr( $plugin, -4 ) // $plugin must end with '.php'.
861 && file_exists( WP_PLUGIN_DIR . '/' . $plugin ) // $plugin must exist.
862 // Not already included as a network plugin.
863 && ( ! $network_plugins || ! in_array( WP_PLUGIN_DIR . '/' . $plugin, $network_plugins, true ) )
864 ) {
865 $plugins[] = WP_PLUGIN_DIR . '/' . $plugin;
866 }
867 }
868
869 /*
870 * Remove plugins from the list of active plugins when we're on an endpoint
871 * that should be protected against WSODs and the plugin is paused.
872 */
873 if ( wp_is_recovery_mode() ) {
874 $plugins = wp_skip_paused_plugins( $plugins );
875 }
876
877 return $plugins;
878}
879
880/**
881 * Filters a given list of plugins, removing any paused plugins from it.
882 *
883 * @since 5.2.0
884 *
885 * @param string[] $plugins Array of absolute plugin main file paths.
886 * @return string[] Filtered array of plugins, without any paused plugins.
887 */
888function wp_skip_paused_plugins( array $plugins ) {
889 $paused_plugins = wp_paused_plugins()->get_all();
890
891 if ( empty( $paused_plugins ) ) {
892 return $plugins;
893 }
894
895 foreach ( $plugins as $index => $plugin ) {
896 list( $plugin ) = explode( '/', plugin_basename( $plugin ) );
897
898 if ( array_key_exists( $plugin, $paused_plugins ) ) {
899 unset( $plugins[ $index ] );
900
901 // Store list of paused plugins for displaying an admin notice.
902 $GLOBALS['_paused_plugins'][ $plugin ] = $paused_plugins[ $plugin ];
903 }
904 }
905
906 return $plugins;
907}
908
909/**
910 * Retrieves an array of active and valid themes.
911 *
912 * While upgrading or installing WordPress, no themes are returned.
913 *
914 * @since 5.1.0
915 * @access private
916 *
917 * @global string $pagenow The filename of the current screen.
918 *
919 * @return string[] Array of absolute paths to theme directories.
920 */
921function wp_get_active_and_valid_themes() {
922 global $pagenow;
923
924 $themes = array();
925
926 if ( wp_installing() && 'wp-activate.php' !== $pagenow ) {
927 return $themes;
928 }
929
930 if ( TEMPLATEPATH !== STYLESHEETPATH ) {
931 $themes[] = STYLESHEETPATH;
932 }
933
934 $themes[] = TEMPLATEPATH;
935
936 /*
937 * Remove themes from the list of active themes when we're on an endpoint
938 * that should be protected against WSODs and the theme is paused.
939 */
940 if ( wp_is_recovery_mode() ) {
941 $themes = wp_skip_paused_themes( $themes );
942
943 // If no active and valid themes exist, skip loading themes.
944 if ( empty( $themes ) ) {
945 add_filter( 'wp_using_themes', '__return_false' );
946 }
947 }
948
949 return $themes;
950}
951
952/**
953 * Filters a given list of themes, removing any paused themes from it.
954 *
955 * @since 5.2.0
956 *
957 * @param string[] $themes Array of absolute theme directory paths.
958 * @return string[] Filtered array of absolute paths to themes, without any paused themes.
959 */
960function wp_skip_paused_themes( array $themes ) {
961 $paused_themes = wp_paused_themes()->get_all();
962
963 if ( empty( $paused_themes ) ) {
964 return $themes;
965 }
966
967 foreach ( $themes as $index => $theme ) {
968 $theme = basename( $theme );
969
970 if ( array_key_exists( $theme, $paused_themes ) ) {
971 unset( $themes[ $index ] );
972
973 // Store list of paused themes for displaying an admin notice.
974 $GLOBALS['_paused_themes'][ $theme ] = $paused_themes[ $theme ];
975 }
976 }
977
978 return $themes;
979}
980
981/**
982 * Is WordPress in Recovery Mode.
983 *
984 * In this mode, plugins or themes that cause WSODs will be paused.
985 *
986 * @since 5.2.0
987 *
988 * @return bool
989 */
990function wp_is_recovery_mode() {
991 return wp_recovery_mode()->is_active();
992}
993
994/**
995 * Determines whether we are currently on an endpoint that should be protected against WSODs.
996 *
997 * @since 5.2.0
998 *
999 * @global string $pagenow The filename of the current screen.
1000 *
1001 * @return bool True if the current endpoint should be protected.
1002 */
1003function is_protected_endpoint() {
1004 // Protect login pages.
1005 if ( isset( $GLOBALS['pagenow'] ) && 'wp-login.php' === $GLOBALS['pagenow'] ) {
1006 return true;
1007 }
1008
1009 // Protect the admin backend.
1010 if ( is_admin() && ! wp_doing_ajax() ) {
1011 return true;
1012 }
1013
1014 // Protect Ajax actions that could help resolve a fatal error should be available.
1015 if ( is_protected_ajax_action() ) {
1016 return true;
1017 }
1018
1019 /**
1020 * Filters whether the current request is against a protected endpoint.
1021 *
1022 * This filter is only fired when an endpoint is requested which is not already protected by
1023 * WordPress core. As such, it exclusively allows providing further protected endpoints in
1024 * addition to the admin backend, login pages and protected Ajax actions.
1025 *
1026 * @since 5.2.0
1027 *
1028 * @param bool $is_protected_endpoint Whether the currently requested endpoint is protected.
1029 * Default false.
1030 */
1031 return (bool) apply_filters( 'is_protected_endpoint', false );
1032}
1033
1034/**
1035 * Determines whether we are currently handling an Ajax action that should be protected against WSODs.
1036 *
1037 * @since 5.2.0
1038 *
1039 * @return bool True if the current Ajax action should be protected.
1040 */
1041function is_protected_ajax_action() {
1042 if ( ! wp_doing_ajax() ) {
1043 return false;
1044 }
1045
1046 if ( ! isset( $_REQUEST['action'] ) ) {
1047 return false;
1048 }
1049
1050 $actions_to_protect = array(
1051 'edit-theme-plugin-file', // Saving changes in the core code editor.
1052 'heartbeat', // Keep the heart beating.
1053 'install-plugin', // Installing a new plugin.
1054 'install-theme', // Installing a new theme.
1055 'search-plugins', // Searching in the list of plugins.
1056 'search-install-plugins', // Searching for a plugin in the plugin install screen.
1057 'update-plugin', // Update an existing plugin.
1058 'update-theme', // Update an existing theme.
1059 );
1060
1061 /**
1062 * Filters the array of protected Ajax actions.
1063 *
1064 * This filter is only fired when doing Ajax and the Ajax request has an 'action' property.
1065 *
1066 * @since 5.2.0
1067 *
1068 * @param string[] $actions_to_protect Array of strings with Ajax actions to protect.
1069 */
1070 $actions_to_protect = (array) apply_filters( 'wp_protected_ajax_actions', $actions_to_protect );
1071
1072 if ( ! in_array( $_REQUEST['action'], $actions_to_protect, true ) ) {
1073 return false;
1074 }
1075
1076 return true;
1077}
1078
1079/**
1080 * Set internal encoding.
1081 *
1082 * In most cases the default internal encoding is latin1, which is
1083 * of no use, since we want to use the `mb_` functions for `utf-8` strings.
1084 *
1085 * @since 3.0.0
1086 * @access private
1087 */
1088function wp_set_internal_encoding() {
1089 if ( function_exists( 'mb_internal_encoding' ) ) {
1090 $charset = get_option( 'blog_charset' );
1091 // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
1092 if ( ! $charset || ! @mb_internal_encoding( $charset ) ) {
1093 mb_internal_encoding( 'UTF-8' );
1094 }
1095 }
1096}
1097
1098/**
1099 * Add magic quotes to `$_GET`, `$_POST`, `$_COOKIE`, and `$_SERVER`.
1100 *
1101 * Also forces `$_REQUEST` to be `$_GET + $_POST`. If `$_SERVER`,
1102 * `$_COOKIE`, or `$_ENV` are needed, use those superglobals directly.
1103 *
1104 * @since 3.0.0
1105 * @access private
1106 */
1107function wp_magic_quotes() {
1108 // Escape with wpdb.
1109 $_GET = add_magic_quotes( $_GET );
1110 $_POST = add_magic_quotes( $_POST );
1111 $_COOKIE = add_magic_quotes( $_COOKIE );
1112 $_SERVER = add_magic_quotes( $_SERVER );
1113
1114 // Force REQUEST to be GET + POST.
1115 $_REQUEST = array_merge( $_GET, $_POST );
1116}
1117
1118/**
1119 * Runs just before PHP shuts down execution.
1120 *
1121 * @since 1.2.0
1122 * @access private
1123 */
1124function shutdown_action_hook() {
1125 /**
1126 * Fires just before PHP shuts down execution.
1127 *
1128 * @since 1.2.0
1129 */
1130 do_action( 'shutdown' );
1131
1132 wp_cache_close();
1133}
1134
1135/**
1136 * Copy an object.
1137 *
1138 * @since 2.7.0
1139 * @deprecated 3.2.0
1140 *
1141 * @param object $input_object The object to clone.
1142 * @return object The cloned object.
1143 */
1144function wp_clone( $input_object ) {
1145 // Use parens for clone to accommodate PHP 4. See #17880.
1146 return clone( $input_object );
1147}
1148
1149/**
1150 * Determines whether the current request is for the login screen.
1151 *
1152 * @since 6.1.0
1153 *
1154 * @see wp_login_url()
1155 *
1156 * @return bool True if inside WordPress login screen, false otherwise.
1157 */
1158function is_login() {
1159 return false !== stripos( wp_login_url(), $_SERVER['SCRIPT_NAME'] );
1160}
1161
1162/**
1163 * Determines whether the current request is for an administrative interface page.
1164 *
1165 * Does not check if the user is an administrator; use current_user_can()
1166 * for checking roles and capabilities.
1167 *
1168 * For more information on this and similar theme functions, check out
1169 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
1170 * Conditional Tags} article in the Theme Developer Handbook.
1171 *
1172 * @since 1.5.1
1173 *
1174 * @global WP_Screen $current_screen WordPress current screen object.
1175 *
1176 * @return bool True if inside WordPress administration interface, false otherwise.
1177 */
1178function is_admin() {
1179 if ( isset( $GLOBALS['current_screen'] ) ) {
1180 return $GLOBALS['current_screen']->in_admin();
1181 } elseif ( defined( 'WP_ADMIN' ) ) {
1182 return WP_ADMIN;
1183 }
1184
1185 return false;
1186}
1187
1188/**
1189 * Determines whether the current request is for a site's administrative interface.
1190 *
1191 * e.g. `/wp-admin/`
1192 *
1193 * Does not check if the user is an administrator; use current_user_can()
1194 * for checking roles and capabilities.
1195 *
1196 * @since 3.1.0
1197 *
1198 * @global WP_Screen $current_screen WordPress current screen object.
1199 *
1200 * @return bool True if inside WordPress site administration pages.
1201 */
1202function is_blog_admin() {
1203 if ( isset( $GLOBALS['current_screen'] ) ) {
1204 return $GLOBALS['current_screen']->in_admin( 'site' );
1205 } elseif ( defined( 'WP_BLOG_ADMIN' ) ) {
1206 return WP_BLOG_ADMIN;
1207 }
1208
1209 return false;
1210}
1211
1212/**
1213 * Determines whether the current request is for the network administrative interface.
1214 *
1215 * e.g. `/wp-admin/network/`
1216 *
1217 * Does not check if the user is an administrator; use current_user_can()
1218 * for checking roles and capabilities.
1219 *
1220 * Does not check if the site is a Multisite network; use is_multisite()
1221 * for checking if Multisite is enabled.
1222 *
1223 * @since 3.1.0
1224 *
1225 * @global WP_Screen $current_screen WordPress current screen object.
1226 *
1227 * @return bool True if inside WordPress network administration pages.
1228 */
1229function is_network_admin() {
1230 if ( isset( $GLOBALS['current_screen'] ) ) {
1231 return $GLOBALS['current_screen']->in_admin( 'network' );
1232 } elseif ( defined( 'WP_NETWORK_ADMIN' ) ) {
1233 return WP_NETWORK_ADMIN;
1234 }
1235
1236 return false;
1237}
1238
1239/**
1240 * Determines whether the current request is for a user admin screen.
1241 *
1242 * e.g. `/wp-admin/user/`
1243 *
1244 * Does not check if the user is an administrator; use current_user_can()
1245 * for checking roles and capabilities.
1246 *
1247 * @since 3.1.0
1248 *
1249 * @global WP_Screen $current_screen WordPress current screen object.
1250 *
1251 * @return bool True if inside WordPress user administration pages.
1252 */
1253function is_user_admin() {
1254 if ( isset( $GLOBALS['current_screen'] ) ) {
1255 return $GLOBALS['current_screen']->in_admin( 'user' );
1256 } elseif ( defined( 'WP_USER_ADMIN' ) ) {
1257 return WP_USER_ADMIN;
1258 }
1259
1260 return false;
1261}
1262
1263/**
1264 * If Multisite is enabled.
1265 *
1266 * @since 3.0.0
1267 *
1268 * @return bool True if Multisite is enabled, false otherwise.
1269 */
1270function is_multisite() {
1271 if ( defined( 'MULTISITE' ) ) {
1272 return MULTISITE;
1273 }
1274
1275 if ( defined( 'SUBDOMAIN_INSTALL' ) || defined( 'VHOST' ) || defined( 'SUNRISE' ) ) {
1276 return true;
1277 }
1278
1279 return false;
1280}
1281
1282/**
1283 * Retrieve the current site ID.
1284 *
1285 * @since 3.1.0
1286 *
1287 * @global int $blog_id
1288 *
1289 * @return int Site ID.
1290 */
1291function get_current_blog_id() {
1292 global $blog_id;
1293 return absint( $blog_id );
1294}
1295
1296/**
1297 * Retrieves the current network ID.
1298 *
1299 * @since 4.6.0
1300 *
1301 * @return int The ID of the current network.
1302 */
1303function get_current_network_id() {
1304 if ( ! is_multisite() ) {
1305 return 1;
1306 }
1307
1308 $current_network = get_network();
1309
1310 if ( ! isset( $current_network->id ) ) {
1311 return get_main_network_id();
1312 }
1313
1314 return absint( $current_network->id );
1315}
1316
1317/**
1318 * Attempt an early load of translations.
1319 *
1320 * Used for errors encountered during the initial loading process, before
1321 * the locale has been properly detected and loaded.
1322 *
1323 * Designed for unusual load sequences (like setup-config.php) or for when
1324 * the script will then terminate with an error, otherwise there is a risk
1325 * that a file can be double-included.
1326 *
1327 * @since 3.4.0
1328 * @access private
1329 *
1330 * @global WP_Textdomain_Registry $wp_textdomain_registry WordPress Textdomain Registry.
1331 * @global WP_Locale $wp_locale WordPress date and time locale object.
1332 */
1333function wp_load_translations_early() {
1334 global $wp_textdomain_registry, $wp_locale;
1335
1336 static $loaded = false;
1337 if ( $loaded ) {
1338 return;
1339 }
1340 $loaded = true;
1341
1342 if ( function_exists( 'did_action' ) && did_action( 'init' ) ) {
1343 return;
1344 }
1345
1346 // We need $wp_local_package.
1347 require ABSPATH . WPINC . '/version.php';
1348
1349 // Translation and localization.
1350 require_once ABSPATH . WPINC . '/pomo/mo.php';
1351 require_once ABSPATH . WPINC . '/l10n.php';
1352 require_once ABSPATH . WPINC . '/class-wp-textdomain-registry.php';
1353 require_once ABSPATH . WPINC . '/class-wp-locale.php';
1354 require_once ABSPATH . WPINC . '/class-wp-locale-switcher.php';
1355
1356 // General libraries.
1357 require_once ABSPATH . WPINC . '/plugin.php';
1358
1359 $locales = array();
1360 $locations = array();
1361
1362 if ( ! $wp_textdomain_registry instanceof WP_Textdomain_Registry ) {
1363 $wp_textdomain_registry = new WP_Textdomain_Registry();
1364 }
1365
1366 while ( true ) {
1367 if ( defined( 'WPLANG' ) ) {
1368 if ( '' === WPLANG ) {
1369 break;
1370 }
1371 $locales[] = WPLANG;
1372 }
1373
1374 if ( isset( $wp_local_package ) ) {
1375 $locales[] = $wp_local_package;
1376 }
1377
1378 if ( ! $locales ) {
1379 break;
1380 }
1381
1382 if ( defined( 'WP_LANG_DIR' ) && @is_dir( WP_LANG_DIR ) ) {
1383 $locations[] = WP_LANG_DIR;
1384 }
1385
1386 if ( defined( 'WP_CONTENT_DIR' ) && @is_dir( WP_CONTENT_DIR . '/languages' ) ) {
1387 $locations[] = WP_CONTENT_DIR . '/languages';
1388 }
1389
1390 if ( @is_dir( ABSPATH . 'wp-content/languages' ) ) {
1391 $locations[] = ABSPATH . 'wp-content/languages';
1392 }
1393
1394 if ( @is_dir( ABSPATH . WPINC . '/languages' ) ) {
1395 $locations[] = ABSPATH . WPINC . '/languages';
1396 }
1397
1398 if ( ! $locations ) {
1399 break;
1400 }
1401
1402 $locations = array_unique( $locations );
1403
1404 foreach ( $locales as $locale ) {
1405 foreach ( $locations as $location ) {
1406 if ( file_exists( $location . '/' . $locale . '.mo' ) ) {
1407 load_textdomain( 'default', $location . '/' . $locale . '.mo', $locale );
1408 if ( defined( 'WP_SETUP_CONFIG' ) && file_exists( $location . '/admin-' . $locale . '.mo' ) ) {
1409 load_textdomain( 'default', $location . '/admin-' . $locale . '.mo', $locale );
1410 }
1411 break 2;
1412 }
1413 }
1414 }
1415
1416 break;
1417 }
1418
1419 $wp_locale = new WP_Locale();
1420}
1421
1422/**
1423 * Check or set whether WordPress is in "installation" mode.
1424 *
1425 * If the `WP_INSTALLING` constant is defined during the bootstrap, `wp_installing()` will default to `true`.
1426 *
1427 * @since 4.4.0
1428 *
1429 * @param bool $is_installing Optional. True to set WP into Installing mode, false to turn Installing mode off.
1430 * Omit this parameter if you only want to fetch the current status.
1431 * @return bool True if WP is installing, otherwise false. When a `$is_installing` is passed, the function will
1432 * report whether WP was in installing mode prior to the change to `$is_installing`.
1433 */
1434function wp_installing( $is_installing = null ) {
1435 static $installing = null;
1436
1437 // Support for the `WP_INSTALLING` constant, defined before WP is loaded.
1438 if ( is_null( $installing ) ) {
1439 $installing = defined( 'WP_INSTALLING' ) && WP_INSTALLING;
1440 }
1441
1442 if ( ! is_null( $is_installing ) ) {
1443 $old_installing = $installing;
1444 $installing = $is_installing;
1445 return (bool) $old_installing;
1446 }
1447
1448 return (bool) $installing;
1449}
1450
1451/**
1452 * Determines if SSL is used.
1453 *
1454 * @since 2.6.0
1455 * @since 4.6.0 Moved from functions.php to load.php.
1456 *
1457 * @return bool True if SSL, otherwise false.
1458 */
1459function is_ssl() {
1460 if ( isset( $_SERVER['HTTPS'] ) ) {
1461 if ( 'on' === strtolower( $_SERVER['HTTPS'] ) ) {
1462 return true;
1463 }
1464
1465 if ( '1' == $_SERVER['HTTPS'] ) {
1466 return true;
1467 }
1468 } elseif ( isset( $_SERVER['SERVER_PORT'] ) && ( '443' == $_SERVER['SERVER_PORT'] ) ) {
1469 return true;
1470 }
1471 return false;
1472}
1473
1474/**
1475 * Converts a shorthand byte value to an integer byte value.
1476 *
1477 * @since 2.3.0
1478 * @since 4.6.0 Moved from media.php to load.php.
1479 *
1480 * @link https://www.php.net/manual/en/function.ini-get.php
1481 * @link https://www.php.net/manual/en/faq.using.php#faq.using.shorthandbytes
1482 *
1483 * @param string $value A (PHP ini) byte value, either shorthand or ordinary.
1484 * @return int An integer byte value.
1485 */
1486function wp_convert_hr_to_bytes( $value ) {
1487 $value = strtolower( trim( $value ) );
1488 $bytes = (int) $value;
1489
1490 if ( false !== strpos( $value, 'g' ) ) {
1491 $bytes *= GB_IN_BYTES;
1492 } elseif ( false !== strpos( $value, 'm' ) ) {
1493 $bytes *= MB_IN_BYTES;
1494 } elseif ( false !== strpos( $value, 'k' ) ) {
1495 $bytes *= KB_IN_BYTES;
1496 }
1497
1498 // Deal with large (float) values which run into the maximum integer size.
1499 return min( $bytes, PHP_INT_MAX );
1500}
1501
1502/**
1503 * Determines whether a PHP ini value is changeable at runtime.
1504 *
1505 * @since 4.6.0
1506 *
1507 * @link https://www.php.net/manual/en/function.ini-get-all.php
1508 *
1509 * @param string $setting The name of the ini setting to check.
1510 * @return bool True if the value is changeable at runtime. False otherwise.
1511 */
1512function wp_is_ini_value_changeable( $setting ) {
1513 static $ini_all;
1514
1515 if ( ! isset( $ini_all ) ) {
1516 $ini_all = false;
1517 // Sometimes `ini_get_all()` is disabled via the `disable_functions` option for "security purposes".
1518 if ( function_exists( 'ini_get_all' ) ) {
1519 $ini_all = ini_get_all();
1520 }
1521 }
1522
1523 // Bit operator to workaround https://bugs.php.net/bug.php?id=44936 which changes access level to 63 in PHP 5.2.6 - 5.2.17.
1524 if ( isset( $ini_all[ $setting ]['access'] ) && ( INI_ALL === ( $ini_all[ $setting ]['access'] & 7 ) || INI_USER === ( $ini_all[ $setting ]['access'] & 7 ) ) ) {
1525 return true;
1526 }
1527
1528 // If we were unable to retrieve the details, fail gracefully to assume it's changeable.
1529 if ( ! is_array( $ini_all ) ) {
1530 return true;
1531 }
1532
1533 return false;
1534}
1535
1536/**
1537 * Determines whether the current request is a WordPress Ajax request.
1538 *
1539 * @since 4.7.0
1540 *
1541 * @return bool True if it's a WordPress Ajax request, false otherwise.
1542 */
1543function wp_doing_ajax() {
1544 /**
1545 * Filters whether the current request is a WordPress Ajax request.
1546 *
1547 * @since 4.7.0
1548 *
1549 * @param bool $wp_doing_ajax Whether the current request is a WordPress Ajax request.
1550 */
1551 return apply_filters( 'wp_doing_ajax', defined( 'DOING_AJAX' ) && DOING_AJAX );
1552}
1553
1554/**
1555 * Determines whether the current request should use themes.
1556 *
1557 * @since 5.1.0
1558 *
1559 * @return bool True if themes should be used, false otherwise.
1560 */
1561function wp_using_themes() {
1562 /**
1563 * Filters whether the current request should use themes.
1564 *
1565 * @since 5.1.0
1566 *
1567 * @param bool $wp_using_themes Whether the current request should use themes.
1568 */
1569 return apply_filters( 'wp_using_themes', defined( 'WP_USE_THEMES' ) && WP_USE_THEMES );
1570}
1571
1572/**
1573 * Determines whether the current request is a WordPress cron request.
1574 *
1575 * @since 4.8.0
1576 *
1577 * @return bool True if it's a WordPress cron request, false otherwise.
1578 */
1579function wp_doing_cron() {
1580 /**
1581 * Filters whether the current request is a WordPress cron request.
1582 *
1583 * @since 4.8.0
1584 *
1585 * @param bool $wp_doing_cron Whether the current request is a WordPress cron request.
1586 */
1587 return apply_filters( 'wp_doing_cron', defined( 'DOING_CRON' ) && DOING_CRON );
1588}
1589
1590/**
1591 * Checks whether the given variable is a WordPress Error.
1592 *
1593 * Returns whether `$thing` is an instance of the `WP_Error` class.
1594 *
1595 * @since 2.1.0
1596 *
1597 * @param mixed $thing The variable to check.
1598 * @return bool Whether the variable is an instance of WP_Error.
1599 */
1600function is_wp_error( $thing ) {
1601 $is_wp_error = ( $thing instanceof WP_Error );
1602
1603 if ( $is_wp_error ) {
1604 /**
1605 * Fires when `is_wp_error()` is called and its parameter is an instance of `WP_Error`.
1606 *
1607 * @since 5.6.0
1608 *
1609 * @param WP_Error $thing The error object passed to `is_wp_error()`.
1610 */
1611 do_action( 'is_wp_error_instance', $thing );
1612 }
1613
1614 return $is_wp_error;
1615}
1616
1617/**
1618 * Determines whether file modifications are allowed.
1619 *
1620 * @since 4.8.0
1621 *
1622 * @param string $context The usage context.
1623 * @return bool True if file modification is allowed, false otherwise.
1624 */
1625function wp_is_file_mod_allowed( $context ) {
1626 /**
1627 * Filters whether file modifications are allowed.
1628 *
1629 * @since 4.8.0
1630 *
1631 * @param bool $file_mod_allowed Whether file modifications are allowed.
1632 * @param string $context The usage context.
1633 */
1634 return apply_filters( 'file_mod_allowed', ! defined( 'DISALLOW_FILE_MODS' ) || ! DISALLOW_FILE_MODS, $context );
1635}
1636
1637/**
1638 * Start scraping edited file errors.
1639 *
1640 * @since 4.9.0
1641 */
1642function wp_start_scraping_edited_file_errors() {
1643 if ( ! isset( $_REQUEST['wp_scrape_key'] ) || ! isset( $_REQUEST['wp_scrape_nonce'] ) ) {
1644 return;
1645 }
1646 $key = substr( sanitize_key( wp_unslash( $_REQUEST['wp_scrape_key'] ) ), 0, 32 );
1647 $nonce = wp_unslash( $_REQUEST['wp_scrape_nonce'] );
1648
1649 if ( get_transient( 'scrape_key_' . $key ) !== $nonce ) {
1650 echo "###### wp_scraping_result_start:$key ######";
1651 echo wp_json_encode(
1652 array(
1653 'code' => 'scrape_nonce_failure',
1654 'message' => __( 'Scrape key check failed. Please try again.' ),
1655 )
1656 );
1657 echo "###### wp_scraping_result_end:$key ######";
1658 die();
1659 }
1660 if ( ! defined( 'WP_SANDBOX_SCRAPING' ) ) {
1661 define( 'WP_SANDBOX_SCRAPING', true );
1662 }
1663 register_shutdown_function( 'wp_finalize_scraping_edited_file_errors', $key );
1664}
1665
1666/**
1667 * Finalize scraping for edited file errors.
1668 *
1669 * @since 4.9.0
1670 *
1671 * @param string $scrape_key Scrape key.
1672 */
1673function wp_finalize_scraping_edited_file_errors( $scrape_key ) {
1674 $error = error_get_last();
1675 echo "\n###### wp_scraping_result_start:$scrape_key ######\n";
1676 if ( ! empty( $error ) && in_array( $error['type'], array( E_CORE_ERROR, E_COMPILE_ERROR, E_ERROR, E_PARSE, E_USER_ERROR, E_RECOVERABLE_ERROR ), true ) ) {
1677 $error = str_replace( ABSPATH, '', $error );
1678 echo wp_json_encode( $error );
1679 } else {
1680 echo wp_json_encode( true );
1681 }
1682 echo "\n###### wp_scraping_result_end:$scrape_key ######\n";
1683}
1684
1685/**
1686 * Checks whether current request is a JSON request, or is expecting a JSON response.
1687 *
1688 * @since 5.0.0
1689 *
1690 * @return bool True if `Accepts` or `Content-Type` headers contain `application/json`.
1691 * False otherwise.
1692 */
1693function wp_is_json_request() {
1694
1695 if ( isset( $_SERVER['HTTP_ACCEPT'] ) && wp_is_json_media_type( $_SERVER['HTTP_ACCEPT'] ) ) {
1696 return true;
1697 }
1698
1699 if ( isset( $_SERVER['CONTENT_TYPE'] ) && wp_is_json_media_type( $_SERVER['CONTENT_TYPE'] ) ) {
1700 return true;
1701 }
1702
1703 return false;
1704
1705}
1706
1707/**
1708 * Checks whether current request is a JSONP request, or is expecting a JSONP response.
1709 *
1710 * @since 5.2.0
1711 *
1712 * @return bool True if JSONP request, false otherwise.
1713 */
1714function wp_is_jsonp_request() {
1715 if ( ! isset( $_GET['_jsonp'] ) ) {
1716 return false;
1717 }
1718
1719 if ( ! function_exists( 'wp_check_jsonp_callback' ) ) {
1720 require_once ABSPATH . WPINC . '/functions.php';
1721 }
1722
1723 $jsonp_callback = $_GET['_jsonp'];
1724 if ( ! wp_check_jsonp_callback( $jsonp_callback ) ) {
1725 return false;
1726 }
1727
1728 /** This filter is documented in wp-includes/rest-api/class-wp-rest-server.php */
1729 $jsonp_enabled = apply_filters( 'rest_jsonp_enabled', true );
1730
1731 return $jsonp_enabled;
1732
1733}
1734
1735/**
1736 * Checks whether a string is a valid JSON Media Type.
1737 *
1738 * @since 5.6.0
1739 *
1740 * @param string $media_type A Media Type string to check.
1741 * @return bool True if string is a valid JSON Media Type.
1742 */
1743function wp_is_json_media_type( $media_type ) {
1744 static $cache = array();
1745
1746 if ( ! isset( $cache[ $media_type ] ) ) {
1747 $cache[ $media_type ] = (bool) preg_match( '/(^|\s|,)application\/([\w!#\$&-\^\.\+]+\+)?json(\+oembed)?($|\s|;|,)/i', $media_type );
1748 }
1749
1750 return $cache[ $media_type ];
1751}
1752
1753/**
1754 * Checks whether current request is an XML request, or is expecting an XML response.
1755 *
1756 * @since 5.2.0
1757 *
1758 * @return bool True if `Accepts` or `Content-Type` headers contain `text/xml`
1759 * or one of the related MIME types. False otherwise.
1760 */
1761function wp_is_xml_request() {
1762 $accepted = array(
1763 'text/xml',
1764 'application/rss+xml',
1765 'application/atom+xml',
1766 'application/rdf+xml',
1767 'text/xml+oembed',
1768 'application/xml+oembed',
1769 );
1770
1771 if ( isset( $_SERVER['HTTP_ACCEPT'] ) ) {
1772 foreach ( $accepted as $type ) {
1773 if ( false !== strpos( $_SERVER['HTTP_ACCEPT'], $type ) ) {
1774 return true;
1775 }
1776 }
1777 }
1778
1779 if ( isset( $_SERVER['CONTENT_TYPE'] ) && in_array( $_SERVER['CONTENT_TYPE'], $accepted, true ) ) {
1780 return true;
1781 }
1782
1783 return false;
1784}
1785
1786/**
1787 * Checks if this site is protected by HTTP Basic Auth.
1788 *
1789 * At the moment, this merely checks for the present of Basic Auth credentials. Therefore, calling
1790 * this function with a context different from the current context may give inaccurate results.
1791 * In a future release, this evaluation may be made more robust.
1792 *
1793 * Currently, this is only used by Application Passwords to prevent a conflict since it also utilizes
1794 * Basic Auth.
1795 *
1796 * @since 5.6.1
1797 *
1798 * @global string $pagenow The filename of the current screen.
1799 *
1800 * @param string $context The context to check for protection. Accepts 'login', 'admin', and 'front'.
1801 * Defaults to the current context.
1802 * @return bool Whether the site is protected by Basic Auth.
1803 */
1804function wp_is_site_protected_by_basic_auth( $context = '' ) {
1805 global $pagenow;
1806
1807 if ( ! $context ) {
1808 if ( 'wp-login.php' === $pagenow ) {
1809 $context = 'login';
1810 } elseif ( is_admin() ) {
1811 $context = 'admin';
1812 } else {
1813 $context = 'front';
1814 }
1815 }
1816
1817 $is_protected = ! empty( $_SERVER['PHP_AUTH_USER'] ) || ! empty( $_SERVER['PHP_AUTH_PW'] );
1818
1819 /**
1820 * Filters whether a site is protected by HTTP Basic Auth.
1821 *
1822 * @since 5.6.1
1823 *
1824 * @param bool $is_protected Whether the site is protected by Basic Auth.
1825 * @param string $context The context to check for protection. One of 'login', 'admin', or 'front'.
1826 */
1827 return apply_filters( 'wp_is_site_protected_by_basic_auth', $is_protected, $context );
1828}