Make WordPress Core

Ticket #57553: load.php

File load.php, 49.9 KB (added by mahbubmr500, 2 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}