'2022-11-28', '8.0' => '2023-11-26', '8.1' => '2025-12-31', '8.2' => '2026-12-31', '8.3' => '2027-12-31', '8.4' => '2028-12-31', ]; $php = PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION; if (isset($eol[$php])) { $is_eol = strtotime($eol[$php]) < time(); $f[] = $this->finding( 'php_version', $is_eol ? 'bad' : (version_compare($php, '8.1', '<') ? 'warn' : 'ok'), 'PHP version', PHP_VERSION, $is_eol ? "EOL since {$eol[$php]} — upgrade urgently." : "Supported until {$eol[$php]}." ); } else { $f[] = $this->finding('php_version', 'info', 'PHP version', PHP_VERSION, 'EOL date unknown for this branch.'); } // WP version vs latest global $wp_version; if (!function_exists('get_core_updates')) require_once ABSPATH . 'wp-admin/includes/update.php'; $updates = function_exists('get_core_updates') ? get_core_updates(['dismissed' => true]) : []; $latest = (!empty($updates) && !empty($updates[0]->current)) ? $updates[0]->current : $wp_version; $behind = version_compare($wp_version, $latest, '<'); $f[] = $this->finding( 'wp_version', $behind ? 'warn' : 'ok', 'WordPress version', $wp_version, $behind ? "Latest is {$latest} — update available." : 'Up to date.' ); // Disk usage on ABSPATH $free = @disk_free_space(ABSPATH); $total = @disk_total_space(ABSPATH); if ($free !== false && $total !== false && $total > 0) { $used_pct = round(($total - $free) / $total * 100, 1); $level = $used_pct > 90 ? 'bad' : ($used_pct > 80 ? 'warn' : 'ok'); $f[] = $this->finding( 'disk_usage', $level, 'Disk usage', $used_pct . '% used', size_format($total - $free) . ' of ' . size_format($total) . ' (free: ' . size_format($free) . ')' ); } // wp-config flags $flags = [ 'WP_DEBUG' => false, 'WP_DEBUG_DISPLAY' => true, // default true; we want false on production 'WP_DEBUG_LOG' => false, 'DISALLOW_FILE_EDIT' => false, // we want this true 'WP_ENVIRONMENT_TYPE'=> 'production', ]; foreach ($flags as $const => $expected_for_prod) { if (!defined($const)) { if ($const === 'WP_ENVIRONMENT_TYPE') continue; // optional $f[] = $this->finding('flag_' . strtolower($const), 'info', $const, 'not defined', 'Default applies.'); continue; } $val = constant($const); if ($const === 'WP_ENVIRONMENT_TYPE') { $f[] = $this->finding('flag_env_type', 'info', 'WP_ENVIRONMENT_TYPE', (string) $val, ''); continue; } $bool = (bool) $val; $ok = ($const === 'DISALLOW_FILE_EDIT') ? ($bool === true) : ($bool === false); $level = $ok ? 'ok' : ($const === 'WP_DEBUG_DISPLAY' ? 'bad' : 'warn'); $f[] = $this->finding( 'flag_' . strtolower($const), $level, $const, $bool ? 'true' : 'false', $ok ? '' : ($const === 'WP_DEBUG_DISPLAY' ? 'Errors are being shown to visitors — turn this off on production.' : 'Recommended: ' . ($expected_for_prod ? 'true' : 'false') . ' on production.') ); } // Permissions on key paths foreach ([ 'wp-config.php' => ABSPATH . 'wp-config.php', 'wp-content/' => WP_CONTENT_DIR, 'uploads/' => wp_get_upload_dir()['basedir'] ?? WP_CONTENT_DIR . '/uploads', ] as $label => $path) { if (!file_exists($path)) continue; $perms = substr(sprintf('%o', fileperms($path)), -4); // wp-config: 600 or 640; dirs: 755 (loose check) $is_cfg = $label === 'wp-config.php'; $ok = $is_cfg ? in_array($perms, ['0600', '0640'], true) : in_array($perms, ['0755', '0750'], true); $f[] = $this->finding( 'perm_' . sanitize_key($label), $ok ? 'ok' : 'warn', 'Permissions: ' . $label, $perms, $ok ? '' : ($is_cfg ? 'Recommend 600 or 640.' : 'Recommend 755 or 750.') ); } // Error log size (PHP error_log + WP debug.log) foreach ([ 'PHP error_log' => ini_get('error_log'), 'WP debug.log' => WP_CONTENT_DIR . '/debug.log', ] as $label => $path) { if (!$path || !file_exists($path) || !is_readable($path)) continue; $size = filesize($path); $level = $size > 10 * MB_IN_BYTES ? 'warn' : 'info'; $f[] = $this->finding( 'log_' . sanitize_key($label), $level, $label, size_format($size), $path . ($level === 'warn' ? ' — large file, consider rotating + reviewing tail.' : '') ); } return $f; } };