plugin_version = $GLOBALS['wpmdb_meta'][ $this->core_slug ]['version'];
$this->max_insert_string_len = 50000; // 50000 is the default as defined by PhpMyAdmin
add_filter( 'plugin_action_links_' . $this->plugin_basename, array( $this, 'plugin_action_links' ) );
add_filter( 'network_admin_plugin_action_links_' . $this->plugin_basename, array( $this, 'plugin_action_links' ) );
// internal AJAX handlers
add_action( 'wp_ajax_wpmdb_delete_migration_profile', array( $this, 'ajax_delete_migration_profile' ) );
add_action( 'wp_ajax_wpmdb_save_profile', array( $this, 'ajax_save_profile' ) );
add_action( 'wp_ajax_wpmdb_save_setting', array( $this, 'ajax_save_setting' ) );
add_action( 'wp_ajax_wpmdb_initiate_migration', array( $this, 'ajax_initiate_migration' ) );
add_action( 'wp_ajax_wpmdb_migrate_table', array( $this, 'ajax_migrate_table' ) );
add_action( 'wp_ajax_wpmdb_clear_log', array( $this, 'ajax_clear_log' ) );
add_action( 'wp_ajax_wpmdb_get_log', array( $this, 'ajax_get_log' ) );
add_action( 'wp_ajax_wpmdb_plugin_compatibility', array( $this, 'ajax_plugin_compatibility' ) );
add_action( 'wp_ajax_wpmdb_blacklist_plugins', array( $this, 'ajax_blacklist_plugins' ) );
add_action( 'wp_ajax_wpmdb_update_max_request_size', array( $this, 'ajax_update_max_request_size' ) );
add_action( 'wp_ajax_wpmdb_update_delay_between_requests', array( $this, 'ajax_update_delay_between_requests' ) );
add_action( 'wp_ajax_wpmdb_cancel_migration', array( $this, 'ajax_cancel_migration' ) );
add_action( 'wp_ajax_wpmdb_finalize_migration', array( $this, 'ajax_finalize_migration' ) );
add_action( 'wp_ajax_wpmdb_flush', array( $this, 'ajax_flush' ) );
add_action( 'wp_ajax_nopriv_wpmdb_flush', array( $this, 'ajax_nopriv_flush', ) );
$this->accepted_fields = array(
'action',
'save_computer',
'gzip_file',
'connection_info',
'replace_old',
'replace_new',
'table_migrate_option',
'select_tables',
'replace_guids',
'exclude_spam',
'save_migration_profile',
'save_migration_profile_option',
'create_new_profile',
'create_backup',
'remove_backup',
'keep_active_plugins',
'select_post_types',
'backup_option',
'select_backup',
'exclude_transients',
'exclude_post_types',
'exclude_post_revisions',
'compatibility_older_mysql',
'export_dest',
);
$this->default_profile = array(
'action' => 'savefile',
'save_computer' => '1',
'gzip_file' => '1',
'table_migrate_option' => 'migrate_only_with_prefix',
'replace_guids' => '1',
'default_profile' => true,
'name' => '',
'select_tables' => array(),
'select_post_types' => array(),
'backup_option' => 'backup_only_with_prefix',
'exclude_transients' => '1',
'compatibility_older_mysql' => '1',
);
$this->checkbox_options = array(
'save_computer' => '0',
'gzip_file' => '0',
'replace_guids' => '0',
'exclude_spam' => '0',
'keep_active_plugins' => '0',
'create_backup' => '0',
'exclude_post_types' => '0',
'exclude_transients' => '0',
'compatibility_older_mysql' => '0',
);
$this->plugin_tabs = array(
'' . esc_html( _x( 'Migrate', 'Configure a migration or export', 'wp-migrate-db' ) ) . '',
'' . esc_html( _x( 'Settings', 'Plugin configuration and preferences', 'wp-migrate-db' ) ) . '',
'' . esc_html( _x( 'Addons', 'Plugin extensions', 'wp-migrate-db' ) ) . '',
'' . esc_html( _x( 'Help', 'Get help or contact support', 'wp-migrate-db' ) ) . '',
);
// display a notice when either WP Migrate DB or WP Migrate DB Pro is automatically deactivated
add_action( 'pre_current_active_plugins', array( $this, 'plugin_deactivated_notice' ) );
// check if WP Engine is filtering the buffer and prevent it
add_action( 'plugins_loaded', array( $this, 'maybe_disable_wp_engine_filtering' ) );
// this is how many DB rows are processed at a time, allow devs to change this value
$this->rows_per_segment = apply_filters( 'wpmdb_rows_per_segment', $this->rows_per_segment );
if ( is_multisite() ) {
add_action( 'network_admin_menu', array( $this, 'network_admin_menu' ) );
add_action( 'admin_menu', array( $this, 'network_tools_admin_menu' ) );
/*
* The URL find & replace is locked down (delete & reorder disabled) on multisite installations as we require the URL
* of the remote site for export migrations. This URL is parsed into its various components and
* used to change values in the 'domain' & 'path' columns in the wp_blogs and wp_site tables.
*/
$this->lock_url_find_replace_row = true;
} else {
add_action( 'admin_menu', array( $this, 'admin_menu' ) );
}
}
/**
* Returns a fragment of SQL for creating the table where the alter statements are held during the migration.
*
* @return string
*/
function get_create_alter_table_query() {
if ( ! is_null( $this->create_alter_table_query ) ) {
return $this->create_alter_table_query;
}
$legacy_alter_table_name = $this->get_legacy_alter_table_name();
$this->create_alter_table_query = sprintf( "DROP TABLE IF EXISTS `%s`;\n", $legacy_alter_table_name );
$alter_table_name = $this->get_alter_table_name();
$this->create_alter_table_query .= sprintf( "DROP TABLE IF EXISTS `%s`;\n", $alter_table_name );
$this->create_alter_table_query .= sprintf( "CREATE TABLE `%s` ( `query` LONGTEXT NOT NULL );\n", $alter_table_name );
$this->create_alter_table_query = apply_filters( 'wpmdb_create_alter_table_query', $this->create_alter_table_query );
return $this->create_alter_table_query;
}
/**
* Handler for ajax request to turn on or off Compatibility Mode.
*/
function ajax_plugin_compatibility() {
$this->check_ajax_referer( 'plugin_compatibility' );
$key_rules = array(
'action' => 'key',
'install' => 'numeric',
);
$this->set_post_data( $key_rules );
$mu_dir = ( defined( 'WPMU_PLUGIN_DIR' ) && defined( 'WPMU_PLUGIN_URL' ) ) ? WPMU_PLUGIN_DIR : trailingslashit( WP_CONTENT_DIR ) . 'mu-plugins';
$source = trailingslashit( $this->plugin_dir_path ) . 'compatibility/wp-migrate-db-pro-compatibility.php';
$dest = trailingslashit( $mu_dir ) . 'wp-migrate-db-pro-compatibility.php';
if ( '1' === trim( $this->state_data['install'] ) ) { // install MU plugin
if ( ! wp_mkdir_p( $mu_dir ) ) {
printf( esc_html__( 'The following directory could not be created: %s', 'wp-migrate-db' ), $mu_dir );
exit;
}
if ( ! @copy( $source, $dest ) ) {
printf( esc_html__( 'Could not copy the compatibility plugin from %1$s to %2$s', 'wp-migrate-db' ), $source, $dest );
exit;
}
} else { // uninstall MU plugin
// TODO: Use WP_Filesystem API.
if ( file_exists( $dest ) && ! @unlink( $dest ) ) {
printf( esc_html__( 'Could not remove the compatibility plugin from %s', 'wp-migrate-db' ), $dest );
exit;
}
}
exit;
}
/**
* Handler for updating the plugins that are not to be loaded during a request (Compatibility Mode).
*/
function ajax_blacklist_plugins() {
$this->check_ajax_referer( 'blacklist_plugins' );
$key_rules = array(
'action' => 'key',
'blacklist_plugins' => 'array',
);
$this->set_post_data( $key_rules );
$this->settings['blacklist_plugins'] = (array) $this->state_data['blacklist_plugins'];
update_site_option( 'wpmdb_settings', $this->settings );
exit;
}
/**
* Updates the Maximum Request Size setting.
*
* @return void
*/
function ajax_update_max_request_size() {
$this->check_ajax_referer( 'update-max-request-size' );
$key_rules = array(
'action' => 'key',
'max_request_size' => 'positive_int',
'nonce' => 'key',
);
$this->set_post_data( $key_rules );
$this->settings['max_request'] = (int) $this->state_data['max_request_size'] * 1024;
$result = update_site_option( 'wpmdb_settings', $this->settings );
$this->end_ajax( $result );
}
/**
* Updates the Delay Between Requests setting.
*
* @return void
*/
function ajax_update_delay_between_requests() {
$this->check_ajax_referer( 'update-delay-between-requests' );
$key_rules = array(
'action' => 'key',
'delay_between_requests' => 'positive_int',
'nonce' => 'key',
);
$this->set_post_data( $key_rules );
$this->settings['delay_between_requests'] = (int) $this->state_data['delay_between_requests'];
$result = update_site_option( 'wpmdb_settings', $this->settings );
$this->end_ajax( $result );
}
static function is_json( $string, $strict = false ) {
$json = @json_decode( $string, true );
if ( $strict == true && ! is_array( $json ) ) {
return false;
}
return ! ( $json == null || $json == false );
}
function get_sql_dump_info( $migration_type, $info_type ) {
if ( empty( $this->session_salt ) ) {
$this->session_salt = strtolower( wp_generate_password( 5, false, false ) );
}
$datetime = date( 'YmdHis' );
$ds = ( $info_type == 'path' ? DIRECTORY_SEPARATOR : '/' );
$dump_info = sprintf( '%s%s%s-%s-%s-%s.sql', $this->get_upload_info( $info_type ), $ds, sanitize_title_with_dashes( DB_NAME ), $migration_type, $datetime, $this->session_salt );
return ( $info_type == 'path' ? $this->slash_one_direction( $dump_info ) : $dump_info );
}
/**
* Returns validated and sanitized form data.
*
* @param array|string $data
*
* @return array|string
*/
function parse_migration_form_data( $data ) {
$form_data = parent::parse_migration_form_data( $data );
$this->accepted_fields = apply_filters( 'wpmdb_accepted_profile_fields', $this->accepted_fields );
$form_data = array_intersect_key( $form_data, array_flip( $this->accepted_fields ) );
unset( $form_data['replace_old'][0] );
unset( $form_data['replace_new'][0] );
if ( ! isset( $form_data['replace_old'] ) ) {
$form_data['replace_old'] = array();
}
if ( ! isset( $form_data['replace_new'] ) ) {
$form_data['replace_new'] = array();
}
if ( isset( $form_data['exclude_post_revisions'] ) ) {
$form_data['exclude_post_types'] = '1';
$form_data['select_post_types'][] = 'revision';
$form_data['select_post_types'] = array_unique( $form_data['select_post_types'] );
unset( $form_data['exclude_post_revisions'] );
}
return $form_data;
}
/**
* Adds settings link to plugin page
*
* @param array $links
*
* @return array $links
*/
function plugin_action_links( $links ) {
$link = sprintf( '%s', network_admin_url( $this->plugin_base ) . '#settings', _x( 'Settings', 'Plugin configuration and preferences', 'wp-migrate-db' ) );
array_unshift( $links, $link );
return $links;
}
function ajax_clear_log() {
$this->check_ajax_referer( 'clear-log' );
delete_site_option( 'wpmdb_error_log' );
$result = $this->end_ajax();
return $result;
}
function ajax_get_log() {
$this->check_ajax_referer( 'get-log' );
ob_start();
$this->output_diagnostic_info();
$this->output_log_file();
$return = ob_get_clean();
$result = $this->end_ajax( $return );
return $result;
}
function output_log_file() {
$this->load_error_log();
if ( isset( $this->error_log ) ) {
echo $this->error_log;
}
}
/**
* Outputs diagnostic info for debugging.
*
* Outputs useful diagnostic info text at the Diagnostic Info & Error Log
* section under the Help tab so the information can be viewed or
* downloaded and shared for debugging.
*
* If you would like to add additional diagnostic information use the
* `wpmdb_diagnostic_info` action hook (see {@link https://developer.wordpress.org/reference/functions/add_action/}).
*
*
* add_action( 'wpmdb_diagnostic_info', 'my_diagnostic_info' ) {
* echo "Additional Diagnostic Info: \r\n";
* echo "...\r\n";
* }
*
*
* @return void
*/
function output_diagnostic_info() {
global $wpdb;
$table_prefix = $wpdb->base_prefix;
echo 'site_url(): ';
echo esc_html( site_url() );
echo "\r\n";
echo 'home_url(): ';
echo esc_html( home_url() );
echo "\r\n";
echo 'Database Name: ';
echo esc_html( $wpdb->dbname );
echo "\r\n";
echo 'Table Prefix: ';
echo esc_html( $table_prefix );
echo "\r\n";
echo 'WordPress: ';
echo bloginfo( 'version' );
if ( is_multisite() ) {
$multisite_type = defined( 'SUBDOMAIN_INSTALL' ) && SUBDOMAIN_INSTALL ? 'Sub-domain' : 'Sub-directory';
echo ' Multisite (' . $multisite_type . ')';
echo "\r\n";
if ( defined( 'DOMAIN_CURRENT_SITE' ) ) {
echo 'Domain Current Site: ';
echo DOMAIN_CURRENT_SITE;
echo "\r\n";
}
if ( defined( 'PATH_CURRENT_SITE' ) ) {
echo 'Path Current Site: ';
echo PATH_CURRENT_SITE;
echo "\r\n";
}
if ( defined( 'SITE_ID_CURRENT_SITE' ) ) {
echo 'Site ID Current Site: ';
echo SITE_ID_CURRENT_SITE;
echo "\r\n";
}
if ( defined( 'BLOG_ID_CURRENT_SITE' ) ) {
echo 'Blog ID Current Site: ';
echo BLOG_ID_CURRENT_SITE;
}
}
echo "\r\n";
echo 'Web Server: ';
echo esc_html( ! empty( $_SERVER['SERVER_SOFTWARE'] ) ? $_SERVER['SERVER_SOFTWARE'] : '' );
echo "\r\n";
echo 'PHP: ';
if ( function_exists( 'phpversion' ) ) {
echo esc_html( phpversion() );
}
echo "\r\n";
echo 'MySQL: ';
echo esc_html( empty( $wpdb->use_mysqli ) ? mysql_get_server_info() : mysqli_get_server_info( $wpdb->dbh ) );
echo "\r\n";
echo 'ext/mysqli: ';
echo empty( $wpdb->use_mysqli ) ? 'no' : 'yes';
echo "\r\n";
echo 'WP Memory Limit: ';
echo esc_html( WP_MEMORY_LIMIT );
echo "\r\n";
echo 'Blocked External HTTP Requests: ';
if ( ! defined( 'WP_HTTP_BLOCK_EXTERNAL' ) || ! WP_HTTP_BLOCK_EXTERNAL ) {
echo 'None';
} else {
$accessible_hosts = ( defined( 'WP_ACCESSIBLE_HOSTS' ) ) ? WP_ACCESSIBLE_HOSTS : '';
if ( empty( $accessible_hosts ) ) {
echo 'ALL';
} else {
echo 'Partially (Accessible Hosts: ' . esc_html( $accessible_hosts ) . ')';
}
}
echo "\r\n";
echo 'WPMDB Bottleneck: ';
echo esc_html( size_format( $this->get_bottleneck() ) );
echo "\r\n";
echo 'WP Locale: ';
echo esc_html( get_locale() );
echo "\r\n";
echo 'DB Charset: ';
echo esc_html( DB_CHARSET );
echo "\r\n";
if ( function_exists( 'ini_get' ) && $suhosin_limit = ini_get( 'suhosin.post.max_value_length' ) ) {
echo 'Suhosin Post Max Value Length: ';
echo esc_html( is_numeric( $suhosin_limit ) ? size_format( $suhosin_limit ) : $suhosin_limit );
echo "\r\n";
}
if ( function_exists( 'ini_get' ) && $suhosin_limit = ini_get( 'suhosin.request.max_value_length' ) ) {
echo 'Suhosin Request Max Value Length: ';
echo esc_html( is_numeric( $suhosin_limit ) ? size_format( $suhosin_limit ) : $suhosin_limit );
echo "\r\n";
}
echo 'Debug Mode: ';
echo esc_html( ( defined( 'WP_DEBUG' ) && WP_DEBUG ) ? 'Yes' : 'No' );
echo "\r\n";
echo 'WP Max Upload Size: ';
echo esc_html( size_format( wp_max_upload_size() ) );
echo "\r\n";
echo 'PHP Post Max Size: ';
echo esc_html( size_format( $this->get_post_max_size() ) );
echo "\r\n";
echo 'PHP Time Limit: ';
if ( function_exists( 'ini_get' ) ) {
echo esc_html( ini_get( 'max_execution_time' ) );
}
echo "\r\n";
echo 'PHP Error Log: ';
if ( function_exists( 'ini_get' ) ) {
echo esc_html( ini_get( 'error_log' ) );
}
echo "\r\n";
echo 'fsockopen: ';
if ( function_exists( 'fsockopen' ) ) {
echo 'Enabled';
} else {
echo 'Disabled';
}
echo "\r\n";
echo 'OpenSSL: ';
if ( $this->open_ssl_enabled() ) {
echo esc_html( OPENSSL_VERSION_TEXT );
} else {
echo 'Disabled';
}
echo "\r\n";
echo 'cURL: ';
if ( function_exists( 'curl_init' ) ) {
echo 'Enabled';
} else {
echo 'Disabled';
}
echo "\r\n";
echo 'Enable SSL verification setting: ';
if ( 1 == $this->settings['verify_ssl'] ) {
echo 'Yes';
} else {
echo 'No';
}
echo "\r\n";
echo 'Compatibility Mode: ';
if ( isset( $GLOBALS['wpmdb_compatibility'] ) ) {
echo 'Yes';
} else {
echo 'No';
}
echo "\r\n";
echo 'Delay Between Requests: ';
$delay_between_requests = $this->settings['delay_between_requests'];
$delay_between_requests = $delay_between_requests > 0 ? $delay_between_requests / 1000 : $delay_between_requests;
echo esc_html( $delay_between_requests ) . ' s';
echo "\r\n\r\n";
do_action( 'wpmdb_diagnostic_info' );
if ( has_action( 'wpmdb_diagnostic_info' ) ) {
echo "\r\n";
}
$theme_info = wp_get_theme();
echo "Active Theme Name: " . esc_html( $theme_info->Name ) . "\r\n";
echo "Active Theme Folder: " . esc_html( basename( $theme_info->get_stylesheet_directory() ) ) . "\r\n";
if ( $theme_info->get( 'Template' ) ) {
echo "Parent Theme Folder: " . esc_html( $theme_info->get( 'Template' ) ) . "\r\n";
}
if ( ! file_exists( $theme_info->get_stylesheet_directory() ) ) {
echo "WARNING: Active Theme Folder Not Found\r\n";
}
echo "\r\n";
echo "Active Plugins:\r\n";
if ( isset( $GLOBALS['wpmdb_compatibility'] ) ) {
remove_filter( 'option_active_plugins', 'wpmdbc_exclude_plugins' );
remove_filter( 'site_option_active_sitewide_plugins', 'wpmdbc_exclude_site_plugins' );
$blacklist = array_flip( (array) $this->settings['blacklist_plugins'] );
} else {
$blacklist = array();
}
$active_plugins = (array) get_option( 'active_plugins', array() );
if ( is_multisite() ) {
$network_active_plugins = wp_get_active_network_plugins();
$active_plugins = array_map( array( $this, 'remove_wp_plugin_dir' ), $network_active_plugins );
}
foreach ( $active_plugins as $plugin ) {
$suffix = ( isset( $blacklist[ $plugin ] ) ) ? '*' : '';
$this->print_plugin_details( WP_PLUGIN_DIR . '/' . $plugin, $suffix );
}
if ( isset( $GLOBALS['wpmdb_compatibility'] ) ) {
add_filter( 'option_active_plugins', 'wpmdbc_exclude_plugins' );
add_filter( 'site_option_active_sitewide_plugins', 'wpmdbc_exclude_site_plugins' );
}
$mu_plugins = wp_get_mu_plugins();
if ( $mu_plugins ) {
echo "\r\n";
echo "Must-use Plugins:\r\n";
foreach ( $mu_plugins as $mu_plugin ) {
$this->print_plugin_details( $mu_plugin );
}
echo "\r\n";
}
}
function print_plugin_details( $plugin_path, $suffix = '' ) {
$plugin_data = get_plugin_data( $plugin_path );
if ( empty( $plugin_data['Name'] ) ) {
return;
}
printf( "%s%s (v%s) by %s\r\n", $plugin_data['Name'], $suffix, $plugin_data['Version'], $plugin_data['AuthorName'] );
}
function remove_wp_plugin_dir( $name ) {
$plugin = str_replace( WP_PLUGIN_DIR, '', $name );
return substr( $plugin, 1 );
}
function get_alter_queries() {
global $wpdb;
$alter_table_name = $this->get_alter_table_name();
$alter_queries = array();
$sql = '';
if ( $alter_table_name === $wpdb->get_var( "SHOW TABLES LIKE '$alter_table_name'" ) ) {
$alter_queries = $wpdb->get_results( "SELECT * FROM `{$alter_table_name}`", ARRAY_A );
$alter_queries = apply_filters( 'wpmdb_get_alter_queries', $alter_queries );
}
if ( ! empty( $alter_queries ) ) {
foreach ( $alter_queries as $alter_query ) {
$sql .= $alter_query['query'] . "\n";
}
}
return $sql;
}
function process_chunk( $chunk ) {
// prepare db
global $wpdb;
$this->set_time_limit();
$queries = array_filter( explode( ";\n", $chunk ) );
array_unshift( $queries, "SET sql_mode='NO_AUTO_VALUE_ON_ZERO';" );
ob_start();
$wpdb->show_errors();
if ( empty( $wpdb->charset ) ) {
$charset = ( defined( 'DB_CHARSET' ) ? DB_CHARSET : 'utf8' );
$wpdb->charset = $charset;
$wpdb->set_charset( $wpdb->dbh, $wpdb->charset );
}
foreach ( $queries as $query ) {
if ( false === $wpdb->query( $query ) ) {
$return = ob_get_clean();
$return = array( 'wpmdb_error' => 1, 'body' => $return );
$result = $this->end_ajax( json_encode( $return ) );
return $result;
}
}
return true;
}
/**
* Called for each database table to be migrated.
*
* @return string
*/
function ajax_migrate_table() {
$this->check_ajax_referer( 'migrate-table' );
$key_rules = array(
'action' => 'key',
'migration_state_id' => 'key',
'table' => 'string',
'stage' => 'key',
'current_row' => 'numeric',
'last_table' => 'string',
'primary_keys' => 'string',
'gzip' => 'int',
'nonce' => 'key',
'bottleneck' => 'positive_int',
'prefix' => 'string',
'path_current_site' => 'string',
'domain_current_site' => 'text',
);
$this->set_post_data( $key_rules );
global $wpdb;
$this->form_data = $this->parse_migration_form_data( $this->state_data['form_data'] );
$result = '';
// checks if we're performing a backup, if so, continue with the backup and exit immediately after
if ( $this->state_data['stage'] == 'backup' && $this->state_data['intent'] != 'savefile' ) {
// if performing a push we need to backup the REMOTE machine's DB
if ( $this->state_data['intent'] == 'push' ) {
$data = $this->filter_post_elements(
$this->state_data,
array(
'action',
'remote_state_id',
'url',
'table',
'form_data',
'stage',
'bottleneck',
'prefix',
'current_row',
'last_table',
'gzip',
'primary_keys',
'path_current_site',
'domain_current_site',
)
);
$data['action'] = 'wpmdb_backup_remote_table';
$data['intent'] = 'pull';
$data['sig'] = $this->create_signature( $data, $this->state_data['key'] );
$data['primary_keys'] = addslashes( $data['primary_keys'] );
$ajax_url = $this->ajax_url();
$response = $this->remote_post( $ajax_url, $data, __FUNCTION__ );
ob_start();
$this->display_errors();
$maybe_errors = ob_get_clean();
if ( false === empty( $maybe_errors ) ) {
$maybe_errors = array( 'wpmdb_error' => 1, 'body' => $maybe_errors );
$return = json_encode( $maybe_errors );
} else {
$return = $response;
}
} else {
$return = $this->handle_table_backup();
}
$result = $this->end_ajax( $return );
return $result;
}
// Pull and push need to be handled differently for obvious reasons,
// and trigger different code depending on the migration intent (push or pull).
if ( in_array( $this->state_data['intent'], array( 'push', 'savefile', 'find_replace' ) ) ) {
$this->maximum_chunk_size = $this->get_bottleneck();
if ( isset( $this->state_data['bottleneck'] ) ) {
$this->maximum_chunk_size = (int) $this->state_data['bottleneck'];
}
if ( 'savefile' === $this->state_data['intent'] ) {
$sql_dump_file_name = $this->get_upload_info( 'path' ) . DIRECTORY_SEPARATOR;
$sql_dump_file_name .= $this->format_dump_name( $this->state_data['dump_filename'] );
$this->fp = $this->open( $sql_dump_file_name );
}
if ( ! empty( $this->state_data['db_version'] ) ) {
$this->target_db_version = $this->state_data['db_version'];
if ( 'push' == $this->state_data['intent'] ) {
// $this->target_db_version has been set to remote database's version.
add_filter( 'wpmdb_create_table_query', array( $this, 'mysql_compat_filter' ), 10, 5 );
} elseif ( 'savefile' == $this->state_data['intent'] && ! empty( $this->form_data['compatibility_older_mysql'] ) ) {
// compatibility_older_mysql is currently a checkbox meaning pre-5.5 compatibility (we play safe and target 5.1),
// this may change in the future to be a dropdown or radiobox returning the version to be compatible with.
$this->target_db_version = '5.1';
add_filter( 'wpmdb_create_table_query', array( $this, 'mysql_compat_filter' ), 10, 5 );
}
}
if ( ! empty( $this->state_data['find_replace_pairs'] ) ) {
$this->find_replace_pairs = $this->state_data['find_replace_pairs'];
}
ob_start();
$result = $this->process_table( $this->state_data['table'] );
if ( $this->state_data['intent'] == 'savefile' && isset( $this->fp ) ) {
$this->close( $this->fp );
}
$this->display_errors();
$maybe_errors = trim( ob_get_clean() );
if ( false === empty( $maybe_errors ) ) {
$return = array( 'wpmdb_error' => 1, 'body' => $maybe_errors );
$result = $this->end_ajax( json_encode( $return ) );
return $result;
}
return $result;
} else {
$data = $this->filter_post_elements(
$this->state_data,
array(
'remote_state_id',
'intent',
'url',
'table',
'form_data',
'stage',
'bottleneck',
'current_row',
'last_table',
'gzip',
'primary_keys',
'site_url',
'find_replace_pairs',
)
);
$data['action'] = 'wpmdb_process_pull_request';
$data['pull_limit'] = $this->get_sensible_pull_limit();
$data['db_version'] = $wpdb->db_version();
if ( is_multisite() ) {
$data['path_current_site'] = $this->get_path_current_site();
$data['domain_current_site'] = $this->get_domain_current_site();
}
$data['prefix'] = $wpdb->base_prefix;
if ( isset( $data['find_replace_pairs'] ) ) {
$data['find_replace_pairs'] = serialize( $data['find_replace_pairs'] );
}
if ( isset( $data['sig'] ) ) {
unset( $data['sig'] );
}
$data['sig'] = $this->create_signature( $data, $this->state_data['key'] );
$data['primary_keys'] = addslashes( $data['primary_keys'] );
$data['find_replace_pairs'] = addslashes( $data['find_replace_pairs'] );
$ajax_url = $this->ajax_url();
$response = $this->remote_post( $ajax_url, $data, __FUNCTION__ );
ob_start();
$this->display_errors();
$maybe_errors = trim( ob_get_clean() );
if ( false === empty( $maybe_errors ) ) {
$return = array( 'wpmdb_error' => 1, 'body' => $maybe_errors );
$result = $this->end_ajax( json_encode( $return ) );
return $result;
}
if ( strpos( $response, ';' ) === false ) {
$result = $this->end_ajax( $response );
return $result;
}
// returned data is just a big string like this query;query;query;33
// need to split this up into a chunk and row_tracker
$row_information = trim( substr( strrchr( $response, "\n" ), 1 ) );
$row_information = explode( ',', $row_information );
$chunk = substr( $response, 0, strrpos( $response, ";\n" ) + 1 );
if ( ! empty( $chunk ) ) {
$process_chunk_result = $this->process_chunk( $chunk );
if ( true !== $process_chunk_result ) {
$result = $this->end_ajax( $process_chunk_result );
return $result;
}
}
$result = array(
'current_row' => $row_information[0],
'primary_keys' => $row_information[1],
);
$result = $this->end_ajax( json_encode( $result ) );
}
return $result;
}
/**
* Occurs right before the first table is migrated / backed up during the migration process.
*
* @return string
*
* Does a quick check to make sure the verification string is valid and also opens / creates files for writing to (if required).
*/
function ajax_initiate_migration() {
global $wpdb;
$this->check_ajax_referer( 'initiate-migration' );
$key_rules = array(
'action' => 'key',
'intent' => 'key',
'url' => 'url',
'key' => 'string',
'form_data' => 'string',
'stage' => 'key',
'nonce' => 'key',
'temp_prefix' => 'string',
'site_details' => 'json_array',
'export_dest' => 'string',
);
$this->set_post_data( $key_rules );
$this->form_data = $this->parse_migration_form_data( $this->state_data['form_data'] );
// A little bit of house keeping.
WPMDB_Migration_State::cleanup();
if ( 'savefile' === $this->state_data['intent'] || 'find_replace' === $this->state_data['intent'] ) {
$return = array(
'code' => 200,
'message' => 'OK',
'body' => json_encode( array( 'error' => 0 ) ),
);
if ( 'find_replace' !== $this->state_data['intent'] || 'backup' === $this->state_data['stage'] ) {
$return['dump_path'] = $this->get_sql_dump_info( 'migrate', 'path' );
$return['dump_filename'] = basename( $return['dump_path'] );
$return['dump_url'] = $this->get_sql_dump_info( 'migrate', 'url' );
$dump_filename_no_extension = substr( $return['dump_filename'], 0, -4 );
$create_alter_table_query = $this->get_create_alter_table_query();
// sets up our table to store 'ALTER' queries
$process_chunk_result = $this->process_chunk( $create_alter_table_query );
if ( true !== $process_chunk_result ) {
$result = $this->end_ajax( $process_chunk_result );
return $result;
}
if ( 'savefile' === $this->state_data['intent'] && $this->gzip() && isset( $this->form_data['gzip_file'] ) && $this->form_data['gzip_file'] ) {
$return['dump_path'] .= '.gz';
$return['dump_filename'] .= '.gz';
$return['dump_url'] .= '.gz';
}
$this->fp = $this->open( $this->get_upload_info( 'path' ) . DIRECTORY_SEPARATOR . $return['dump_filename'] );
$this->db_backup_header();
$this->close( $this->fp );
$return['dump_filename'] = $dump_filename_no_extension;
}
} else { // does one last check that our verification string is valid
$data = array(
'action' => 'wpmdb_remote_initiate_migration',
'intent' => $this->state_data['intent'],
'form_data' => $this->state_data['form_data'],
'site_details' => $this->state_data['site_details'],
);
$data['site_details'] = serialize( $data['site_details'] );
$data['sig'] = $this->create_signature( $data, $this->state_data['key'] );
$data['site_details'] = addslashes( $data['site_details'] );
$ajax_url = $this->ajax_url();
$response = $this->remote_post( $ajax_url, $data, __FUNCTION__ );
if ( false === $response ) {
$return = array( 'wpmdb_error' => 1, 'body' => $this->error );
$result = $this->end_ajax( json_encode( $return ) );
return $result;
}
$return = WPMDB_Utils::unserialize( $response, __METHOD__ );
if ( false === $return ) {
$error_msg = __( 'Failed attempting to unserialize the response from the remote server. Please contact support.', 'wp-migrate-db' );
$return = array( 'wpmdb_error' => 1, 'body' => $error_msg );
$this->log_error( $error_msg, $response );
$result = $this->end_ajax( json_encode( $return ) );
return $result;
}
if ( isset( $return['error'] ) && $return['error'] == 1 ) {
$return = array( 'wpmdb_error' => 1, 'body' => $return['message'] );
$result = $this->end_ajax( json_encode( $return ) );
return $result;
}
if ( $this->state_data['intent'] == 'pull' ) {
// sets up our table to store 'ALTER' queries
$create_alter_table_query = $this->get_create_alter_table_query();
$process_chunk_result = $this->process_chunk( $create_alter_table_query );
if ( true !== $process_chunk_result ) {
$result = $this->end_ajax( $process_chunk_result );
return $result;
}
}
if ( ! empty( $this->form_data['create_backup'] ) && $this->state_data['intent'] == 'pull' ) {
$return['dump_filename'] = basename( $this->get_sql_dump_info( 'backup', 'path' ) );
$return['dump_filename'] = substr( $return['dump_filename'], 0, -4 );
$return['dump_url'] = $this->get_sql_dump_info( 'backup', 'url' );
}
}
$return['dump_filename'] = ( empty( $return['dump_filename'] ) ) ? '' : $return['dump_filename'];
$return['dump_url'] = ( empty( $return['dump_url'] ) ) ? '' : $return['dump_url'];
// A successful call to wpmdb_remote_initiate_migration for a Push migration will have set db_version.
// Otherwise ensure it is set with own db_version so that we always return one.
$return['db_version'] = ( empty( $return['db_version'] ) ) ? $wpdb->db_version() : $return['db_version'];
// A successful call to wpmdb_remote_initiate_migration for a Push migration will have set site_url.
// Otherwise ensure it is set with own site_url so that we always return one.
$return['site_url'] = ( empty( $return['site_url'] ) ) ? site_url() : $return['site_url'];
$return['find_replace_pairs'] = $this->parse_find_replace_pairs( $this->state_data['intent'], $return['site_url'] );
// Store current migration state and return its id.
$state = array_merge( $this->state_data, $return );
unset( $return );
$return['migration_state_id'] = $this->migration_state->id();
$return = $this->save_migration_state( $state, $return );
$result = $this->end_ajax( json_encode( $return ) );
return $result;
}
/**
* After table migration, delete old tables and rename new tables removing the temporarily prefix.
*
* @return mixed
*/
function ajax_finalize_migration() {
$this->check_ajax_referer( 'finalize-migration' );
$key_rules = array(
'action' => 'key',
'migration_state_id' => 'key',
'prefix' => 'string',
'tables' => 'string',
'nonce' => 'key',
);
$this->set_post_data( $key_rules );
if ( 'savefile' === $this->state_data['intent'] ) {
return true;
}
$this->form_data = $this->parse_migration_form_data( $this->state_data['form_data'] );
global $wpdb;
if ( 'push' === $this->state_data['intent'] ) {
do_action( 'wpmdb_migration_complete', 'push', $this->state_data['url'] );
$data = $this->filter_post_elements(
$this->state_data,
array(
'remote_state_id',
'url',
'form_data',
'tables',
'temp_prefix',
)
);
$data['action'] = 'wpmdb_remote_finalize_migration';
$data['intent'] = 'pull';
$data['prefix'] = $wpdb->base_prefix;
$data['type'] = 'push';
$data['location'] = home_url();
$data['sig'] = $this->create_signature( $data, $this->state_data['key'] );
$ajax_url = $this->ajax_url();
$response = $this->remote_post( $ajax_url, $data, __FUNCTION__ );
ob_start();
echo esc_html( $response );
$this->display_errors();
$return = ob_get_clean();
} else {
$return = $this->finalize_migration();
}
$result = $this->end_ajax( $return );
return $result;
}
/**
* Internal function for finalizing a migration.
*
* @return bool|null
*/
function finalize_migration() {
$this->set_post_data();
$tables = explode( ',', $this->state_data['tables'] );
$temp_prefix = ( isset( $this->state_data['temp_prefix'] ) ) ? $this->state_data['temp_prefix'] : $this->temp_prefix;
$temp_tables = array();
$type = $this->state_data['intent'];
if ( isset( $this->state_data['type'] ) && 'push' === $this->state_data['type'] ) {
$type = 'push';
}
if ( 'find_replace' === $this->state_data['intent'] ) {
$location = home_url();
} else {
$location = ( isset( $this->state_data['location'] ) ) ? $this->state_data['location'] : $this->state_data['url'];
}
foreach ( $tables as $table ) {
$temp_tables[] = $temp_prefix . apply_filters(
'wpmdb_finalize_target_table_name',
$table,
$type,
$this->state_data['site_details']
);
}
$sql = "SET FOREIGN_KEY_CHECKS=0;\n";
$sql .= $this->get_preserved_options_queries( $temp_tables, $type );
foreach ( $temp_tables as $table ) {
$sql .= 'DROP TABLE IF EXISTS ' . $this->backquote( substr( $table, strlen( $temp_prefix ) ) ) . ';';
$sql .= "\n";
$sql .= 'RENAME TABLE ' . $this->backquote( $table ) . ' TO ' . $this->backquote( substr( $table, strlen( $temp_prefix ) ) ) . ';';
$sql .= "\n";
}
$alter_table_name = $this->get_alter_table_name();
$sql .= $this->get_alter_queries();
$sql .= 'DROP TABLE IF EXISTS ' . $this->backquote( $alter_table_name ) . ";\n";
$process_chunk_result = $this->process_chunk( $sql );
if ( true !== $process_chunk_result ) {
$result = $this->end_ajax( $process_chunk_result );
return $result;
}
if ( ! isset( $this->state_data['location'] ) && 'find_replace' !== $this->state_data['intent'] ) {
$data = array();
$data['action'] = 'wpmdb_fire_migration_complete';
$data['url'] = home_url();
$data['sig'] = $this->create_signature( $data, $this->state_data['key'] );
$ajax_url = $this->ajax_url();
$response = $this->remote_post( $ajax_url, $data, __FUNCTION__ );
ob_start();
echo esc_html( $response );
$this->display_errors();
$maybe_errors = trim( ob_get_clean() );
if ( false === empty( $maybe_errors ) && '1' !== $maybe_errors ) {
$maybe_errors = array( 'wpmdb_error' => 1, 'body' => $maybe_errors );
$result = $this->end_ajax( json_encode( $maybe_errors ) );
return $result;
}
}
do_action( 'wpmdb_migration_complete', $type, $location );
return true;
}
/**
* Returns SQL queries used to preserve options in the
* wp_options or wp_sitemeta tables during a migration.
*
* @param array $temp_tables
* @param string $intent
*
* @return string DELETE and INSERT SQL queries separated by a newline character (\n).
*/
function get_preserved_options_queries( $temp_tables, $intent = '' ) {
$this->set_post_data();
global $wpdb;
$sql = '';
$sitemeta_table_name = '';
$options_table_names = array();
$temp_prefix = isset( $this->state_data['temp_prefix'] ) ? $this->state_data['temp_prefix'] : $this->temp_prefix;
$table_prefix = isset( $this->state_data['prefix'] ) ? $this->state_data['prefix'] : $wpdb->base_prefix;
$prefix = esc_sql( $temp_prefix . $table_prefix );
foreach ( $temp_tables as $temp_table ) {
$table = $wpdb->base_prefix . str_replace( $prefix, '', $temp_table );
// Get sitemeta table
if ( is_multisite() && $this->table_is( 'sitemeta', $table ) ) {
$sitemeta_table_name = $temp_table;
}
// Get array of options tables
if ( $this->table_is( 'options', $table ) ) {
$options_table_names[] = $temp_table;
}
}
// Return if multisite but sitemeta and option tables not in migration scope
if ( is_multisite() && true === empty( $sitemeta_table_name ) && true === empty( $options_table_names ) ) {
return $sql;
}
// Return if options tables not in migration scope for non-multisite.
if ( ! is_multisite() && true === empty( $options_table_names ) ) {
return $sql;
}
$preserved_options = array(
'wpmdb_settings',
'wpmdb_error_log',
'wpmdb_schema_version',
'upload_path',
'upload_url_path',
);
$preserved_sitemeta_options = $preserved_options;
$this->form_data = $this->parse_migration_form_data( $this->state_data['form_data'] );
if ( false === empty( $this->form_data['keep_active_plugins'] ) ) {
$preserved_options[] = 'active_plugins';
$preserved_sitemeta_options[] = 'active_sitewide_plugins';
}
if ( is_multisite() ) {
// Get preserved data in site meta table if being replaced.
if ( ! empty( $sitemeta_table_name ) ) {
$table = $wpdb->base_prefix . str_replace( $prefix, '', $sitemeta_table_name );
$preserved_migration_state_options = $wpdb->get_results(
"SELECT `meta_key` FROM `{$table}` WHERE `meta_key` LIKE '" . WPMDB_Migration_State::OPTION_PREFIX . "%'",
OBJECT_K
);
if ( ! empty( $preserved_migration_state_options ) ) {
$preserved_sitemeta_options = array_merge( $preserved_sitemeta_options, array_keys( $preserved_migration_state_options ) );
}
$preserved_sitemeta_options = apply_filters( 'wpmdb_preserved_sitemeta_options', $preserved_sitemeta_options, $intent );
$preserved_sitemeta_options_escaped = esc_sql( $preserved_sitemeta_options );
$preserved_sitemeta_options_data = $wpdb->get_results(
sprintf(
"SELECT * FROM `{$table}` WHERE `meta_key` IN ('%s')",
implode( "','", $preserved_sitemeta_options_escaped )
),
ARRAY_A
);
$preserved_sitemeta_options_data = apply_filters( 'wpmdb_preserved_sitemeta_options_data', $preserved_sitemeta_options_data, $intent );
// Create preserved data queries for site meta table
foreach ( $preserved_sitemeta_options_data as $option ) {
$sql .= $wpdb->prepare( "DELETE FROM `{$sitemeta_table_name}` WHERE `meta_key` = %s;\n", $option['meta_key'] );
$sql .= $wpdb->prepare(
"INSERT INTO `{$sitemeta_table_name}` ( `meta_id`, `site_id`, `meta_key`, `meta_value` ) VALUES ( NULL , %s, %s, %s );\n",
$option['site_id'],
$option['meta_key'],
$option['meta_value']
);
}
}
} else {
$preserved_migration_state_options = $wpdb->get_results(
"SELECT `option_name` FROM `{$wpdb->options}` WHERE `option_name` LIKE '" . WPMDB_Migration_State::OPTION_PREFIX . "%'",
OBJECT_K
);
if ( ! empty( $preserved_migration_state_options ) ) {
$preserved_options = array_merge( $preserved_options, array_keys( $preserved_migration_state_options ) );
}
}
// Get preserved data in options tables if being replaced.
if ( ! empty( $options_table_names ) ) {
$preserved_options = apply_filters( 'wpmdb_preserved_options', $preserved_options, $intent );
$preserved_options_escaped = esc_sql( $preserved_options );
$preserved_options_data = array();
// Get preserved data in options tables
foreach ( $options_table_names as $option_table ) {
$table = $wpdb->base_prefix . str_replace( $prefix, '', $option_table );
$preserved_options_data[ $option_table ] = $wpdb->get_results(
sprintf(
"SELECT * FROM `{$table}` WHERE `option_name` IN ('%s')",
implode( "','", $preserved_options_escaped )
),
ARRAY_A
);
}
$preserved_options_data = apply_filters( 'wpmdb_preserved_options_data', $preserved_options_data, $intent );
// Create preserved data queries for options tables
foreach ( $preserved_options_data as $key => $value ) {
if ( false === empty( $value ) ) {
foreach ( $value as $option ) {
$sql .= $wpdb->prepare(
"DELETE FROM `{$key}` WHERE `option_name` = %s;\n",
$option['option_name']
);
$sql .= $wpdb->prepare(
"INSERT INTO `{$key}` ( `option_id`, `option_name`, `option_value`, `autoload` ) VALUES ( NULL , %s, %s, %s );\n",
$option['option_name'],
$option['option_value'],
$option['autoload']
);
}
}
}
}
return $sql;
}
/**
* Handles the request to flush caches and cleanup migration when pushing or not migrating user tables.
*
* @return bool|null
*/
function ajax_flush() {
$this->check_ajax_referer( 'flush' );
return $this->ajax_nopriv_flush();
}
/**
* Handles the request to flush caches and cleanup migration when pulling with user tables being migrated.
*
* @return bool|null
*/
function ajax_nopriv_flush() {
$key_rules = array(
'action' => 'key',
'migration_state_id' => 'key',
);
$this->set_post_data( $key_rules );
if ( 'push' === $this->state_data['intent'] ) {
$data = array();
$data['action'] = 'wpmdb_remote_flush';
$data['sig'] = $this->create_signature( $data, $this->state_data['key'] );
$ajax_url = $this->ajax_url();
$response = $this->remote_post( $ajax_url, $data, __FUNCTION__ );
ob_start();
echo esc_html( $response );
$this->display_errors();
$return = ob_get_clean();
} else {
$return = $this->flush();
}
if ( ! $this->migration_state->delete() ) {
$this->log_error( 'Could not delete migration state.' );
}
$result = $this->end_ajax( $return );
return $result;
}
/**
* Flushes the cache and rewrite rules.
*
* @return bool
*/
function flush() {
// flush rewrite rules to prevent 404s and other oddities
wp_cache_flush();
global $wp_rewrite;
$wp_rewrite->init();
flush_rewrite_rules( true ); // true = hard refresh, recreates the .htaccess file
return true;
}
/**
* Handler for the ajax request to save a migration profile.
*
* @return bool|null
*/
function ajax_save_profile() {
$this->check_ajax_referer( 'save-profile' );
$key_rules = array(
'action' => 'key',
'profile' => 'string',
'nonce' => 'key',
);
$this->set_post_data( $key_rules );
$profile = $this->parse_migration_form_data( $this->state_data['profile'] );
$profile = wp_parse_args( $profile, $this->checkbox_options );
if ( isset( $profile['save_migration_profile_option'] ) && $profile['save_migration_profile_option'] == 'new' ) {
$profile['name'] = $profile['create_new_profile'];
$this->settings['profiles'][] = $profile;
} else {
$key = $profile['save_migration_profile_option'];
$name = $this->settings['profiles'][ $key ]['name'];
$this->settings['profiles'][ $key ] = $profile;
$this->settings['profiles'][ $key ]['name'] = $name;
}
update_site_option( 'wpmdb_settings', $this->settings );
end( $this->settings['profiles'] );
$key = key( $this->settings['profiles'] );
$result = $this->end_ajax( $key );
return $result;
}
/**
* Handler for deleting a migration profile.
*
* @return bool|null
*/
function ajax_delete_migration_profile() {
$this->check_ajax_referer( 'delete-migration-profile' );
$key_rules = array(
'action' => 'key',
'profile_id' => 'positive_int',
'nonce' => 'key',
);
$this->set_post_data( $key_rules );
$key = absint( $this->state_data['profile_id'] );
--$key;
$return = '';
if ( isset( $this->settings['profiles'][ $key ] ) ) {
unset( $this->settings['profiles'][ $key ] );
update_site_option( 'wpmdb_settings', $this->settings );
} else {
$return = '-1';
}
$result = $this->end_ajax( $return );
return $result;
}
/**
* Handler for ajax request to save a setting, e.g. accept pull/push requests setting.
*
* @return bool|null
*/
function ajax_save_setting() {
$this->check_ajax_referer( 'save-setting' );
$key_rules = array(
'action' => 'key',
'checked' => 'bool',
'setting' => 'key',
'nonce' => 'key',
);
$this->set_post_data( $key_rules );
$this->settings[ $this->state_data['setting'] ] = ( $this->state_data['checked'] == 'false' ) ? false : true;
update_site_option( 'wpmdb_settings', $this->settings );
$result = $this->end_ajax();
return $result;
}
function format_table_sizes( $size ) {
$size *= 1024;
return size_format( $size );
}
/**
* Return array of post type slugs stored within DB.
*
* @return array List of post types
*/
function get_post_types() {
global $wpdb;
if ( is_multisite() ) {
$tables = $this->get_tables( 'prefix' );
$sql = "SELECT `post_type` FROM `{$wpdb->base_prefix}posts` ";
$prefix_escaped = preg_quote( $wpdb->base_prefix, '/' );
foreach ( $tables as $table ) {
if ( 0 == preg_match( '/' . $prefix_escaped . '[0-9]+_posts/', $table ) ) {
continue;
}
$blog_id = str_replace( array( $wpdb->base_prefix, '_posts' ), array( '', '' ), $table );
$sql .= "UNION SELECT `post_type` FROM `{$wpdb->base_prefix}" . $blog_id . '_posts` ';
}
$sql .= ';';
$post_types = $wpdb->get_results( $sql, ARRAY_A );
} else {
$post_types = $wpdb->get_results(
"SELECT DISTINCT `post_type`
FROM `{$wpdb->base_prefix}posts`
WHERE 1;",
ARRAY_A
);
}
$return = array( 'revision' );
foreach ( $post_types as $post_type ) {
$return[] = $post_type['post_type'];
}
return apply_filters( 'wpmdb_post_types', array_unique( $return ) );
}
// Retrieves the specified profile, if -1, returns the default profile
function get_profile( $profile_id ) {
--$profile_id;
if ( $profile_id == '-1' || ! isset( $this->settings['profiles'][ $profile_id ] ) ) {
return $this->default_profile;
}
return $this->settings['profiles'][ $profile_id ];
}
/**
* Returns an array of table names with their associated row counts.
*
* @return array
*/
function get_table_row_count() {
global $wpdb;
$sql = $wpdb->prepare( 'SELECT table_name, TABLE_ROWS FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = %s ORDER BY table_name', DB_NAME );
$results = $wpdb->get_results( $sql, ARRAY_A );
$return = array();
foreach ( $results as $result ) {
if ( $this->get_legacy_alter_table_name() == $result['table_name'] ) {
continue;
}
$return[ $result['table_name'] ] = ( $result['TABLE_ROWS'] == 0 ? 1 : $result['TABLE_ROWS'] );
}
return $return;
}
/**
* Returns an array of table names with associated size in kilobytes.
*
* @return mixed
*
* NOTE: Returned array may have been altered by wpmdb_table_sizes filter.
*/
function get_table_sizes() {
global $wpdb;
static $return;
if ( ! empty( $return ) ) {
return $return;
}
$return = array();
$sql = $wpdb->prepare(
"SELECT TABLE_NAME AS 'table',
ROUND( ( data_length + index_length ) / 1024, 0 ) AS 'size'
FROM INFORMATION_SCHEMA.TABLES
WHERE INFORMATION_SCHEMA.TABLES.table_schema = %s
AND INFORMATION_SCHEMA.TABLES.table_type = %s
ORDER BY TABLE_NAME",
DB_NAME,
'BASE TABLE'
);
$results = $wpdb->get_results( $sql, ARRAY_A );
if ( ! empty( $results ) ) {
foreach ( $results as $result ) {
if ( $this->get_legacy_alter_table_name() == $result['table'] ) {
continue;
}
$return[ $result['table'] ] = $result['size'];
}
}
// "regular" is passed to the filter as the scope for backwards compatibility (a possible but never used scope was "temp").
return apply_filters( 'wpmdb_table_sizes', $return, 'regular' );
}
function format_dump_name( $dump_name ) {
$extension = '.sql';
$dump_name = sanitize_file_name( $dump_name );
if ( $this->gzip() && isset( $this->form_data['gzip_file'] ) && $this->form_data['gzip_file'] ) {
$extension .= '.gz';
}
return $dump_name . $extension;
}
function options_page() {
$this->template( 'options' );
}
/**
* Load Tools HTML template for tools menu on sites in a Network to help users find WPMDB in Multisite
*
*/
function subsite_tools_options_page() {
$this->template( 'options-tools-subsite' );
}
/**
* Get the remote site's base domain for subdomain multisite search/replace.
*
* @return string|bool The remote site's domain or false on error.
*/
function get_domain_replace() {
$this->set_post_data();
if ( ! isset( $this->domain_replace ) ) {
if ( is_multisite() && ! empty( $this->state_data['domain_current_site'] ) ) {
$this->domain_replace = $this->state_data['domain_current_site'];
} elseif ( is_multisite() && ! empty( $this->form_data['replace_new'][1] ) ) {
$url = $this->form_data['replace_new'][1];
$url = $this->parse_url( $url );
if ( isset( $url['host'] ) ) {
$this->domain_replace = $url['host'];
} else {
$this->domain_replace = false;
}
} else {
$this->domain_replace = false;
}
}
return $this->domain_replace;
}
function process_sql_constraint( $create_query, $table, &$alter_table_query ) {
if ( preg_match( '@CONSTRAINT|FOREIGN[\s]+KEY@', $create_query ) ) {
$sql_constraints_query = '';
$nl_nix = "\n";
$nl_win = "\r\n";
$nl_mac = "\r";
if ( strpos( $create_query, $nl_win ) !== false ) {
$crlf = $nl_win;
} elseif ( strpos( $create_query, $nl_mac ) !== false ) {
$crlf = $nl_mac;
} else {
$crlf = $nl_nix;
}
// Split the query into lines, so we can easily handle it.
// We know lines are separated by $crlf (done few lines above).
$sql_lines = explode( $crlf, $create_query );
$sql_count = count( $sql_lines );
// lets find first line with constraints
for ( $i = 0; $i < $sql_count; $i++ ) {
if ( preg_match(
'@^[\s]*(CONSTRAINT|FOREIGN[\s]+KEY)@',
$sql_lines[ $i ]
) ) {
break;
}
}
// If we really found a constraint
if ( $i != $sql_count ) {
// remove, from the end of create statement
$sql_lines[ $i - 1 ] = preg_replace(
'@,$@',
'',
$sql_lines[ $i - 1 ]
);
// let's do the work
$sql_constraints_query .= 'ALTER TABLE ' . $this->backquote( $table ) . $crlf;
$first = true;
for ( $j = $i; $j < $sql_count; $j++ ) {
if ( preg_match(
'@CONSTRAINT|FOREIGN[\s]+KEY@',
$sql_lines[ $j ]
) ) {
if ( strpos( $sql_lines[ $j ], 'CONSTRAINT' ) === false ) {
$tmp_str = preg_replace(
'/(FOREIGN[\s]+KEY)/',
'ADD \1',
$sql_lines[ $j ]
);
$sql_constraints_query .= $tmp_str;
} else {
$tmp_str = preg_replace(
'/(CONSTRAINT)/',
'ADD \1',
$sql_lines[ $j ]
);
$sql_constraints_query .= $tmp_str;
preg_match(
'/(CONSTRAINT)([\s])([\S]*)([\s])/',
$sql_lines[ $j ],
$matches
);
}
$first = false;
} else {
break;
}
}
$sql_constraints_query .= ";\n";
$create_query = implode(
$crlf,
array_slice( $sql_lines, 0, $i )
)
. $crlf
. implode(
$crlf,
array_slice( $sql_lines, $j, $sql_count - 1 )
);
unset( $sql_lines );
$alter_table_query = $sql_constraints_query;
return $create_query;
}
}
return $create_query;
}
/**
* Loops over data in the provided table to perform a migration.
*
* @param string $table
*
* @return mixed
*/
function process_table( $table ) {
global $wpdb;
// Setup form data
$this->setup_form_data();
$temp_prefix = ( isset( $this->state_data['temp_prefix'] ) ? $this->state_data['temp_prefix'] : $this->temp_prefix );
$site_details = empty( $this->state_data['site_details'] ) ? array() : $this->state_data['site_details'];
$target_table_name = apply_filters( 'wpmdb_target_table_name', $table, $this->form_data['action'], $this->state_data['stage'], $site_details );
$temp_table_name = $temp_prefix . $target_table_name;
$structure_info = $this->get_structure_info( $table );
$row_start = $this->get_current_row();
$this->row_tracker = $row_start;
if ( ! is_array ( $structure_info ) ) {
return $structure_info;
}
$this->pre_process_data( $table, $target_table_name, $temp_table_name );
do {
// Build and run the query
$select_sql = $this->build_select_query( $table, $row_start, $structure_info );
$table_data = $wpdb->get_results( $select_sql );
if ( ! is_array( $table_data ) ) continue;
$to_search = isset( $this->find_replace_pairs['replace_old'] ) ? $this->find_replace_pairs['replace_old'] : '';
$to_replace = isset( $this->find_replace_pairs['replace_new'] ) ? $this->find_replace_pairs['replace_new'] : '';
$replacer = new WPMDB_Replace( array(
'table' => ( 'find_replace' === $this->state_data['stage'] ) ? $temp_table_name : $table,
'search' => $to_search,
'replace' => $to_replace,
'intent' => $this->state_data['intent'],
'base_domain' => $this->get_domain_replace(),
'site_domain' => $this->get_domain_current_site(),
'wpmdb' => $this,
'site_details' => $site_details,
) );
$this->start_query_buffer( $target_table_name, $temp_table_name, $structure_info );
// Loop over the results
foreach ( $table_data as $row ) {
$result = $this->process_row( $table, $replacer, $row, $structure_info );
if ( ! is_bool( $result ) ) {
return $result;
}
}
$this->stow_query_buffer();
$row_start += $this->rows_per_segment;
} while ( count( $table_data ) > 0 );
// Finalize and return.
$this->post_process_data( $table, $target_table_name );
return $this->transfer_chunk();
}
/**
* Initializes the query buffer and template.
*
* @param $target_table_name
* @param $temp_table_name
* @param $structure_info
*
* @return null
*/
function start_query_buffer( $target_table_name, $temp_table_name, $structure_info ) {
if ( 'find_replace' !== $this->state_data['stage'] ) {
$fields = implode( ', ', $structure_info['field_set'] );
$table_to_insert = $temp_table_name;
if ( 'savefile' === $this->form_data['action'] || 'backup' === $this->state_data['stage'] ) {
$table_to_insert = $target_table_name;
}
$this->query_template = 'INSERT INTO ' . $this->backquote( $table_to_insert ) . ' ( ' . $fields . ") VALUES\n";
}
$this->query_buffer = $this->query_template;
}
/**
* Responsible for stowing a chunk of processed data.
*/
function stow_query_buffer() {
if ( $this->query_buffer !== $this->query_template ) {
$this->query_buffer = rtrim( $this->query_buffer, "\n," );
$this->query_buffer .= " ;\n";
$this->stow( $this->query_buffer );
$this->query_buffer = $this->query_template;
$this->query_size = 0;
}
}
/**
* Sets up the form data for the migration.
*/
function setup_form_data() {
$this->set_time_limit();
$this->set_post_data();
if ( empty( $this->form_data ) ) {
$this->form_data = $this->parse_migration_form_data( $this->state_data['form_data'] );
}
}
/**
* Returns the current row, checking the state data.
*
* @return int
*/
function get_current_row() {
$current_row = 0;
if ( ! empty( $this->state_data['current_row'] ) ) {
$temp_current_row = trim( $this->state_data['current_row'] );
if ( ! empty( $temp_current_row ) ) {
$current_row = (int) $temp_current_row;
}
}
$current_row = ( 0 > $current_row ) ? 0 : $current_row;
return $current_row;
}
/**
* Returns the table structure for the provided table.
*
* @param string $table
*
* @return array|bool
*/
function get_table_structure( $table ) {
global $wpdb;
$table_structure = false;
if ( $this->table_exists( $table ) ) {
$table_structure = $wpdb->get_results( 'DESCRIBE ' . $this->backquote( $table ) );
}
if ( ! $table_structure ) {
$this->error = __( 'Failed to retrieve table structure, please ensure your database is online. (#125)', 'wp-migrate-db' );
}
return $table_structure;
}
/**
* Parses the provided table structure.
*
* @param array $table_structure
*
* @return array
*/
function get_structure_info( $table, $table_structure = array() ) {
if ( empty( $table_structure ) ) {
$table_structure = $this->get_table_structure( $table );
}
if ( ! is_array( $table_structure ) ) {
$return = array( 'wpmdb_error' => 1, 'body' => __( 'Failed to get table structure.', 'wpmdb' ) );
$result = $this->end_ajax( json_encode( $return ) );
return $result;
}
// $defs = mysql defaults, looks up the default for that particular column, used later on to prevent empty inserts values for that column
// $ints = holds a list of the possible integer types so as to not wrap them in quotation marks later in the insert statements
$defs = array();
$ints = array();
$bins = array();
$bits = array();
$field_set = array();
$this->primary_keys = array();
$use_primary_keys = true;
foreach ( $table_structure as $struct ) {
if ( ( 0 === strpos( $struct->Type, 'tinyint' ) ) ||
( 0 === strpos( strtolower( $struct->Type ), 'smallint' ) ) ||
( 0 === strpos( strtolower( $struct->Type ), 'mediumint' ) ) ||
( 0 === strpos( strtolower( $struct->Type ), 'int' ) ) ||
( 0 === strpos( strtolower( $struct->Type ), 'bigint' ) )
) {
$defs[ strtolower( $struct->Field ) ] = ( null === $struct->Default ) ? 'NULL' : $struct->Default;
$ints[ strtolower( $struct->Field ) ] = '1';
} elseif ( 0 === strpos( $struct->Type, 'binary' ) ) {
$bins[ strtolower( $struct->Field ) ] = '1';
} elseif ( 0 === strpos( $struct->Type, 'bit' ) ) {
$bits[ strtolower( $struct->Field ) ] = '1';
}
$field_set[] = $this->backquote( $struct->Field );
if ( 'PRI' === $struct->Key && true === $use_primary_keys ) {
if ( false === strpos( $struct->Type, 'int' ) ) {
$use_primary_keys = false;
$this->primary_keys = array();
continue;
}
$this->primary_keys[ $struct->Field ] = 0;
}
}
if ( ! empty( $this->state_data['primary_keys'] ) ) {
$this->state_data['primary_keys'] = trim( $this->state_data['primary_keys'] );
$this->primary_keys = WPMDB_Utils::unserialize( stripslashes( $this->state_data['primary_keys'] ), __METHOD__ );
if ( false !== $this->primary_keys && ! empty( $this->state_data['primary_keys'] ) ) {
$this->first_select = false;
}
}
$return = array(
'defs' => $defs,
'ints' => $ints,
'bins' => $bins,
'bits' => $bits,
'field_set' => $field_set,
);
return $return;
}
/**
* Runs before processing the data in a table.
*
* @param string $table
* @param string $target_table_name
* @param string $temp_table_name
*/
function pre_process_data( $table, $target_table_name, $temp_table_name ) {
if ( 0 !== $this->row_tracker ) return;
if ( 'find_replace' === $this->form_data['action'] ) {
if ( 'backup' === $this->state_data['stage'] ) {
$this->build_table_header( $table, $target_table_name, $temp_table_name );
} else {
$create = $this->create_temp_table( $table );
if ( true !== $create ) {
$message = sprintf( __( 'Error creating temporary table. Table "%s" does not exist.', 'wp-migrate-db' ), esc_html( $table ) );
return $this->end_ajax( json_encode( array( 'wpmdb_error', 1, 'body' => $message ) ) );
}
}
} else {
$this->build_table_header( $table, $target_table_name, $temp_table_name );
}
/**
* Fires just before processing the data for a table.
*
* @param string $table
* @param string $target_table_name
* @param string $temp_table_name
*/
do_action( 'wpmdb_pre_process_table_data', $table, $target_table_name, $temp_table_name );
}
/**
* Creates a temporary table with a copy of the existing table's data.
*
* @param $table
*
* @return bool|mixed
*/
function create_temp_table( $table ) {
if ( $this->table_exists( $table ) ) {
$src_table = $this->backquote( $table );
$temp_table = $this->backquote( $this->temp_prefix . $table );
$query = "DROP TABLE IF EXISTS {$temp_table};\n";
$query .= "CREATE TABLE {$temp_table} LIKE {$src_table};\n";
$query .= "INSERT INTO {$temp_table} SELECT * FROM {$src_table};";
return $this->process_chunk( $query );
}
return false;
}
/**
* Checks if a given table exists.
*
* @param $table
*
* @return bool
*/
function table_exists( $table ) {
global $wpdb;
$table = esc_sql( $table );
if ( $wpdb->get_var( "SHOW TABLES LIKE '$table'" ) ) {
return true;
}
return false;
}
/**
* Runs after processing data in a table.
*
* @param string $table
* @param string $target_table_name
*/
function post_process_data( $table, $target_table_name ) {
if ( 'savefile' == $this->form_data['action'] || 'backup' == $this->state_data['stage'] ) {
$this->build_table_footer( $table, $target_table_name );
}
/**
* Fires just after processing the data for a table.
*
* @param string $table
* @param string $target_table_name
*/
do_action( 'wpmdb_post_process_table_data', $table, $target_table_name );
$this->row_tracker = -1;
}
/**
* Creates the header for a table in a SQL file.
*
* @param string $table
* @param string $target_table_name
* @param string $temp_table_name
*
* @return null|bool
*/
function build_table_header( $table, $target_table_name, $temp_table_name ) {
global $wpdb;
// Don't stow data until after `wpmdb_create_table_query` filter is applied as mysql_compat_filter() can return an error
$stow = '';
$is_backup = false;
$table_to_stow = $temp_table_name;
if ( 'savefile' === $this->form_data['action'] || 'backup' === $this->state_data['stage'] ) {
$is_backup = true;
$table_to_stow = $target_table_name;
}
// Add SQL statement to drop existing table
if ( $is_backup ) {
$stow .= ( "\n\n" );
$stow .= ( "#\n" );
$stow .= ( '# ' . sprintf( __( 'Delete any existing table %s', 'wp-migrate-db' ), $this->backquote( $table_to_stow ) ) . "\n" );
$stow .= ( "#\n" );
$stow .= ( "\n" );
}
$stow .= ( 'DROP TABLE IF EXISTS ' . $this->backquote( $table_to_stow ) . ";\n" );
// Table structure
// Comment in SQL-file
if ( $is_backup ) {
$stow .= ( "\n\n" );
$stow .= ( "#\n" );
$stow .= ( '# ' . sprintf( __( 'Table structure of table %s', 'wp-migrate-db' ), $this->backquote( $table_to_stow ) ) . "\n" );
$stow .= ( "#\n" );
$stow .= ( "\n" );
}
$create_table = $wpdb->get_results( 'SHOW CREATE TABLE ' . $this->backquote( $table ), ARRAY_N );
if ( false === $create_table ) {
$this->error = __( 'Failed to generate the create table query, please ensure your database is online. (#126)', 'wp-migrate-db' );
return false;
}
$create_table[0][1] = str_replace( 'CREATE TABLE `' . $table . '`', 'CREATE TABLE `' . $table_to_stow . '`', $create_table[0][1] );
$create_table[0][1] = str_replace( 'TYPE=', 'ENGINE=', $create_table[0][1] );
$alter_table_query = '';
$create_table[0][1] = $this->process_sql_constraint( $create_table[0][1], $target_table_name, $alter_table_query );
$create_table[0][1] = apply_filters( 'wpmdb_create_table_query', $create_table[0][1], $table_to_stow, $this->target_db_version, $this->form_data['action'], $this->state_data['stage'] );
$stow .= ( $create_table[0][1] . ";\n" );
$this->stow( $stow );
if ( ! empty( $alter_table_query ) ) {
$alter_table_name = $this->get_alter_table_name();
$insert = sprintf( "INSERT INTO %s ( `query` ) VALUES ( '%s' );\n", $this->backquote( $alter_table_name ), esc_sql( $alter_table_query ) );
if ( $is_backup ) {
$process_chunk_result = $this->process_chunk( $insert );
if ( true !== $process_chunk_result ) {
$result = $this->end_ajax( $process_chunk_result );
return $result;
}
} else {
$this->stow( $insert );
}
}
$alter_data_queries = array();
$alter_data_queries = apply_filters( 'wpmdb_alter_data_queries', $alter_data_queries, $table_to_stow, $this->form_data['action'], $this->state_data['stage'] );
if ( ! empty( $alter_data_queries ) ) {
$alter_table_name = $this->get_alter_table_name();
$insert = '';
foreach ( $alter_data_queries as $alter_data_query ) {
$insert .= sprintf( "INSERT INTO %s ( `query` ) VALUES ( '%s' );\n", $this->backquote( $alter_table_name ), esc_sql( $alter_data_query ) );
}
if ( $is_backup ) {
$process_chunk_result = $this->process_chunk( $insert );
if ( true !== $process_chunk_result ) {
$result = $this->end_ajax( $process_chunk_result );
return $result;
}
} else {
$this->stow( $insert );
}
}
// Comment in SQL-file
if ( $is_backup ) {
$this->stow( "\n\n" );
$this->stow( "#\n" );
$this->stow( '# ' . sprintf( __( 'Data contents of table %s', 'wp-migrate-db' ), $this->backquote( $table_to_stow ) ) . "\n" );
$this->stow( "#\n" );
}
}
/**
* Creates the footer for a table in a SQL file.
*
* @param $table
* @param $target_table_name
*
* @return null
*/
function build_table_footer( $table, $target_table_name ) {
global $wpdb;
$this->stow( "\n" );
$this->stow( "#\n" );
$this->stow( '# ' . sprintf( __( 'End of data contents of table %s', 'wp-migrate-db' ), $this->backquote( $target_table_name ) ) . "\n" );
$this->stow( "# --------------------------------------------------------\n" );
$this->stow( "\n" );
if ( $this->state_data['last_table'] == '1' ) {
$this->stow( "#\n" );
$this->stow( "# Add constraints back in and apply any alter data queries.\n" );
$this->stow( "#\n\n" );
$this->stow( $this->get_alter_queries() );
$alter_table_name = $this->get_alter_table_name();
$wpdb->query( 'DROP TABLE IF EXISTS ' . $this->backquote( $alter_table_name ) . ';' );
if ( 'backup' == $this->state_data['stage'] ) {
// Re-create our table to store 'ALTER' queries so we don't get duplicates.
$create_alter_table_query = $this->get_create_alter_table_query();
$process_chunk_result = $this->process_chunk( $create_alter_table_query );
if ( true !== $process_chunk_result ) {
$result = $this->end_ajax( $process_chunk_result );
return $result;
}
}
}
}
/**
* Builds the SELECT query to get data to migrate.
*
* @param string $table
* @param int $row_start
* @param array $structure_info
*
* @return string
*/
function build_select_query( $table, $row_start, $structure_info ) {
global $wpdb;
$join = array();
$where = 'WHERE 1=1';
$order_by = '';
// We need ORDER BY here because with LIMIT, sometimes it will return
// the same results from the previous query and we'll have duplicate insert statements
if ( 'backup' != $this->state_data['stage'] && false === empty( $this->form_data['exclude_spam'] ) ) {
if ( $this->table_is( 'comments', $table ) ) {
$where .= ' AND comment_approved != "spam"';
} elseif ( $this->table_is( 'commentmeta', $table ) ) {
$tables = $this->get_ms_compat_table_names( array( 'commentmeta', 'comments' ), $table );
$join[] = sprintf( 'INNER JOIN %1$s ON %1$s.comment_ID = %2$s.comment_id', $this->backquote( $tables['comments_table'] ), $this->backquote( $tables['commentmeta_table'] ) );
$where .= sprintf( ' AND %1$s.comment_approved != \'spam\'', $this->backquote( $tables['comments_table'] ) );
}
}
if ( 'backup' != $this->state_data['stage'] && isset( $this->form_data['exclude_post_types'] ) && ! empty( $this->form_data['select_post_types'] ) ) {
$post_types = '\'' . implode( '\', \'', $this->form_data['select_post_types'] ) . '\'';
if ( $this->table_is( 'posts', $table ) ) {
$where .= ' AND `post_type` NOT IN ( ' . $post_types . ' )';
} elseif ( $this->table_is( 'postmeta', $table ) ) {
$tables = $this->get_ms_compat_table_names( array( 'postmeta', 'posts' ), $table );
$join[] = sprintf( 'INNER JOIN %1$s ON %1$s.ID = %2$s.post_id', $this->backquote( $tables['posts_table'] ), $this->backquote( $tables['postmeta_table'] ) );
$where .= sprintf( ' AND %1$s.post_type NOT IN ( ' . $post_types . ' )', $this->backquote( $tables['posts_table'] ) );
} elseif ( $this->table_is( 'comments', $table ) ) {
$tables = $this->get_ms_compat_table_names( array( 'comments', 'posts' ), $table );
$join[] = sprintf( 'INNER JOIN %1$s ON %1$s.ID = %2$s.comment_post_ID', $this->backquote( $tables['posts_table'] ), $this->backquote( $tables['comments_table'] ) );
$where .= sprintf( ' AND %1$s.post_type NOT IN ( ' . $post_types . ' )', $this->backquote( $tables['posts_table'] ) );
} elseif ( $this->table_is( 'commentmeta', $table ) ) {
$tables = $this->get_ms_compat_table_names( array( 'commentmeta', 'posts', 'comments' ), $table );
$join[] = sprintf( 'INNER JOIN %1$s ON %1$s.comment_ID = %2$s.comment_id', $this->backquote( $tables['comments_table'] ), $this->backquote( $tables['commentmeta_table'] ) );
$join[] = sprintf( 'INNER JOIN %2$s ON %2$s.ID = %1$s.comment_post_ID', $this->backquote( $tables['comments_table'] ), $this->backquote( $tables['posts_table'] ) );
$where .= sprintf( ' AND %1$s.post_type NOT IN ( ' . $post_types . ' )', $this->backquote( $tables['posts_table'] ) );
}
}
if ( 'backup' != $this->state_data['stage'] && true === apply_filters( 'wpmdb_exclude_transients', true ) && isset( $this->form_data['exclude_transients'] ) && '1' === $this->form_data['exclude_transients'] && ( $this->table_is( 'options', $table ) || ( isset( $wpdb->sitemeta ) && $wpdb->sitemeta == $table ) ) ) {
$col_name = 'option_name';
if ( isset( $wpdb->sitemeta ) && $wpdb->sitemeta == $table ) {
$col_name = 'meta_key';
}
$where .= " AND `{$col_name}` NOT LIKE '\_transient\_%' AND `{$col_name}` NOT LIKE '\_site\_transient\_%'";
}
// don't export/migrate wpmdb specific option rows unless we're performing a backup
if ( 'backup' != $this->state_data['stage'] && ( $this->table_is( 'options', $table ) || ( isset( $wpdb->sitemeta ) && $wpdb->sitemeta == $table ) ) ) {
$col_name = 'option_name';
if ( isset( $wpdb->sitemeta ) && $wpdb->sitemeta == $table ) {
$col_name = 'meta_key';
}
$where .= " AND `{$col_name}` != 'wpmdb_settings'";
$where .= " AND `{$col_name}` != 'wpmdb_error_log'";
$where .= " AND `{$col_name}` != 'wpmdb_schema_version'";
$where .= " AND `{$col_name}` NOT LIKE 'wpmdb_state_%'";
}
$limit = "LIMIT {$row_start}, {$this->rows_per_segment}";
if ( ! empty( $this->primary_keys ) ) {
$primary_keys_keys = array_keys( $this->primary_keys );
$primary_keys_keys = array_map( array( $this, 'backquote' ), $primary_keys_keys );
$order_by = 'ORDER BY ' . implode( ',', $primary_keys_keys );
$limit = "LIMIT {$this->rows_per_segment}";
if ( false === $this->first_select ) {
$where .= ' AND ';
$temp_primary_keys = $this->primary_keys;
$primary_key_count = count( $temp_primary_keys );
// build a list of clauses, iteratively reducing the number of fields compared in the compound key
// e.g. (a = 1 AND b = 2 AND c > 3) OR (a = 1 AND b > 2) OR (a > 1)
$clauses = array();
for ( $j = 0; $j < $primary_key_count; $j++ ) {
// build a subclause for each field in the compound index
$subclauses = array();
$i = 0;
foreach ( $temp_primary_keys as $primary_key => $value ) {
// only the last field in the key should be different in this subclause
$operator = ( count( $temp_primary_keys ) - 1 == $i ? '>' : '=' );
$subclauses[] = sprintf( '%s %s %s', $this->backquote( $primary_key ), $operator, $wpdb->prepare( '%s', $value ) );
++$i;
}
// remove last field from array to reduce fields in next clause
array_pop( $temp_primary_keys );
// join subclauses into a single clause
// NB: AND needs to be wrapped in () as it has higher precedence than OR
$clauses[] = '( ' . implode( ' AND ', $subclauses ) . ' )';
}
// join clauses into a single clause
// NB: OR needs to be wrapped in () as it has lower precedence than AND
$where .= '( ' . implode( ' OR ', $clauses ) . ' )';
}
$this->first_select = false;
}
$sel = $this->backquote( $table ) . '.*';
if ( ! empty( $structure_info['bins'] ) ) {
foreach ( $structure_info['bins'] as $key => $bin ) {
$hex_key = strtolower( $key ) . '__hex';
$sel .= ', HEX(' . $this->backquote( $key ) . ') as ' . $this->backquote( $hex_key );
}
}
if ( ! empty( $structure_info['bits'] ) ) {
foreach ( $structure_info['bits'] as $key => $bit ) {
$bit_key = strtolower( $key ) . '__bit';
$sel .= ', ' . $this->backquote( $key ) . '+0 as ' . $this->backquote( $bit_key );
}
}
$join = implode( ' ', array_unique( $join ) );
$join = apply_filters( 'wpmdb_rows_join', $join, $table );
$where = apply_filters( 'wpmdb_rows_where', $where, $table );
$order_by = apply_filters( 'wpmdb_rows_order_by', $order_by, $table );
$limit = apply_filters( 'wpmdb_rows_limit', $limit, $table );
$sql = 'SELECT ' . $sel . ' FROM ' . $this->backquote( $table ) . " $join $where $order_by $limit";
$sql = apply_filters( 'wpmdb_rows_sql', $sql, $table );
return $sql;
}
/**
* Processes the data in a given row.
*
* @param string $table
* @param object $replacer
* @param array $row
* @param array $structure_info
*
* @return array|void
*/
function process_row( $table, $replacer, $row, $structure_info ) {
global $wpdb;
$skip_row = false;
$updates_pending = false;
$update_sql = array();
$where_sql = array();
$values = array();
$query = '';
if ( ! apply_filters( 'wpmdb_table_row', $row, $table, $this->form_data['action'], $this->state_data['stage'] ) ) {
$skip_row = true;
}
if ( ! $skip_row ) {
foreach ( $row as $key => $value ) {
$data_to_fix = $value;
if ( 'find_replace' === $this->state_data['stage'] && in_array( $key, array_keys( $this->primary_keys ) ) ) {
$where_sql[] = $this->backquote( $key ) . ' = "' . $this->mysql_escape_mimic( $data_to_fix ) . '"';
continue;
}
$replacer->set_column( $key );
if ( isset( $structure_info['ints'][ strtolower( $key ) ] ) && $structure_info['ints'][ strtolower( $key ) ] ) {
// make sure there are no blank spots in the insert syntax,
// yet try to avoid quotation marks around integers
$value = ( null === $value || '' === $value ) ? $structure_info['defs'][ strtolower( $key ) ] : $value;
$values[] = ( '' === $value ) ? "''" : $value;
continue;
}
if ( null === $value ) {
$values[] = 'NULL';
continue;
}
// If we have binary data, substitute in hex encoded version and remove hex encoded version from row.
$hex_key = strtolower( $key ) . '__hex';
if ( isset( $structure_info['bins'][ strtolower( $key ) ] ) && $structure_info['bins'][ strtolower( $key ) ] && isset( $row->$hex_key ) ) {
$value = "UNHEX('" . $row->$hex_key . "')";
$values[] = $value;
unset( $row->$hex_key );
continue;
}
// If we have bit data, substitute in properly bit encoded version.
$bit_key = strtolower( $key ) . '__bit';
if ( isset( $structure_info['bits'][ strtolower( $key ) ] ) && $structure_info['bits'][ strtolower( $key ) ] && isset( $row->$bit_key ) ) {
$value = "b'" . $row->$bit_key . "'";
$values[] = $value;
unset( $row->$bit_key );
continue;
}
if ( is_multisite() && ( $wpdb->site == $table || $wpdb->blogs == $table ) ) {
if ( ! in_array( $this->state_data['stage'], array( 'backup', 'find_replace' ) ) ) {
if ( 'path' == $key ) {
$old_path_current_site = $this->get_path_current_site();
$new_path_current_site = '';
if ( ! empty( $this->state_data['path_current_site'] ) ) {
$new_path_current_site = $this->state_data['path_current_site'];
} elseif ( ! empty ( $this->form_data['replace_new'][1] ) ) {
$new_path_current_site = $this->get_path_from_url( $this->form_data['replace_new'][1] );
}
$new_path_current_site = apply_filters( 'wpmdb_new_path_current_site', $new_path_current_site );
if ( ! empty( $new_path_current_site ) && $old_path_current_site != $new_path_current_site ) {
$pos = strpos( $value, $old_path_current_site );
$value = substr_replace( $value, $new_path_current_site, $pos, strlen( $old_path_current_site ) );
}
}
if ( 'domain' == $key ) {
if ( ! empty( $this->state_data['domain_current_site'] ) ) {
$main_domain_replace = $this->state_data['domain_current_site'];
} elseif ( ! empty ( $this->form_data['replace_new'][1] ) ) {
$url = $this->parse_url( $this->form_data['replace_new'][1] );
$main_domain_replace = $url['host'];
}
$domain_replaces = array();
$main_domain_find = sprintf( '/%s/', preg_quote( $this->get_domain_current_site(), '/' ) );
if ( isset( $main_domain_replace ) ) {
$domain_replaces[ $main_domain_find ] = $main_domain_replace;
}
$domain_replaces = apply_filters( 'wpmdb_domain_replaces', $domain_replaces );
$value = preg_replace( array_keys( $domain_replaces ), array_values( $domain_replaces ), $value );
}
}
}
if ( 'guid' != $key || ( false === empty( $this->form_data['replace_guids'] ) && $this->table_is( 'posts', $table ) ) ) {
if ( $this->state_data['stage'] != 'backup' ) {
$value = $replacer->recursive_unserialize_replace( $value );
}
}
if ( 'find_replace' === $this->state_data['stage'] ) {
$value = $this->mysql_escape_mimic( $value );
$data_to_fix = $this->mysql_escape_mimic( $data_to_fix );
if ( $value !== $data_to_fix ) {
$update_sql[] = $this->backquote( $key ) . ' = "' . $value . '"';
$updates_pending = true;
}
} else {
// \x08\\x09, not required
$multibyte_search = array( "\x00", "\x0a", "\x0d", "\x1a" );
$multibyte_replace = array( '\0', '\n', '\r', '\Z' );
$value = $this->sql_addslashes( $value );
$value = str_replace( $multibyte_search, $multibyte_replace, $value );
}
$values[] = "'" . $value . "'";
}
// Determine what to do with updates.
if ( 'find_replace' === $this->state_data['stage'] ) {
if ( $updates_pending && ! empty( $where_sql ) ) {
$table_to_update = $this->backquote( $this->temp_prefix . $table );
$query .= 'UPDATE ' . $table_to_update . ' SET ' . implode( ', ', $update_sql ) . ' WHERE ' . implode( ' AND ', array_filter( $where_sql ) ) . ";\n";
}
} else {
$query .= '(' . implode( ', ', $values ) . '),' . "\n";
}
}
if ( ( strlen( $this->current_chunk ) + strlen( $query ) + strlen( $this->query_buffer ) + 30 ) > $this->maximum_chunk_size ) {
if ( $this->query_buffer == $this->query_template ) {
$this->query_buffer .= $query;
++$this->row_tracker;
if ( ! empty( $this->primary_keys ) ) {
foreach ( $this->primary_keys as $primary_key => $value ) {
$this->primary_keys[ $primary_key ] = $row->$primary_key;
}
}
}
$this->stow_query_buffer();
return $this->transfer_chunk();
}
if ( ( $this->query_size + strlen( $query ) ) > $this->max_insert_string_len ) {
$this->stow_query_buffer();
}
$this->query_buffer .= $query;
$this->query_size += strlen( $query );
++$this->row_tracker;
if ( ! empty( $this->primary_keys ) ) {
foreach ( $this->primary_keys as $primary_key => $value ) {
$this->primary_keys[ $primary_key ] = $row->$primary_key;
}
}
return true;
}
function delete_temporary_tables( $prefix ) {
$tables = $this->get_tables();
$delete_queries = '';
foreach ( $tables as $table ) {
if ( 0 !== strpos( $table, $prefix ) ) {
continue;
}
$delete_queries .= sprintf( "DROP TABLE %s;\n", $this->backquote( $table ) );
}
$this->process_chunk( $delete_queries );
}
/**
* Mimics the mysql_real_escape_string function. Adapted from a post by 'feedr' on php.net.
*
* @link http://php.net/manual/en/function.mysql-real-escape-string.php#101248
* @param string $input The string to escape.
*
* @return string
*/
function mysql_escape_mimic( $input ) {
if ( is_array( $input ) ) {
return array_map( __METHOD__, $input );
}
if ( ! empty( $input ) && is_string( $input ) ) {
return str_replace( array( '\\', "\0", "\n", "\r", "'", '"', "\x1a" ), array( '\\\\', '\\0', '\\n', '\\r', "\\'", '\\"', '\\Z' ), $input );
}
return $input;
}
/**
* Check that the given table is of the desired type,
* including single and multisite installs.
* eg: wp_posts, wp_2_posts
*
* The scope argument can take one of the following:
*
* 'table' - Match on the un-prefixed table name, this is the default.
* 'all' - Match on 'blog' and 'global' tables. No old tables are returned.
* 'blog' - Match the blog-level tables for the queried blog.
* 'global' - Match the global tables for the installation, matching multisite tables only if running multisite.
* 'ms_global' - Match the multisite global tables, regardless if current installation is multisite.
* 'non_ms_global' - Match the non multisite global tables, regardless if current installation is multisite.
* 'old' - Matches tables which are deprecated.
*
* @param string $desired_table Can be empty to match on tables from scopes other than 'table'.
* @param string $given_table
* @param string $scope Optional type of table to match against, default is 'table'.
* @param string $new_prefix Optional new prefix already added to $given_table.
* @param int $blog_id Optional Only used with 'blog' scope to test against a specific subsite's tables other than current for $wpdb.
*
* @return boolean
*/
function table_is( $desired_table, $given_table, $scope = 'table', $new_prefix = '', $blog_id = 0 ) {
global $wpdb;
$scopes = array( 'all', 'blog', 'global', 'ms_global', 'non_ms_global', 'old' );
if ( ! in_array( $scope, $scopes ) ) {
$scope = 'table';
}
if ( empty( $desired_table ) && 'table' === $scope ) {
return false;
}
if ( ! empty( $new_prefix ) && 0 === stripos( $given_table, $new_prefix ) ) {
$given_table = substr_replace( $given_table, $wpdb->base_prefix, 0, strlen( $new_prefix ) );
}
$match = false;
$prefix_escaped = preg_quote( $wpdb->base_prefix, '/' );
$desired_table_escaped = preg_quote( $desired_table, '/' );
if ( 'table' === $scope ) {
if ( $wpdb->{$desired_table} == $given_table ||
preg_match( '/' . $prefix_escaped . '[0-9]+_' . $desired_table_escaped . '/', $given_table )
) {
$match = true;
}
} else {
if ( 'non_ms_global' === $scope ) {
$tables = array_diff_key( $wpdb->tables( 'global', true, $blog_id ), $wpdb->tables( 'ms_global', true, $blog_id ) );
} else {
$tables = $wpdb->tables( $scope, true, $blog_id );
}
if ( ! empty( $desired_table ) ) {
$tables = array_intersect_key( $tables, array( $desired_table => '' ) );
}
if ( ! empty( $tables ) ) {
foreach ( $tables as $table_name ) {
if ( ! empty( $table_name ) && strtolower( $table_name ) === strtolower( $given_table ) ) {
$match = true;
break;
}
}
}
}
return $match;
}
/**
* Return multisite-compatible names for requested
* tables, based on queried table name
*
* @param array $tables List of table names required
* @param string $queried_table Name of table from which to derive the blog ID
*
* @return array List of table names altered for multisite compatibility
*/
function get_ms_compat_table_names( $tables, $queried_table ) {
global $wpdb;
// default table prefix
$prefix = $wpdb->base_prefix;
$prefix_escaped = preg_quote( $prefix, '/' );
// if multisite, extract blog ID from queried table name and add to prefix
// won't match for primary blog because it uses standard table names, i.e. blog_id will never be 1
if ( is_multisite() && preg_match( '/^' . $prefix_escaped . '([0-9]+)_/', $queried_table, $matches ) ) {
$blog_id = $matches[1];
$prefix .= $blog_id . '_';
}
// build table names
$ms_compat_table_names = array();
foreach ( $tables as $table ) {
$ms_compat_table_names[ $table . '_table' ] = $prefix . $table;
}
return $ms_compat_table_names;
}
function db_backup_header() {
$charset = ( defined( 'DB_CHARSET' ) ? DB_CHARSET : 'utf8' );
$this->stow( '# ' . __( 'WordPress MySQL database migration', 'wp-migrate-db' ) . "\n", false );
$this->stow( "#\n", false );
$this->stow( '# ' . sprintf( __( 'Generated: %s', 'wp-migrate-db' ), date( 'l j. F Y H:i T' ) ) . "\n", false );
$this->stow( '# ' . sprintf( __( 'Hostname: %s', 'wp-migrate-db' ), DB_HOST ) . "\n", false );
$this->stow( '# ' . sprintf( __( 'Database: %s', 'wp-migrate-db' ), $this->backquote( DB_NAME ) ) . "\n", false );
$this->stow( "# --------------------------------------------------------\n\n", false );
$this->stow( "/*!40101 SET NAMES $charset */;\n\n", false );
$this->stow( "SET sql_mode='NO_AUTO_VALUE_ON_ZERO';\n\n", false );
}
function gzip() {
return function_exists( 'gzopen' );
}
function open( $filename = '', $mode = 'a' ) {
if ( '' == $filename ) {
return false;
}
if ( $this->gzip() && isset( $this->form_data['gzip_file'] ) && $this->form_data['gzip_file'] ) {
$fp = gzopen( $filename, $mode );
} else {
$fp = fopen( $filename, $mode );
}
return $fp;
}
function close( $fp ) {
if ( $this->gzip() && isset( $this->form_data['gzip_file'] ) && $this->form_data['gzip_file'] ) {
gzclose( $fp );
} else {
fclose( $fp );
}
unset( $this->fp );
}
/**
* Write query line to chunk, file pointer, or buffer depending on migration stage/action.
*
* @param string $query_line
* @param bool $replace
*
* @return bool
*/
function stow( $query_line, $replace = true ) {
$this->set_post_data();
$this->current_chunk .= $query_line;
if ( 0 === strlen( $query_line ) ) {
return true;
}
if ( $this->form_data['action'] == 'savefile' || $this->state_data['stage'] == 'backup' ) {
if ( $this->gzip() && isset( $this->form_data['gzip_file'] ) && $this->form_data['gzip_file'] ) {
if ( ! @gzwrite( $this->fp, $query_line ) ) {
$this->error = __( 'Failed to write the gzipped SQL data to the file. (#127)', 'wp-migrate-db' );
return false;
}
} else {
// TODO: Use WP_Filesystem API.
if ( false === @fwrite( $this->fp, $query_line ) ) {
$this->error = __( 'Failed to write the SQL data to the file. (#128)', 'wp-migrate-db' );
return false;
}
}
} elseif ( $this->state_data['intent'] == 'pull' ) {
echo apply_filters( 'wpmdb_before_response', $query_line );
} elseif ( 'find_replace' === $this->state_data['stage'] ) {
return $this->process_chunk( $query_line );
}
}
/**
* Called once our chunk buffer is full, will transfer the SQL to the remote server for importing
*
* @return array|void
*/
function transfer_chunk() {
$this->set_post_data();
if ( 'savefile' === $this->state_data['intent'] || 'find_replace' === $this->state_data['intent'] || 'backup' === $this->state_data['stage'] ) {
if ( 'find_replace' === $this->state_data['stage'] ) {
$this->process_chunk( $this->query_buffer );
} else {
$this->close( $this->fp );
}
$result = array(
'current_row' => $this->row_tracker,
'primary_keys' => serialize( $this->primary_keys ),
);
if ( $this->state_data['intent'] == 'savefile' && $this->state_data['last_table'] == '1' ) {
$result['dump_filename'] = $this->state_data['dump_filename'];
$result['dump_path'] = $this->state_data['dump_path'];
}
$result = $this->end_ajax( json_encode( $result ) );
return $result;
}
if ( $this->state_data['intent'] == 'pull' ) {
$result = $this->end_ajax( $this->row_tracker . ',' . serialize( $this->primary_keys ) );
return $result;
}
$chunk_gzipped = '0';
if ( isset( $this->state_data['gzip'] ) && $this->state_data['gzip'] == '1' && $this->gzip() ) {
$this->current_chunk = gzcompress( $this->current_chunk );
$chunk_gzipped = '1';
}
$data = array(
'action' => 'wpmdb_process_chunk',
'remote_state_id' => $this->state_data['remote_state_id'],
'table' => $this->state_data['table'],
'chunk_gzipped' => $chunk_gzipped,
'chunk' => $this->current_chunk,
// NEEDS TO BE the last element in this array because of adding it back into the array in ajax_process_chunk()
);
$data['sig'] = $this->create_signature( $data, $this->state_data['key'] );
$ajax_url = $this->ajax_url();
$response = $this->remote_post( $ajax_url, $data, __FUNCTION__ );
ob_start();
$this->display_errors();
$maybe_errors = trim( ob_get_clean() );
if ( false === empty( $maybe_errors ) ) {
$maybe_errors = array( 'wpmdb_error' => 1, 'body' => $maybe_errors );
$result = $this->end_ajax( json_encode( $maybe_errors ) );
return $result;
}
if ( '1' !== $response ) {
$return = array( 'wpmdb_error' => 1, 'body' => $response );
$result = $this->end_ajax( json_encode( $return ) );
return $result;
}
$result = $this->end_ajax( json_encode(
array(
'current_row' => $this->row_tracker,
'primary_keys' => serialize( $this->primary_keys ),
)
) );
return $result;
}
/**
* Add backquotes to tables and db-names in
* SQL queries. Taken from phpMyAdmin.
*
* @param $a_name
*
* @return array|string
*/
function backquote( $a_name ) {
if ( ! empty( $a_name ) && $a_name != '*' ) {
if ( is_array( $a_name ) ) {
$result = array();
reset( $a_name );
while ( list( $key, $val ) = each( $a_name ) ) {
$result[ $key ] = '`' . $val . '`';
}
return $result;
} else {
return '`' . $a_name . '`';
}
} else {
return $a_name;
}
}
/**
* Better addslashes for SQL queries.
* Taken from phpMyAdmin.
*
* @param string $a_string
* @param bool $is_like
*
* @return mixed
*/
function sql_addslashes( $a_string = '', $is_like = false ) {
if ( $is_like ) {
$a_string = str_replace( '\\', '\\\\\\\\', $a_string );
} else {
$a_string = str_replace( '\\', '\\\\', $a_string );
}
return str_replace( '\'', '\\\'', $a_string );
}
function network_admin_menu() {
$title = ( $this->is_pro ) ? __( 'Migrate DB Pro', 'wp-migrate-db' ) : __( 'Migrate DB', 'wp-migrate-db' );
$hook_suffix = add_submenu_page( 'settings.php',
$title,
$title,
'manage_network_options',
$this->core_slug,
array( $this, 'options_page' ) );
$this->after_admin_menu( $hook_suffix );
}
/**
* Add a tools menu item to sites on a Multisite network
*
*/
function network_tools_admin_menu() {
add_management_page(
$this->get_plugin_title(),
$this->get_plugin_title(),
'manage_network_options',
$this->core_slug,
array( $this, 'subsite_tools_options_page' )
);
}
function admin_menu() {
$title = ( $this->is_pro ) ? __( 'Migrate DB Pro', 'wp-migrate-db' ) : __( 'Migrate DB', 'wp-migrate-db' );
$hook_suffix = add_management_page( $title,
$title,
'export',
$this->core_slug,
array( $this, 'options_page' ) );
$this->after_admin_menu( $hook_suffix );
}
function after_admin_menu( $hook_suffix ) {
add_action( 'admin_head-' . $hook_suffix, array( $this, 'admin_head_connection_info' ) );
add_action( 'load-' . $hook_suffix, array( $this, 'load_assets' ) );
// Remove licence from the database if constant is set
if ( $this->is_licence_constant() && ! empty( $this->settings['licence'] ) ) {
$this->settings['licence'] = '';
update_site_option( 'wpmdb_settings', $this->settings );
}
}
function admin_body_class( $classes ) {
if ( ! $classes ) {
$classes = array();
} else {
$classes = explode( ' ', $classes );
}
$version_class = 'wpmdb-not-pro';
if ( true == $this->is_pro ) {
$version_class = 'wpmdb-pro';
}
$classes[] = $version_class;
// Recommended way to target WP 3.8+
// http://make.wordpress.org/ui/2013/11/19/targeting-the-new-dashboard-design-in-a-post-mp6-world/
if ( version_compare( $GLOBALS['wp_version'], '3.8-alpha', '>' ) ) {
if ( ! in_array( 'mp6', $classes ) ) {
$classes[] = 'mp6';
}
}
return implode( ' ', $classes );
}
/**
* Check for download
* if found prepare file for download
*
* @return void
*/
function http_verify_download() {
if ( ! empty( $_GET['download'] ) ) {
$this->download_file();
}
}
/**
* Check for wpmdb-download-log and related nonce
* if found begin diagnostic logging
*
* @return void
*/
function http_prepare_download_log() {
if ( isset( $_GET['wpmdb-download-log'] ) && wp_verify_nonce( $_GET['nonce'], 'wpmdb-download-log' ) ) {
ob_start();
$this->output_diagnostic_info();
$this->output_log_file();
$log = ob_get_clean();
$url = $this->parse_url( home_url() );
$host = sanitize_file_name( $url['host'] );
$filename = sprintf( '%s-diagnostic-log-%s.txt', $host, date( 'YmdHis' ) );
header( 'Content-Description: File Transfer' );
header( 'Content-Type: application/octet-stream' );
header( 'Content-Length: ' . strlen( $log ) );
header( 'Content-Disposition: attachment; filename=' . $filename );
echo $log;
exit;
}
}
/**
* Check for wpmdb-remove-licence and related nonce
* if found cleanup routines related to licenced product
*
* @return void
*/
function http_remove_license() {
if ( isset( $_GET['wpmdb-remove-licence'] ) && wp_verify_nonce( $_GET['nonce'], 'wpmdb-remove-licence' ) ) {
$this->settings['licence'] = '';
update_site_option( 'wpmdb_settings', $this->settings );
// delete these transients as they contain information only valid for authenticated licence holders
delete_site_transient( 'update_plugins' );
delete_site_transient( 'wpmdb_upgrade_data' );
delete_site_transient( 'wpmdb_licence_response' );
// redirecting here because we don't want to keep the query string in the web browsers address bar
wp_redirect( network_admin_url( $this->plugin_base . '#settings' ) );
exit;
}
}
/**
* Check for wpmdb-disable-ssl and related nonce
* if found temporaily disable ssl via transient
*
* @return void
*/
function http_disable_ssl() {
if ( isset( $_GET['wpmdb-disable-ssl'] ) && wp_verify_nonce( $_GET['nonce'], 'wpmdb-disable-ssl' ) ) {
set_site_transient( 'wpmdb_temporarily_disable_ssl', '1', 60 * 60 * 24 * 30 ); // 30 days
$hash = ( isset( $_GET['hash'] ) ) ? '#' . sanitize_title( $_GET['hash'] ) : '';
// delete the licence transient as we want to attempt to fetch the licence details again
delete_site_transient( 'wpmdb_licence_response' );
// redirecting here because we don't want to keep the query string in the web browsers address bar
wp_redirect( network_admin_url( $this->plugin_base . $hash ) );
exit;
}
}
/**
* Check for wpmdb-check-licence and related nonce
* if found refresh licence details
*
* @return void
*/
function http_refresh_licence() {
if ( isset( $_GET['wpmdb-check-licence'] ) && wp_verify_nonce( $_GET['nonce'], 'wpmdb-check-licence' ) ) {
$hash = ( isset( $_GET['hash'] ) ) ? '#' . sanitize_title( $_GET['hash'] ) : '';
// delete the licence transient as we want to attempt to fetch the licence details again
delete_site_transient( 'wpmdb_licence_response' );
// redirecting here because we don't want to keep the query string in the web browsers address bar
wp_redirect( network_admin_url( $this->plugin_base . $hash ) );
exit;
}
}
/**
* Checks and sets up plugin assets.
* Filter actions, enqueue scripts, define configuration, and constants.
*
* @return void
*/
function load_assets() {
$this->http_verify_download();
$this->http_prepare_download_log();
$this->http_remove_license();
$this->http_disable_ssl();
$this->http_refresh_licence();
// add our custom CSS classes to
local site has the MySQL setting lower_case_table_names
set to 1
.", 'wp-migrate-db' ); ?>
remote site has the MySQL setting lower_case_table_names
set to 1
.", 'wp-migrate-db' ); ?>
our documentation, proceed with caution.', 'wp-migrate-db' ), 'https://deliciousbrains.com/wp-migrate-db-pro/doc/mixed-case-table-names/' ); ?>