wp_config = new WP_Config_Transformer; // already in the DLM\Classes namespace, so, no need to repeat } /** * Get status of WP_DEBUG * * @since 1.0.0 */ public function get_status() { // If non-existent, create an empty index to prevent directory browsing and download of the debug log file $uploads_path = wp_upload_dir()['basedir'] . '/debug-log-manager'; if ( ! is_file( $uploads_path . '/index.php' ) ) { file_put_contents( $uploads_path . '/index.php', '' . esc_html__( 'Error Logging', 'debug-log-manager' ) . ': ' . ucfirst( esc_html__( 'enabled', 'debug-log-manager' ) ) . ' ' . esc_html__( 'on', 'debug-log-manager' ) . ' ' . esc_html( $date_time ) . ''; } elseif ( 'disabled' == $status ) { return '
' . esc_html__( 'Error Logging', 'debug-log-manager' ) . ': ' . ucfirst( esc_html__( 'disabled', 'debug-log-manager' ) ) . ' ' . esc_html__( 'on', 'debug-log-manager' ) . ' ' . esc_html( $date_time ) . '
'; } else {} } /** * Get log auto-refresh status * * @since 1.3.0 */ public function get_autorefresh_status() { if ( false !== get_option( 'debug_log_manager_autorefresh' ) ) { $autorefresh_status = get_option( 'debug_log_manager_autorefresh' ); } else { $autorefresh_status = 'disabled'; update_option( 'debug_log_manager_autorefresh', $autorefresh_status, false ); } if ( 'enabled' == $autorefresh_status ) { return '
Auto-Refresh: ' . ucfirst( esc_html__( 'enabled', 'debug-log-manager' ) ) . '
'; } elseif ( 'disabled' == $autorefresh_status ) { return '
Auto-Refresh: ' . ucfirst( esc_html__( 'disabled', 'debug-log-manager' ) ) . '
'; } } /** * Enable / disable WP_DEBUG * * @since 1.0.0 */ public function toggle_debugging() { if ( isset( $_REQUEST ) && current_user_can( 'manage_options' ) ) { if ( wp_verify_nonce( sanitize_text_field( $_REQUEST['nonce'] ), 'dlm-app' . get_current_user_id() ) ) { $log_info = get_option( 'debug_log_manager' ); $dlm_debug_log_file_path = get_option( 'debug_log_manager_file_path' ); $modify_script_debug_status = get_option( 'debug_log_manager_modify_script_debug', 'enabled' ); if ( function_exists( 'wp_date' ) ) { $date_time = wp_date( 'M j, Y - H:i:s' ); // Localized according to WP timezone settings } else { $date_time = date_i18n( 'M j, Y - H:i:s' ); } $date_time_for_option = date( 'M j, Y H:i:s' ); // in UTC if ( 'disabled' == $log_info['status'] ) { $option_value = array( 'status' => 'enabled', 'on' => $date_time_for_option, ); update_option( 'debug_log_manager', $option_value, false ); // If WP_DEBUG_LOG is defined, copy content of existing debug.log file into the log file created by this plugin if ( $this->wp_config->exists( 'constant', 'WP_DEBUG_LOG' ) ) { $wp_debug_log_const = $this->wp_config->get_value( 'constant', 'WP_DEBUG_LOG' ); if ( in_array( $wp_debug_log_const, array( 'true', 'false' ), true ) ) { $wp_debug_log_const = (bool) $wp_debug_log_const; } if ( is_bool( $wp_debug_log_const ) ) { // WP_DEBUG_LOG is true or false. Log file is in default location of /wp-content/debug.log. if ( is_file( WP_CONTENT_DIR . '/debug.log' ) ) { // Copy existing debug log content to this plugin's debug log. $default_debug_log_content = file_get_contents( WP_CONTENT_DIR . '/debug.log' ); file_put_contents( $dlm_debug_log_file_path, $default_debug_log_content ); unlink( realpath( WP_CONTENT_DIR . '/debug.log' ) ); // delete existing debug log } } elseif ( is_string( $wp_debug_log_const ) ) { // WP_DEBUG_LOG is custom path to log file. Copy existing debug log content to this plugin's debug log. if ( is_file( $wp_debug_log_const ) && ( $wp_debug_log_const != $dlm_debug_log_file_path ) ) { $custom_debug_log_content = file_get_contents( $wp_debug_log_const ); file_put_contents( $dlm_debug_log_file_path, $custom_debug_log_content ); unlink( $wp_debug_log_const ); // delete existing debug log } } $copy = true; // existing debug.log file's entries are copied to this plugin's debug.log file } else { $copy = false; // existing debug.log file's entries are NOT copied to this plugin's debug.log file } $log_trimmer = new Log_Trimmer(); $log_trimmer->maybe_trim_log( $dlm_debug_log_file_path ); // Define Debug constants in wp-config.php $options = array( 'add' => true, // Add the config if missing. 'raw' => true, // Display value in raw format without quotes. 'normalize' => false, // Normalize config output using WP Coding Standards. ); $this->wp_config->update( 'constant', 'WP_DEBUG', 'true', $options ); if ( 'enabled' == $modify_script_debug_status ) { $options = array( 'add' => true, // Add the config if missing. 'raw' => true, // Display value in raw format without quotes. 'normalize' => false, // Normalize config output using WP Coding Standards. ); $this->wp_config->update( 'constant', 'SCRIPT_DEBUG', 'true', $options ); } $options = array( 'add' => true, // Add the config if missing. 'raw' => false, // Display value in raw format without quotes. 'normalize' => false, // Normalize config output using WP Coding Standards. ); $this->wp_config->update( 'constant', 'WP_DEBUG_LOG', get_option( 'debug_log_manager_file_path' ), $options ); $options = array( 'add' => true, // Add the config if missing. 'raw' => true, // Display value in raw format without quotes. 'normalize' => false, // Normalize config output using WP Coding Standards. ); $this->wp_config->update( 'constant', 'WP_DEBUG_DISPLAY', 'false', $options ); $options = array( 'add' => true, // Add the config if missing. 'raw' => true, // Display value in raw format without quotes. 'normalize' => false, // Normalize config output using WP Coding Standards. ); $this->wp_config->update( 'constant', 'DISALLOW_FILE_EDIT', 'false', $options ); // Get the debug.log file size $log_file_path = get_option( 'debug_log_manager_file_path' ); $log_file_shortpath = str_replace( sanitize_text_field( $_SERVER['DOCUMENT_ROOT'] ), "", $log_file_path ); $file_size = size_format( (int) filesize( $log_file_path ) ); // Prepare entries from the debug log for the data table $errors_master_list = json_decode( $this->get_processed_entries(), true ); $n = 1; $entries = array(); foreach ( $errors_master_list as $error ) { if ( function_exists( 'wp_date' ) ) { $localized_timestamp = wp_date( 'M j, Y - H:i:s', strtotime( $error['occurrences'][0] ) ); // last occurrence } else { $localized_timestamp = date_i18n( 'M j, Y - H:i:s', strtotime( $error['occurrences'][0] ) ); } $occurrence_count = count( $error['occurrences'] ); $entry = array( $n, $error['type'], $error['details'], $localized_timestamp . '
(' . sprintf( _n( '%s occurrence logged', '%s occurrences logged', $occurrence_count, 'debug-log-manager' ), number_format_i18n( $occurrence_count ) ) . ')', ); $entries[] = $entry; $n++; } // Assemble data to return $data = array( 'status' => 'enabled', 'copy' => $copy, 'message' => '' . esc_html__( 'Error Logging', 'debug-log-manager' ) . ': ' . esc_html__( 'Enabled on', 'debug-log-manager' ) . ' ' . esc_html( $date_time ), 'entries' => $entries, 'size' => $file_size, ); echo json_encode( $data ); } elseif ( 'enabled' == $log_info['status'] ) { $option_value = array( 'status' => 'disabled', 'on' => $date_time_for_option, ); update_option( 'debug_log_manager', $option_value, false ); // Remove Debug constants in wp-config.php $this->wp_config->remove( 'constant', 'WP_DEBUG' ); if ( 'enabled' == $modify_script_debug_status ) { $this->wp_config->remove( 'constant', 'SCRIPT_DEBUG' ); } $this->wp_config->remove( 'constant', 'WP_DEBUG_LOG' ); $this->wp_config->remove( 'constant', 'WP_DEBUG_DISPLAY' ); $this->wp_config->remove( 'constant', 'DISALLOW_FILE_EDIT' ); // Assemble data to return $data = array( 'status' => 'disabled', 'copy' => false, 'message' => '' . esc_html__( 'Error Logging', 'debug-log-manager' ) . ': ' . esc_html__( 'Disabled on', 'debug-log-manager' ) . ' ' . esc_html( $date_time ), 'entries' => '', 'size' => '', ); echo json_encode( $data ); } else {} } } } /** * Toggle auto-refresh of entries table * * @since 1.3.0 */ public function toggle_autorefresh() { if ( isset( $_REQUEST ) && current_user_can( 'manage_options' ) ) { if ( wp_verify_nonce( sanitize_text_field( $_REQUEST['nonce'] ), 'dlm-app' . get_current_user_id() ) ) { $autorefresh_status = get_option( 'debug_log_manager_autorefresh' ); if ( $autorefresh_status == 'disabled' ) { update_option( 'debug_log_manager_autorefresh', 'enabled', false ); $data = array( 'status' => 'enabled', 'message' => '' . esc_html__( 'Auto-Refresh', 'debug-log-manager' ) . ': ' . esc_html__( 'Enabled', 'debug-log-manager' ), ); echo json_encode( $data ); } elseif ( $autorefresh_status == 'enabled' ) { update_option( 'debug_log_manager_autorefresh', 'disabled', false ); $data = array( 'status' => 'disabled', 'message' => '' . esc_html__( 'Auto-Refresh', 'debug-log-manager' ) . ': ' . esc_html__( 'Disabled', 'debug-log-manager' ), ); echo json_encode( $data ); } else {} } } } /** * Toggle JS error logging status * * @since 1.3.0 */ public function toggle_js_error_logging() { if ( isset( $_REQUEST ) && current_user_can( 'manage_options' ) ) { if ( wp_verify_nonce( sanitize_text_field( $_REQUEST['nonce'] ), 'dlm-app' . get_current_user_id() ) ) { $js_error_logging_status = get_option( 'debug_log_manager_js_error_logging', 'enabled' ); if ( $js_error_logging_status == 'disabled' ) { update_option( 'debug_log_manager_js_error_logging', 'enabled', false ); $data = array( 'status' => 'enabled', ); echo json_encode( $data ); } elseif ( $js_error_logging_status == 'enabled' ) { update_option( 'debug_log_manager_js_error_logging', 'disabled', false ); $data = array( 'status' => 'disabled', ); echo json_encode( $data ); } else {} } } } /** * Toggle SCRIPT_DEBUG modification status * * @since 1.3.0 */ public function toggle_script_debug_modification_status() { if ( isset( $_REQUEST ) && current_user_can( 'manage_options' ) ) { if ( wp_verify_nonce( sanitize_text_field( $_REQUEST['nonce'] ), 'dlm-app' . get_current_user_id() ) ) { $modify_script_debug_status = get_option( 'debug_log_manager_modify_script_debug', 'enabled' ); if ( $modify_script_debug_status == 'disabled' ) { update_option( 'debug_log_manager_modify_script_debug', 'enabled', false ); $data = array( 'status' => 'enabled', ); echo json_encode( $data ); } elseif ( $modify_script_debug_status == 'enabled' ) { update_option( 'debug_log_manager_modify_script_debug', 'disabled', false ); $data = array( 'status' => 'disabled', ); echo json_encode( $data ); } else {} } } } /** * Toggle processing non-UTC timezones status * * @since 1.3.0 */ public function toggle_process_non_utc_timezones_status() { if ( isset( $_REQUEST ) && current_user_can( 'manage_options' ) ) { if ( wp_verify_nonce( sanitize_text_field( $_REQUEST['nonce'] ), 'dlm-app' . get_current_user_id() ) ) { $process_non_utc_timezones_status = get_option( 'debug_log_manager_process_non_utc_timezones', 'enabled' ); if ( $process_non_utc_timezones_status == 'disabled' ) { update_option( 'debug_log_manager_process_non_utc_timezones', 'enabled', false ); $data = array( 'status' => 'enabled', ); echo json_encode( $data ); } elseif ( $process_non_utc_timezones_status == 'enabled' ) { update_option( 'debug_log_manager_process_non_utc_timezones', 'disabled', false ); $data = array( 'status' => 'disabled', ); echo json_encode( $data ); } else {} } } } /** * Get the processed debug log data * * @return string $errors_master_list The processed error log entries * @since 1.2.0 */ public function get_processed_entries() { // Paths with no trailing slash (/) $wp_admin_path = ABSPATH . 'wp-admin'; $wp_includes_path = ABSPATH . 'wp-includes'; $theme_dir_path = get_theme_root(); $wp_plugin_dir_path = WP_PLUGIN_DIR; $debug_log_file_path = get_option( 'debug_log_manager_file_path' ); $process_non_utc_timezones_status = get_option( 'debug_log_manager_process_non_utc_timezones', 'enabled' ); $log_trimmer = new Log_Trimmer(); $log_trimmer->maybe_trim_log( $debug_log_file_path ); // Read the errors log file $log = file_get_contents( $debug_log_file_path ); // Ignore words between square brackets, // e.g. [DEBUG], [INFO], [WARNING], [ERROR] may come after timestamp [29-Nov-2023 01:30:03 UTC] // This regex will extract DEBUG, INFO, WARNING, ERROR // Prevents log entry with two bracket sets e.g. [timestamp] [someinfo] Details.... // from being returned as "No error message specified" $log = preg_replace("/\[([a-zA-Z\s\-]+)\]/", "$1", $log); $log = str_replace( "[\\", "^\\", $log ); // certain error message contains the '[\' string, which will make the following split via explode() to split lines at places in the message it's not supposed to. So, we temporarily replace those with '^\' $log = str_replace( "[\"", "^\"", $log ); // certain error message contains the '["' string, which will make the following split via explode() to split lines at places in the message it's not supposed to. So, we temporarily replace those with '^"' $log = str_replace( ":[", ":^", $log ); // certain error message contains the ':[' string, which will make the following split via explode() to split lines at places in the message it's not supposed to. So, we temporarily replace those with '^"' $log = str_replace( "[internal function]", "^internal function^", $log ); // We are splitting the log file not using PHP_EOL to preserve the stack traces for PHP Fatal Errors among other things $lines = explode("[", $log); $prepended_lines = array(); // Pluck out the last 100k entries, the newest entry is last // To pluck out the first 100000 entries, use array_slice( $lines, 0, 100000 ) $lines = array_slice( $lines, -100000 ); foreach ( $lines as $line ) { if ( ! empty( $line ) ) { $timezone_strings_to_replace = array( 'UTC]', 'Abidjan]', 'Accra]', 'Addis_Ababa]', 'Algiers]', 'Asmara]', 'Bamako]', 'Bangui]', 'Banjul]', 'Bissau]', 'Blantyre]', 'Brazzaville]', 'Bujumbura]', 'Cairo]', 'Casablanca]', 'Ceuta]', 'Conakry]', 'Dakar]', 'Dar_es_Salaam]', 'Djibouti]', 'Douala]', 'El_Aaiun]', 'Freetown]', 'Gaborone]', 'Harare]', 'Johannesburg]', 'Juba]', 'Kampala]', 'Khartoum]', 'Kigali]', 'Kinshasa]', 'Lagos]', 'Libreville]', 'Lome]', 'Luanda]', 'Lubumbashi]', 'Lusaka]', 'Malabo]', 'Maputo]', 'Maseru]', 'Mbabane]', 'Mogadishu]', 'Monrovia]', 'Nairobi]', 'Ndjamena]', 'Niamey]', 'Nouakchott]', 'Ouagadougou]', 'Porto-Novo]', 'Sao_Tome]', 'Tripoli]', 'Tunis]', 'Windhoek]', 'Adak]', 'Anchorage]', 'Anguilla]', 'Antigua]', 'Araguaina]', 'Argentina/Buenos_Aires]', 'Argentina/Catamarca]', 'Argentina/Cordoba]', 'Argentina/Jujuy]', 'Argentina/La_Rioja]', 'Argentina/Mendoza]', 'Argentina/Rio_Gallegos]', 'Argentina/Salta]', 'Argentina/San_Juan]', 'Argentina/San_Luis]', 'Argentina/Tucuman]', 'Argentina/Ushuaia]', 'Aruba]', 'Asuncion]', 'Atikokan]', 'Bahia]', 'Bahia_Banderas]', 'Barbados]', 'Belem]', 'Belize]', 'Blanc-Sablon]', 'Boa_Vista]', 'Bogota]', 'Boise]', 'Cambridge_Bay]', 'Campo_Grande]', 'Cancun]', 'Caracas]', 'Cayenne]', 'Cayman]', 'Chicago]', 'Chihuahua]', 'Ciudad_Juarez]', 'Costa_Rica]', 'Coyhaique]', 'Creston]', 'Cuiaba]', 'Curacao]', 'Danmarkshavn]', 'Dawson]', 'Dawson_Creek]', 'Denver]', 'Detroit]', 'Dominica]', 'Edmonton]', 'Eirunepe]', 'El_Salvador]', 'Fort_Nelson]', 'Fortaleza]', 'Glace_Bay]', 'Goose_Bay]', 'Grand_Turk]', 'Grenada]', 'Guadeloupe]', 'Guatemala]', 'Guayaquil]', 'Guyana]', 'Halifax]', 'Havana]', 'Hermosillo]', 'Indiana/Indianapolis]', 'Indiana/Knox]', 'Indiana/Marengo]', 'Indiana/Petersburg]', 'Indiana/Tell_City]', 'Indiana/Vevay]', 'Indiana/Vincennes]', 'Indiana/Winamac]', 'Inuvik]', 'Iqaluit]', 'Jamaica]', 'Juneau]', 'Kentucky/Louisville]', 'Kentucky/Monticello]', 'Kralendijk]', 'La_Paz]', 'Lima]', 'Los_Angeles]', 'Lower_Princes]', 'Maceio]', 'Managua]', 'Manaus]', 'Marigot]', 'Martinique]', 'Matamoros]', 'Mazatlan]', 'Menominee]', 'Merida]', 'Metlakatla]', 'Mexico_City]', 'Miquelon]', 'Moncton]', 'Monterrey]', 'Montevideo]', 'Montserrat]', 'Nassau]', 'New_York]', 'Nome]', 'Noronha]', 'North_Dakota/Beulah]', 'North_Dakota/Center]', 'North_Dakota/New_Salem]', 'Nuuk]', 'Ojinaga]', 'Panama]', 'Paramaribo]', 'Phoenix]', 'Port-au-Prince]', 'Port_of_Spain]', 'Porto_Velho]', 'Puerto_Rico]', 'Punta_Arenas]', 'Rankin_Inlet]', 'Recife]', 'Regina]', 'Resolute]', 'Rio_Branco]', 'Santarem]', 'Santiago]', 'Santo_Domingo]', 'Sao_Paulo]', 'Scoresbysund]', 'Sitka]', 'St_Barthelemy]', 'St_Johns]', 'St_Kitts]', 'St_Lucia]', 'St_Thomas]', 'St_Vincent]', 'Swift_Current]', 'Tegucigalpa]', 'Thule]', 'Tijuana]', 'Toronto]', 'Tortola]', 'Vancouver]', 'Whitehorse]', 'Winnipeg]', 'Yakutat]', 'Casey]', 'Davis]', 'DumontDUrville]', 'Macquarie]', 'Mawson]', 'McMurdo]', 'Palmer]', 'Rothera]', 'Syowa]', 'Troll]', 'Vostok]', 'Longyearbyen]', 'Aden]', 'Almaty]', 'Amman]', 'Anadyr]', 'Aqtau]', 'Aqtobe]', 'Ashgabat]', 'Atyrau]', 'Baghdad]', 'Bahrain]', 'Baku]', 'Bangkok]', 'Barnaul]', 'Beirut]', 'Bishkek]', 'Brunei]', 'Chita]', 'Colombo]', 'Damascus]', 'Dhaka]', 'Dili]', 'Dubai]', 'Dushanbe]', 'Famagusta]', 'Gaza]', 'Hebron]', 'Ho_Chi_Minh]', 'Hong_Kong]', 'Hovd]', 'Irkutsk]', 'Jakarta]', 'Jayapura]', 'Jerusalem]', 'Kabul]', 'Kamchatka]', 'Karachi]', 'Kathmandu]', 'Khandyga]', 'Kolkata]', 'Krasnoyarsk]', 'Kuala_Lumpur]', 'Kuching]', 'Kuwait]', 'Macau]', 'Magadan]', 'Makassar]', 'Manila]', 'Muscat]', 'Nicosia]', 'Novokuznetsk]', 'Novosibirsk]', 'Omsk]', 'Oral]', 'Phnom_Penh]', 'Pontianak]', 'Pyongyang]', 'Qatar]', 'Qostanay]', 'Qyzylorda]', 'Riyadh]', 'Sakhalin]', 'Samarkand]', 'Seoul]', 'Shanghai]', 'Singapore]', 'Srednekolymsk]', 'Taipei]', 'Tashkent]', 'Tbilisi]', 'Tehran]', 'Thimphu]', 'Tokyo]', 'Tomsk]', 'Ulaanbaatar]', 'Urumqi]', 'Ust-Nera]', 'Vientiane]', 'Vladivostok]', 'Yakutsk]', 'Yangon]', 'Yekaterinburg]', 'Yerevan]', 'Atlantic/Azores]', 'Atlantic/Bermuda]', 'Atlantic/Canary]', 'Atlantic/Cape_Verde]', 'Atlantic/Faroe]', 'Atlantic/Madeira]', 'Atlantic/Reykjavik]', 'Atlantic/South_Georgia]', 'Atlantic/St_Helena]', 'Atlantic/Stanley]', 'Australia/Adelaide]', 'Australia/Brisbane]', 'Australia/Broken_Hill]', 'Australia/Darwin]', 'Australia/Eucla]', 'Australia/Hobart]', 'Australia/Lindeman]', 'Australia/Lord_Howe]', 'Australia/Melbourne]', 'Australia/Perth]', 'Australia/Sydney]', 'Amsterdam]', 'Andorra]', 'Astrakhan]', 'Athens]', 'Belgrade]', 'Berlin]', 'Bratislava]', 'Brussels]', 'Bucharest]', 'Budapest]', 'Busingen]', 'Chisinau]', 'Copenhagen]', 'Dublin]', 'Gibraltar]', 'Guernsey]', 'Helsinki]', 'Isle_of_Man]', 'Istanbul]', 'Jersey]', 'Kaliningrad]', 'Kirov]', 'Kyiv]', 'Lisbon]', 'Ljubljana]', 'London]', 'Luxembourg]', 'Madrid]', 'Malta]', 'Mariehamn]', 'Minsk]', 'Monaco]', 'Moscow]', 'Oslo]', 'Paris]', 'Podgorica]', 'Prague]', 'Riga]', 'Rome]', 'Samara]', 'San_Marino]', 'Sarajevo]', 'Saratov]', 'Simferopol]', 'Skopje]', 'Sofia]', 'Stockholm]', 'Tallinn]', 'Tirane]', 'Ulyanovsk]', 'Vaduz]', 'Vatican]', 'Vienna]', 'Vilnius]', 'Volgograd]', 'Warsaw]', 'Zagreb]', 'Zurich]', 'Antananarivo]', 'Chagos]', 'Christmas]', 'Cocos]', 'Comoro]', 'Kerguelen]', 'Mahe]', 'Maldives]', 'Mauritius]', 'Mayotte]', 'Reunion]', 'Apia]', 'Auckland]', 'Bougainville]', 'Chatham]', 'Chuuk]', 'Easter]', 'Efate]', 'Fakaofo]', 'Fiji]', 'Funafuti]', 'Galapagos]', 'Gambier]', 'Guadalcanal]', 'Guam]', 'Honolulu]', 'Kanton]', 'Kiritimati]', 'Kosrae]', 'Kwajalein]', 'Majuro]', 'Marquesas]', 'Midway]', 'Nauru]', 'Niue]', 'Norfolk]', 'Noumea]', 'Pago_Pago]', 'Palau]', 'Pitcairn]', 'Pohnpei]', 'Port_Moresby]', 'Rarotonga]', 'Saipan]', 'Tahiti]', 'Tarawa]', 'Tongatapu]', 'Wake]', 'Wallis]', ); $timezone_replacement_strings = array( 'UTC]@@@', 'Abidjan]@@@', 'Accra]@@@', 'Addis_Ababa]@@@', 'Algiers]@@@', 'Asmara]@@@', 'Bamako]@@@', 'Bangui]@@@', 'Banjul]@@@', 'Bissau]@@@', 'Blantyre]@@@', 'Brazzaville]@@@', 'Bujumbura]@@@', 'Cairo]@@@', 'Casablanca]@@@', 'Ceuta]@@@', 'Conakry]@@@', 'Dakar]@@@', 'Dar_es_Salaam]@@@', 'Djibouti]@@@', 'Douala]@@@', 'El_Aaiun]@@@', 'Freetown]@@@', 'Gaborone]@@@', 'Harare]@@@', 'Johannesburg]@@@', 'Juba]@@@', 'Kampala]@@@', 'Khartoum]@@@', 'Kigali]@@@', 'Kinshasa]@@@', 'Lagos]@@@', 'Libreville]@@@', 'Lome]@@@', 'Luanda]@@@', 'Lubumbashi]@@@', 'Lusaka]@@@', 'Malabo]@@@', 'Maputo]@@@', 'Maseru]@@@', 'Mbabane]@@@', 'Mogadishu]@@@', 'Monrovia]@@@', 'Nairobi]@@@', 'Ndjamena]@@@', 'Niamey]@@@', 'Nouakchott]@@@', 'Ouagadougou]@@@', 'Porto-Novo]@@@', 'Sao_Tome]@@@', 'Tripoli]@@@', 'Tunis]@@@', 'Windhoek]@@@', 'Adak]@@@', 'Anchorage]@@@', 'Anguilla]@@@', 'Antigua]@@@', 'Araguaina]@@@', 'Argentina/Buenos_Aires]@@@', 'Argentina/Catamarca]@@@', 'Argentina/Cordoba]@@@', 'Argentina/Jujuy]@@@', 'Argentina/La_Rioja]@@@', 'Argentina/Mendoza]@@@', 'Argentina/Rio_Gallegos]@@@', 'Argentina/Salta]@@@', 'Argentina/San_Juan]@@@', 'Argentina/San_Luis]@@@', 'Argentina/Tucuman]@@@', 'Argentina/Ushuaia]@@@', 'Aruba]@@@', 'Asuncion]@@@', 'Atikokan]@@@', 'Bahia]@@@', 'Bahia_Banderas]@@@', 'Barbados]@@@', 'Belem]@@@', 'Belize]@@@', 'Blanc-Sablon]@@@', 'Boa_Vista]@@@', 'Bogota]@@@', 'Boise]@@@', 'Cambridge_Bay]@@@', 'Campo_Grande]@@@', 'Cancun]@@@', 'Caracas]@@@', 'Cayenne]@@@', 'Cayman]@@@', 'Chicago]@@@', 'Chihuahua]@@@', 'Ciudad_Juarez]@@@', 'Costa_Rica]@@@', 'Coyhaique]@@@', 'Creston]@@@', 'Cuiaba]@@@', 'Curacao]@@@', 'Danmarkshavn]@@@', 'Dawson]@@@', 'Dawson_Creek]@@@', 'Denver]@@@', 'Detroit]@@@', 'Dominica]@@@', 'Edmonton]@@@', 'Eirunepe]@@@', 'El_Salvador]@@@', 'Fort_Nelson]@@@', 'Fortaleza]@@@', 'Glace_Bay]@@@', 'Goose_Bay]@@@', 'Grand_Turk]@@@', 'Grenada]@@@', 'Guadeloupe]@@@', 'Guatemala]@@@', 'Guayaquil]@@@', 'Guyana]@@@', 'Halifax]@@@', 'Havana]@@@', 'Hermosillo]@@@', 'Indiana/Indianapolis]@@@', 'Indiana/Knox]@@@', 'Indiana/Marengo]@@@', 'Indiana/Petersburg]@@@', 'Indiana/Tell_City]@@@', 'Indiana/Vevay]@@@', 'Indiana/Vincennes]@@@', 'Indiana/Winamac]@@@', 'Inuvik]@@@', 'Iqaluit]@@@', 'Jamaica]@@@', 'Juneau]@@@', 'Kentucky/Louisville]@@@', 'Kentucky/Monticello]@@@', 'Kralendijk]@@@', 'La_Paz]@@@', 'Lima]@@@', 'Los_Angeles]@@@', 'Lower_Princes]@@@', 'Maceio]@@@', 'Managua]@@@', 'Manaus]@@@', 'Marigot]@@@', 'Martinique]@@@', 'Matamoros]@@@', 'Mazatlan]@@@', 'Menominee]@@@', 'Merida]@@@', 'Metlakatla]@@@', 'Mexico_City]@@@', 'Miquelon]@@@', 'Moncton]@@@', 'Monterrey]@@@', 'Montevideo]@@@', 'Montserrat]@@@', 'Nassau]@@@', 'New_York]@@@', 'Nome]@@@', 'Noronha]@@@', 'North_Dakota/Beulah]@@@', 'North_Dakota/Center]@@@', 'North_Dakota/New_Salem]@@@', 'Nuuk]@@@', 'Ojinaga]@@@', 'Panama]@@@', 'Paramaribo]@@@', 'Phoenix]@@@', 'Port-au-Prince]@@@', 'Port_of_Spain]@@@', 'Porto_Velho]@@@', 'Puerto_Rico]@@@', 'Punta_Arenas]@@@', 'Rankin_Inlet]@@@', 'Recife]@@@', 'Regina]@@@', 'Resolute]@@@', 'Rio_Branco]@@@', 'Santarem]@@@', 'Santiago]@@@', 'Santo_Domingo]@@@', 'Sao_Paulo]@@@', 'Scoresbysund]@@@', 'Sitka]@@@', 'St_Barthelemy]@@@', 'St_Johns]@@@', 'St_Kitts]@@@', 'St_Lucia]@@@', 'St_Thomas]@@@', 'St_Vincent]@@@', 'Swift_Current]@@@', 'Tegucigalpa]@@@', 'Thule]@@@', 'Tijuana]@@@', 'Toronto]@@@', 'Tortola]@@@', 'Vancouver]@@@', 'Whitehorse]@@@', 'Winnipeg]@@@', 'Yakutat]@@@', 'Casey]@@@', 'Davis]@@@', 'DumontDUrville]@@@', 'Macquarie]@@@', 'Mawson]@@@', 'McMurdo]@@@', 'Palmer]@@@', 'Rothera]@@@', 'Syowa]@@@', 'Troll]@@@', 'Vostok]@@@', 'Longyearbyen]@@@', 'Aden]@@@', 'Almaty]@@@', 'Amman]@@@', 'Anadyr]@@@', 'Aqtau]@@@', 'Aqtobe]@@@', 'Ashgabat]@@@', 'Atyrau]@@@', 'Baghdad]@@@', 'Bahrain]@@@', 'Baku]@@@', 'Bangkok]@@@', 'Barnaul]@@@', 'Beirut]@@@', 'Bishkek]@@@', 'Brunei]@@@', 'Chita]@@@', 'Colombo]@@@', 'Damascus]@@@', 'Dhaka]@@@', 'Dili]@@@', 'Dubai]@@@', 'Dushanbe]@@@', 'Famagusta]@@@', 'Gaza]@@@', 'Hebron]@@@', 'Ho_Chi_Minh]@@@', 'Hong_Kong]@@@', 'Hovd]@@@', 'Irkutsk]@@@', 'Jakarta]@@@', 'Jayapura]@@@', 'Jerusalem]@@@', 'Kabul]@@@', 'Kamchatka]@@@', 'Karachi]@@@', 'Kathmandu]@@@', 'Khandyga]@@@', 'Kolkata]@@@', 'Krasnoyarsk]@@@', 'Kuala_Lumpur]@@@', 'Kuching]@@@', 'Kuwait]@@@', 'Macau]@@@', 'Magadan]@@@', 'Makassar]@@@', 'Manila]@@@', 'Muscat]@@@', 'Nicosia]@@@', 'Novokuznetsk]@@@', 'Novosibirsk]@@@', 'Omsk]@@@', 'Oral]@@@', 'Phnom_Penh]@@@', 'Pontianak]@@@', 'Pyongyang]@@@', 'Qatar]@@@', 'Qostanay]@@@', 'Qyzylorda]@@@', 'Riyadh]@@@', 'Sakhalin]@@@', 'Samarkand]@@@', 'Seoul]@@@', 'Shanghai]@@@', 'Singapore]@@@', 'Srednekolymsk]@@@', 'Taipei]@@@', 'Tashkent]@@@', 'Tbilisi]@@@', 'Tehran]@@@', 'Thimphu]@@@', 'Tokyo]@@@', 'Tomsk]@@@', 'Ulaanbaatar]@@@', 'Urumqi]@@@', 'Ust-Nera]@@@', 'Vientiane]@@@', 'Vladivostok]@@@', 'Yakutsk]@@@', 'Yangon]@@@', 'Yekaterinburg]@@@', 'Yerevan]@@@', 'Atlantic/Azores]@@@', 'Atlantic/Bermuda]@@@', 'Atlantic/Canary]@@@', 'Atlantic/Cape_Verde]@@@', 'Atlantic/Faroe]@@@', 'Atlantic/Madeira]@@@', 'Atlantic/Reykjavik]@@@', 'Atlantic/South_Georgia]@@@', 'Atlantic/St_Helena]@@@', 'Atlantic/Stanley]@@@', 'Australia/Adelaide]@@@', 'Australia/Brisbane]@@@', 'Australia/Broken_Hill]@@@', 'Australia/Darwin]@@@', 'Australia/Eucla]@@@', 'Australia/Hobart]@@@', 'Australia/Lindeman]@@@', 'Australia/Lord_Howe]@@@', 'Australia/Melbourne]@@@', 'Australia/Perth]@@@', 'Australia/Sydney]@@@', 'Amsterdam]@@@', 'Andorra]@@@', 'Astrakhan]@@@', 'Athens]@@@', 'Belgrade]@@@', 'Berlin]@@@', 'Bratislava]@@@', 'Brussels]@@@', 'Bucharest]@@@', 'Budapest]@@@', 'Busingen]@@@', 'Chisinau]@@@', 'Copenhagen]@@@', 'Dublin]@@@', 'Gibraltar]@@@', 'Guernsey]@@@', 'Helsinki]@@@', 'Isle_of_Man]@@@', 'Istanbul]@@@', 'Jersey]@@@', 'Kaliningrad]@@@', 'Kirov]@@@', 'Kyiv]@@@', 'Lisbon]@@@', 'Ljubljana]@@@', 'London]@@@', 'Luxembourg]@@@', 'Madrid]@@@', 'Malta]@@@', 'Mariehamn]@@@', 'Minsk]@@@', 'Monaco]@@@', 'Moscow]@@@', 'Oslo]@@@', 'Paris]@@@', 'Podgorica]@@@', 'Prague]@@@', 'Riga]@@@', 'Rome]@@@', 'Samara]@@@', 'San_Marino]@@@', 'Sarajevo]@@@', 'Saratov]@@@', 'Simferopol]@@@', 'Skopje]@@@', 'Sofia]@@@', 'Stockholm]@@@', 'Tallinn]@@@', 'Tirane]@@@', 'Ulyanovsk]@@@', 'Vaduz]@@@', 'Vatican]@@@', 'Vienna]@@@', 'Vilnius]@@@', 'Volgograd]@@@', 'Warsaw]@@@', 'Zagreb]@@@', 'Zurich]@@@', 'Antananarivo]@@@', 'Chagos]@@@', 'Christmas]@@@', 'Cocos]@@@', 'Comoro]@@@', 'Kerguelen]@@@', 'Mahe]@@@', 'Maldives]@@@', 'Mauritius]@@@', 'Mayotte]@@@', 'Reunion]@@@', 'Apia]@@@', 'Auckland]@@@', 'Bougainville]@@@', 'Chatham]@@@', 'Chuuk]@@@', 'Easter]@@@', 'Efate]@@@', 'Fakaofo]@@@', 'Fiji]@@@', 'Funafuti]@@@', 'Galapagos]@@@', 'Gambier]@@@', 'Guadalcanal]@@@', 'Guam]@@@', 'Honolulu]@@@', 'Kanton]@@@', 'Kiritimati]@@@', 'Kosrae]@@@', 'Kwajalein]@@@', 'Majuro]@@@', 'Marquesas]@@@', 'Midway]@@@', 'Nauru]@@@', 'Niue]@@@', 'Norfolk]@@@', 'Noumea]@@@', 'Pago_Pago]@@@', 'Palau]@@@', 'Pitcairn]@@@', 'Pohnpei]@@@', 'Port_Moresby]@@@', 'Rarotonga]@@@', 'Saipan]@@@', 'Tahiti]@@@', 'Tarawa]@@@', 'Tongatapu]@@@', 'Wake]@@@', 'Wallis]@@@', ); if ( 'enabled' == $process_non_utc_timezones_status ) { $line = str_replace( $timezone_strings_to_replace, $timezone_replacement_strings, $line ); // add '@@@' as marker/separator after time stamp } else { $line = str_replace( 'UTC]', 'UTC]@@@', $line ); // add '@@@' as marker/separator after time stamp } $line = str_replace( "Stack trace:", "
Stack trace:", $line ); // add line break for stack trace section if ( strpos( $line, 'PHP Fatal' ) !== false ) { $line = str_replace( "#", "
#", $line ); // add line break on PHP Fatal error's stack trace lines } $line = str_replace( "Argument
#", "Argument #", $line ); // remove hr on certain error message $line = str_replace( "parameter
#", "parameter #", $line ); // remove hr on certain error message $line = str_replace( "the
#", "the #", $line ); // remove hr on certain error message $line = str_replace( "^\\", "[\\", $line ); // reverse the temporary replacement of '[\' with '^\' $line = str_replace( "^\"", "[\"", $line ); // reverse the temporary replacement of '["' with '^"' $line = str_replace( ":^", ":[", $line ); // reverse the temporary replacement of '[]' with '$#' $line = str_replace( "^internal function^", "[internal function]", $line ); $prepended_line = '[' . $line; // Put back the missing '[' after explode operation $prepended_lines[] = $prepended_line; } } // Reverse the order of the entries, so the newest entry is first $latest_lines = array_reverse( $prepended_lines ); // Will hold error details types $errors_master_list = array(); foreach( $latest_lines as $line ) { $line = wp_kses_post( $line ); if ( false !== strpos( $line, '@@@' ) ) { $line = explode("@@@ ", trim( $line ) ); // split the line using the '@@@' marker/separator defined earlier. '@@@' will be deleted by explode(). } if ( is_array( $line ) && isset( $line[0] ) ) { $timestamp = str_replace( [ "[", "]" ], "", $line[0] ); } else { $timestamp = ''; } $wp_version = get_bloginfo( 'version' ); // Initialize error-related variables $error = ''; $error_source = ''; $error_source_key = ''; $error_file = ''; $error_file_path = ''; $error_file_line = ''; $error_file_directory = ''; $error_source_plugin_path_file = ''; $error_source_plugin_name = ''; $error_source_plugin_uri = ''; $error_source_theme_dir = ''; $error_source_theme_name = ''; $error_source_theme_uri = ''; if ( is_array( $line ) && isset( $line[1] ) ) { $error = $line[1]; // Check if there is a file path to pluck out of the error line if ( false !== strpos( $error, ABSPATH ) ) { // Separata file path and error line from error message // Handling for PHP Fatal errors with stack trace included if ( false !== strpos( $error, 'Stack trace:' ) ) { $error_parts = explode( 'Stack trace:', $error ); $error_message = str_replace( '
', '', $error_parts[0] ); if ( isset( $error_parts[1] ) ) { $error_stack_trace = ' ' . $error_parts[1]; } $error_message_parts = explode( ' in /', $error_message ); // Reconstruct the error details without error file path and line info $error = $error_message_parts[0] . '
Stack trace:' . $error_stack_trace; // Shorten the file path in the error details $error = str_replace( ABSPATH, '/', $error ); if ( isset( $error_message_parts[1] ) ) { $error_file = '/' . $error_message_parts[1]; $error_file_info = explode ( ':', $error_file ); $error_file_path = $error_file_info[0]; if ( array_key_exists('1', $error_file_info) ) { $error_file_line = $error_file_info[1]; } } } else { $error_message_parts = explode( ' in /', $error ); $error = $error_message_parts[0]; if ( isset( $error_message_parts[1] ) ) { $error_file = '/' . $error_message_parts[1]; $error_file_info = explode ( ' on line ', $error_file ); $error_file_path = $error_file_info[0]; if ( array_key_exists('1', $error_file_info) ) { $error_file_line = $error_file_info[1]; } } } // Define whether source of error is WP Core, Theme, Plugin or Other if ( ( false !== strpos( $error_file_path, $wp_admin_path ) ) || ( false !== strpos( $error_file_path, $wp_includes_path ) ) ) { $error_source_key = 'core'; $error_source = __( 'WordPress core', 'debug-log-manager' ); $error_file_path_for_url = str_replace( ABSPATH, '', $error_file_path ); $error_file_path = str_replace( array( $wp_admin_path, $wp_includes_path ), '', $error_file_path ); // e.g. /post.php $error_file_path_final = str_replace( ABSPATH, '/', $wp_admin_path ) . str_replace( array( $wp_admin_path, $wp_includes_path ), '/', $error_file_path ); // e.g. /post.php } elseif ( ( false !== strpos( $error_file_path, $theme_dir_path ) ) ) { $error_source_key = 'theme'; $error_source = __( 'Theme', 'debug-log-manager' ); $error_file_path = str_replace( $theme_dir_path, '', $error_file_path ); // e.g. /twentytwentyfive/functions.php $error_file_path_final = str_replace( ABSPATH, '/', $theme_dir_path ) . str_replace( $theme_dir_path, '', $error_file_path ); // e.g. /wp-content/themes/twentytwentyfive/functions.php } elseif ( ( false !== strpos( $error_file_path, $wp_plugin_dir_path ) ) ) { $error_source_key = 'plugin'; $error_source = __( 'Plugin', 'debug-log-manager' ); $error_file_path = str_replace( $wp_plugin_dir_path, '', $error_file_path ); // e.g. /debug-log-manager/bootstrap.php $error_file_path_final = str_replace( ABSPATH, '/', $wp_plugin_dir_path ) . str_replace( $wp_plugin_dir_path, '', $error_file_path ); // e.g. /wp-content/plugins/debug-log-manager/bootstrap.php } else { $error_source_key = ''; $error_source = ''; $error_file_path = ''; $error_file_path_final = ''; } // Get plugin/theme directory slug of error file when error source is plugin or theme. if ( in_array( $error_source_key, array( 'plugin', 'theme' ), true ) && ! empty( $error_file_path ) ) { $relative_path = ltrim( $error_file_path, '/' ); $error_file_directory = strtok( $relative_path, '/' ); } // Get plugin name. if ( 'plugin' === $error_source_key && ! empty( $error_file_directory ) ) { $plugins = get_plugins(); foreach ( $plugins as $plugin_path_file => $plugin_info ) { if ( 0 === strpos( $plugin_path_file, $error_file_directory . '/' ) || $plugin_path_file === $error_file_directory . '.php' ) { $error_source_plugin_path_file = $plugin_path_file; $error_source_plugin_name = $plugin_info['Name']; $error_source_plugin_uri = $plugin_info['PluginURI']; break; } } if ( empty( $error_source_plugin_name ) ) { $error_source_plugin_name = $error_file_directory; } } // Get theme name. if ( 'theme' === $error_source_key && ! empty( $error_file_directory ) ) { $theme = wp_get_theme( $error_file_directory ); if ( $theme->exists() ) { $error_source_theme_dir = $error_file_directory; $error_source_theme_name = $theme->get( 'Name' ); $error_source_theme_uri = $theme->get( 'ThemeURI' ); } else { $error_source_theme_dir = $error_file_directory; $error_source_theme_name = $error_file_directory; } } } } else { // $error = __( 'No error message specified...', 'debug-log-manager' ); $error = $line; // Raw log entry } // Stopgap measure to prevent fatal error in strpos() beneath, which expects $error to be a string if ( is_array( $error ) ) { $error = maybe_serialize( $error ); } if ( false !== strpos( $error, '[DLM JS]' ) ) { $error_type = __( 'JavaScript', 'debug-log-manager' ); $error_details = str_replace( '[DLM JS] ', '', $error ); } elseif ( false !== strpos( $error, 'JavaScript Error' ) ) { $error_type = __( 'JavaScript', 'debug-log-manager' ); $error_details = str_replace( 'JavaScript Error: ', '', $error ); } elseif ( ( false !== strpos( $error, 'PHP Fatal' ) ) || ( false !== strpos( $error, 'FATAL' ) ) || ( false !== strpos( $error, 'E_ERROR' ) ) ) { $error_type = __( 'PHP Fatal', 'debug-log-manager' ); $error_details = str_replace( "PHP Fatal error: ", "", $error ); $error_details = str_replace( "PHP Fatal: ", "", $error_details ); $error_details = str_replace( "FATAL ", "", $error_details ); $error_details = str_replace( "E_ERROR: ", "", $error_details ); } elseif ( ( false !== strpos( $error, 'PHP Warning' ) ) || ( false !== strpos( $error, 'E_WARNING' ) ) ) { $error_type = __( 'PHP Warning', 'debug-log-manager' ); $error_details = str_replace( "PHP Warning: ", "", $error ); $error_details = str_replace( "E_WARNING: ", "", $error_details ); } elseif ( ( false !== strpos( $error, 'PHP Notice' ) ) || ( false !== strpos( $error, 'E_NOTICE' ) ) ) { $error_type = __( 'PHP Notice', 'debug-log-manager' ); $error_details = str_replace( "PHP Notice: ", "", $error ); $error_details = str_replace( "E_NOTICE: ", "", $error_details ); } elseif ( false !== strpos( $error, 'PHP Deprecated' ) ) { $error_type = __( 'PHP Deprecated', 'debug-log-manager' ); $error_details = str_replace( "PHP Deprecated: ", "", $error ); } elseif ( ( false !== strpos( $error, 'PHP Parse' ) ) || ( false !== strpos( $error, 'E_PARSE' ) ) ) { $error_type = __( 'PHP Parse', 'debug-log-manager' ); $error_details = str_replace( "PHP Parse error: ", "", $error ); $error_details = str_replace( "E_PARSE: ", "", $error_details ); } elseif ( false !== strpos( $error, 'EXCEPTION:' ) ) { $error_type = __( 'PHP Exception', 'debug-log-manager' ); $error_details = str_replace( "EXCEPTION: ", "", $error ); } elseif ( false !== strpos( $error, 'WordPress database error' ) ) { $error_type = __( 'Database', 'debug-log-manager' ); $error_details = str_replace( "WordPress database error ", "", $error ); } else { $error_type = __( 'Other', 'debug-log-manager' ); $error_details = $error; if ( $this->is_json( $error_details ) ) { // For JSON string in error message, originally added via error_log( json_encode( $variable ) ) // This will output said JSON string as well-formated array in the log entries table $error_details = '
' . print_r( json_decode( $error_details, true ), true ) . '
'; } } // Append error source, file path and line number info to error details. If core plugin/theme editor is not disabled, link file path to the editor view. if ( ! empty( $error_source_key ) ) { if ( 'core' === $error_source_key ) { $file_viewer_url = 'https://github.com/WordPress/wordpress-develop/blob/' . $wp_version . '/src/' . $error_file_path_for_url . '#L' . $error_file_line; $error_details = '' . $error_details . '
' . $error_source . '
' . __( 'File', 'debug-log-manager' ) . ': ' . $error_file_path_final . '
' . __( 'Line', 'debug-log-manager' ) . ': ' . $error_file_line; } elseif ( 'theme' === $error_source_key ) { if ( ! empty( $error_source_theme_uri ) ) { $theme_source_name = '' . $error_source_theme_name . ''; } else { $theme_source_name = $error_source_theme_name; } if ( ! defined( 'DISALLOW_FILE_EDIT' ) || ( false === constant( 'DISALLOW_FILE_EDIT' ) ) ) { if ( ! empty( $error_source_theme_dir ) ) { $file_viewer_url = get_admin_url() . 'theme-editor.php?file=' . urlencode( str_replace( '/' . $error_source_theme_dir . '/', '', $error_file_path ) ) . '&theme=' . $error_source_theme_dir; $file_line = __( 'File', 'debug-log-manager' ) . ': ' . $error_file_path_final . ''; } else { $file_line = __( 'File', 'debug-log-manager' ) . ': ' . $error_file_path_final; } $error_details = '' . $error_details . '
' . $error_source . ': ' . $theme_source_name . '
' . $file_line . '
' . __( 'Line', 'debug-log-manager' ) . ': ' . $error_file_line; } if ( defined( 'DISALLOW_FILE_EDIT' ) && ( true === constant( 'DISALLOW_FILE_EDIT' ) ) ) { $error_details = '' . $error_details . '
' . $error_source . ': ' . $theme_source_name . '
' . __( 'File', 'debug-log-manager' ) . ': ' . $error_file_path_final . '
' . __( 'Line', 'debug-log-manager' ) . ': ' . $error_file_line; } } elseif ( 'plugin' === $error_source_key ) { if ( ! empty( $error_source_plugin_uri ) ) { $plugin_source_name = '' . $error_source_plugin_name . ''; } else { $plugin_source_name = $error_source_plugin_name; } if ( ! defined( 'DISALLOW_FILE_EDIT' ) || ( false === constant( 'DISALLOW_FILE_EDIT' ) ) ) { if ( ! empty( $error_source_plugin_path_file ) ) { $file_viewer_url = get_admin_url() . 'plugin-editor.php?file=' . urlencode( substr( $error_file_path, 1 ) ) . '&plugin=' . urlencode( $error_source_plugin_path_file ); $file_line = __( 'File', 'debug-log-manager' ) . ': ' . $error_file_path_final . ''; } else { $file_line = __( 'File', 'debug-log-manager' ) . ': ' . $error_file_path_final; } $error_details = '' . $error_details . '
' . $error_source . ': ' . $plugin_source_name . '
' . $file_line . '
' . __( 'Line', 'debug-log-manager' ) . ': ' . $error_file_line; } if ( defined( 'DISALLOW_FILE_EDIT' ) && ( true === constant( 'DISALLOW_FILE_EDIT' ) ) ) { $error_details = '' . $error_details . '
' . $error_source . ': ' . $plugin_source_name . '
' . __( 'File', 'debug-log-manager' ) . ': ' . $error_file_path_final . '
' . __( 'Line', 'debug-log-manager' ) . ': ' . $error_file_line; } } } // https://www.php.net/manual/en/function.array-search.php#120784 if ( array_search( trim( $error_details ), array_column( $errors_master_list, 'details' ) ) === false ) { $errors_master_list[] = array( 'type' => $error_type, 'details' => trim( $error_details ), 'occurrences' => array( $timestamp ), ); } else { $error_position = array_search( trim( $error_details ), array_column( $errors_master_list, 'details' ) ); // integer array_push( $errors_master_list[$error_position]['occurrences'], $timestamp ); } } return json_encode( $errors_master_list ); } /** * Get the latest entries for auto-refresh feature * * @since 1.0.0 */ public function get_latest_entries() { if ( isset( $_REQUEST ) && current_user_can( 'manage_options' ) ) { if ( wp_verify_nonce( sanitize_text_field( $_REQUEST['nonce'] ), 'dlm-app' . get_current_user_id() ) ) { $errors_master_list = json_decode( $this->get_processed_entries(), true ); $n = 1; $entries = array(); foreach ( $errors_master_list as $error ) { if ( function_exists( 'wp_date' ) ) { $localized_timestamp = wp_date( 'M j, Y - H:i:s', strtotime( $error['occurrences'][0] ) ); // last occurrence } else { $localized_timestamp = date_i18n( 'M j, Y - H:i:s', strtotime( $error['occurrences'][0] ) ); } $occurrence_count = count( $error['occurrences'] ); $entry = array( $n, $error['type'], $error['details'], $localized_timestamp . '
(' . sprintf( _n( '%s occurrence logged', '%s occurrences logged', $occurrence_count, 'debug-log-manager' ), number_format_i18n( $occurrence_count ) ) . ')', ); $entries[] = $entry; $n++; } $data = array( 'entries' => $entries, ); } } else { $data = array(); } echo json_encode( $data ); } /** * Get debug log in data table format * * @since 1.0.0 */ public function get_entries_datatable() { ?>
get_processed_entries(), true ); $n = 1; foreach ( $errors_master_list as $error ) { if ( function_exists( 'wp_date' ) ) { $localized_timestamp = wp_date( 'M j, Y - H:i:s', strtotime( $error['occurrences'][0] ) ); // last occurrence } else { $localized_timestamp = date_i18n( 'M j, Y - H:i:s', strtotime( $error['occurrences'][0] ) ); } $occurrence_count = count( $error['occurrences'] ); ?>
#
get_processed_entries(), true ); $n = 1; $entries_to_show = 5; ?>
true, // Add the config if missing. 'raw' => true, // Display value in raw format without quotes. 'normalize' => false, // Normalize config output using WP Coding Standards. ); $this->wp_config->update( 'constant', 'DISALLOW_FILE_EDIT', 'true', $options ); // Prepare entries from the debug log for the data table $errors_master_list = json_decode( $this->get_processed_entries(), true ); $n = 1; $entries = array(); foreach ( $errors_master_list as $error ) { if ( function_exists( 'wp_date' ) ) { $localized_timestamp = wp_date( 'M j, Y - H:i:s', strtotime( $error['occurrences'][0] ) ); // last occurrence } else { $localized_timestamp = date_i18n( 'M j, Y - H:i:s', strtotime( $error['occurrences'][0] ) ); } $occurrence_count = count( $error['occurrences'] ); $entry = array( $n, $error['type'], $error['details'], $localized_timestamp . '
(' . sprintf( _n( '%s occurrence logged', '%s occurrences logged', $occurrence_count, 'debug-log-manager' ), number_format_i18n( $occurrence_count ) ) . ')', ); $entries[] = $entry; $n++; } // Assemble data to return $data = array( 'status' => 'disabled', // Plugin/theme editor 'entries' => $entries, // To parse data table with unlinked plugin/theme file paths ); echo json_encode( $data ); } } } /** * Whether JS error logging is enabled. * * @since 2.5.1 * @return bool */ private function is_js_error_logging_enabled() { $default_value = array( 'status' => 'disabled', 'on' => date( 'Y-m-d H:i:s' ), ); $log_info = get_option( 'debug_log_manager', $default_value ); $js_error_logging_status = get_option( 'debug_log_manager_js_error_logging', 'enabled' ); return ( 'enabled' === $log_info['status'] && 'enabled' === $js_error_logging_status ); } /** * Sanitize a field before writing to debug.log. * * @since 2.5.1 * @param mixed $value Raw value. * @param int $max_length Maximum allowed length. * @return string */ private function sanitize_log_field( $value, $max_length = 500 ) { if ( ! is_string( $value ) ) { $value = (string) $value; } $filtered = sanitize_text_field( $value ); // Strip ASCII control characters and DEL. $filtered = preg_replace( '/[\x00-\x1F\x7F]/u', '', $filtered ); // Strip Unicode line and paragraph separators. $filtered = preg_replace( '/[\x{2028}\x{2029}]/u', '', $filtered ); // Collapse whitespace. $filtered = preg_replace( '/\s+/u', ' ', $filtered ); $filtered = trim( $filtered ); if ( function_exists( 'mb_substr' ) ) { return mb_substr( $filtered, 0, $max_length ); } return substr( $filtered, 0, $max_length ); } /** * Validate Origin or Referer matches this site. * * @since 2.5.1 * @return bool */ private function validate_request_origin() { /** * Skip same-site Origin/Referer validation for JS error logging. * * @since 2.5.1 * @param bool $skip Whether to skip validation. */ if ( apply_filters( 'dlm_js_error_log_skip_origin_check', false ) ) { return true; } $site_host = wp_parse_url( home_url(), PHP_URL_HOST ); if ( empty( $site_host ) ) { return false; } $request_host = ''; if ( ! empty( $_SERVER['HTTP_ORIGIN'] ) ) { $request_host = wp_parse_url( esc_url_raw( wp_unslash( $_SERVER['HTTP_ORIGIN'] ) ), PHP_URL_HOST ); } elseif ( ! empty( $_SERVER['HTTP_REFERER'] ) ) { $request_host = wp_parse_url( esc_url_raw( wp_unslash( $_SERVER['HTTP_REFERER'] ) ), PHP_URL_HOST ); } else { return false; } if ( empty( $request_host ) ) { return false; } return ( strtolower( $request_host ) === strtolower( $site_host ) ); } /** * Check rate limit for JS error logging. * * @since 2.5.1 * @return bool True if within limit, false if exceeded. */ private function check_js_error_rate_limit() { $ip = ''; if ( ! empty( $_SERVER['REMOTE_ADDR'] ) ) { $ip = sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ); } $ua = ''; if ( ! empty( $_SERVER['HTTP_USER_AGENT'] ) ) { $ua = sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ); } $key = 'dlm_js_log_' . md5( $ip . $ua ); $count = (int) get_transient( $key ); if ( $count >= self::JS_LOG_RATE_LIMIT ) { return false; } set_transient( $key, $count + 1, self::JS_LOG_RATE_WINDOW ); return true; } /** * Log javascript errors * * @since 1.4.0 */ public function log_js_errors() { if ( ! $this->is_js_error_logging_enabled() ) { wp_die(); } // Since we are using XHR for the js error logging, JSON data comes in via php://input. $request = json_decode( file_get_contents( 'php://input' ), true ); if ( ! is_array( $request ) ) { wp_die(); } // Verify error content and nonce and then log the JS error. // Source: https://plugins.svn.wordpress.org/lh-javascript-error-log/trunk/lh-javascript-error-log.php if ( ! isset( $request['message'], $request['script'], $request['lineNo'], $request['columnNo'] ) || empty( $request['nonce'] ) || ! wp_verify_nonce( $request['nonce'], DLM__SLUG ) ) { wp_die(); } $request_type = isset( $request['type'] ) ? sanitize_text_field( $request['type'] ) : ''; if ( 'wp-admin' === $request_type ) { if ( ! is_user_logged_in() || ! current_user_can( 'manage_options' ) ) { wp_die(); } } elseif ( ! is_user_logged_in() ) { if ( ! $this->validate_request_origin() ) { wp_die(); } } if ( ! $this->check_js_error_rate_limit() ) { wp_die( '', '', 429 ); } $message = $this->sanitize_log_field( $request['message'] ); $script = $this->sanitize_log_field( $request['script'] ); $line_number = $this->sanitize_log_field( $request['lineNo'], 20 ); $column_number = $this->sanitize_log_field( $request['columnNo'], 20 ); $page_url = isset( $request['pageUrl'] ) ? $this->sanitize_log_field( $request['pageUrl'] ) : ''; error_log( self::JS_LOG_PREFIX . $message . ' in ' . $script . ' on line ' . $line_number . ' column ' . $column_number . ' at ' . get_site_url() . $page_url ); wp_die(); } /** * Check if a string is valid JSON * * @link https://stackoverflow.com/a/6041773 * @since 2.1.0 */ public function is_json( $string ) { json_decode( $string ); return json_last_error() === JSON_ERROR_NONE; } }