File: /home/emerlux/public_html/wp-content/plugins/wpvulnerability/wpvulnerability-run.php
<?php
/**
* Running functions
*
* @package WPVulnerability
*
* @version 2.0.0
*/
defined( 'ABSPATH' ) || die( 'No script kiddies please!' );
/**
* Adds a settings link to the plugin row in the plugins list.
*
* This function conditionally adds either a network admin settings link for multisite
* or a standard settings link for single site installations.
*
* @since 3.5.0
*
* @param array $links The links that appear in the plugin row.
*
* @return array The modified array of links.
*/
function wpvulnerability_add_settings_link( $links ) {
// Check if the user has the required capabilities to view the settings link.
if ( wpvulnerability_capabilities() ) {
// Determine the correct settings link based on the environment.
if ( is_multisite() && is_network_admin() ) {
// Network admin settings link for multisite.
$links[] = '<a href="' . network_admin_url( 'settings.php?page=wpvulnerability-options' ) . '">' . __( 'Network Settings', 'wpvulnerability' ) . '</a>';
} elseif ( ! is_multisite() && is_admin() ) {
// Standard settings link for single site.
$links[] = '<a href="' . get_admin_url( null, 'options-general.php?page=wpvulnerability-options' ) . '">' . __( 'Settings', 'wpvulnerability' ) . '</a>';
}
}
return $links;
}
// Hook the function to the appropriate filters.
if ( is_multisite() ) {
add_filter( 'network_admin_plugin_action_links_' . WPVULNERABILITY_PLUGIN_BASE, 'wpvulnerability_add_settings_link' );
} else {
add_filter( 'plugin_action_links_' . WPVULNERABILITY_PLUGIN_BASE, 'wpvulnerability_add_settings_link' );
}
/**
* Updates the plugin's vulnerability data.
*
* This function updates the vulnerability data for WordPress core, plugins, themes, PHP, Apache, nginx, MariaDB, and MySQL.
* It ensures that the required functions are available by including the necessary files.
* After updating the vulnerabilities, it flushes the WordPress cache.
*
* @since 2.0.0
*
* @return void
*/
function wpvulnerability_update_database_data() {
// Ensure necessary files are included for core, plugins, and themes.
require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-core.php';
require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-plugins.php';
require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-themes.php';
require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-software.php';
wpvulnerability_delete_transients();
// Update core, plugins, and themes vulnerabilities.
wpvulnerability_core_get_vulnerabilities_clean();
wpvulnerability_plugin_get_vulnerabilities_clean();
wpvulnerability_theme_get_vulnerabilities_clean();
// Array of software types to update.
$software_types = array( 'php', 'apache', 'nginx', 'mariadb', 'mysql', 'imagemagick', 'curl', 'memcached', 'redis', 'sqlite' );
// Update vulnerabilities for each software type.
foreach ( $software_types as $software ) {
wpvulnerability_get_vulnerabilities_clean( $software );
}
wpvulnerability_statistics_get();
// Clean the WordPress cache.
wp_cache_flush();
}
/**
* Updates the plugin's vulnerability data if the cache has expired.
*
* This function checks if the cached vulnerability data for various components (core, plugins, themes, PHP, Apache, nginx, MariaDB, MySQL) has expired and updates it accordingly.
* It ensures that the required functions are available by including the necessary files.
* The function handles both multisite and single site installations.
*
* @since 3.0.0
*
* @return void
*/
function wpvulnerability_expired_database_data() {
// Ensure necessary files are included for core, plugins, and themes.
require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-core.php';
require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-plugins.php';
require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-themes.php';
require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-software.php';
// Current time for cache expiration comparison.
$cache_time = time();
// Check and update core, plugins, and themes vulnerabilities if cache has expired.
$components = array(
'core' => 'wpvulnerability-core-cache',
'plugin' => 'wpvulnerability-plugins-cache',
'theme' => 'wpvulnerability-themes-cache',
);
foreach ( $components as $component => $cache_key ) {
$cache_value = is_multisite() ? get_site_option( $cache_key ) : get_option( $cache_key );
if ( json_decode( $cache_value ) < $cache_time ) {
call_user_func( "wpvulnerability_{$component}_get_vulnerabilities_clean" );
}
}
// Array of software types to update.
$software_types = array( 'php', 'apache', 'nginx', 'mariadb', 'mysql', 'imagemagick', 'curl', 'memcached', 'redis', 'sqlite' );
// Ensure necessary files are included and update vulnerabilities for each software type.
foreach ( $software_types as $software ) {
if ( is_multisite() ) {
if ( json_decode( get_site_option( 'wpvulnerability-' . $software . '-cache' ) ) < $cache_time ) {
wpvulnerability_get_vulnerabilities_clean( $software );
}
} elseif ( json_decode( get_option( 'wpvulnerability-' . $software . '-cache' ) ) < $cache_time ) {
wpvulnerability_get_vulnerabilities_clean( $software );
}
}
wpvulnerability_statistics_get();
unset( $cache_time );
}
/**
* Callback function for when the plugin is activated.
* Adds plugin data options if they are not already created.
*
* @since 2.0.0
*
* @return void
*/
function wpvulnerability_activation() {
$is_multisite = is_multisite();
$config_key = $is_multisite ? 'get_site_option' : 'get_option';
$add_option = $is_multisite ? 'add_site_option' : 'add_option';
$update_option = $is_multisite ? 'update_site_option' : 'update_option';
wpvulnerability_delete_transients();
// Add wpvulnerability-config option if it does not exist.
if ( ! $config_key( 'wpvulnerability-config' ) ) {
$default_config = array(
'emails' => get_bloginfo( 'admin_email' ),
'period' => 'weekly',
'day' => 'monday',
'hour' => 0,
'minute' => 0,
'cache' => 12,
'notify' => array(
'email' => 'y',
'slack' => 'n',
'teams' => 'n',
),
'slack_webhook' => '',
'teams_webhook' => '',
);
$add_option( 'wpvulnerability-config', $default_config );
}
// Add other options if they do not exist.
$options = array(
'wpvulnerability-plugins' => '',
'wpvulnerability-plugins-cache' => 0,
'wpvulnerability-plugins-vulnerable' => 0,
'wpvulnerability-plugins-data' => '',
'wpvulnerability-plugins-data-cache' => 0,
'wpvulnerability-themes' => '',
'wpvulnerability-themes-cache' => 0,
'wpvulnerability-themes-vulnerable' => 0,
'wpvulnerability-core' => '',
'wpvulnerability-core-cache' => 0,
'wpvulnerability-core-vulnerable' => 0,
'wpvulnerability-php' => '',
'wpvulnerability-php-cache' => 0,
'wpvulnerability-php-vulnerable' => 0,
'wpvulnerability-apache' => '',
'wpvulnerability-apache-cache' => 0,
'wpvulnerability-apache-vulnerable' => 0,
'wpvulnerability-nginx' => '',
'wpvulnerability-nginx-cache' => 0,
'wpvulnerability-nginx-vulnerable' => 0,
'wpvulnerability-mariadb' => '',
'wpvulnerability-mariadb-cache' => 0,
'wpvulnerability-mariadb-vulnerable' => 0,
'wpvulnerability-mysql' => '',
'wpvulnerability-mysql-cache' => 0,
'wpvulnerability-mysql-vulnerable' => 0,
'wpvulnerability-imagemagick' => '',
'wpvulnerability-imagemagick-cache' => 0,
'wpvulnerability-imagemagick-vulnerable' => 0,
'wpvulnerability-curl' => '',
'wpvulnerability-curl-cache' => 0,
'wpvulnerability-curl-vulnerable' => 0,
'wpvulnerability-memcached' => '',
'wpvulnerability-memcached-cache' => 0,
'wpvulnerability-memcached-vulnerable' => 0,
'wpvulnerability-redis' => '',
'wpvulnerability-redis-cache' => 0,
'wpvulnerability-redis-vulnerable' => 0,
'wpvulnerability-sqlite' => '',
'wpvulnerability-sqlite-cache' => 0,
'wpvulnerability-sqlite-vulnerable' => 0,
'wpvulnerability-statistics' => '',
'wpvulnerability-statistics-cache' => 0,
);
foreach ( $options as $key => $value ) {
if ( ! $config_key( $key ) ) {
$add_option( $key, $value );
}
}
// Add wpvulnerability-analyze option if it does not exist.
if ( ! $config_key( 'wpvulnerability-analyze' ) ) {
$default_analyze = array(
'core' => 0,
'plugins' => 0,
'themes' => 0,
'php' => 0,
'apache' => 0,
'nginx' => 0,
'mariadb' => 0,
'mysql' => 0,
'imagemagick' => 0,
'curl' => 0,
'memcached' => 0,
'redis' => 0,
'sqlite' => 0,
);
foreach ( array_keys( $default_analyze ) as $component ) {
$constant = 'WPVULNERABILITY_HIDE_' . strtoupper( $component );
if ( defined( $constant ) && constant( $constant ) ) {
$default_analyze[ $component ] = 1;
}
}
$current_option = $config_key( 'wpvulnerability-analyze' );
if ( false === $current_option ) {
$add_option( 'wpvulnerability-analyze', $default_analyze );
} else {
$updated_option = array_merge( $default_analyze, $current_option );
if ( $updated_option !== $current_option ) {
$update_option( 'wpvulnerability-analyze', $updated_option );
}
}
}
}
/**
* Callback function to run when the plugin is deactivated.
* Deletes options and removes scheduled wp-cron jobs.
*
* @since 2.0.0
*
* @return void
*/
function wpvulnerability_deactivation() {
$options = array(
'wpvulnerability_settings',
'wpvulnerability-data',
'wpvulnerability-analyze',
'wpvulnerability-themes',
'wpvulnerability-themes-cache',
'wpvulnerability-themes-vulnerable',
'wpvulnerability-plugins',
'wpvulnerability-plugins-cache',
'wpvulnerability-plugins-vulnerable',
'wpvulnerability-core',
'wpvulnerability-core-cache',
'wpvulnerability-core-vulnerable',
'wpvulnerability-php',
'wpvulnerability-php-cache',
'wpvulnerability-php-vulnerable',
'wpvulnerability-apache',
'wpvulnerability-apache-cache',
'wpvulnerability-apache-vulnerable',
'wpvulnerability-nginx',
'wpvulnerability-nginx-cache',
'wpvulnerability-nginx-vulnerable',
'wpvulnerability-mariadb',
'wpvulnerability-mariadb-cache',
'wpvulnerability-mariadb-vulnerable',
'wpvulnerability-mysql',
'wpvulnerability-mysql-cache',
'wpvulnerability-mysql-vulnerable',
'wpvulnerability-imagemagick',
'wpvulnerability-imagemagick-cache',
'wpvulnerability-imagemagick-vulnerable',
'wpvulnerability-curl',
'wpvulnerability-curl-cache',
'wpvulnerability-curl-vulnerable',
'wpvulnerability-memcached',
'wpvulnerability-memcached-cache',
'wpvulnerability-memcached-vulnerable',
'wpvulnerability-redis',
'wpvulnerability-redis-cache',
'wpvulnerability-redis-vulnerable',
'wpvulnerability-sqlite',
'wpvulnerability-sqlite-cache',
'wpvulnerability-sqlite-vulnerable',
'wpvulnerability-statistics',
'wpvulnerability-statistics-cache',
);
// Delete options based on the installation type.
$delete_option_func = is_multisite() ? 'delete_site_option' : 'delete_option';
foreach ( $options as $option ) {
$delete_option_func( $option );
}
wpvulnerability_delete_transients();
// Unschedule and remove scheduled wp-cron jobs.
$cron_jobs = array(
'wpvulnerability_notification',
'wpvulnerability_update_database',
'wpvulnerability_pull_db_data_event',
);
foreach ( $cron_jobs as $job ) {
wp_unschedule_event( wp_next_scheduled( $job ), $job );
wp_clear_scheduled_hook( $job );
}
}
/**
* Deletes all transients that start with 'wpvulnerability_'.
*
* @since 3.5.0
*
* @return void
*/
function wpvulnerability_delete_transients() {
global $wpdb;
// Determine if the site is multisite.
$is_multisite = is_multisite();
// Define the prefix according to whether it is multisite or not.
$transient_prefix = $is_multisite ? '_site_transient_wpvulnerability_' : '_transient_wpvulnerability_';
// Prepare the LIKE pattern securely.
$like_pattern = $wpdb->esc_like( $transient_prefix ) . '%';
// Try to get transients from cache first.
$cache_key = 'wpvulnerability_transients_list';
$transients = wp_cache_get( $cache_key );
if ( false === $transients ) {
// If cache is empty, query the database for matching transients.
$transients = $wpdb->get_col( // phpcs:ignore
$wpdb->prepare(
"SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE %s",
$like_pattern
)
); // phpcs:ignore
// Store the result in cache for future use.
wp_cache_set( $cache_key, $transients, '', HOUR_IN_SECONDS );
}
// If no transients are found, exit early.
if ( empty( $transients ) ) {
return;
}
foreach ( $transients as $transient ) {
if ( $is_multisite ) {
// For multisite, delete using delete_site_transient.
$transient_name = str_replace( '_site_transient_', '', $transient );
delete_site_transient( $transient_name );
} else {
// For single sites, delete using delete_transient.
$transient_name = str_replace( '_transient_', '', $transient );
delete_transient( $transient_name );
}
}
// Optionally clear the cache after deletion.
wp_cache_delete( $cache_key );
}
/**
* Callback function to run when the plugin is uninstalled.
* Deletes options and removes scheduled wp-cron jobs.
*
* @since 3.0.0
*
* @return void
*/
function wpvulnerability_uninstall() {
// Delete deprecated options.
delete_option( 'wpvulnerability_settings' );
delete_option( 'wpvulnerability-data' );
// Options to delete for both single site and multisite.
$options = array(
'wpvulnerability-themes',
'wpvulnerability-themes-cache',
'wpvulnerability-themes-vulnerable',
'wpvulnerability-plugins',
'wpvulnerability-plugins-cache',
'wpvulnerability-plugins-vulnerable',
'wpvulnerability-core',
'wpvulnerability-core-cache',
'wpvulnerability-core-vulnerable',
'wpvulnerability-php',
'wpvulnerability-php-cache',
'wpvulnerability-php-vulnerable',
'wpvulnerability-apache',
'wpvulnerability-apache-cache',
'wpvulnerability-apache-vulnerable',
'wpvulnerability-nginx',
'wpvulnerability-nginx-cache',
'wpvulnerability-nginx-vulnerable',
'wpvulnerability-mariadb',
'wpvulnerability-mariadb-cache',
'wpvulnerability-mariadb-vulnerable',
'wpvulnerability-mysql',
'wpvulnerability-mysql-cache',
'wpvulnerability-mysql-vulnerable',
'wpvulnerability-imagemagick',
'wpvulnerability-imagemagick-cache',
'wpvulnerability-imagemagick-vulnerable',
'wpvulnerability-curl',
'wpvulnerability-curl-cache',
'wpvulnerability-curl-vulnerable',
'wpvulnerability-memcached',
'wpvulnerability-memcached-cache',
'wpvulnerability-memcached-vulnerable',
'wpvulnerability-redis',
'wpvulnerability-redis-cache',
'wpvulnerability-redis-vulnerable',
'wpvulnerability-sqlite',
'wpvulnerability-sqlite-cache',
'wpvulnerability-sqlite-vulnerable',
'wpvulnerability-statistics',
'wpvulnerability-statistics-cache',
'wpvulnerability-analyze',
);
// Delete options based on the installation type.
$delete_option_func = is_multisite() ? 'delete_site_option' : 'delete_option';
foreach ( $options as $option ) {
$delete_option_func( $option );
}
// Delete config data.
$delete_option_func( 'wpvulnerability-config' );
wpvulnerability_delete_transients();
// Unschedule and remove scheduled wp-cron jobs.
$cron_jobs = array(
'wpvulnerability_notification',
'wpvulnerability_update_database',
);
foreach ( $cron_jobs as $job ) {
wp_unschedule_event( wp_next_scheduled( $job ), $job );
wp_clear_scheduled_hook( $job );
}
}
/**
* Filters and returns the WPVulnerability analysis setting for a given type.
*
* This function retrieves the WPVulnerability analysis settings, either from
* the single site or the multisite network, depending on the WordPress setup.
* It returns false if the specified type ('core', 'plugins', 'themes',
* 'php', 'apache', 'nginx', 'mariadb', 'mysql') is set. If the type is not set or is invalid, it returns true.
*
* @since 3.3.0
*
* @param string $type The type of analysis setting to retrieve ('core', 'plugins', 'themes', 'php', 'apache', 'nginx', 'mariadb', 'mysql').
*
* @return bool False if the specified type is set, true if not set or invalid.
*/
function wpvulnerability_analyze_filter( $type ) {
// Retrieve the analysis settings based on the WordPress setup.
$wpvulnerability_analyze = is_multisite() ? get_site_option( 'wpvulnerability-analyze', array() ) : get_option( 'wpvulnerability-analyze', array() );
// Define the valid types for analysis.
$valid_types = array( 'core', 'plugins', 'themes', 'php', 'apache', 'nginx', 'mariadb', 'mysql', 'imagemagick', 'curl', 'memcached', 'redis', 'sqlite' );
if ( in_array( $type, $valid_types, true ) ) {
$constant = 'WPVULNERABILITY_HIDE_' . strtoupper( $type );
if ( defined( $constant ) && constant( $constant ) ) {
return false;
}
return ! ( isset( $wpvulnerability_analyze[ $type ] ) && (int) $wpvulnerability_analyze[ $type ] );
}
return true; // Return true for invalid types.
}
/**
* Clean the cache after an update.
*
* This function is triggered after a plugin or theme update to clean the cache
* and refresh the vulnerability data.
*
* @since 2.0.0
*
* @return void
*/
add_action( 'upgrader_process_complete', 'wpvulnerability_update_database_data', 10, 2 );
/**
* Adds a notification count to the Plugins menu item in the WordPress admin if there are vulnerable plugins.
*
* This function retrieves the number of vulnerable plugins from the cache, either from a single site
* or a multisite setup, and displays the count in the WordPress admin menu next to the Plugins menu item.
* The count is shown with a gold background (#FFD700) and black text.
*
* @since 3.3.5
*
* @return void
*/
function wpvulnerability_counter_plugins() {
if ( ! wpvulnerability_analyze_filter( 'plugins' ) ) {
return; // Skip if plugin analysis is disabled.
}
// Retrieve the number of vulnerable plugins from cache.
$wpvulnerability_plugins_count = is_multisite() && is_network_admin()
? get_site_option( 'wpvulnerability-plugins-vulnerable' )
: get_option( 'wpvulnerability-plugins-vulnerable' );
// Decode the count from JSON, default to 0 if not set.
$wpvulnerability_plugins_total = $wpvulnerability_plugins_count ? json_decode( $wpvulnerability_plugins_count ) : 0;
if ( $wpvulnerability_plugins_total > 0 ) {
global $menu;
foreach ( $menu as $key => $value ) {
if ( 'plugins.php' === $menu[ $key ][2] ) {
$menu[ $key ][0] .= ' <span class="update-plugins" style="background-color: #FFD700; color: #000000;"><span class="update-count" title="' . __( 'Vulnerabilities', 'wpvulnerability' ) . '">' . esc_html( $wpvulnerability_plugins_total ) . '</span></span>'; // phpcs:ignore
break;
}
}
}
}
// Hook into the appropriate admin menu action based on the site type.
if ( is_multisite() && is_network_admin() ) {
add_action( 'network_admin_menu', 'wpvulnerability_counter_plugins' );
} elseif ( ! is_multisite() ) {
add_action( 'admin_menu', 'wpvulnerability_counter_plugins' );
}
/**
* Adds a notification count to the Themes menu item in the WordPress admin if there are vulnerable themes.
*
* This function retrieves the number of vulnerable themes from the cache, either from a single site
* or a multisite setup, and displays the count in the WordPress admin menu next to the Themes menu item.
* The count is displayed with a gold background (#FFD700) and black text.
*
* @since 3.3.5
*
* @return void
*/
function wpvulnerability_counter_themes() {
if ( ! wpvulnerability_analyze_filter( 'themes' ) ) {
return; // Skip if theme analysis is disabled.
}
// Retrieve the number of theme vulnerabilities from cache.
$wpvulnerability_themes_count = ( is_multisite() && is_network_admin() )
? get_site_option( 'wpvulnerability-themes-vulnerable' )
: get_option( 'wpvulnerability-themes-vulnerable' );
// Decode the count from JSON, default to 0 if not set.
$wpvulnerability_themes_total = $wpvulnerability_themes_count ? json_decode( $wpvulnerability_themes_count ) : 0;
if ( $wpvulnerability_themes_total > 0 ) {
// Check if we are in a multisite setup or not.
if ( ! is_multisite() ) {
global $submenu;
// Check if the submenu for themes exists.
if ( isset( $submenu['themes.php'] ) ) {
foreach ( $submenu['themes.php'] as $key => $value ) {
if ( 'themes.php' === $submenu['themes.php'][ $key ][2] ) {
$submenu['themes.php'][ $key ][0] .= ' <span class="update-plugins" style="background-color: #FFD700; color: #000000;"><span class="update-count" title="' . esc_html__( 'Vulnerabilities', 'wpvulnerability' ) . '">' . esc_html( $wpvulnerability_themes_total ) . '</span></span>'; // phpcs:ignore
break;
}
}
}
} elseif ( is_network_admin() ) {
global $menu;
foreach ( $menu as $key => $value ) {
if ( 'themes.php' === $menu[ $key ][2] ) {
$menu[ $key ][0] .= ' <span class="update-plugins" style="background-color: #FFD700; color: #000000;"><span class="update-count" title="' . esc_html__( 'Vulnerabilities', 'wpvulnerability' ) . '">' . esc_html( $wpvulnerability_themes_total ) . '</span></span>'; // phpcs:ignore
break;
}
}
}
}
}
// Hook into the appropriate admin menu action based on the site type.
if ( is_multisite() && is_network_admin() ) {
add_action( 'network_admin_menu', 'wpvulnerability_counter_themes' );
} elseif ( ! is_multisite() ) {
add_action( 'admin_menu', 'wpvulnerability_counter_themes' );
}
/**
* Adds a notification count to the Updates submenu item under Dashboard in the WordPress admin if there are core updates.
*
* This function checks for core updates and then displays the count in the WordPress admin submenu
* next to the Updates menu item with a gold background (#FFD700) and black text.
*
* @since 3.3.5
*
* @return void
*/
function wpvulnerability_counter_core() {
if ( ! wpvulnerability_analyze_filter( 'core' ) ) {
return; // Skip if core analysis is disabled.
}
// Retrieve the number of core vulnerabilities from cache.
$wpvulnerability_core_count = is_multisite() && is_network_admin()
? get_site_option( 'wpvulnerability-core-vulnerable' )
: get_option( 'wpvulnerability-core-vulnerable' );
// Decode the count from JSON, default to 0 if not set.
$wpvulnerability_core_total = $wpvulnerability_core_count ? json_decode( $wpvulnerability_core_count ) : 0;
if ( $wpvulnerability_core_total > 0 ) {
global $submenu;
if ( isset( $submenu['index.php'] ) ) {
foreach ( $submenu['index.php'] as $key => $value ) {
if ( 'update-core.php' === $submenu['index.php'][ $key ][2] ) {
$submenu['index.php'][ $key ][0] .= ' <span class="update-plugins" style="background-color: #FFD700; color: #000000;"><span class="update-count" title="' . __( 'Vulnerabilities', 'wpvulnerability' ) . '">' . esc_html( $wpvulnerability_core_total ) . '</span></span>'; // phpcs:ignore
break;
}
}
}
}
}
// Hook into the appropriate admin menu action based on the site type.
if ( is_multisite() && is_network_admin() ) {
add_action( 'network_admin_menu', 'wpvulnerability_counter_core' );
} elseif ( ! is_multisite() ) {
add_action( 'admin_menu', 'wpvulnerability_counter_core' );
}