*/ class Wp_Database_Tools_Database_Options extends Wp_Database_Tools_Database { /** * All the information processed from the options * * @since 1.0.0 * @access protected * @var array $data Options data. */ protected $data; /** * The general data of database. * * @since 1.0.0 * @access protected * @var array $data The general data of database. */ protected $count; /** * Initialize the class. * * @since 1.0.0 * * @param array $plugins Values plugins. * @param array $themes Values themes. * @param String $matching Value of the source. * @param String $license_status Value of the source. */ public function __construct( $plugins, $themes, $matching, $license_status ) { $this->plugins = $plugins; $this->themes = $themes; $this->matching = $matching; $this->license_status = $license_status; // Set total count. $this->check_count(); } /** * Sets the total number of records * * @since 1.0.0 */ public function check_count() { global $wpdb; $num_rows = $wpdb->get_var( 'SELECT COUNT(option_id) FROM ' . $wpdb->prefix . "options WHERE option_name NOT LIKE ('%\_transient\_%')" ); $this->count = $num_rows; } /** * Prepare data to loop over records * * @since 1.0.0 */ private function prepare_data() { // Custom key. $this->key = 'options'; // Limit to query. $this->limit = 1000; // Multiples origins. $this->is_multiple = false; // Loading ajax call. $this->current_loading = 0; // Prepare data. $this->full_data = parent::init_full_data(); // API data. $this->api_data = parent::get_api_data( $this->key ); // Data loop transient. $this->data_loop = parent::get_data_loop( $this->key ); // Feedback. $this->feedback = parent::get_user_feedback( $this->key ); // Cache files. $this->cache_data = parent::get_data_cache_indicator( $this->key ); // Force scanner active. $this->force_execute_scanner = get_option( WPDBT_PREFIX . 'force_execute_scanner' ); // Load dependencies. parent::load_dependencies_child( $this->key ); // Set transient loading. parent::set_status_loading( 'loading', $this->current_loading, $this->data_loop, false ); } /** * Prepares the database data and applies the detection algorithm * * @since 1.0.0 */ public function check_data() { // TODO: Better way, loop json encode. ini_set( 'memory_limit', '-1' ); set_time_limit( 0 ); $this->prepare_data(); // Options data. global $wpdb; $rows = $wpdb->get_results( 'SELECT *, LENGTH(option_id) + LENGTH(option_value) + LENGTH(option_name) + LENGTH(autoload) as size FROM ' . $wpdb->prefix . "options WHERE option_name NOT LIKE ('%\_transient\_%') LIMIT " . $this->limit . ' OFFSET ' . $this->data_loop['offset'] ); // Loading ajax call. $max_loading = count( $rows ); // Count for cache. $sql = $wpdb->prepare( 'SELECT SUM(%1s) AS sum_ids FROM %1s WHERE %1s NOT LIKE %s', 'option_id', $wpdb->prefix . 'options', 'option_name', '%_transient_%' ); $sum_ids = $wpdb->get_results( $sql ); $sum_ids = strval( $sum_ids[0]->sum_ids ); // Count ids from cache. $sum_ids_cache = strval( array_sum( array_column( (array) $this->cache_data['source']['data'], 'id' ) ) ); if ( $sum_ids === $sum_ids_cache && $this->cache_data['indicators']->api === strlen( wp_json_encode( $this->api_data['source'] ) ) && $this->cache_data['indicators']->status === strlen( wp_json_encode( array( $this->feedback, $this->license_status ) ) ) ) { if ( ! empty( $this->cache_data['source'] ) && ! is_null( $this->cache_data['source'] ) ) { if ( $this->license_status ) { Wp_Database_Tools_Logger::info( 'OPTIONS: load data by cache' ); // Set data loop (total). parent::set_data_loop( $this->limit, $this->data_loop['offset'], $this->count, $this->key ); $this->data_loop = parent::get_data_loop( $this->key ); $this->data = parent::calculate_data_source_size( $this->cache_data['source'] ); // Set status loading. parent::set_status_loading( 'success', 100, $this->data_loop, true ); return; } } } elseif ( false === $this->data_loop['is_finish'] ) { // Count ids from cache. if ( isset( $this->cache_data['source']['data'] ) ) { $sum_ids_cache = strval( array_sum( array_column( $this->cache_data['source']['data'], 'id' ) ) ); $sum_ids_cache = ( $this->cache_data['indicators']->ids < $sum_ids && $this->data_loop['loops'] !== 1 ) ? $sum_ids_cache + $this->cache_data['indicators']->ids : $sum_ids_cache; } elseif ( $this->cache_data['indicators']->ids > $sum_ids ) { $sum_ids_cache = 0; } parent::set_cache_indicators( $this->key, $this->api_data['source'], $this->feedback, $sum_ids_cache ); } Wp_Database_Tools_Logger::info( 'OPTIONS: starting to process data' ); // TODO: Pass cache management to other class $cache_path = plugin_dir_path( __DIR__ ) . 'data/cache/' . WPDBT_PREFIX . $this->key; // IF first loop reset cache file. if ( 0 === $this->data_loop['offset'] ) { $success_cache = file_put_contents( $cache_path . '_' . $this->key . '.json', wp_json_encode( mb_convert_encoding( array(), 'UTF-8' ) ) ); } // Set data loop. parent::set_data_loop( $this->limit, $this->data_loop['offset'], $this->count, $this->key ); // Get if finish. $this->data_loop = parent::get_data_loop( $this->key ); Wp_Database_Tools_Logger::info( 'OPTIONS: ' . json_encode( $this->data_loop ) ); // Si ha finalizado establecesmos la data. if ( true === $this->data_loop['is_finish'] ) { // Get cache. $this->cache_data['source'] = json_decode( file_get_contents( $cache_path . '_' . $this->key . '.json' ), true ); Wp_Database_Tools_Logger::info( 'OPTIONS: ending to process data ' . count( $this->cache_data['source'] ) ); // Get source data and calculate finihs size. $this->data = parent::calculate_data_source_size( $this->cache_data['source'] ); // Set status loading. parent::set_status_loading( 'success', 100, $this->data_loop, false ); // Reset values loop. parent::remove_data_loop( $this->key ); return; } foreach ( $rows as $row_option ) { $option = new Wp_Database_Tools_Database_Data_Option( $row_option, $this->feedback ); // sum size. $this->full_data['size']['total']['value'] += $option->get_size(); if ( $option->get_autoload() == 'yes' ) { $this->full_data['size']['autoload']['value'] += $option->get_size(); } $key_api_data = false; // If license is valid. if ( $this->license_status ) { // Prepare origin. if ( $this->api_data['source'] != null ) { $search_term = ( $option->get_regex() !== false ) ? $option->get_regex() : $option->get_name(); $key_api_data = array_keys( array_column( (array) $this->api_data['source'], 'name' ), $search_term ); } // If key found. if ( false !== $key_api_data && ! empty( $key_api_data ) ) { // Check multiple only for verified registers. $key_api_data_verified = $key_api_data; foreach ( $key_api_data_verified as $index => $key ) { if ( $this->api_data['source'][ $key ]->verified !== 1 ) { unset( $key_api_data_verified[ $index ] ); } } $this->is_multiple = count( $key_api_data_verified ) > 1; // Multiples values. if ( $this->is_multiple ) { $option->set_multiple( true ); $option->origin = array(); foreach ( $key_api_data_verified as $key ) { $api_data = parent::set_data_api( $this->api_data['source'][ $key ], $this->api_data['plugins'], $this->api_data['themes'], $this->api_data['cores'], $this->api_data['marketplaces'], $this->api_data['authors'], $this->key ); $origin = new Wp_Database_Tools_Database_Data_Origin(); $origin->set_origin_by_api( $api_data, $this->key ); // Marketplace. $marketplace = $origin->get_marketplace(); $origin->set_marketplace( $marketplace->return_object_vars() ); // Auhor. $author = $origin->get_author(); $origin->set_author( $author->return_object_vars() ); // Origin. $origin->set_status( $this->plugins, $this->themes ); $origin->set_question( $option->get_name() ); $this->full_data['origins'] = $origin->check_choices( $this->full_data['origins'] ); array_push( $option->origin, $origin->return_object_vars() ); } // Simple values. } else { $this->is_multiple = false; $key_api_data = $key_api_data[0]; $api_data = parent::set_data_api( $this->api_data['source'][ $key_api_data ], $this->api_data['plugins'], $this->api_data['themes'], $this->api_data['cores'], $this->api_data['marketplaces'], $this->api_data['authors'], $this->key ); $option->origin->set_origin_by_api( $api_data, $this->key ); $option->origin->set_question( $option->get_name() ); $option->origin->set_status( $this->plugins, $this->themes ); } } else { $this->is_multiple = false; if ( 'NO' === $this->force_execute_scanner && false === $option->get_regex() ) { $data_algorithm = $option->get_matching_data( $this->matching, $this->plugins, $this->themes, $option->get_name() ); if ( ! is_null( $data_algorithm ) ) { $option->set_data_by_algorithm( $data_algorithm ); $option->origin->set_status( $this->plugins, $this->themes ); } } } } if ( ! $this->is_multiple ) { $this->full_data['origins'] = $option->origin->check_choices( $this->full_data['origins'] ); // Marketplace. $marketplace = $option->origin->get_marketplace(); $option->origin->set_marketplace( $marketplace->return_object_vars() ); // Auhor. $author = $option->origin->get_author(); $option->origin->set_author( $author->return_object_vars() ); // Origin. $option->set_origin( $option->origin->return_object_vars() ); } $option_array = $option->return_object_vars( $option ); // Prevent encoding. if ( ! mb_check_encoding( $option_array ) ) { Wp_Database_Tools_Logger::error( 'OPTIONS: error encoding ' . $option_array['name'] ); continue; } if ( is_array( $option_array ) ) { array_push( $this->full_data['data'], $option_array ); } else { Wp_Database_Tools_Logger::error( 'OPTIONS: error add ' . $option_array['name'] ); continue; } parent::set_status_loading( 'loading', 100 * $this->current_loading / $max_loading, $this->data_loop, false ); $this->current_loading++; // Memory optimization. unset( $row_option ); } $this->full_data['plugins'] = $this->plugins; $this->full_data['themes'] = $this->themes; // If it is finished we establish the data. if ( false === $this->data_loop['is_finish'] ) { // Get cache data. $current_cache = json_decode( file_get_contents( $cache_path . '_' . $this->key . '.json' ), true ); // Encoding current data. $new_cache = $this->full_data; if ( ! isset( $new_cache['data'] ) ) { Wp_Database_Tools_Logger::error( 'OPTIONS: error data new cache not found' ); } if ( ! isset( $current_cache['data'] ) ) { Wp_Database_Tools_Logger::error( 'OPTIONS: error data current cache not found' ); } if ( mb_check_encoding( $this->full_data ) ) { Wp_Database_Tools_Logger::info( 'OPTIONS: available encoding' ); try { $new_cache = mb_convert_encoding( $this->full_data, 'UTF-8' ); } catch ( Exception $e ) { $new_cache = $this->full_data; Wp_Database_Tools_Logger::error( 'OPTIONS: the data cache has not been encoded properly' ); } if ( $new_cache === null || ! isset( $new_cache['data'] ) ) { Wp_Database_Tools_Logger::error( 'OPTIONS: the data cache has not been encoded properly' ); $new_cache = $this->full_data; } } if ( ! isset( $new_cache['data'] ) ) { Wp_Database_Tools_Logger::error( 'OPTIONS: error data new cache after encoding' ); } if ( ! isset( $current_cache['data'] ) ) { Wp_Database_Tools_Logger::error( 'OPTIONS: error data current cache after encoding' ); } // Merge data. $current_cache = array_merge_recursive( $current_cache, $new_cache ); if ( ! isset( $current_cache['data'] ) ) { Wp_Database_Tools_Logger::error( 'OPTIONS: error merge options data' ); } // Save data cache. $current_cache = wp_json_encode( $current_cache ); $save_cache = file_put_contents( $cache_path . '_' . $this->key . '.json', $current_cache ); if ( false === $save_cache ) { Wp_Database_Tools_Logger::error( 'OPTIONS: error save json' ); } } // Loading status. parent::set_status_loading( 'loading', 0, $this->data_loop, false ); // Memory optimization. unset( $this->full_data ); unset( $this->api_data ); unset( $this->cache_data ); unset( $new_cache ); unset( $current_cache ); gc_collect_cycles(); } /** * Call a specific method depending on the action to be performed. * * @since 1.0.0 */ public function action_form() { // TODO: nonce verification. switch ( $_POST['action-type'] ) { case 'delete': $this->delete(); break; case 'edit': $this->edit(); break; } wp_redirect( $_POST['current-url'] . '&' . WPDBT_PREFIX . 'notice=options' ); } /** * Deletes the records that are indicated in $POST through keys. * These keys are used in a query. The result is stored in a transient, * which is then returned as a warning to the user.. * * @since 1.0.0 */ public function delete() { // TODO: nonce verification. $action_keys = $_POST['action-keys']; $action_keys = explode( '↕', $action_keys ); $errors_messages = ''; $successes_messages = ''; $options_array_successes = array(); $options_array_errors = array(); foreach ( $action_keys as $option_key ) { $option_delete = delete_option( $option_key ); if ( $option_delete === true ) { array_push( $options_array_successes, $option_key ); } else { array_push( $options_array_errors, $option_key ); } } if ( ! empty( $options_array_successes ) ) { $successes_messages .= parent::generate_message_success( 'options', 'option_names', $options_array_successes, __( 'removed', 'wp-database-tools' ) ); set_transient( WPDBT_PREFIX . 'successes', $successes_messages ); } if ( ! empty( $options_array_errors ) ) { $errors_messages .= parent::generate_message_error( 'options', 'option_names', $options_array_errors, __( 'removed', 'wp-database-tools' ) ); set_transient( WPDBT_PREFIX . 'errors', $errors_messages ); } parent::set_cache_indicators( 'options', 0, 0, 0 ); } /** * Edit the records that are indicated in $POST through keys. * These keys are used in a query. The result is stored in a transient, * which is then returned as a warning to the user.. * * @since 1.0.0 */ public function edit() { // TODO: nonce verification. $action_keys = $_POST['action-keys']; $action_keys = explode( '↕', $action_keys ); $autoload = $_POST['autoload']; $errors_messages = ''; $successes_messages = ''; $options_array_successes = array(); $options_array_errors = array(); foreach ( $action_keys as $option_key ) { global $wpdb; $table_name = $wpdb->prefix . 'options'; $sql = $wpdb->prepare( 'UPDATE %1s SET autoload = %s WHERE option_name LIKE %s', $table_name, $autoload, $option_key ); $resuls = $wpdb->get_results( $sql ); if ( ! empty( $resuls ) ) { array_push( $options_array_errors, $option_key ); } else { array_push( $options_array_successes, $option_key ); } } if ( ! empty( $options_array_successes ) ) { $successes_messages .= parent::generate_message_success( 'options', 'option_names', $options_array_successes, __( 'edited', 'wp-database-tools' ) ); set_transient( WPDBT_PREFIX . 'successes', $successes_messages ); } if ( ! empty( $options_array_errors ) ) { $errors_messages .= parent::generate_message_error( 'options', 'option_names', $options_array_errors, __( 'edited', 'wp-database-tools' ) ); set_transient( WPDBT_PREFIX . 'errors', $errors_messages ); } parent::set_cache_indicators( 'options', 0, 0, 0 ); } /** * The array of data of general database. * * @since 1.0.0 * @return array The array of data. */ public function get_data() { $count_data = is_array( $this->data ) ? count( $this->data['data'] ) : 'null'; Wp_Database_Tools_Logger::info( 'OPTIONS: return data ' . $count_data ); return $this->data; } /** * The array of data of general database. * * @since 1.0.0 * @return array The array of data. */ public function get_count() { return $this->count; } }