: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
if (!defined('WORDFENCE_VERSION')) {
if (!isset($diagnostic)) {
$diagnostic = new wfDiagnostic;
$plugins = get_plugins();
if (!isset($activePlugins)) {
$activePlugins = array_flip(get_option('active_plugins'));
if (!isset($activeNetworkPlugins)) {
$activeNetworkPlugins = is_multisite() ? array_flip(wp_get_active_network_plugins()) : array();
if (!isset($muPlugins)) {
$muPlugins = get_mu_plugins();
$themes = wp_get_themes();
if (!isset($currentTheme)) {
$currentTheme = wp_get_theme();
foreach ($diagnostic->getResults() as $title => $tests):
foreach ($tests['results'] as $result) {
$infoOnly = isset($result['infoOnly']) && $result['infoOnly'];
} else if ($result['test'] && $result['message'] !== 'OK') {
} else if (!$result['test'] && $result['message'] !== 'FAIL') {
if (is_array($result['message'])) {
$message .= $result['message']['textonly'];
$message .= strip_tags($result['message']);
if (isset($result['detail']) && !empty($result['detail'])) {
$message .= "\nAdditional Detail:\n";
if (is_array($result['detail'])) {
$message .= $result['detail']['textonly'];
$message .= strip_tags($result['detail']);
strip_tags((is_array($result['label']) && isset($result['label']['raw']) && $result['label']['raw']) ? $result['label']['value'] : $result['label']),
echo wfHelperString::plainTextTable($table) . "\n\n";
## <?php esc_html_e('IP Detection', 'wordfence') ?>: <?php esc_html_e('Methods of detecting a visitor\'s IP address.', 'wordfence') ?> ##
$howGet = wfConfig::get('howGetIPs', false);
list($currentIP, $currentServerVarForIP) = wfUtils::getIPAndServerVariable();
$howGetHasErrors = $howGet && (!$currentServerVarForIP || $howGet !== $currentServerVarForIP);
__('Value', 'wordfence'),
$serverVariables = array(
'REMOTE_ADDR' => 'REMOTE_ADDR',
'HTTP_CF_CONNECTING_IP' => 'CF-Connecting-IP',
'HTTP_X_REAL_IP' => 'X-Real-IP',
'HTTP_X_FORWARDED_FOR' => 'X-Forwarded-For',
foreach (wfUtils::getAllServerVariableIPs() as $variable => $ip) {
$ipValue = __('(not set)', 'wordfence');
} elseif (is_array($ip)) {
$ipValue = array_map('strip_tags', $ip);
$ipValue = str_replace($currentIP, "**$currentIP**", implode(', ', $ipValue));
$ipValue = strip_tags($ip);
if ($currentServerVarForIP && $currentServerVarForIP === $variable) {
$used = __('In use', 'wordfence');
} else if ($howGet === $variable) {
$used = __('Configured but not valid', 'wordfence');
isset($serverVariables[$variable]) ? $serverVariables[$variable] : $variable,
$proxies = wfConfig::get('howGetIPs_trusted_proxies', '');
__('Trusted Proxies', 'wordfence'),
strip_tags(implode(', ', explode("\n", empty($proxies) ? __('(not set)', 'wordfence') : $proxies))),
$preset = wfConfig::get('howGetIPs_trusted_proxy_preset');
$presets = wfConfig::getJSON('ipResolutionList', array());
__('Trusted Proxy Preset', 'wordfence'),
strip_tags((is_array($presets) && isset($presets[$preset])) ? $presets[$preset]['name'] : __('(not set)', 'wordfence')),
echo wfHelperString::plainTextTable($table) . "\n\n";
## <?php esc_html_e('WordPress Settings', 'wordfence') ?>: <?php esc_html_e('WordPress version and internal settings/constants.', 'wordfence') ?> ##
__('Setting Name', 'wordfence'),
__('Description', 'wordfence'),
__('Value', 'wordfence'),
foreach (wfDiagnostic::getWordpressValues() as $settingName => $settingData) {
$escapedName = strip_tags($settingName);
$escapedDescription = '';
$escapedValue = __('(not set)', 'wordfence');
if (is_array($settingData)) {
$escapedDescription = strip_tags($settingData['description']);
if (isset($settingData['value'])) {
$escapedValue = strip_tags($settingData['value']);
$escapedDescription = strip_tags($settingData);
if (defined($settingName)) {
$escapedValue = strip_tags(constant($settingName));
echo wfHelperString::plainTextTable($table) . "\n\n";
## <?php esc_html_e('WordPress Plugins', 'wordfence') ?>: <?php esc_html_e('Status of installed plugins.', 'wordfence') ?> ##
array(__('Name', 'wordfence'), __('Status', 'wordfence')),
foreach ($plugins as $plugin => $pluginData) {
if (preg_match('/^([^\/]+)\//', $plugin, $tableMatches)) {
$slug = $tableMatches[1];
} else if (preg_match('/^([^\/.]+)\.php$/', $plugin, $tableMatches)) {
$slug = $tableMatches[1];
$name = strip_tags(sprintf('%s (%s)', $pluginData['Name'], $slug));
if (!empty($pluginData['Version'])) {
$name .= ' - ' . strip_tags(sprintf(__('Version %s', 'wordfence'), $pluginData['Version']));
if (array_key_exists(trailingslashit(WP_PLUGIN_DIR) . $plugin, $activeNetworkPlugins)) {
$status = __('Network Activated', 'wordfence');
} elseif (array_key_exists($plugin, $activePlugins)) {
$status = __('Active', 'wordfence');
$status = __('Inactive', 'wordfence');
echo wfHelperString::plainTextTable($table) . "\n\n";
## <?php esc_html_e('Must-Use WordPress Plugins', 'wordfence') ?>: <?php esc_html_e('WordPress "mu-plugins" that are always active, including those provided by hosts.', 'wordfence') ?> ##
array(__('Name', 'wordfence'), __('Status', 'wordfence')),
if (!empty($muPlugins)) {
foreach ($muPlugins as $plugin => $pluginData) {
if (preg_match('/^([^\/]+)\//', $plugin, $tableMatches)) {
$slug = $tableMatches[1];
} else if (preg_match('/^([^\/.]+)\.php$/', $plugin, $tableMatches)) {
$slug = $tableMatches[1];
$name = strip_tags(sprintf('%s (%s)', $pluginData['Name'], $slug));
if (!empty($pluginData['Version'])) {
$name .= ' - ' . strip_tags(sprintf(__('Version %s', 'wordfence'), $pluginData['Version']));
__('Active', 'wordfence'),
__('No MU-Plugins', 'wordfence'),
echo wfHelperString::plainTextTable($table) . "\n\n";
## <?php esc_html_e('Drop-In WordPress Plugins', 'wordfence') ?>: <?php esc_html_e('WordPress "drop-in" plugins that are active.', 'wordfence') ?> ##
//Taken from plugin.php and modified to always show multisite drop-ins
'advanced-cache.php' => array(__('Advanced caching plugin', 'wordfence'), 'WP_CACHE'), // WP_CACHE
'db.php' => array(__('Custom database class', 'wordfence'), true), // auto on load
'db-error.php' => array(__('Custom database error message', 'wordfence'), true), // auto on error
'install.php' => array(__('Custom installation script', 'wordfence'), true), // auto on installation
'maintenance.php' => array(__('Custom maintenance message', 'wordfence'), true), // auto on maintenance
'object-cache.php' => array(__('External object cache', 'wordfence'), true), // auto on load
'php-error.php' => array(__('Custom PHP error message', 'wordfence'), true), // auto on error
'fatal-error-handler.php' => array(__('Custom PHP fatal error handler', 'wordfence'), true), // auto on error
$dropins['sunrise.php'] = array(__('Executed before Multisite is loaded', 'wordfence'), is_multisite() && 'SUNRISE'); // SUNRISE
$dropins['blog-deleted.php'] = array(__('Custom site deleted message', 'wordfence'), is_multisite()); // auto on deleted blog
$dropins['blog-inactive.php'] = array(__('Custom site inactive message', 'wordfence'), is_multisite()); // auto on inactive blog
$dropins['blog-suspended.php'] = array(__('Custom site suspended message', 'wordfence'), is_multisite()); // auto on archived or spammed blog
array(__('Name', 'wordfence'), __('Status', 'wordfence')),
foreach ($dropins as $file => $data) {
$active = file_exists(WP_CONTENT_DIR . DIRECTORY_SEPARATOR . $file) && is_readable(WP_CONTENT_DIR . DIRECTORY_SEPARATOR . $file) && $data[1];
sprintf('%s (%s)', $data[0], $file),
$active ? __('Active', 'wordfence') : __('Inactive', 'wordfence'),
echo wfHelperString::plainTextTable($table) . "\n\n";
## <?php esc_html_e('Themes', 'wordfence') ?>: <?php esc_html_e('Status of installed themes.', 'wordfence') ?> ##
array(__('Name', 'wordfence'), __('Status', 'wordfence')),
foreach ($themes as $theme => $themeData) {
if (preg_match('/^([^\/]+)\//', $theme, $tableMatches)) {
$slug = $tableMatches[1];
} else if (preg_match('/^([^\/.]+)\.php$/', $theme, $tableMatches)) {
$slug = $tableMatches[1];
$name = strip_tags(sprintf('%s (%s)', $themeData['Name'], $slug));
if (!empty($themeData['Version'])) {
$name .= ' - ' . strip_tags(sprintf(__('Version %s', 'wordfence'), $themeData['Version']));
if ($currentTheme instanceof WP_Theme && $theme === $currentTheme->get_stylesheet()) {
$status = __('Active', 'wordfence');
$status = __('Inactive', 'wordfence');
__('No Themes', 'wordfence'),
echo wfHelperString::plainTextTable($table) . "\n\n";
## <?php esc_html_e('Cron Jobs', 'wordfence') ?>: <?php esc_html_e('List of WordPress cron jobs scheduled by WordPress, plugins, or themes.', 'wordfence') ?> ##
$cron = _get_cron_array();
array(__('Run Time', 'wordfence'), __('Job', 'wordfence')),
foreach ($cron as $timestamp => $values) {
foreach ($values as $cron_job => $v) {
if (is_numeric($timestamp)) {
$overdue = ((time() - 1800) > $timestamp);
strip_tags(date('r', $timestamp)) . ($overdue ? ' **(' . __('Overdue', 'wordfence') . ')**' : ''),
echo wfHelperString::plainTextTable($table) . "\n\n";
## <?php esc_html_e('Database Tables', 'wordfence') ?>: <?php esc_html_e('Database table names, sizes, timestamps, and other metadata.', 'wordfence') ?> ##
//This must be done this way because MySQL with InnoDB tables does a full regeneration of all metadata if we don't. That takes a long time with a large table count.
$tables = $wfdb->querySelect('SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA=DATABASE() ORDER BY TABLE_NAME ASC LIMIT 250');
$total = $wfdb->querySingle('SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA=DATABASE() LIMIT 250');
foreach ($tables as &$t) {
$t = "'" . esc_sql($t['TABLE_NAME']) . "'";
$q = $wfdb->querySelect("SHOW TABLE STATUS WHERE Name IN (" . implode(',', $tables) . ')');
$databaseCols = count($q[0]);
_e('Unable to verify - table count too high', 'wordfence');
$schemaTables = wfSchema::tableList();
$existingTables = wfUtils::array_column($q, 'Name');
$existingTables = wfUtils::array_strtolower($existingTables);
} //Windows MySQL installations are case-insensitive
$missingTables = array();
foreach ($schemaTables as $t) {
$table = wfDB::networkTable($t);
$table = strtolower($table);
if (!in_array($table, $existingTables)) {
\WordfenceLS\Controller_DB::TABLE_2FA_SECRETS,
\WordfenceLS\Controller_DB::TABLE_SETTINGS,
$table = \WordfenceLS\Controller_DB::network_table($t);
if (!in_array($table, $existingTables)) {
_e('All Tables Exist', 'wordfence');
printf(/* translators: 1. WordPress table prefix. 2. Wordfence table case. 3. List of database tables. */ __('Tables missing (prefix %1$s, %2$s): %3$s', 'wordfence'), wfDB::networkPrefix(), wfSchema::usingLowercase() ? __('lowercase', 'wordfence') : __('regular case', 'wordfence'), implode(', ', $missingTables));
printf(/* translators: 1. Number of tables */ _n('%1$s Table in Database', '%1$s Tables in Database', $total, 'wordfence' ), $total );
$val = wfUtils::array_first($q);
$actualKeyOrder = array_keys($val);
$preferredKeyOrder = array('Name', 'Comment', 'Engine', 'Rows', 'Avg_row_length', 'Data_length', 'Index_length', 'Auto_increment', 'Create_time', 'Row_format', 'Collation', 'Version', 'Max_data_length', 'Data_free', 'Update_time', 'Check_time', 'Checksum', 'Create_options');
$displayKeyOrder = array();
foreach ($preferredKeyOrder as $k) {
if (in_array($k, $actualKeyOrder)) {
$diff = array_diff($actualKeyOrder, $preferredKeyOrder);
$displayKeyOrder = array_merge($displayKeyOrder, $diff);
foreach ($displayKeyOrder as $tkey) {
$tableRow[] = isset($val[$tkey]) ? $val[$tkey] : '';
if ($count >= 250 && $total > $count) {
$tableRow = array_fill(0, $databaseCols, '');
$tableRow[0] = sprintf(__('and %d more', 'wordfence'), $total - $count);
echo wfHelperString::plainTextTable($table) . "\n\n";
## <?php esc_html_e('Log Files', 'wordfence') ?>: <?php esc_html_e('PHP error logs generated by your site, if enabled by your host.', 'wordfence') ?> ##
$errorLogs = wfErrorLogHandler::getErrorLogs();
if (count($errorLogs) < 1) {
__('No log files found.', 'wordfence'),
foreach ($errorLogs as $log => $readable) {
if (is_callable('filesize')) {
$rawSize = @filesize($log);
if ($rawSize !== false) {
$metadata[] = wfUtils::formatBytes(filesize($log));
if (is_callable('lstat')) {
if (is_array($rawStat) && isset($rawStat['mtime'])) {
$utc = new DateTimeZone('UTC');
$dtStr = gmdate("c", (int) $ts); //Have to do it this way because of PHP 5.2
$dt = new DateTime($dtStr, $utc);
$metadata[] = $dt->format('M j, Y G:i:s') . ' ' . __('UTC', 'wordfence');
if (strpos($shortLog, ABSPATH) === 0) {
$shortLog = '~/' . substr($shortLog, strlen(ABSPATH));