get_row( $wpdb->prepare( "SELECT data_json, expires_at FROM {$wpdb->prefix}aipsc_vulnerability_cache WHERE slug = %s AND software_type = %s AND provider = %s LIMIT 1", $slug, $software_type, $provider ) ); if ( ! $row ) { return null; } // Check expiry. if ( strtotime( $row->expires_at ) < time() ) { return null; } $data = json_decode( $row->data_json, true ); return is_array( $data ) ? $data : null; } /** * Store vulnerability data in cache. * * @param string $slug Software slug. * @param string $software_type plugin|theme|core. * @param string $provider Provider name. * @param array $data Vulnerability data. * @param int $ttl TTL in seconds. * @return bool */ public function set( $slug, $software_type, $provider, array $data, $ttl = self::DEFAULT_TTL ) { global $wpdb; $now = current_time( 'mysql', true ); $expires = gmdate( 'Y-m-d H:i:s', time() + $ttl ); // Upsert via delete + insert (dbDelta-friendly). // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}aipsc_vulnerability_cache WHERE slug = %s AND software_type = %s AND provider = %s", $slug, $software_type, $provider ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery return (bool) $wpdb->insert( $wpdb->prefix . 'aipsc_vulnerability_cache', array( 'slug' => $slug, 'software_type' => $software_type, 'provider' => $provider, 'data_json' => wp_json_encode( $data ), 'fetched_at' => $now, 'expires_at' => $expires, ), array( '%s', '%s', '%s', '%s', '%s', '%s' ) ); } /** * Flush expired entries. * * @return int Rows deleted. */ public function flush_expired() { global $wpdb; $now = current_time( 'mysql', true ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching return (int) $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}aipsc_vulnerability_cache WHERE expires_at < %s", $now ) ); } /** * Flush all entries. * * @return int Rows deleted. */ public function flush_all() { global $wpdb; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching return (int) $wpdb->query( "TRUNCATE TABLE {$wpdb->prefix}aipsc_vulnerability_cache" ); } /** * Get cache statistics. * * @return array */ public function stats() { global $wpdb; $now = current_time( 'mysql', true ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter $total = (int) $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->prefix}aipsc_vulnerability_cache" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter $expired = (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM {$wpdb->prefix}aipsc_vulnerability_cache WHERE expires_at < %s", $now ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter $by_provider = $wpdb->get_results( "SELECT provider, COUNT(*) as cnt FROM {$wpdb->prefix}aipsc_vulnerability_cache GROUP BY provider", OBJECT_K ); $providers = array(); foreach ( $by_provider as $key => $row ) { $providers[ $key ] = (int) $row->cnt; } return array( 'total_entries' => $total, 'expired' => $expired, 'valid' => $total - $expired, 'by_provider' => $providers, ); } }