.
*
* ███████╗███████╗██████╗ ██╗ ██╗███╗ ███╗ █████╗ ███████╗██╗ ██╗
* ██╔════╝██╔════╝██╔══██╗██║ ██║████╗ ████║██╔══██╗██╔════╝██║ ██╔╝
* ███████╗█████╗ ██████╔╝██║ ██║██╔████╔██║███████║███████╗█████╔╝
* ╚════██║██╔══╝ ██╔══██╗╚██╗ ██╔╝██║╚██╔╝██║██╔══██║╚════██║██╔═██╗
* ███████║███████╗██║ ██║ ╚████╔╝ ██║ ╚═╝ ██║██║ ██║███████║██║ ██╗
* ╚══════╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
*/
if ( ! defined( 'ABSPATH' ) ) {
die( 'Kangaroos cannot jump here' );
}
abstract class Ai1wm_Database {
/**
* WordPress database handler
*
* @var object
*/
protected $wpdb = null;
/**
* WordPress database base tables
*
* @var array
*/
protected $base_tables = null;
/**
* WordPress database views
*
* @var array
*/
protected $views = null;
/**
* WordPress database tables
*
* @var array
*/
protected $tables = null;
/**
* Old table prefixes
*
* @var array
*/
protected $old_table_prefixes = array();
/**
* New table prefixes
*
* @var array
*/
protected $new_table_prefixes = array();
/**
* Old column prefixes
*
* @var array
*/
protected $old_column_prefixes = array();
/**
* New column prefixes
*
* @var array
*/
protected $new_column_prefixes = array();
/**
* Reserved column prefixes
*
* @var array
*/
protected $reserved_column_prefixes = array();
/**
* Old replace values
*
* @var array
*/
protected $old_replace_values = array();
/**
* New replace values
*
* @var array
*/
protected $new_replace_values = array();
/**
* Old raw replace values
*
* @var array
*/
protected $old_replace_raw_values = array();
/**
* New raw replace values
*
* @var array
*/
protected $new_replace_raw_values = array();
/**
* Table where query
*
* @var array
*/
protected $table_where_query = array();
/**
* Table select columns
*
* @var array
*/
protected $table_select_columns = array();
/**
* Table prefix columns
*
* @var array
*/
protected $table_prefix_columns = array();
/**
* Table prefix filters
*
* @var array
*/
protected $table_prefix_filters = array();
/**
* List all tables that should not be affected by the timeout of the current request
*
* @var array
*/
protected $atomic_tables = array();
/**
* List all tables that should not be populated on import
*
* @var array
*/
protected $empty_tables = array();
/**
* Visual Composer
*
* @var boolean
*/
protected $visual_composer = false;
/**
* Oxygen Builder
*
* @var boolean
*/
protected $oxygen_builder = false;
/**
* BeTheme Responsive
*
* @var boolean
*/
protected $betheme_responsive = false;
/**
* Optimize Press
*
* @var boolean
*/
protected $optimize_press = false;
/**
* Avada Fusion Builder
*
* @var boolean
*/
protected $avada_fusion_builder = false;
/**
* Constructor
*
* @param object $wpdb WPDB instance
*/
public function __construct( $wpdb ) {
$this->wpdb = $wpdb;
// Check Microsoft SQL Server support
if ( is_resource( $this->wpdb->dbh ) ) {
if ( get_resource_type( $this->wpdb->dbh ) === 'SQL Server Connection' ) {
throw new Ai1wm_Database_Exception(
__(
'Your WordPress installation uses Microsoft SQL Server. ' .
'To use All-in-One WP Migration, please change your installation to MySQL and try again. ' .
'Technical details',
AI1WM_PLUGIN_NAME
),
501
);
}
}
// Set database host (HyberDB)
if ( empty( $this->wpdb->dbhost ) ) {
if ( isset( $this->wpdb->last_used_server['host'] ) ) {
$this->wpdb->dbhost = $this->wpdb->last_used_server['host'];
}
}
// Set database name (HyperDB)
if ( empty( $this->wpdb->dbname ) ) {
if ( isset( $this->wpdb->last_used_server['name'] ) ) {
$this->wpdb->dbname = $this->wpdb->last_used_server['name'];
}
}
}
/**
* Set old table prefixes
*
* @param array $prefixes List of table prefixes
* @return object
*/
public function set_old_table_prefixes( $prefixes ) {
$this->old_table_prefixes = $prefixes;
return $this;
}
/**
* Get old table prefixes
*
* @return array
*/
public function get_old_table_prefixes() {
return $this->old_table_prefixes;
}
/**
* Set new table prefixes
*
* @param array $prefixes List of table prefixes
* @return object
*/
public function set_new_table_prefixes( $prefixes ) {
$this->new_table_prefixes = $prefixes;
return $this;
}
/**
* Get new table prefixes
*
* @return array
*/
public function get_new_table_prefixes() {
return $this->new_table_prefixes;
}
/**
* Set old column prefixes
*
* @param array $prefixes List of column prefixes
* @return object
*/
public function set_old_column_prefixes( $prefixes ) {
$this->old_column_prefixes = $prefixes;
return $this;
}
/**
* Get old column prefixes
*
* @return array
*/
public function get_old_column_prefixes() {
return $this->old_column_prefixes;
}
/**
* Set new column prefixes
*
* @param array $prefixes List of column prefixes
* @return object
*/
public function set_new_column_prefixes( $prefixes ) {
$this->new_column_prefixes = $prefixes;
return $this;
}
/**
* Get new column prefixes
*
* @return array
*/
public function get_new_column_prefixes() {
return $this->new_column_prefixes;
}
/**
* Set reserved column prefixes
*
* @param array $prefixes List of column prefixes
* @return object
*/
public function set_reserved_column_prefixes( $prefixes ) {
$this->reserved_column_prefixes = $prefixes;
return $this;
}
/**
* Get reserved column prefixes
*
* @return array
*/
public function get_reserved_column_prefixes() {
return $this->reserved_column_prefixes;
}
/**
* Set old replace values
*
* @param array $values List of values
* @return object
*/
public function set_old_replace_values( $values ) {
$this->old_replace_values = $values;
return $this;
}
/**
* Get old replace values
*
* @return array
*/
public function get_old_replace_values() {
return $this->old_replace_values;
}
/**
* Set new replace values
*
* @param array $values List of values
* @return object
*/
public function set_new_replace_values( $values ) {
$this->new_replace_values = $values;
return $this;
}
/**
* Get new replace values
*
* @return array
*/
public function get_new_replace_values() {
return $this->new_replace_values;
}
/**
* Set old replace raw values
*
* @param array $values List of values
* @return object
*/
public function set_old_replace_raw_values( $values ) {
$this->old_replace_raw_values = $values;
return $this;
}
/**
* Get old replace raw values
*
* @return array
*/
public function get_old_replace_raw_values() {
return $this->old_replace_raw_values;
}
/**
* Set new replace raw values
*
* @param array $values List of values
* @return object
*/
public function set_new_replace_raw_values( $values ) {
$this->new_replace_raw_values = $values;
return $this;
}
/**
* Get new replace raw values
*
* @return array
*/
public function get_new_replace_raw_values() {
return $this->new_replace_raw_values;
}
/**
* Set table where query
*
* @param string $table_name Table name
* @param array $where_$query Table query
* @return object
*/
public function set_table_where_query( $table_name, $where_query ) {
$this->table_where_query[ strtolower( $table_name ) ] = $where_query;
return $this;
}
/**
* Get table where query
*
* @param string $table_name Table name
* @return string
*/
public function get_table_where_query( $table_name ) {
if ( isset( $this->table_where_query[ strtolower( $table_name ) ] ) ) {
return $this->table_where_query[ strtolower( $table_name ) ];
}
}
/**
* Set table select columns
*
* @param string $table_name Table name
* @param array $column_names Column names
* @return object
*/
public function set_table_select_columns( $table_name, $column_names ) {
foreach ( $column_names as $column_name => $column_expression ) {
$this->table_select_columns[ strtolower( $table_name ) ][ strtolower( $column_name ) ] = $column_expression;
}
return $this;
}
/**
* Get table select columns
*
* @param string $table_name Table name
* @return array
*/
public function get_table_select_columns( $table_name ) {
if ( isset( $this->table_select_columns[ strtolower( $table_name ) ] ) ) {
return $this->table_select_columns[ strtolower( $table_name ) ];
}
}
/**
* Set table prefix columns
*
* @param string $table_name Table name
* @param array $column_names Column names
* @return object
*/
public function set_table_prefix_columns( $table_name, $column_names ) {
foreach ( $column_names as $column_name ) {
$this->table_prefix_columns[ strtolower( $table_name ) ][ strtolower( $column_name ) ] = true;
}
return $this;
}
/**
* Get table prefix columns
*
* @param string $table_name Table name
* @return array
*/
public function get_table_prefix_columns( $table_name ) {
if ( isset( $this->table_prefix_columns[ strtolower( $table_name ) ] ) ) {
return $this->table_prefix_columns[ strtolower( $table_name ) ];
}
}
/**
* Add table prefix filter
*
* @param string $table_prefix Table prefix
* @param string $exclude_prefix Exclude prefix
* @return object
*/
public function add_table_prefix_filter( $table_prefix, $exclude_prefix = null ) {
$this->table_prefix_filters[] = array( $table_prefix, $exclude_prefix );
return $this;
}
/**
* Get table prefix filter
*
* @return array
*/
public function get_table_prefix_filters() {
return $this->table_prefix_filters;
}
/**
* Set atomic tables
*
* @param array $tables List of tables
* @return object
*/
public function set_atomic_tables( $tables ) {
$this->atomic_tables = $tables;
return $this;
}
/**
* Get atomic tables
*
* @return array
*/
public function get_atomic_tables() {
return $this->atomic_tables;
}
/**
* Set empty tables
*
* @param array $tables List of tables
* @return object
*/
public function set_empty_tables( $tables ) {
$this->empty_tables = $tables;
return $this;
}
/**
* Get empty tables
*
* @return array
*/
public function get_empty_tables() {
return $this->empty_tables;
}
/**
* Set Visual Composer
*
* @param boolean $active Is Visual Composer Active?
* @return object
*/
public function set_visual_composer( $active ) {
$this->visual_composer = $active;
return $this;
}
/**
* Get Visual Composer
*
* @return boolean
*/
public function get_visual_composer() {
return $this->visual_composer;
}
/**
* Set Oxygen Builder
*
* @param boolean $active Is Oxygen Builder Active?
* @return object
*/
public function set_oxygen_builder( $active ) {
$this->oxygen_builder = $active;
return $this;
}
/**
* Get Oxygen Builder
*
* @return boolean
*/
public function get_oxygen_builder() {
return $this->oxygen_builder;
}
/**
* Set BeTheme Responsive
*
* @param boolean $active Is BeTheme Responsive Active?
* @return object
*/
public function set_betheme_responsive( $active ) {
$this->betheme_responsive = $active;
return $this;
}
/**
* Get BeTheme Responsive
*
* @return boolean
*/
public function get_betheme_responsive() {
return $this->betheme_responsive;
}
/**
* Set Optimize Press
*
* @param boolean $active Is Optimize Press Active?
* @return object
*/
public function set_optimize_press( $active ) {
$this->optimize_press = $active;
return $this;
}
/**
* Get Optimize Press
*
* @return boolean
*/
public function get_optimize_press() {
return $this->optimize_press;
}
/**
* Set Avada Fusion Builder
*
* @param boolean $active Is Avada Fusion Builder Active?
* @return object
*/
public function set_avada_fusion_builder( $active ) {
$this->avada_fusion_builder = $active;
return $this;
}
/**
* Get Avada Fusion Builder
*
* @return boolean
*/
public function get_avada_fusion_builder() {
return $this->avada_fusion_builder;
}
/**
* Get views
*
* @return array
*/
protected function get_views() {
if ( is_null( $this->views ) ) {
$where_query = array();
// Get lower case table names
$lower_case_table_names = $this->get_lower_case_table_names();
// Loop over table prefixes
if ( $this->get_table_prefix_filters() ) {
foreach ( $this->get_table_prefix_filters() as $prefix_filter ) {
if ( isset( $prefix_filter[0], $prefix_filter[1] ) ) {
if ( $lower_case_table_names ) {
$where_query[] = sprintf( "(`Tables_in_%s` REGEXP '^%s' AND `Tables_in_%s` NOT REGEXP '^%s')", $this->wpdb->dbname, $prefix_filter[0], $this->wpdb->dbname, $prefix_filter[1] );
} else {
$where_query[] = sprintf( "(CAST(`Tables_in_%s` AS BINARY) REGEXP BINARY '^%s' AND CAST(`Tables_in_%s` AS BINARY) NOT REGEXP BINARY '^%s')", $this->wpdb->dbname, $prefix_filter[0], $this->wpdb->dbname, $prefix_filter[1] );
}
} else {
if ( $lower_case_table_names ) {
$where_query[] = sprintf( "`Tables_in_%s` REGEXP '^%s'", $this->wpdb->dbname, $prefix_filter[0] );
} else {
$where_query[] = sprintf( "CAST(`Tables_in_%s` AS BINARY) REGEXP BINARY '^%s'", $this->wpdb->dbname, $prefix_filter[0] );
}
}
}
} else {
$where_query[] = 1;
}
$this->views = array();
// Loop over views
$result = $this->query( sprintf( "SHOW FULL TABLES FROM `%s` WHERE `Table_type` = 'VIEW' AND (%s)", $this->wpdb->dbname, implode( ' OR ', $where_query ) ) );
while ( $row = $this->fetch_row( $result ) ) {
if ( isset( $row[0] ) ) {
$this->views[] = $row[0];
}
}
// Close result cursor
$this->free_result( $result );
}
return $this->views;
}
/**
* Get base tables
*
* @return array
*/
protected function get_base_tables() {
if ( is_null( $this->base_tables ) ) {
$where_query = array();
// Get lower case table names
$lower_case_table_names = $this->get_lower_case_table_names();
// Loop over table prefixes
if ( $this->get_table_prefix_filters() ) {
foreach ( $this->get_table_prefix_filters() as $prefix_filter ) {
if ( isset( $prefix_filter[0], $prefix_filter[1] ) ) {
if ( $lower_case_table_names ) {
$where_query[] = sprintf( "(`Tables_in_%s` REGEXP '^%s' AND `Tables_in_%s` NOT REGEXP '^%s')", $this->wpdb->dbname, $prefix_filter[0], $this->wpdb->dbname, $prefix_filter[1] );
} else {
$where_query[] = sprintf( "(CAST(`Tables_in_%s` AS BINARY) REGEXP BINARY '^%s' AND CAST(`Tables_in_%s` AS BINARY) NOT REGEXP BINARY '^%s')", $this->wpdb->dbname, $prefix_filter[0], $this->wpdb->dbname, $prefix_filter[1] );
}
} else {
if ( $lower_case_table_names ) {
$where_query[] = sprintf( "`Tables_in_%s` REGEXP '^%s'", $this->wpdb->dbname, $prefix_filter[0] );
} else {
$where_query[] = sprintf( "CAST(`Tables_in_%s` AS BINARY) REGEXP BINARY '^%s'", $this->wpdb->dbname, $prefix_filter[0] );
}
}
}
} else {
$where_query[] = 1;
}
$this->base_tables = array();
// Loop over base tables
$result = $this->query( sprintf( "SHOW FULL TABLES FROM `%s` WHERE `Table_type` = 'BASE TABLE' AND (%s)", $this->wpdb->dbname, implode( ' OR ', $where_query ) ) );
while ( $row = $this->fetch_row( $result ) ) {
if ( isset( $row[0] ) ) {
$this->base_tables[] = $row[0];
}
}
// Close result cursor
$this->free_result( $result );
}
return $this->base_tables;
}
/**
* Set tables
*
* @param array $tables List of tables
* @return object
*/
public function set_tables( $tables ) {
$this->tables = $tables;
return $this;
}
/**
* Get tables
*
* @return array
*/
public function get_tables() {
if ( is_null( $this->tables ) ) {
return array_merge( $this->get_base_tables(), $this->get_views() );
}
return $this->tables;
}
/**
* Export database into a file
*
* @param string $file_name File name
* @param integer $query_offset Query offset
* @param integer $table_index Table index
* @param integer $table_offset Table offset
* @param integer $table_rows Table rows
* @return boolean
*/
public function export( $file_name, &$query_offset = 0, &$table_index = 0, &$table_offset = 0, &$table_rows = 0 ) {
// Set file handler
$file_handler = ai1wm_open( $file_name, 'cb' );
// Start time
$start = microtime( true );
// Flag to hold if all tables have been processed
$completed = true;
// Set SQL mode
$this->query( "SET SESSION sql_mode = ''" );
// Get tables
$tables = $this->get_tables();
// Get views
$views = $this->get_views();
// Set file pointer at the query offset
if ( fseek( $file_handler, $query_offset ) !== -1 ) {
// Write headers
if ( $query_offset === 0 ) {
ai1wm_write( $file_handler, $this->get_header() );
}
// Export tables
for ( ; $table_index < count( $tables ); ) {
// Get table name
$table_name = $tables[ $table_index ];
// Replace table name prefixes
$new_table_name = $this->replace_table_prefixes( $table_name, 0 );
// Loop over tables and views
if ( in_array( $table_name, $views ) ) {
// Get create view statement
if ( $table_offset === 0 ) {
// Write view drop statement
$drop_view = "\nDROP VIEW IF EXISTS `{$new_table_name}`;\n";
// Write drop view statement
ai1wm_write( $file_handler, $drop_view );
// Get create view statement
$create_view = $this->get_create_view( $table_name );
// Replace create view name
$create_view = $this->replace_view_name( $create_view, $table_name, $new_table_name );
// Replace create view identifiers
$create_view = $this->replace_view_identifiers( $create_view );
// Replace create view options
$create_view = $this->replace_view_options( $create_view );
// Write create view statement
ai1wm_write( $file_handler, $create_view );
// Write end of statement
ai1wm_write( $file_handler, ";\n\n" );
}
// Set curent table index
$table_index++;
// Set current table offset
$table_offset = 0;
} else {
// Get create table statement
if ( $table_offset === 0 ) {
// Write table drop statement
$drop_table = "\nDROP TABLE IF EXISTS `{$new_table_name}`;\n";
// Write table statement
ai1wm_write( $file_handler, $drop_table );
// Get create table statement
$create_table = $this->get_create_table( $table_name );
// Replace create table name
$create_table = $this->replace_table_name( $create_table, $table_name, $new_table_name );
// Replace create table comments
$create_table = $this->replace_table_comments( $create_table );
// Replace create table constraints
$create_table = $this->replace_table_constraints( $create_table );
// Replace create table options
$create_table = $this->replace_table_options( $create_table );
// Write create table statement
ai1wm_write( $file_handler, $create_table );
// Write end of statement
ai1wm_write( $file_handler, ";\n\n" );
}
// Get primary keys
$primary_keys = $this->get_primary_keys( $table_name );
// Get column types
$column_types = $this->get_column_types( $table_name );
// Get prefix columns
$prefix_columns = $this->get_table_prefix_columns( $table_name );
do {
// Set query
if ( $primary_keys ) {
// Set table keys
$table_keys = array();
foreach ( $primary_keys as $key ) {
$table_keys[] = sprintf( '`%s`', $key );
}
$table_keys = implode( ', ', $table_keys );
// Set table where query
if ( ! ( $table_where = $this->get_table_where_query( $table_name ) ) ) {
$table_where = 1;
}
// Set table select columns
if ( ! ( $select_columns = $this->get_table_select_columns( $table_name ) ) ) {
$select_columns = array( 't1.*' );
}
$select_columns = implode( ', ', $select_columns );
// Set query with offset and rows count
$query = sprintf( 'SELECT %s FROM `%s` AS t1 JOIN (SELECT %s FROM `%s` WHERE %s ORDER BY %s LIMIT %d, %d) AS t2 USING (%s)', $select_columns, $table_name, $table_keys, $table_name, $table_where, $table_keys, $table_offset, AI1WM_MAX_SELECT_RECORDS, $table_keys );
} else {
$table_keys = 1;
// Set table where query
if ( ! ( $table_where = $this->get_table_where_query( $table_name ) ) ) {
$table_where = 1;
}
// Set table select columns
if ( ! ( $select_columns = $this->get_table_select_columns( $table_name ) ) ) {
$select_columns = array( '*' );
}
$select_columns = implode( ', ', $select_columns );
// Set query with offset and rows count
$query = sprintf( 'SELECT %s FROM `%s` WHERE %s ORDER BY %s LIMIT %d, %d', $select_columns, $table_name, $table_where, $table_keys, $table_offset, AI1WM_MAX_SELECT_RECORDS );
}
// Run SQL query
$result = $this->query( $query );
// Repair table data
if ( $this->errno() === 1194 ) {
// Current table is marked as crashed and should be repaired
$this->repair_table( $table_name );
// Run SQL query
$result = $this->query( $query );
}
// Generate insert statements
if ( $num_rows = $this->num_rows( $result ) ) {
// Loop over table rows
while ( $row = $this->fetch_assoc( $result ) ) {
// Write start transaction
if ( $table_offset % AI1WM_MAX_TRANSACTION_QUERIES === 0 ) {
ai1wm_write( $file_handler, "START TRANSACTION;\n" );
}
$items = array();
foreach ( $row as $key => $value ) {
// Replace table prefix columns
if ( isset( $prefix_columns[ strtolower( $key ) ] ) ) {
$value = $this->replace_column_prefixes( $value, 0 );
}
$items[] = $this->prepare_table_values( $value, $column_types[ strtolower( $key ) ] );
}
// Set table values
$table_values = implode( ',', $items );
// Set insert statement
$table_insert = "INSERT INTO `{$new_table_name}` VALUES ({$table_values});\n";
// Write insert statement
ai1wm_write( $file_handler, $table_insert );
// Set current table offset
$table_offset++;
// Set current table rows
$table_rows++;
// Write end of transaction
if ( $table_offset % AI1WM_MAX_TRANSACTION_QUERIES === 0 ) {
ai1wm_write( $file_handler, "COMMIT;\n" );
}
}
} else {
// Write end of transaction
if ( $table_offset % AI1WM_MAX_TRANSACTION_QUERIES !== 0 ) {
ai1wm_write( $file_handler, "COMMIT;\n" );
}
// Set curent table index
$table_index++;
// Set current table offset
$table_offset = 0;
}
// Close result cursor
$this->free_result( $result );
// Time elapsed
if ( ( $timeout = apply_filters( 'ai1wm_completed_timeout', 10 ) ) ) {
if ( ( microtime( true ) - $start ) > $timeout ) {
$completed = false;
break 2;
}
}
} while ( $num_rows > 0 );
}
}
}
// Set query offset
$query_offset = ftell( $file_handler );
// Close file handler
ai1wm_close( $file_handler );
return $completed;
}
/**
* Import database from a file
*
* @param string $file_name File name
* @param integer $query_offset Query offset
* @return boolean
*/
public function import( $file_name, &$query_offset = 0 ) {
// Set max allowed packet
$max_allowed_packet = $this->get_max_allowed_packet();
// Set file handler
$file_handler = ai1wm_open( $file_name, 'rb' );
// Start time
$start = microtime( true );
// Flag to hold if all tables have been processed
$completed = true;
// Set SQL Mode
$this->query( "SET SESSION sql_mode = ''" );
// Set file pointer at the query offset
if ( fseek( $file_handler, $query_offset ) !== -1 ) {
$query = null;
// Start transaction
$this->query( 'START TRANSACTION' );
// Read database file line by line
while ( ( $line = fgets( $file_handler ) ) !== false ) {
$query .= $line;
// End of query
if ( preg_match( '/;\s*$/S', $query ) ) {
$query = trim( $query );
// Check max allowed packet
if ( strlen( $query ) <= $max_allowed_packet ) {
// Replace table prefixes
$query = $this->replace_table_prefixes( $query );
// Skip table query
if ( $this->should_ignore_query( $query ) === false ) {
// Replace table collations
$query = $this->replace_table_collations( $query );
// Replace table values
$query = $this->replace_table_values( $query );
// Replace raw values
$query = $this->replace_raw_values( $query );
// Run SQL query
$this->query( $query );
// Replace table engines (Azure)
if ( $this->errno() === 1030 ) {
// Replace table engines
$query = $this->replace_table_engines( $query );
// Run SQL query
$this->query( $query );
}
// Replace table row format (MyISAM and InnoDB)
if ( $this->errno() === 1071 || $this->errno() === 1709 ) {
// Replace table row format
$query = $this->replace_table_row_format( $query );
// Run SQL query
$this->query( $query );
}
// Replace table full-text indexes (MySQL <= 5.5)
if ( $this->errno() === 1214 ) {
// Full-text searches are supported for MyISAM tables only.
// In MySQL 5.6 and up, they can also be used with InnoDB tables
$query = $this->replace_table_fulltext_indexes( $query );
// Run SQL query
$this->query( $query );
}
// Check tablespace exists
if ( $this->errno() === 1813 ) {
throw new Ai1wm_Database_Exception( __( 'Error importing database table. Technical details', AI1WM_PLUGIN_NAME ), 503 );
}
// Check max queries per hour
if ( $this->errno() === 1226 ) {
if ( stripos( $this->error(), 'max_queries_per_hour' ) !== false ) {
throw new Ai1wm_Database_Exception(
__(
'Your WordPress installation has reached the maximum allowed queries per hour set by your server admin or hosting provider. ' .
'To use All-in-One WP Migration, please increase MySQL max_queries_per_hour limit. ' .
'Technical details',
AI1WM_PLUGIN_NAME
),
503
);
} elseif ( stripos( $this->error(), 'max_updates_per_hour' ) !== false ) {
throw new Ai1wm_Database_Exception(
__(
'Your WordPress installation has reached the maximum allowed updates per hour set by your server admin or hosting provider. ' .
'To use All-in-One WP Migration, please increase MySQL max_updates_per_hour limit. ' .
'Technical details',
AI1WM_PLUGIN_NAME
),
503
);
} elseif ( stripos( $this->error(), 'max_connections_per_hour' ) !== false ) {
throw new Ai1wm_Database_Exception(
__(
'Your WordPress installation has reached the maximum allowed connections per hour set by your server admin or hosting provider. ' .
'To use All-in-One WP Migration, please increase MySQL max_connections_per_hour limit. ' .
'Technical details',
AI1WM_PLUGIN_NAME
),
503
);
} elseif ( stripos( $this->error(), 'max_user_connections' ) !== false ) {
throw new Ai1wm_Database_Exception(
__(
'Your WordPress installation has reached the maximum allowed user connections set by your server admin or hosting provider. ' .
'To use All-in-One WP Migration, please increase MySQL max_user_connections limit. ' .
'Technical details',
AI1WM_PLUGIN_NAME
),
503
);
}
}
}
// Time elapsed
if ( ( $timeout = apply_filters( 'ai1wm_completed_timeout', 10 ) ) ) {
if ( ! $this->is_atomic_query( $query ) ) {
if ( ( microtime( true ) - $start ) > $timeout ) {
$completed = false;
break;
}
}
}
}
$query = null;
}
}
// End transaction
$this->query( 'COMMIT' );
}
// Set query offset
$query_offset = ftell( $file_handler );
// Close file handler
ai1wm_close( $file_handler );
return $completed;
}
/**
* Flush database
*
* @return void
*/
public function flush() {
$views = $this->get_views();
foreach ( $this->get_tables() as $table_name ) {
if ( in_array( $table_name, $views ) ) {
$this->query( "DROP VIEW IF EXISTS `{$table_name}`" );
} else {
$this->query( "DROP TABLE IF EXISTS `{$table_name}`" );
}
}
}
/**
* Get MySQL version
*
* @return string
*/
protected function get_version() {
$result = $this->query( "SHOW VARIABLES LIKE 'version'" );
$row = $this->fetch_assoc( $result );
// Close result cursor
$this->free_result( $result );
// Get version
if ( isset( $row['Value'] ) ) {
return $row['Value'];
}
}
/**
* Get MySQL max allowed packet
*
* @return integer
*/
protected function get_max_allowed_packet() {
$result = $this->query( "SHOW VARIABLES LIKE 'max_allowed_packet'" );
$row = $this->fetch_assoc( $result );
// Close result cursor
$this->free_result( $result );
// Get max allowed packet
if ( isset( $row['Value'] ) ) {
return $row['Value'];
}
}
/**
* Get MySQL lower case table names
*
* @return integer
*/
protected function get_lower_case_table_names() {
$result = $this->query( "SHOW VARIABLES LIKE 'lower_case_table_names'" );
$row = $this->fetch_assoc( $result );
// Close result cursor
$this->free_result( $result );
// Get lower case table names
if ( isset( $row['Value'] ) ) {
return $row['Value'];
}
}
/**
* Get MySQL collation name
*
* @param string $collation_name Collation name
* @return string
*/
protected function get_collation( $collation_name ) {
$result = $this->query( "SHOW COLLATION LIKE '{$collation_name}'" );
$row = $this->fetch_assoc( $result );
// Close result cursor
$this->free_result( $result );
// Get collation name
if ( isset( $row['Collation'] ) ) {
return $row['Collation'];
}
}
/**
* Get MySQL create view
*
* @param string $view_name View name
* @return string
*/
protected function get_create_view( $view_name ) {
$result = $this->query( "SHOW CREATE VIEW `{$view_name}`" );
$row = $this->fetch_assoc( $result );
// Close result cursor
$this->free_result( $result );
// Get create view
if ( isset( $row['Create View'] ) ) {
return $row['Create View'];
}
}
/**
* Get MySQL create table
*
* @param string $table_name Table name
* @return string
*/
protected function get_create_table( $table_name ) {
$result = $this->query( "SHOW CREATE TABLE `{$table_name}`" );
$row = $this->fetch_assoc( $result );
// Close result cursor
$this->free_result( $result );
// Get create table
if ( isset( $row['Create Table'] ) ) {
return $row['Create Table'];
}
}
/**
* Repair MySQL table
*
* @param string $table_name Table name
* @return void
*/
protected function repair_table( $table_name ) {
$this->query( "REPAIR TABLE `{$table_name}`" );
}
/**
* Get MySQL primary keys
*
* @param string $table_name Table name
* @return array
*/
protected function get_primary_keys( $table_name ) {
$primary_keys = array();
// Get primary keys
$result = $this->query( "SHOW KEYS FROM `{$table_name}` WHERE `Key_name` = 'PRIMARY'" );
while ( $row = $this->fetch_assoc( $result ) ) {
if ( isset( $row['Column_name'] ) ) {
$primary_keys[] = $row['Column_name'];
}
}
// Close result cursor
$this->free_result( $result );
return $primary_keys;
}
/**
* Get MySQL unique keys
*
* @param string $table_name Table name
* @return array
*/
protected function get_unique_keys( $table_name ) {
$unique_keys = array();
// Get unique keys
$result = $this->query( "SHOW KEYS FROM `{$table_name}` WHERE `Non_unique` = 0" );
while ( $row = $this->fetch_assoc( $result ) ) {
if ( isset( $row['Column_name'] ) ) {
$unique_keys[] = $row['Column_name'];
}
}
// Close result cursor
$this->free_result( $result );
return $unique_keys;
}
/**
* Get MySQL column types
*
* @param string $table_name Table name
* @return array
*/
protected function get_column_types( $table_name ) {
$column_types = array();
// Get column types
$result = $this->query( "SHOW COLUMNS FROM `{$table_name}`" );
while ( $row = $this->fetch_assoc( $result ) ) {
if ( isset( $row['Field'] ) ) {
$column_types[ strtolower( $row['Field'] ) ] = $row['Type'];
}
}
// Close result cursor
$this->free_result( $result );
return $column_types;
}
/**
* Get MySQL column names
*
* @param string $table_name Table name
* @return array
*/
public function get_column_names( $table_name ) {
$column_names = array();
// Get column types
$result = $this->query( "SHOW COLUMNS FROM `{$table_name}`" );
while ( $row = $this->fetch_assoc( $result ) ) {
if ( isset( $row['Field'] ) ) {
$column_names[ strtolower( $row['Field'] ) ] = $row['Field'];
}
}
// Close result cursor
$this->free_result( $result );
return $column_names;
}
/**
* Replace table name
*
* @param string $input Table value
* @param string $old_table_name Old table name
* @param string $new_table_name New table name
* @return string
*/
protected function replace_table_name( $input, $old_table_name, $new_table_name ) {
$position = stripos( $input, "`$old_table_name`" );
if ( $position !== false ) {
$input = substr_replace( $input, "`$new_table_name`", $position, strlen( "`$old_table_name`" ) );
}
return $input;
}
/**
* Replace view name
*
* @param string $input View value
* @param string $old_view_name Old view name
* @param string $new_view_name New view name
* @return string
*/
protected function replace_view_name( $input, $old_view_name, $new_view_name ) {
$position = stripos( $input, "`$old_view_name`" );
if ( $position !== false ) {
$input = substr_replace( $input, "`$new_view_name`", $position, strlen( "`$old_view_name`" ) );
}
return $input;
}
/**
* Replace view identifiers
*
* @param string $input Table value
* @return string
*/
protected function replace_view_identifiers( $input ) {
$base_tables = $this->get_base_tables();
foreach ( $base_tables as $table_name ) {
if ( ( $new_table_name = $this->replace_table_prefixes( $table_name, 0 ) ) ) {
$input = str_ireplace( "`$table_name`", "`$new_table_name`", $input );
}
}
return $input;
}
/**
* Replace view options
*
* @param string $input Table value
* @return string
*/
protected function replace_view_options( $input ) {
return preg_replace( '/CREATE(.+?)VIEW/i', 'CREATE VIEW', $input );
}
/**
* Replace table prefixes
*
* @param string $input Table value
* @param mixed $position Replace first occurrence at a specified position
* @return string
*/
protected function replace_table_prefixes( $input, $position = false ) {
$search = $this->get_old_table_prefixes();
$replace = $this->get_new_table_prefixes();
// Replace first occurrence at a specified position
if ( $position !== false ) {
for ( $i = 0; $i < count( $search ); $i++ ) {
$current = stripos( $input, $search[ $i ], $position );
if ( $current === $position ) {
$input = substr_replace( $input, $replace[ $i ], $current, strlen( $search[ $i ] ) );
}
}
return $input;
}
return str_ireplace( $search, $replace, $input );
}
/**
* Replace column prefixes
*
* @param string $input Column value
* @param mixed $position Replace first occurrence at a specified position
* @return string
*/
protected function replace_column_prefixes( $input, $position = false ) {
$search = $this->get_old_column_prefixes();
$replace = $this->get_new_column_prefixes();
$reserved = $this->get_reserved_column_prefixes();
// Replace first occurrence at a specified position
if ( $position !== false ) {
for ( $i = 0; $i < count( $reserved ); $i++ ) {
$current = stripos( $input, $reserved[ $i ], $position );
if ( $current === $position ) {
return $input;
}
}
for ( $i = 0; $i < count( $search ); $i++ ) {
$current = stripos( $input, $search[ $i ], $position );
if ( $current === $position ) {
$input = substr_replace( $input, $replace[ $i ], $current, strlen( $search[ $i ] ) );
}
}
return $input;
}
return str_ireplace( $search, $replace, $input );
}
/**
* Replace table values
*
* @param string $input Table value
* @return string
*/
protected function replace_table_values( $input ) {
// Replace base64 encoded values (Visual Composer)
if ( $this->get_visual_composer() ) {
$input = preg_replace_callback( '/\[vc_raw_html\]([a-zA-Z0-9\/+]+={0,2})\[\/vc_raw_html\]/S', array( $this, 'replace_visual_composer_values_callback' ), $input );
}
// Replace base64 encoded values (Oxygen Builder)
if ( $this->get_oxygen_builder() ) {
$input = preg_replace_callback( '/\\\\"(code-php|code-css|code-js)\\\\":\\\\"([a-zA-Z0-9\/+]+={0,2})\\\\"/S', array( $this, 'replace_oxygen_builder_values_callback' ), $input );
}
// Replace base64 encoded values (BeTheme Responsive, Optimize Press and Avada Fusion Builder)
if ( $this->get_betheme_responsive() || $this->get_optimize_press() || $this->get_avada_fusion_builder() ) {
$input = preg_replace_callback( "/'([a-zA-Z0-9\/+]+={0,2})'/S", array( $this, 'replace_base64_values_callback' ), $input );
}
// Replace serialized values
foreach ( $this->get_old_replace_values() as $old_value ) {
if ( strpos( $input, $this->escape( $old_value ) ) !== false ) {
$input = preg_replace_callback( "/'(.*?)(?get_old_replace_values(), $this->get_new_replace_values(), $matches[1] );
// Encode base64 characters
$matches[1] = Ai1wm_Database_Utility::base64_encode( $matches[1] );
}
return '[vc_raw_html]' . $matches[1] . '[/vc_raw_html]';
}
/**
* Replace base64 values callback (Oxygen Builder)
*
* @param array $matches List of matches
* @return string
*/
protected function replace_oxygen_builder_values_callback( $matches ) {
// Validate base64 data
if ( Ai1wm_Database_Utility::base64_validate( $matches[2] ) ) {
// Decode base64 characters
$matches[2] = Ai1wm_Database_Utility::base64_decode( $matches[2] );
// Replace values
$matches[2] = Ai1wm_Database_Utility::replace_values( $this->get_old_replace_values(), $this->get_new_replace_values(), $matches[2] );
// Encode base64 characters
$matches[2] = Ai1wm_Database_Utility::base64_encode( $matches[2] );
}
return '\"' . $matches[1] . '\":\"' . $matches[2] . '\"';
}
/**
* Replace base64 values callback (BeTheme Responsive and Optimize Press)
*
* @param array $matches List of matches
* @return string
*/
protected function replace_base64_values_callback( $matches ) {
// Validate base64 data
if ( Ai1wm_Database_Utility::base64_validate( $matches[1] ) ) {
// Decode base64 characters
$matches[1] = Ai1wm_Database_Utility::base64_decode( $matches[1] );
// Replace serialized values
$matches[1] = Ai1wm_Database_Utility::replace_serialized_values( $this->get_old_replace_values(), $this->get_new_replace_values(), $matches[1] );
// Encode base64 characters
$matches[1] = Ai1wm_Database_Utility::base64_encode( $matches[1] );
}
return "'" . $matches[1] . "'";
}
/**
* Replace table values callback
*
* @param array $matches List of matches
* @return string
*/
protected function replace_table_values_callback( $matches ) {
// Unescape MySQL special characters
$matches[1] = Ai1wm_Database_Utility::unescape_mysql( $matches[1] );
// Replace serialized values
$matches[1] = Ai1wm_Database_Utility::replace_serialized_values( $this->get_old_replace_values(), $this->get_new_replace_values(), $matches[1] );
// Escape MySQL special characters
$matches[1] = Ai1wm_Database_Utility::escape_mysql( $matches[1] );
return "'" . $matches[1] . "'";
}
/**
* Replace table collations
*
* @param string $input SQL statement
* @return string
*/
protected function replace_table_collations( $input ) {
static $search = array();
static $replace = array();
// Replace table collations
if ( empty( $search ) || empty( $replace ) ) {
if ( ! $this->wpdb->has_cap( 'utf8mb4_520' ) ) {
if ( ! $this->wpdb->has_cap( 'utf8mb4' ) ) {
$search = array( 'utf8mb4_0900_ai_ci', 'utf8mb4_unicode_520_ci', 'utf8mb4' );
$replace = array( 'utf8_unicode_ci', 'utf8_unicode_ci', 'utf8' );
} else {
$search = array( 'utf8mb4_0900_ai_ci', 'utf8mb4_unicode_520_ci' );
$replace = array( 'utf8mb4_unicode_ci', 'utf8mb4_unicode_ci' );
}
} else {
$search = array( 'utf8mb4_0900_ai_ci' );
$replace = array( 'utf8mb4_unicode_520_ci' );
}
}
return str_replace( $search, $replace, $input );
}
/**
* Replace raw values
*
* @param string $input SQL statement
* @return string
*/
protected function replace_raw_values( $input ) {
return Ai1wm_Database_Utility::replace_values( $this->get_old_replace_raw_values(), $this->get_new_replace_raw_values(), $input );
}
/**
* Replace table comments
*
* @param string $input SQL statement
* @return string
*/
protected function replace_table_comments( $input ) {
return preg_replace( '/\/\*(.+?)\*\//s', '', $input );
}
/**
* Replace table constraints
*
* @param string $input SQL statement
* @return string
*/
protected function replace_table_constraints( $input ) {
$pattern = array(
'/\s+CONSTRAINT(.+)REFERENCES(.+),/i',
'/,\s+CONSTRAINT(.+)REFERENCES(.+)/i',
);
return preg_replace( $pattern, '', $input );
}
/**
* Check whether input is transient query
*
* @param string $input SQL statement
* @return boolean
*/
protected function is_transient_query( $input ) {
return strpos( $input, "'_transient_" ) !== false;
}
/**
* Check whether input is site transient query
*
* @param string $input SQL statement
* @return boolean
*/
protected function is_site_transient_query( $input ) {
return strpos( $input, "'_site_transient_" ) !== false;
}
/**
* Check whether input is WooCommerce session query
*
* @param string $input SQL statement
* @return boolean
*/
protected function is_wc_session_query( $input ) {
return strpos( $input, "'_wc_session_" ) !== false;
}
/**
* Check whether input is START TRANSACTION query
*
* @param string $input SQL statement
* @return boolean
*/
protected function is_start_transaction_query( $input ) {
return strpos( $input, 'START TRANSACTION' ) === 0;
}
/**
* Check whether input is COMMIT query
*
* @param string $input SQL statement
* @return boolean
*/
protected function is_commit_query( $input ) {
return strpos( $input, 'COMMIT' ) === 0;
}
/**
* Check whether input is DROP TABLE query
*
* @param string $input SQL statement
* @return boolean
*/
protected function is_drop_table_query( $input ) {
return strpos( $input, 'DROP TABLE' ) === 0;
}
/**
* Check whether input is CREATE TABLE query
*
* @param string $input SQL statement
* @return boolean
*/
protected function is_create_table_query( $input ) {
return strpos( $input, 'CREATE TABLE' ) === 0;
}
/**
* Check whether input is INSERT INTO query
*
* @param string $input SQL statement
* @param string $table_name Table name (case insensitive)
* @return boolean
*/
protected function is_insert_into_query( $input, $table_name ) {
return stripos( $input, sprintf( 'INSERT INTO `%s`', $table_name ) ) === 0;
}
/**
* Should ignore query on import?
*
* @param string $input SQL statement
* @return boolean
*/
public function should_ignore_query( $input ) {
$ignore = false;
// Ignore query based on table query
switch ( true ) {
case $this->is_transient_query( $input ):
case $this->is_site_transient_query( $input ):
case $this->is_wc_session_query( $input ):
$ignore = true;
break;
default:
foreach ( $this->get_empty_tables() as $table_name ) {
if ( $this->is_insert_into_query( $input, $table_name ) ) {
$ignore = true;
break;
}
}
}
return $ignore;
}
/**
* Check whether input is atomic query
*
* @param string $input SQL statement
* @return boolean
*/
protected function is_atomic_query( $input ) {
$atomic = false;
// Skip timeout based on table query
switch ( true ) {
case $this->is_drop_table_query( $input ):
case $this->is_create_table_query( $input ):
case $this->is_start_transaction_query( $input ):
case $this->is_commit_query( $input ):
$atomic = true;
break;
default:
// Skip timeout based on table query and table name
foreach ( $this->get_atomic_tables() as $table_name ) {
if ( $this->is_insert_into_query( $input, $table_name ) ) {
$atomic = true;
break;
}
}
}
return $atomic;
}
/**
* Replace table options
*
* @param string $input SQL statement
* @return string
*/
protected function replace_table_options( $input ) {
$search = array(
'TYPE=InnoDB',
'TYPE=MyISAM',
'ENGINE=Aria',
'TRANSACTIONAL=0',
'TRANSACTIONAL=1',
'PAGE_CHECKSUM=0',
'PAGE_CHECKSUM=1',
'TABLE_CHECKSUM=0',
'TABLE_CHECKSUM=1',
'ROW_FORMAT=PAGE',
'ROW_FORMAT=FIXED',
'ROW_FORMAT=DYNAMIC',
);
$replace = array(
'ENGINE=InnoDB',
'ENGINE=MyISAM',
'ENGINE=MyISAM',
'',
'',
'',
'',
'',
'',
'',
'',
'',
);
return str_ireplace( $search, $replace, $input );
}
/**
* Replace table engines
*
* @param string $input SQL statement
* @return string
*/
protected function replace_table_engines( $input ) {
$search = array(
'ENGINE=MyISAM',
'ENGINE=Aria',
);
$replace = array(
'ENGINE=InnoDB',
'ENGINE=InnoDB',
);
return str_ireplace( $search, $replace, $input );
}
/**
* Replace table row format
*
* @param string $input SQL statement
* @return string
*/
protected function replace_table_row_format( $input ) {
$search = array(
'ENGINE=InnoDB',
'ENGINE=MyISAM',
);
$replace = array(
'ENGINE=InnoDB ROW_FORMAT=DYNAMIC',
'ENGINE=MyISAM ROW_FORMAT=DYNAMIC',
);
return str_ireplace( $search, $replace, $input );
}
/**
* Replace table full-text indexes (MySQL <= 5.5)
*
* @param string $input SQL statement
* @return string
*/
protected function replace_table_fulltext_indexes( $input ) {
$pattern = array(
'/\s+FULLTEXT KEY(.+),/i',
'/,\s+FULLTEXT KEY(.+)/i',
);
return preg_replace( $pattern, '', $input );
}
/**
* Returns header for dump file
*
* @return string
*/
protected function get_header() {
// Some info about software, source and time
$header = sprintf(
"-- All-in-One WP Migration SQL Dump\n" .
"-- https://servmask.com/\n" .
"--\n" .
"-- Host: %s\n" .
"-- Database: %s\n" .
"-- Class: %s\n" .
"--\n",
$this->wpdb->dbhost,
$this->wpdb->dbname,
get_class( $this )
);
return $header;
}
/**
* Prepare table values
*
* @param string $input Table value
* @param integer $column_type Column type
* @return string
*/
protected function prepare_table_values( $input, $column_type ) {
switch ( true ) {
case is_null( $input ):
return 'NULL';
case stripos( $column_type, 'tinyint' ) === 0:
case stripos( $column_type, 'smallint' ) === 0:
case stripos( $column_type, 'mediumint' ) === 0:
case stripos( $column_type, 'int' ) === 0:
case stripos( $column_type, 'bigint' ) === 0:
case stripos( $column_type, 'float' ) === 0:
case stripos( $column_type, 'double' ) === 0:
case stripos( $column_type, 'decimal' ) === 0:
case stripos( $column_type, 'bit' ) === 0:
return $input;
case stripos( $column_type, 'binary' ) === 0:
case stripos( $column_type, 'varbinary' ) === 0:
case stripos( $column_type, 'tinyblob' ) === 0:
case stripos( $column_type, 'mediumblob' ) === 0:
case stripos( $column_type, 'longblob' ) === 0:
case stripos( $column_type, 'blob' ) === 0:
return '0x' . bin2hex( $input );
default:
return "'" . $this->escape( $input ) . "'";
}
}
/**
* Run MySQL query
*
* @param string $input SQL query
* @return resource
*/
abstract public function query( $input );
/**
* Escape string input for mysql query
*
* @param string $input String to escape
* @return string
*/
abstract public function escape( $input );
/**
* Return the error code for the most recent function call
*
* @return integer
*/
abstract public function errno();
/**
* Return a string description of the last error
*
* @return string
*/
abstract public function error();
/**
* Return server version
*
* @return string
*/
abstract public function version();
/**
* Return the result from MySQL query as associative array
*
* @param resource $result MySQL resource
* @return array
*/
abstract public function fetch_assoc( $result );
/**
* Return the result from MySQL query as row
*
* @param resource $result MySQL resource
* @return array
*/
abstract public function fetch_row( $result );
/**
* Return the number for rows from MySQL results
*
* @param resource $result MySQL resource
* @return integer
*/
abstract public function num_rows( $result );
/**
* Free MySQL result memory
*
* @param resource $result MySQL resource
* @return boolean
*/
abstract public function free_result( $result );
}