*/ class Wp_Database_Tools_Database_Tables extends Wp_Database_Tools_Database { /** * All the information processed from the tables * * @since 1.0.0 * @access protected * @var array $data Tables data. */ protected $data; /** * The general data of database. * * @since 1.0.0 * @access protected * @var array $data The general data of database. */ protected $size; /** * The general data of database. * * @since 1.0.0 * @access protected * @var array $data The general data of database. */ protected $count; 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(); } public function check_count() { global $wpdb; $num_rows = $wpdb->get_var( "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = '" . $wpdb->dbname . "'" ); $this->count = $num_rows; } /** * Prepare data to loop over records * * @since 1.0.4 */ private function prepare_data() { // Custom key. $this->key = 'tables'; // 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 ); } public function check_data() { // TODO: Better way, loop json encode. ini_set( 'memory_limit', '-1' ); set_time_limit( 0 ); $this->prepare_data(); // Tables data. global $wpdb; $rows = $wpdb->get_results( 'SHOW table STATUS' ); // Loading ajax call. $max_loading = count( $rows ); $sum_ids = $max_loading; // Custom atributtes. $db_size = 0; if ( $sum_ids === $this->cache_data['indicators']->ids && $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'] ) ) { Wp_Database_Tools_Logger::info( 'TABLES: cache data is ok' ); if ( $this->license_status ) { Wp_Database_Tools_Logger::info( 'TABLES: license valid' ); // 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 ); // Log cache. $count_data = is_array( $this->cache_data['source'] ) ? count( $this->cache_data['source']['data'] ) : 'null'; Wp_Database_Tools_Logger::info( 'TABLES: return data cache ' . $count_data ); $this->data = $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. // In tables we only give a single loop. $sum_ids_cache = $sum_ids; parent::set_cache_indicators( $this->key, $this->api_data['source'], $this->feedback, $sum_ids_cache ); } // 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 ); // 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( 'TABLES: 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_table ) { $table = new Wp_Database_Tools_Database_Data_Table( $row_table, $this->feedback ); $db_size += $table->get_size(); $key_api_data = false; // If license is valid. if ( $this->license_status ) { // Prepare origin. if ( null !== $this->api_data['source'] ) { $key_api_data = array_keys( array_column( $this->api_data['source'], 'name' ), $table->get_name() ); } // 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; $this->is_multiple = false; // Multiples values. if ( $this->is_multiple ) { $table->set_multiple( true ); $table->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( $table->get_name() ); $this->full_data['origins'] = $origin->check_choices( $this->full_data['origins'] ); array_push( $table->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 ); $table->origin->set_origin_by_api( $api_data, $this->key ); $table->origin->set_question( $table->get_name() ); $table->origin->set_status( $this->plugins, $this->themes ); } } else { $this->is_multiple = false; if ( 'NO' === $this->force_execute_scanner ) { $data_algorithm = $table->get_matching_data( $this->matching, $this->plugins, $this->themes, $table->get_name_without_prefix() ); if ( ! is_null( $data_algorithm ) ) { $table->set_data_by_algorithm( $data_algorithm ); $table->origin->set_status( $this->plugins, $this->themes ); } } } } if ( ! $this->is_multiple ) { $this->full_data['origins'] = $table->origin->check_choices( $this->full_data['origins'] ); // Marketplace. $marketplace = $table->origin->get_marketplace(); $table->origin->set_marketplace( $marketplace->return_object_vars() ); // Auhor. $author = $table->origin->get_author(); $table->origin->set_author( $author->return_object_vars() ); // Origin. $table->set_origin( $table->origin->return_object_vars() ); } // Return object vars. $table_array = $table->return_object_vars( $table ); // Prevent encoding. if ( ! mb_check_encoding( $table_array ) ) { Wp_Database_Tools_Logger::error( 'TABLES: error encoding ' . $table_array['name'] ); continue; } if ( is_array( $table_array ) ) { array_push( $this->full_data['data'], $table_array ); } else { Wp_Database_Tools_Logger::error( 'TABLES: error add ' . $table_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_table ); } if ( ! isset( $this->full_data['data'] ) ) { Wp_Database_Tools_Logger::error( 'TABLES: error tables data empty' ); } $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( 'TABLES: error data new cache not found' ); } if ( ! isset( $current_cache['data'] ) ) { Wp_Database_Tools_Logger::error( 'TABLES: error data current cache not found' ); } if ( mb_check_encoding( $new_cache ) ) { try { $new_cache = mb_convert_encoding( $this->full_data, 'UTF-8' ); } catch ( Exception $e ) { $new_cache = $this->full_data; Wp_Database_Tools_Logger::error( 'TABLES: the data cache has not been encoded properly' ); } if ( $new_cache === null || ! isset( $new_cache['data'] ) ) { Wp_Database_Tools_Logger::error( 'TABLES: the data cache has not been encoded properly' ); $new_cache = $this->full_data; } } if ( ! isset( $new_cache['data'] ) ) { Wp_Database_Tools_Logger::error( 'TABLES: error data new cache after encoding' ); } if ( ! isset( $current_cache['data'] ) ) { Wp_Database_Tools_Logger::error( 'TABLES: 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( 'TABLES: error merge tables 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( 'TABLES: error save json' ); } } unset( $new_cache ); unset( $current_cache ); // Loading status. parent::set_status_loading( 'loading', 0, $this->data_loop, false ); } /** * 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 'empty': $this->empty(); break; case 'optimize': $this->optimize(); break; case 'repair': $this->repair(); break; } wp_redirect( $_POST['current-url'] . '&' . WPDBT_PREFIX . 'notice=tables' ); } /** * 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. global $wpdb; $action_keys = $_POST['action-keys']; $action_keys = explode( '↕', $action_keys ); $action_prefix = $_POST['action-prefix']; $action_prefix = explode( '↕', $action_prefix ); $errors_messages = ''; $successes_messages = ''; $tables_array_successes = array(); $tables_array_errors = array(); foreach ( $action_keys as $key => $table_name ) { if ( $action_prefix[ $key ] == 'true' ) { $table_name = $wpdb->prefix . $table_name; } $sql = $wpdb->prepare( 'DROP TABLE IF EXISTS %1s', $table_name ); $result = $wpdb->query( $sql ); if ( $result === false ) { array_push( $tables_array_errors, $table_name ); } else { array_push( $tables_array_successes, $table_name ); } } if ( ! empty( $tables_array_successes ) ) { $successes_messages .= parent::generate_message_success( $this->key, 'names', $tables_array_successes, __( 'removed', 'wp-database-tools' ) ); set_transient( WPDBT_PREFIX . 'successes', $successes_messages ); } if ( ! empty( $tables_array_errors ) ) { $errors_messages .= parent::generate_message_error( $this->key, 'names', $tables_array_errors, __( 'removed', 'wp-database-tools' ) ); set_transient( WPDBT_PREFIX . 'errors', $errors_messages ); } parent::set_cache_indicators( 'tables', 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 empty() { // TODO: nonce verification. global $wpdb; $action_keys = $_POST['action-keys']; $action_keys = explode( '↕', $action_keys ); $action_prefix = $_POST['action-prefix']; $action_prefix = explode( '↕', $action_prefix ); $errors_messages = ''; $successes_messages = ''; $tables_array_successes = array(); $tables_array_errors = array(); foreach ( $action_keys as $key => $table_name ) { if ( $action_prefix[ $key ] == 'true' ) { $table_name = $wpdb->prefix . $table_name; } $sql = $wpdb->prepare( 'TRUNCATE TABLE %1s', $table_name ); $result = $wpdb->query( $sql ); if ( $result === false ) { array_push( $tables_array_errors, $table_name ); } else { array_push( $tables_array_successes, $table_name ); } } if ( ! empty( $tables_array_successes ) ) { $successes_messages .= parent::generate_message_success( $this->key, 'names', $tables_array_successes, __( 'emptied', 'wp-database-tools' ) ); set_transient( WPDBT_PREFIX . 'successes', $successes_messages ); } if ( ! empty( $tables_array_errors ) ) { $errors_messages .= parent::generate_message_error( $this->key, 'names', $tables_array_errors, __( 'emptied', 'wp-database-tools' ) ); set_transient( WPDBT_PREFIX . 'errors', $errors_messages ); } parent::set_cache_indicators( 'tables', 0, 0, 0 ); } public function optimize() { global $wpdb; $action_keys = $_POST['action-keys']; $action_keys = explode( '↕', $action_keys ); $action_prefix = $_POST['action-prefix']; $action_prefix = explode( '↕', $action_prefix ); $errors_messages = ''; $successes_messages = ''; $tables_array_successes = array(); $tables_array_errors = array(); foreach ( $action_keys as $key => $table_name ) { if ( $action_prefix[ $key ] == 'true' ) { $table_name = $wpdb->prefix . $table_name; } $sql = $wpdb->prepare( 'OPTIMIZE TABLE %1s', $table_name ); $results = $wpdb->get_results( $sql ); if ( str_contains( json_encode( $results ), 'Operation failed' ) ) { array_push( $tables_array_errors, $table_name ); } else { array_push( $tables_array_successes, $table_name ); } } if ( ! empty( $tables_array_successes ) ) { $successes_messages .= parent::generate_message_success( $this->key, 'names', $tables_array_successes, __( 'optimized', 'wp-database-tools' ) ); set_transient( WPDBT_PREFIX . 'successes', $successes_messages ); } if ( ! empty( $tables_array_errors ) ) { $errors_messages .= parent::generate_message_error( $this->key, 'names', $tables_array_errors, __( 'optimized', 'wp-database-tools' ) ); set_transient( WPDBT_PREFIX . 'errors', $errors_messages ); } parent::set_cache_indicators( 'tables', 0, 0, 0 ); } public function repair() { global $wpdb; $action_keys = $_POST['action-keys']; $action_keys = explode( '↕', $action_keys ); $action_prefix = $_POST['action-prefix']; $action_prefix = explode( '↕', $action_prefix ); $errors_messages = ''; $successes_messages = ''; $tables_array_successes = array(); $tables_array_errors = array(); foreach ( $action_keys as $key => $table_name ) { if ( $action_prefix[ $key ] == 'true' ) { $table_name = $wpdb->prefix . $table_name; } $sql = $wpdb->prepare( 'REPAIR TABLE %1s', $table_name ); $results = $wpdb->get_results( $sql ); if ( str_contains( json_encode( $results ), 'Operation failed' ) ) { array_push( $tables_array_errors, $table_name ); } else { array_push( $tables_array_successes, $table_name ); } } if ( ! empty( $tables_array_successes ) ) { $successes_messages .= parent::generate_message_success( $this->key, 'names', $tables_array_successes, __( 'repaired', 'wp-database-tools' ) ); set_transient( WPDBT_PREFIX . 'successes', $successes_messages ); } if ( ! empty( $tables_array_errors ) ) { $errors_messages .= parent::generate_message_error( $this->key, 'names', $tables_array_errors, __( 'repaired', 'wp-database-tools' ) ); set_transient( WPDBT_PREFIX . 'errors', $errors_messages ); } parent::set_cache_indicators( 'tables', 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( 'TABLES: 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_size() { return $this->size; } /** * The array of data of general database. * * @since 1.0.0 * @return array The array of data. */ public function get_count() { return $this->count; } }