# wpvulnerability/5.1.2/wpvulnerability-debug.php

WPVulnerability, version 5.1.2. 665 lines.

- Page: https://pluginprobe.com/plugins/wpvulnerability/5.1.2/code/wpvulnerability-debug.php
- Raw: https://pluginprobe.com/plugins/wpvulnerability/5.1.2/raw/wpvulnerability-debug.php
- Modified: 2026-08-07T10:49:46+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/wpvulnerability/5.1.2/code/wpvulnerability-debug.php#L10-L20`.

```php
<?php
/**
 * Debug functions
 *
 * @package WPVulnerability
 *
 * @version 4.3.0
 */

defined( 'ABSPATH' ) || die( 'No script kiddies please!' );

// Load required plugin files if not already loaded.
if ( ! function_exists( 'wpvulnerability_analyze_filter' ) ) {
	require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-general.php';
	require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-run.php';
}

if ( ! function_exists( 'wpvulnerability_get_software_version' ) ) {
	require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-software.php';
}

/**
 * Retrieves debug log file information.
 *
 * Detects the location of the WordPress debug log file and checks if it's accessible.
 *
 * @since 4.3.0
 *
 * @return array<string, mixed> Array with 'path', 'exists', 'size', 'url', and 'accessible' keys.
 */
function wpvulnerability_debug_get_log_file_info() {
	$log_info = array(
		'path'       => null,
		'exists'     => false,
		'size'       => 0,
		'url'        => null,
		'accessible' => false,
	);

	// Check if WP_DEBUG_LOG is enabled.
	if ( ! defined( 'WP_DEBUG_LOG' ) || ! WP_DEBUG_LOG ) {
		return $log_info;
	}

	// Determine log file path.
	// WP_DEBUG_LOG can be a string (custom path) or true/false.
	// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.runtime_configuration_constant -- need runtime value for type narrowing
	$wp_debug_log_value = defined( 'WP_DEBUG_LOG' ) ? WP_DEBUG_LOG : false;
	if ( is_string( $wp_debug_log_value ) ) { // @phpstan-ignore function.impossibleType (WP_DEBUG_LOG may be a string path at runtime)
		// Custom path specified.
		$log_file = $wp_debug_log_value;
	} else {
		// Default path: wp-content/debug.log.
		$log_file = WP_CONTENT_DIR . '/debug.log';
	}

	$log_info['path'] = $log_file;

	// Check if file exists.
	if ( file_exists( $log_file ) ) {
		$log_info['exists'] = true;

		// Get file size.
		$size = filesize( $log_file );
		if ( false !== $size ) {
			$log_info['size'] = $size;
		}

		// Check if file is within wp-content (accessible via web).
		$wp_content_dir = realpath( WP_CONTENT_DIR );
		$log_file_real  = realpath( $log_file );

		if ( $wp_content_dir && $log_file_real && 0 === strpos( $log_file_real, $wp_content_dir ) ) {
			// File is within wp-content, generate URL.
			$relative_path          = str_replace( $wp_content_dir, '', $log_file_real );
			$relative_path          = str_replace( '\\', '/', $relative_path );
			$log_info['url']        = content_url() . $relative_path;
			$log_info['accessible'] = true;
		}
	}

	return $log_info;
}

/**
 * Enhanced web server detection for debug purposes.
 *
 * Detects a wider range of web servers including nginx, Apache, LiteSpeed,
 * Caddy, IIS, Angie, OpenLiteSpeed, and others.
 *
 * @since 4.3.0
 *
 * @return array<string, string> Array with 'name' and 'version' keys.
 */
function wpvulnerability_debug_detect_webserver() {
	$webserver = array(
		'name'    => 'Unknown',
		'version' => '',
	);

	// First try the plugin's standard detection.
	$detected = wpvulnerability_detect_webserver();
	if ( ! empty( $detected['name'] ) ) {
		$webserver['name'] = $detected['name'];
		if ( ! empty( $detected['version'] ) ) {
			$webserver['version'] = $detected['version'];
		}
	}

	// If still unknown, try enhanced detection from SERVER_SOFTWARE.
	if ( 'Unknown' === $webserver['name'] && isset( $_SERVER['SERVER_SOFTWARE'] ) ) {
		$server_software = sanitize_text_field( wp_unslash( is_string( $_SERVER['SERVER_SOFTWARE'] ) ? $_SERVER['SERVER_SOFTWARE'] : '' ) );
		$server_lower    = strtolower( $server_software );

		// LiteSpeed detection.
		if ( false !== stripos( $server_lower, 'litespeed' ) ) {
			if ( preg_match( '/litespeed/i', $server_software, $match ) ) {
				$webserver['name'] = 'LiteSpeed';
				if ( preg_match( '/litespeed\/?v?(\d+\.\d+(?:\.\d+)?)/i', $server_software, $version_match ) ) {
					$webserver['version'] = $version_match[1];
				}
			}
		}

		// OpenLiteSpeed detection.
		if ( false !== stripos( $server_lower, 'openlitespeed' ) ) {
			$webserver['name'] = 'OpenLiteSpeed';
			if ( preg_match( '/openlitespeed\/?v?(\d+\.\d+(?:\.\d+)?)/i', $server_software, $version_match ) ) {
				$webserver['version'] = $version_match[1];
			}
		}

		// Caddy detection.
		if ( false !== stripos( $server_lower, 'caddy' ) ) {
			$webserver['name'] = 'Caddy';
			if ( preg_match( '/caddy\/?v?(\d+\.\d+(?:\.\d+)?)/i', $server_software, $version_match ) ) {
				$webserver['version'] = $version_match[1];
			}
		}

		// IIS detection.
		if ( false !== stripos( $server_lower, 'microsoft-iis' ) || false !== stripos( $server_lower, 'iis' ) ) {
			$webserver['name'] = 'Microsoft IIS';
			if ( preg_match( '/(?:microsoft-)?iis\/?(\d+\.\d+(?:\.\d+)?)/i', $server_software, $version_match ) ) {
				$webserver['version'] = $version_match[1];
			}
		}

		// Angie detection (nginx fork).
		if ( false !== stripos( $server_lower, 'angie' ) ) {
			$webserver['name'] = 'Angie';
			if ( preg_match( '/angie\/?(\d+\.\d+(?:\.\d+)?)/i', $server_software, $version_match ) ) {
				$webserver['version'] = $version_match[1];
			}
		}

		// OpenResty detection (nginx-based).
		if ( false !== stripos( $server_lower, 'openresty' ) ) {
			$webserver['name'] = 'OpenResty';
			if ( preg_match( '/openresty\/?(\d+\.\d+(?:\.\d+)?(?:\.\d+)?)/i', $server_software, $version_match ) ) {
				$webserver['version'] = $version_match[1];
			}
		}

		// Tengine detection (nginx fork).
		if ( false !== stripos( $server_lower, 'tengine' ) ) {
			$webserver['name'] = 'Tengine';
			if ( preg_match( '/tengine\/?(\d+\.\d+(?:\.\d+)?)/i', $server_software, $version_match ) ) {
				$webserver['version'] = $version_match[1];
			}
		}
	}

	// Try shell commands for additional detection if shell_exec is allowed.
	if ( 'Unknown' === $webserver['name'] && function_exists( 'wpvulnerability_safe_shell_exec' ) ) {
		// Try LiteSpeed. `which` prints the binary path on success; on failure it
		// prints a "which: no litespeed ..." message to stderr. The wrapper merges
		// stderr into stdout (2>&1), so validate that the output is actually a path.
		$litespeed_test = wpvulnerability_safe_shell_exec( 'apache', 'which litespeed' );
		if ( ! empty( $litespeed_test ) && 0 === strpos( trim( (string) $litespeed_test ), '/' ) ) {
			$webserver['name'] = 'LiteSpeed';
		}

		// Try OpenLiteSpeed.
		$openlitespeed_test = wpvulnerability_safe_shell_exec( 'apache', 'which openlitespeed' );
		if ( ! empty( $openlitespeed_test ) && 0 === strpos( trim( (string) $openlitespeed_test ), '/' ) ) {
			$webserver['name'] = 'OpenLiteSpeed';
		}

		// Try Caddy. The version regex guards against false positives: a "command
		// not found" message does not match a version pattern.
		$caddy_version = wpvulnerability_safe_shell_exec( 'apache', 'caddy version' );
		if ( ! empty( $caddy_version ) && preg_match( '/v?(\d+\.\d+\.\d+)/', $caddy_version, $version_match ) ) {
			$webserver['name']    = 'Caddy';
			$webserver['version'] = $version_match[1];
		}
	}

	return $webserver;
}

/**
 * Retrieves comprehensive system information for debugging.
 *
 * @since 4.3.0
 *
 * @return array<string, mixed> Associative array containing system information.
 */
function wpvulnerability_debug_get_system_info() {
	global $wp_version, $wpdb;

	// Detect database type (MariaDB vs MySQL).
	$sqlserver  = wpvulnerability_detect_sqlserver();
	$db_type    = ! empty( $sqlserver['name'] ) ? $sqlserver['name'] : 'MySQL';
	$db_version = ! empty( $sqlserver['version'] ) ? $sqlserver['version'] : $wpdb->db_version();

	// Detect web server with enhanced detection.
	$webserver      = wpvulnerability_debug_detect_webserver();
	$webserver_name = $webserver['name'];
	if ( ! empty( $webserver['version'] ) ) {
		$webserver_name .= ' ' . $webserver['version'];
	}

	$info = array(
		'wordpress' => array(
			'version'   => $wp_version,
			'multisite' => is_multisite(),
			'language'  => get_locale(),
			'home_url'  => home_url(),
			'site_url'  => site_url(),
		),
		'php'       => array(
			'version'    => phpversion(),
			'extensions' => array(
				'curl'     => extension_loaded( 'curl' ),
				'json'     => extension_loaded( 'json' ),
				'mbstring' => extension_loaded( 'mbstring' ),
				'xml'      => extension_loaded( 'xml' ),
				'zip'      => extension_loaded( 'zip' ),
			),
			'memory'     => array(
				'limit' => ini_get( 'memory_limit' ),
				'usage' => size_format( memory_get_usage( true ) ),
				'peak'  => size_format( memory_get_peak_usage( true ) ),
			),
		),
		'database'  => array(
			'type'    => $db_type,
			'version' => $db_version,
		),
		'webserver' => array(
			'software' => $webserver_name,
		),
		'debug'     => array(
			'wp_debug'         => defined( 'WP_DEBUG' ) && WP_DEBUG,
			'wp_debug_log'     => defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG,
			'wp_debug_display' => defined( 'WP_DEBUG_DISPLAY' ) && WP_DEBUG_DISPLAY,
			'script_debug'     => defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG,
			'log_file'         => wpvulnerability_debug_get_log_file_info(),
		),
		'plugin'    => array(
			'version' => WPVULNERABILITY_PLUGIN_VERSION,
			'path'    => WPVULNERABILITY_PLUGIN_PATH,
		),
	);

	return $info;
}

/**
 * Retrieves the status of all trackable components.
 *
 * @since 4.3.0
 *
 * @return array<int, array<string, mixed>> Array of component statuses.
 */
function wpvulnerability_debug_get_component_status() {
	$components = array(
		'core',
		'plugins',
		'themes',
		'php',
		'apache',
		'nginx',
		'mysql',
		'mariadb',
		'imagemagick',
		'curl',
		'memcached',
		'redis',
		'sqlite',
	);

	$status = array();

	foreach ( $components as $component ) {
		$version    = null;
		$detected   = false;
		$analyzed   = wpvulnerability_analyze_filter( $component );
		$cache_time = is_multisite()
			? get_site_option( 'wpvulnerability-' . $component . '-cache' )
			: get_option( 'wpvulnerability-' . $component . '-cache' );

		// Decode cache time if it's JSON-encoded.
		if ( $cache_time && is_string( $cache_time ) ) {
			$decoded = json_decode( $cache_time );
			if ( null !== $decoded ) {
				$cache_time = $decoded;
			}
		}

		// Determine detection status and version.
		switch ( $component ) {
			case 'core':
				global $wp_version;
				$version  = $wp_version;
				$detected = true;
				break;

			case 'plugins':
				if ( ! function_exists( 'get_plugins' ) ) {
					require_once ABSPATH . 'wp-admin/includes/plugin.php';
				}
				$all_plugins = get_plugins();
				$version     = count( $all_plugins ) . ' installed';
				$detected    = true;
				break;

			case 'themes':
				$all_themes = wp_get_themes();
				$version    = count( $all_themes ) . ' installed';
				$detected   = true;
				break;

			case 'php':
			case 'apache':
			case 'nginx':
			case 'mysql':
			case 'mariadb':
			case 'imagemagick':
			case 'curl':
			case 'memcached':
			case 'redis':
			case 'sqlite':
				if ( function_exists( 'wpvulnerability_get_software_version' ) ) {
					$version = wpvulnerability_get_software_version( $component );
					if ( null !== $version ) {
						$detected = true;
					}
				}
				break;
		}

		// Calculate cache status.
		$cache_status = 'No cache';
		if ( $cache_time && is_numeric( $cache_time ) ) {
			$cache_time_int = (int) $cache_time;
			$time_left      = $cache_time_int - time();
			if ( $time_left > 0 ) {
				$hours        = floor( $time_left / 3600 );
				$cache_status = sprintf( 'Fresh (%dh left)', $hours );
			} else {
				$cache_status = 'Expired';
			}
		}

		$status[] = array(
			'component'    => $component,
			'detected'     => $detected,
			'version'      => $version ? $version : '-',
			'analyzed'     => $analyzed,
			'cache_status' => $cache_status,
			'cache_time'   => $cache_time,
		);
	}

	return $status;
}

/**
 * Tests API connectivity for a specific component.
 *
 * @since 4.3.0
 *
 * @param string $component The component to test (e.g., 'core', 'plugins', 'php').
 *
 * @return array<string, mixed> Result array with success status, response data, and timing.
 */
function wpvulnerability_debug_test_api_component( $component ) {
	$result = array(
		'success'       => false,
		'component'     => $component,
		'http_code'     => 0,
		'response_time' => 0,
		'message'       => '',
		'data_preview'  => '',
	);

	// Validate component.
	$valid_components = array( 'core', 'plugins', 'themes', 'php', 'apache', 'nginx', 'mysql', 'mariadb', 'imagemagick', 'curl', 'memcached', 'redis', 'sqlite' );
	if ( ! in_array( $component, $valid_components, true ) ) {
		$result['message'] = __( 'Invalid component specified.', 'wpvulnerability' );
		return $result;
	}

	// Get version for the component.
	$version = null;
	switch ( $component ) {
		case 'core':
			global $wp_version;
			$version = $wp_version;
			break;
		case 'plugins':
		case 'themes':
			// Use a generic version for testing.
			$version = '1.0.0';
			break;
		default:
			if ( function_exists( 'wpvulnerability_get_software_version' ) ) {
				$version = wpvulnerability_get_software_version( $component );
			}
			break;
	}

	if ( ! $version ) {
		$result['message'] = __( 'Version not detected for this component.', 'wpvulnerability' );
		return $result;
	}

	// Build API URL.
	$url = WPVULNERABILITY_API_HOST . $component . '/' . $version . '/';

	// Execute request with timing.
	$start_time = microtime( true );
	$response   = wp_remote_get(
		$url,
		array(
			'timeout' => 10,
		)
	);
	$end_time   = microtime( true );

	$result['response_time'] = round( ( $end_time - $start_time ) * 1000, 2 );

	// Process response.
	if ( is_wp_error( $response ) ) {
		$result['message'] = $response->get_error_message();
		return $result;
	}

	$result['http_code'] = wp_remote_retrieve_response_code( $response );
	$body                = wp_remote_retrieve_body( $response );

	if ( 200 === $result['http_code'] ) {
		$result['success'] = true;
		$result['message'] = __( 'API request successful.', 'wpvulnerability' );

		// Create a preview of the response data.
		$decoded = json_decode( $body, true );
		if ( $decoded ) {
			$encoded = wp_json_encode( $decoded, JSON_PRETTY_PRINT );
			$preview = false !== $encoded ? $encoded : '';
			if ( strlen( $preview ) > 500 ) {
				$preview = substr( $preview, 0, 500 ) . '...';
			}
			$result['data_preview'] = $preview;
		} else {
			$result['data_preview'] = substr( $body, 0, 500 );
		}
	} else {
		$result['message'] = sprintf(
			/* translators: %d: HTTP status code */
			__( 'API returned HTTP code %d.', 'wpvulnerability' ),
			$result['http_code']
		);
	}

	return $result;
}

/**
 * Retrieves cron job status information.
 *
 * @since 4.3.0
 *
 * @return array<string, array<string, mixed>> Cron status information.
 */
function wpvulnerability_debug_get_cron_status() {
	$cron_status = array(
		'update_database'   => array(
			'hook'      => 'wpvulnerability_update_database',
			'next_run'  => null,
			'last_run'  => null,
			'scheduled' => false,
		),
		'send_notification' => array(
			'hook'      => 'wpvulnerability_notification',
			'next_run'  => null,
			'last_run'  => null,
			'scheduled' => false,
		),
	);

	// Check update database cron.
	$next_update = wp_next_scheduled( 'wpvulnerability_update_database' );
	if ( $next_update ) {
		$cron_status['update_database']['next_run']  = $next_update;
		$cron_status['update_database']['scheduled'] = true;
	}

	// Check notification cron.
	$next_notification = wp_next_scheduled( 'wpvulnerability_notification' );
	if ( $next_notification ) {
		$cron_status['send_notification']['next_run']  = $next_notification;
		$cron_status['send_notification']['scheduled'] = true;
	}

	// Last run = most recent API response log (stored as the wpvulnerability_log CPT).
	$last_log = get_posts(
		array(
			'post_type'      => 'wpvulnerability_log',
			'post_status'    => 'any',
			'posts_per_page' => 1,
			'orderby'        => 'date',
			'order'          => 'DESC',
			'fields'         => 'ids',
			'no_found_rows'  => true,
		)
	);
	if ( ! empty( $last_log ) ) {
		$timestamp = get_post_timestamp( $last_log[0] );
		if ( false !== $timestamp ) {
			$cron_status['update_database']['last_run'] = $timestamp;
		}
	}

	return $cron_status;
}

/**
 * Exports comprehensive debug information as JSON.
 *
 * @since 4.3.0
 *
 * @return string JSON-encoded debug information.
 */
function wpvulnerability_debug_export_info() {
	$config = is_multisite()
		? get_site_option( 'wpvulnerability-config', array() )
		: get_option( 'wpvulnerability-config', array() );

	$debug_data = array(
		'timestamp'            => current_time( 'mysql' ),
		'system_info'          => wpvulnerability_debug_get_system_info(),
		'components'           => wpvulnerability_debug_get_component_status(),
		'configuration'        => $config,
		'cron_status'          => wpvulnerability_debug_get_cron_status(),
		'vulnerability_counts' => array(),
	);

	// Add vulnerability counts for each component.
	$components = array( 'core', 'plugins', 'themes', 'php', 'apache', 'nginx', 'mysql', 'mariadb', 'imagemagick', 'curl', 'memcached', 'redis', 'sqlite' );
	foreach ( $components as $component ) {
		$vulnerable_option = is_multisite()
			? get_site_option( 'wpvulnerability-' . $component . '-vulnerable', 0 )
			: get_option( 'wpvulnerability-' . $component . '-vulnerable', 0 );
		$count             = is_numeric( $vulnerable_option ) ? (int) $vulnerable_option : 0;
		$debug_data['vulnerability_counts'][ $component ] = $count;
	}

	$encoded_debug = wp_json_encode( $debug_data, JSON_PRETTY_PRINT );
	return false !== $encoded_debug ? $encoded_debug : '';
}

/**
 * Clears all plugin caches and transients.
 *
 * @since 4.3.0
 *
 * @return bool True if successful, false otherwise.
 */
function wpvulnerability_debug_clear_all_caches() {
	$components = array( 'core', 'plugins', 'themes', 'php', 'apache', 'nginx', 'mysql', 'mariadb', 'imagemagick', 'curl', 'memcached', 'redis', 'sqlite' );

	foreach ( $components as $component ) {
		$key = 'wpvulnerability_' . $component;

		if ( is_multisite() ) {
			delete_site_transient( $key );
			delete_site_option( 'wpvulnerability-' . $component . '-cache' );
		} else {
			delete_transient( $key );
			delete_option( 'wpvulnerability-' . $component . '-cache' );
		}
	}

	return true;
}

/**
 * Resets plugin signatures (MD5 hashes) for plugins and themes.
 *
 * @since 4.3.0
 *
 * @return bool True if successful, false otherwise.
 */
function wpvulnerability_debug_reset_signatures() {
	if ( is_multisite() ) {
		delete_site_option( 'wpvulnerability-plugins-signature' );
		delete_site_option( 'wpvulnerability-themes-signature' );
	} else {
		delete_option( 'wpvulnerability-plugins-signature' );
		delete_option( 'wpvulnerability-themes-signature' );
	}

	return true;
}

/**
 * Retrieves all database options related to WPVulnerability.
 *
 * @since 4.3.0
 *
 * @return array<int, string> Array of option names.
 */
function wpvulnerability_debug_get_option_names() {
	$options = array(
		'wpvulnerability-config',
		'wpvulnerability-analyze',
		'wpvulnerability-statistics',
		'wpvulnerability-logs',
	);

	$components = array( 'core', 'plugins', 'themes', 'php', 'apache', 'nginx', 'mysql', 'mariadb', 'imagemagick', 'curl', 'memcached', 'redis', 'sqlite' );

	foreach ( $components as $component ) {
		$options[] = 'wpvulnerability-' . $component;
		$options[] = 'wpvulnerability-' . $component . '-cache';
		$options[] = 'wpvulnerability-' . $component . '-version';
		$options[] = 'wpvulnerability-' . $component . '-vulnerable';
	}

	$options[] = 'wpvulnerability-plugins-signature';
	$options[] = 'wpvulnerability-themes-signature';

	return $options;
}

/**
 * Retrieves the value of a specific WPVulnerability option.
 *
 * @since 4.3.0
 *
 * @param string $option_name The option name to retrieve.
 *
 * @return mixed|null The option value or null if not found.
 */
function wpvulnerability_debug_get_option_value( $option_name ) {
	if ( is_multisite() ) {
		return get_site_option( $option_name, null );
	} else {
		return get_option( $option_name, null );
	}
}

```
