The updated data array containing vulnerability information. */ function wpvulnerability_get_fresh_vulnerabilities( $software ) { $version = null; $data = array( 'vulnerabilities' => null, 'vulnerable' => 0, 'lifecycle' => array(), ); switch ( $software ) { case 'php': case 'apache': case 'nginx': case 'mysql': case 'mariadb': case 'imagemagick': case 'curl': case 'memcached': case 'redis': case 'sqlite': $version = wpvulnerability_get_software_version( $software ); break; default: return $data; } if ( $version ) { $transient_key = 'wpvulnerability_' . $software; // Delete the transient so the next call fetches fresh data and repopulates it. if ( is_multisite() ) { delete_site_transient( $transient_key ); } else { delete_transient( $transient_key ); } switch ( $software ) { case 'php': case 'apache': case 'nginx': case 'mysql': case 'mariadb': case 'imagemagick': case 'curl': case 'memcached': case 'redis': case 'sqlite': // cache=1: transient was just cleared, so a fresh API call is made and result cached. $api_response = wpvulnerability_get_vulnerabilities( $software, $version, 1 ); break; } if ( ! empty( $api_response ) ) { $data['vulnerabilities'] = $api_response; $data['vulnerable'] = 1; } // Read back the transient to extract lifecycle fields from the full API response. $raw_body = is_multisite() ? get_site_transient( $transient_key ) : get_transient( $transient_key ); $raw_response = json_decode( is_string( $raw_body ) ? $raw_body : '', true ); if ( is_array( $raw_response ) && isset( $raw_response['data'] ) && is_array( $raw_response['data'] ) ) { $resp_data = $raw_response['data']; $data['lifecycle'] = array( 'name' => is_scalar( $resp_data['name'] ?? '' ) ? (string) ( $resp_data['name'] ?? '' ) : '', 'status' => is_scalar( $resp_data['status'] ?? '' ) ? (string) ( $resp_data['status'] ?? '' ) : '', 'date_start' => is_scalar( $resp_data['date_start'] ?? '' ) ? (string) ( $resp_data['date_start'] ?? '' ) : '', 'date_end' => is_scalar( $resp_data['date_end'] ?? '' ) ? (string) ( $resp_data['date_end'] ?? '' ) : '', ); } } return $data; } /** * Get Installed Software * * Retrieves the list of installed software versions, checks for vulnerabilities, * caches the data, and sends an email notification if vulnerabilities are detected. * * @since 3.5.0 * * @param string $software The software name (e.g., 'php', 'apache'). * * @return string JSON-encoded array of software data with vulnerabilities and vulnerable status. */ function wpvulnerability_get_installed( $software ) { $wpvulnerability_software_vulnerable = 0; // Retrieve fresh vulnerabilities for the installed software version. $data = wpvulnerability_get_fresh_vulnerabilities( $software ); // Check if the software version is vulnerable and count the vulnerabilities. if ( isset( $data['vulnerable'] ) && is_numeric( $data['vulnerable'] ) && (int) $data['vulnerable'] ) { $vulns = isset( $data['vulnerabilities'] ) && is_array( $data['vulnerabilities'] ) ? $data['vulnerabilities'] : array(); $wpvulnerability_software_vulnerable = count( $vulns ); } // Cache the vulnerability data and the timestamp for cache expiration. if ( is_multisite() ) { update_site_option( 'wpvulnerability-' . $software, wp_json_encode( $data ) ); update_site_option( 'wpvulnerability-' . $software . '-vulnerable', wp_json_encode( number_format( $wpvulnerability_software_vulnerable, 0, '.', '' ) ) ); update_site_option( 'wpvulnerability-' . $software . '-cache', wp_json_encode( number_format( time() + ( 3600 * wpvulnerability_cache_hours() ), 0, '.', '' ) ) ); } else { update_option( 'wpvulnerability-' . $software, wp_json_encode( $data ), false ); update_option( 'wpvulnerability-' . $software . '-vulnerable', wp_json_encode( number_format( $wpvulnerability_software_vulnerable, 0, '.', '' ) ), false ); update_option( 'wpvulnerability-' . $software . '-cache', wp_json_encode( number_format( time() + ( 3600 * wpvulnerability_cache_hours() ), 0, '.', '' ) ), false ); } // Return the JSON-encoded array of software data. $encoded = wp_json_encode( $data ); return false !== $encoded ? $encoded : ''; } /** * Get cached software vulnerabilities without triggering remote calls. * * @since 3.5.0 * * @param string $software The software name (e.g., 'php', 'apache'). * * @return array|null Array of software data with vulnerabilities, or null if software is invalid. */ function wpvulnerability_software_get_vulnerabilities( $software ) { $valid_software = array( 'php', 'apache', 'mariadb', 'mysql', 'nginx', 'imagemagick', 'curl', 'memcached', 'redis', 'sqlite' ); // Use strict comparison for in_array. if ( in_array( $software, $valid_software, true ) ) { if ( is_multisite() ) { $raw = get_site_option( 'wpvulnerability-' . $software ); $data = json_decode( is_string( $raw ) ? $raw : '', true ); } else { $raw = get_option( 'wpvulnerability-' . $software ); $data = json_decode( is_string( $raw ) ? $raw : '', true ); } return is_array( $data ) ? $data : array(); } else { return null; } } /** * Update the software cache and remove any old cache data. * * @since 3.0.0 * * @param string $software The software name (e.g., 'php', 'apache'). * * @return void */ function wpvulnerability_get_vulnerabilities_clean( $software ) { // Skip detection for components the administrator has hidden (either via the // analysis settings or a WPVULNERABILITY_HIDE_* wp-config constant). This // prevents shell_exec from running for components that are meant to be // deactivated, matching the behaviour of the core/plugins/themes clean functions. if ( ! wpvulnerability_analyze_filter( $software ) ) { return; } // Update the installed software cache. wpvulnerability_get_installed( $software ); }