Files
2018-06-25 00:00:37 +02:00

1661 lines
60 KiB
PHP

<?php
class WPMDBPro extends WPMDB {
function __construct( $plugin_file_path ) {
$this->is_pro = true;
$this->unhook_templates = array( 'exclude_post_revisions', 'wordpress_org_support', 'progress_upgrade', 'sidebar' );
parent::__construct( $plugin_file_path );
// templating actions
add_action( 'wpmdb_notices', array( $this, 'template_outdated_addons_warning' ) );
add_action( 'wpmdb_notices', array( $this, 'template_secret_key_warning' ) );
add_action( 'wpmdb_notices', array( $this, 'template_block_external_warning' ) );
// Internal AJAX handlers
add_action( 'wp_ajax_wpmdb_verify_connection_to_remote_site', array( $this, 'ajax_verify_connection_to_remote_site' ) );
add_action( 'wp_ajax_wpmdb_fire_migration_complete', array( $this, 'fire_migration_complete' ) );
// Required for Pull if user tables being updated.
add_action( 'wp_ajax_wpmdb_reset_api_key', array( $this, 'ajax_reset_api_key' ) );
add_action( 'wp_ajax_wpmdb_activate_licence', array( $this, 'ajax_activate_licence' ) );
add_action( 'wp_ajax_wpmdb_check_licence', array( $this, 'ajax_check_licence' ) );
add_action( 'wp_ajax_wpmdb_copy_licence_to_remote_site', array( $this, 'ajax_copy_licence_to_remote_site' ) );
add_action( 'wp_ajax_wpmdb_reactivate_licence', array( $this, 'ajax_reactivate_licence' ) );
add_action( 'wp_ajax_wpmdb_process_notice_link', array( $this, 'ajax_process_notice_link' ) );
// external AJAX handlers
add_action( 'wp_ajax_nopriv_wpmdb_verify_connection_to_remote_site', array( $this, 'respond_to_verify_connection_to_remote_site' ) );
add_action( 'wp_ajax_nopriv_wpmdb_remote_initiate_migration', array( $this, 'respond_to_remote_initiate_migration' ) );
add_action( 'wp_ajax_nopriv_wpmdb_process_chunk', array( $this, 'respond_to_process_chunk' ) );
add_action( 'wp_ajax_nopriv_wpmdb_process_pull_request', array( $this, 'respond_to_process_pull_request' ) );
add_action( 'wp_ajax_nopriv_wpmdb_fire_migration_complete', array( $this, 'fire_migration_complete' ) );
add_action( 'wp_ajax_nopriv_wpmdb_backup_remote_table', array( $this, 'respond_to_backup_remote_table' ) );
add_action( 'wp_ajax_nopriv_wpmdb_remote_finalize_migration', array( $this, 'respond_to_remote_finalize_migration' ) );
add_action( 'wp_ajax_nopriv_wpmdb_remote_flush', array( $this, 'respond_to_remote_flush' ) );
add_action( 'wp_ajax_nopriv_wpmdb_process_push_migration_cancellation', array( $this, 'respond_to_process_push_migration_cancellation' ) );
add_action( 'wp_ajax_nopriv_wpmdb_copy_licence_to_remote_site', array( $this, 'respond_to_copy_licence_to_remote_site' ) );
// Take over the update check
add_filter( 'site_transient_update_plugins', array( $this, 'site_transient_update_plugins' ) );
// Add some custom JS into the WP admin pages
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_plugin_update_script' ) );
// Add some custom CSS into the WP admin pages
add_action( 'admin_head-plugins.php', array( $this, 'add_plugin_update_styles' ) );
// Hook into the plugin install process, inject addon download url
add_filter( 'plugins_api', array( $this, 'inject_addon_install_resource' ), 10, 3 );
// Short circuit the HTTP request to WordPress.org for plugin information
add_filter( 'plugins_api', array( $this, 'short_circuit_wordpress_org_plugin_info_request' ), 10, 3 );
// Clear update transients when the user clicks the "Check Again" button from the update screen
add_action( 'current_screen', array( $this, 'check_again_clear_transients' ) );
// Add after_plugin_row... action for pro plugin and all addons
add_action( 'after_plugin_row_wp-migrate-db-pro/wp-migrate-db-pro.php', array( $this, 'plugin_row' ), 11, 2 );
add_action( 'after_plugin_row_wp-migrate-db-pro-cli/wp-migrate-db-pro-cli.php', array( $this, 'plugin_row' ), 11, 2 );
add_action( 'after_plugin_row_wp-migrate-db-pro-media-files/wp-migrate-db-pro-media-files.php', array( $this, 'plugin_row' ), 11, 2 );
add_action( 'after_plugin_row_wp-migrate-db-pro-multisite-tools/wp-migrate-db-pro-multisite-tools.php', array( $this, 'plugin_row' ), 11, 2 );
// Seen when the user clicks "view details" on the plugin listing page
add_action( 'install_plugins_pre_plugin-information', array( $this, 'plugin_update_popup' ) );
// Removes the exclude post revision functionality (as seen in the free version of the plugin)
$this->remove_exclude_post_revision_functionality();
// Check if WP Engine is filtering the buffer and prevent it. Added here for ajax pull requests
$this->maybe_disable_wp_engine_filtering();
}
/**
* Short circuits the HTTP request to WordPress.org servers to retrieve plugin information.
* Will only fire on the update-core.php admin page.
*
* @param object|bool $res Plugin resource object or boolean false.
* @param string $action The API call being performed.
* @param object $args Arguments for the API call being performed.
*
* @return object|bool Plugin resource object or boolean false.
*/
function short_circuit_wordpress_org_plugin_info_request( $res, $action, $args ) {
if ( 'plugin_information' != $action || empty( $args->slug ) || 'wp-migrate-db-pro' != $args->slug ) {
return $res;
}
$screen = get_current_screen();
// Only fire on the update-core.php admin page
if ( empty( $screen->id ) || ( 'update-core' !== $screen->id && 'update-core-network' !== $screen->id ) ) {
return $res;
}
$res = new stdClass();
$plugin_info = $this->get_upgrade_data();
if ( isset( $plugin_info['wp-migrate-db-pro']['tested'] ) ) {
$res->tested = $plugin_info['wp-migrate-db-pro']['tested'];
} else {
$res->tested = false;
}
return $res;
}
function template_pull_push_radio_buttons( $loaded_profile ) {
$args = array(
'loaded_profile' => $loaded_profile,
);
$this->template( 'pull-push-radio-buttons', 'pro', $args );
}
function template_select_tables( $loaded_profile ) {
$args = array(
'loaded_profile' => $loaded_profile,
);
$this->template( 'select-tables', 'pro', $args );
}
function template_exclude_post_types( $loaded_profile ) {
$args = array(
'loaded_profile' => $loaded_profile,
);
$this->template( 'exclude-post-types', 'pro', $args );
}
function template_toggle_remote_requests() {
$this->template( 'toggle-remote-requests', 'pro' );
}
function template_request_settings() {
$this->template( 'request-settings', 'pro' );
}
function template_connection_info() {
$args = array(
'connection_info' => sprintf( "%s\r%s", site_url( '', 'https' ), $this->settings['key'] ),
);
$this->template( 'connection-info', 'pro', $args );
}
function template_delay_between_requests() {
$this->template( 'delay-between-requests', 'pro' );
}
function template_licence() {
$args = array(
'licence' => $this->get_licence_key(),
);
$this->template( 'licence', 'pro', $args );
}
function template_addon_tab() {
$this->template( 'addon-tab', 'pro' );
}
function template_licence_info() {
$args = array(
'licence' => $this->get_licence_key(),
);
$this->template( 'licence-info', 'pro', $args );
}
/**
* Shows all the videos on the Help tab.
*
* @return void
*/
function template_videos() {
$args = array(
'videos' => array(
'u7jFkwwfeJc' => array(
'title' => __( 'UI Walkthrough', 'wp-migrate-db' ),
'desc' => __( 'A brief walkthrough of the WP Migrate DB plugin showing all of the different options and explaining them.', 'wp-migrate-db' ),
),
'fHFcH4bCzmU' => array(
'title' => __( 'Pulling Live Data Into Your Local Development&nbsp;Environment', 'wp-migrate-db' ),
'desc' => __( 'This screencast demonstrates how you can pull data from a remote, live WordPress install and update the data in your local development environment.', 'wp-migrate-db' ),
),
'sImZW_sB47g' => array(
'title' => __( 'Pushing Local Development Data to a Staging&nbsp;Environment', 'wp-migrate-db' ),
'desc' => __( 'This screencast demonstrates how you can push a local WordPress database you\'ve been using for development to a staging environment.', 'wp-migrate-db' ),
),
'jjqc5dBX9DY' => array(
'title' => __( 'WP Migrate DB Pro Media Files Addon 1.3 and CLI Addon 1.1', 'wp-migrate-db' ),
'desc' => __( 'A demonstration of what\'s new in WP Migrate DB Pro Media Files Addon 1.3 and CLI Addon 1.1.', 'wp-migrate-db' ),
),
),
);
$this->template( 'videos', 'pro', $args );
}
function template_outdated_addons_warning() {
if ( ! $this->check_notice( 'outdated_addons_warning' ) ) {
return;
};
$this->template( 'outdated-addons-warning', 'pro' );
}
function template_secret_key_warning() {
if ( ! ( $notice_links = $this->check_notice( 'secret_key_warning', true, 604800 ) ) ) {
return;
};
// Only show the warning if the key is 32 characters in length
if ( strlen( $this->settings['key'] ) > 32 ) {
return;
}
$this->template( 'secret-key-warning', 'pro', $notice_links );
}
function template_block_external_warning() {
if ( ! defined( 'WP_HTTP_BLOCK_EXTERNAL' ) || ! WP_HTTP_BLOCK_EXTERNAL ) {
return;
}
if ( ! ( $notice_links = $this->check_notice( 'block_external_warning', true, 604800 ) ) ) {
return;
}
$this->template( 'block-external-warning', 'pro', $notice_links );
}
function template_invalid_licence_warning() {
if ( ! $this->is_valid_licence() ) {
$this->template( 'invalid-licence-warning', 'pro' );
}
}
function template_backup( $loaded_profile ) {
$args = array(
'loaded_profile' => $loaded_profile,
);
$this->template( 'backup', 'pro', $args );
}
/**
* Handler for ajax request to process a link click in a notice, e.g. licence deactivated ... re-check.
*
* @return bool|null
*/
function ajax_process_notice_link() {
$this->check_ajax_referer( 'process-notice-link' );
$key_rules = array(
'action' => 'key',
'nonce' => 'key',
'notice' => 'key',
'type' => 'key',
'reminder' => 'int',
);
$_POST = WPMDB_Sanitize::sanitize_data( $_POST, $key_rules, __METHOD__ );
if ( false === $_POST ) {
exit;
}
global $current_user;
$key = 'wpmdb_' . $_POST['type'] . '_' . $_POST['notice'];
$value = true;
if ( 'reminder' == $_POST['type'] && isset( $_POST['reminder'] ) ) {
$value = strtotime( 'now' ) + ( is_numeric( $_POST['reminder'] ) ? $_POST['reminder'] : 604800 );
}
update_user_meta( $current_user->ID, $key, $value );
$result = $this->end_ajax();
return $result;
}
/**
* AJAX endpoint for the wpmdb_verify_connection_to_remote_site action.
* Verifies that the local site has a valid licence.
* Sends a request to the remote site to collect additional information required to complete the migration.
*
* @return mixed
*/
function ajax_verify_connection_to_remote_site() {
$this->check_ajax_referer( 'verify-connection-to-remote-site' );
$key_rules = array(
'action' => 'key',
'url' => 'url',
'key' => 'string',
'intent' => 'key',
'nonce' => 'key',
'convert_post_type_selection' => 'numeric',
'profile' => 'numeric',
);
$this->set_post_data( $key_rules );
if ( ! $this->is_valid_licence() ) {
$message = __( 'Please activate your license before attempting a pull or push migration.', 'wp-migrate-db' );
$return = array( 'wpmdb_error' => 1, 'body' => $message );
$result = $this->end_ajax( json_encode( $return ) );
return $result;
}
$data = array(
'action' => 'wpmdb_verify_connection_to_remote_site',
'intent' => $this->state_data['intent'],
'referer' => $this->get_short_home_address_from_url( home_url() ),
'version' => $this->plugin_version,
);
$data['sig'] = $this->create_signature( $data, $this->state_data['key'] );
$ajax_url = $this->ajax_url();
$timeout = apply_filters( 'wpmdb_prepare_remote_connection_timeout', 30 );
$serialized_response = $this->remote_post( $ajax_url, $data, __FUNCTION__, compact( 'timeout' ), true );
$url_bits = $this->parse_url( $this->attempting_to_connect_to );
if ( false === $serialized_response ) {
$return = array(
'wpmdb_error' => 1,
'body' => $this->error,
'scheme' => $url_bits['scheme'],
);
$result = $this->end_ajax( json_encode( $return ) );
return $result;
}
$response = WPMDB_Utils::unserialize( $serialized_response, __METHOD__ );
if ( false === $response ) {
$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,
'scheme' => $url_bits['scheme'],
);
$this->log_error( $error_msg, $serialized_response );
$result = $this->end_ajax( json_encode( $return ) );
return $result;
}
if ( isset( $response['error'] ) && $response['error'] == 1 ) {
$return = array(
'wpmdb_error' => 1,
'body' => $response['message'],
'scheme' => $url_bits['scheme'],
);
if ( isset( $response['error_id'] ) ) {
if ( 'version_mismatch' === $response['error_id'] ) {
$return['body'] = str_replace( '%%plugins_url%%', network_admin_url( 'plugins.php' ), $return['body'] );
}
}
$this->log_error( $return['body'], $response );
$result = $this->end_ajax( json_encode( $return ) );
return $result;
}
if ( isset( $this->state_data['convert_post_type_selection'] ) && '1' == $this->state_data['convert_post_type_selection'] ) {
$profile = (int) $this->state_data['profile'];
unset( $this->settings['profiles'][ $profile ]['post_type_migrate_option'] );
$this->settings['profiles'][ $profile ]['exclude_post_types'] = '1';
$this->settings['profiles'][ $profile ]['select_post_types'] = array_values( array_diff( $response['post_types'], $this->settings['profiles'][ $profile ]['select_post_types'] ) );
$response['select_post_types'] = $this->settings['profiles'][ $profile ]['select_post_types'];
update_site_option( 'wpmdb_settings', $this->settings );
}
$response['scheme'] = $url_bits['scheme'];
$return = json_encode( $response );
$result = $this->end_ajax( $return );
return $result;
}
/**
* The remote's handler for a request to finalize a migration.
*
* @return bool|null
*/
function respond_to_remote_finalize_migration() {
add_filter( 'wpmdb_before_response', array( $this, 'scramble' ) );
$key_rules = array(
'action' => 'key',
'remote_state_id' => 'key',
'intent' => 'key',
'url' => 'url',
'form_data' => 'string',
'tables' => 'string',
'temp_prefix' => 'string',
'prefix' => 'string',
'type' => 'key',
'location' => 'url',
'sig' => 'string',
);
$this->set_post_data( $key_rules, 'remote_state_id' );
$filtered_post = $this->filter_post_elements(
$this->state_data,
array(
'action',
'remote_state_id',
'intent',
'url',
'form_data',
'tables',
'temp_prefix',
'prefix',
'type',
'location',
)
);
if ( ! $this->verify_signature( $filtered_post, $this->settings['key'] ) ) {
$error_msg = $this->invalid_content_verification_error . ' (#123)';
$this->log_error( $error_msg, $filtered_post );
$result = $this->end_ajax( $error_msg );
return $result;
}
$this->form_data = $this->parse_migration_form_data( $this->state_data['form_data'] );
$return = $this->finalize_migration();
$result = $this->end_ajax( $return );
return $result;
}
/**
* Perform flushes on remote.
*
* @return bool|null
*/
function respond_to_remote_flush() {
add_filter( 'wpmdb_before_response', array( $this, 'scramble' ) );
$key_rules = array(
'action' => 'key',
'sig' => 'string',
);
$this->set_post_data( $key_rules );
$filtered_post = $this->filter_post_elements( $this->state_data, array( 'action' ) );
if ( ! $this->verify_signature( $filtered_post, $this->settings['key'] ) ) {
$error_msg = $this->invalid_content_verification_error . ' (#123)';
$this->log_error( $error_msg, $filtered_post );
$result = $this->end_ajax( $error_msg );
return $result;
}
$return = $this->flush();
$result = $this->end_ajax( $return );
return $result;
}
/**
* The remote's handler for requests to backup a table.
*
* @return bool|mixed|null
*/
function respond_to_backup_remote_table() {
add_filter( 'wpmdb_before_response', array( $this, 'scramble' ) );
$key_rules = array(
'action' => 'key',
'remote_state_id' => 'key',
'intent' => 'key',
'url' => 'url',
'table' => 'string',
'form_data' => 'string',
'stage' => 'key',
'bottleneck' => 'positive_int',
'prefix' => 'string',
'current_row' => 'int',
'last_table' => 'positive_int',
'gzip' => 'positive_int',
'primary_keys' => 'serialized',
'path_current_site' => 'string',
'domain_current_site' => 'text',
'sig' => 'string',
);
$this->set_post_data( $key_rules, 'remote_state_id' );
$filtered_post = $this->filter_post_elements(
$this->state_data,
array(
'action',
'remote_state_id',
'intent',
'url',
'table',
'form_data',
'stage',
'bottleneck',
'prefix',
'current_row',
'last_table',
'gzip',
'primary_keys',
'path_current_site',
'domain_current_site',
)
);
$filtered_post['primary_keys'] = stripslashes( $filtered_post['primary_keys'] );
if ( ! $this->verify_signature( $filtered_post, $this->settings['key'] ) ) {
$error_msg = $this->invalid_content_verification_error . ' (#137)';
$this->log_error( $error_msg, $filtered_post );
$result = $this->end_ajax( $error_msg );
return $result;
}
$this->form_data = $this->parse_migration_form_data( $this->state_data['form_data'] );
$result = $this->handle_table_backup();
return $result;
}
/**
* Exports table data from remote site during a Pull migration.
*
* @return string
*/
function respond_to_process_pull_request() {
add_filter( 'wpmdb_before_response', array( $this, 'scramble' ) );
$key_rules = array(
'action' => 'key',
'remote_state_id' => 'key',
'intent' => 'key',
'url' => 'url',
'table' => 'string',
'form_data' => 'string',
'stage' => 'key',
'bottleneck' => 'positive_int',
'current_row' => 'int',
'last_table' => 'positive_int',
'gzip' => 'positive_int',
'primary_keys' => 'serialized',
'site_url' => 'url',
'find_replace_pairs' => 'serialized',
'pull_limit' => 'positive_int',
'db_version' => 'string',
'path_current_site' => 'string',
'domain_current_site' => 'text',
'prefix' => 'string',
'sig' => 'string',
);
$this->set_post_data( $key_rules, 'remote_state_id' );
$filtered_post = $this->filter_post_elements(
$this->state_data,
array(
'action',
'remote_state_id',
'intent',
'url',
'table',
'form_data',
'stage',
'bottleneck',
'current_row',
'last_table',
'gzip',
'primary_keys',
'site_url',
'find_replace_pairs',
'pull_limit',
'db_version',
'path_current_site',
'domain_current_site',
'prefix',
)
);
$filtered_post['primary_keys'] = stripslashes( $filtered_post['primary_keys'] );
$filtered_post['find_replace_pairs'] = stripslashes( $filtered_post['find_replace_pairs'] );
if ( ! $this->verify_signature( $filtered_post, $this->settings['key'] ) ) {
$error_msg = $this->invalid_content_verification_error . ' (#124)';
$this->log_error( $error_msg, $filtered_post );
$result = $this->end_ajax( $error_msg );
return $result;
}
if ( $this->settings['allow_pull'] != true ) {
$return = __( 'The connection succeeded but the remote site is configured to reject pull connections. You can change this in the "settings" tab on the remote site. (#141)', 'wp-migrate-db' );
$return = array( 'wpmdb_error' => 1, 'body' => $return );
$result = $this->end_ajax( json_encode( $return ) );
return $result;
}
if ( ! empty( $filtered_post['db_version'] ) ) {
$this->target_db_version = $filtered_post['db_version'];
add_filter( 'wpmdb_create_table_query', array( $this, 'mysql_compat_filter' ), 10, 5 );
}
$this->find_replace_pairs = WPMDB_Utils::unserialize( $filtered_post['find_replace_pairs'], __METHOD__ );
$this->maximum_chunk_size = $this->state_data['pull_limit'];
$this->process_table( $this->state_data['table'] );
ob_start();
$this->display_errors();
$return = ob_get_clean();
$result = $this->end_ajax( $return );
return $result;
}
/**
* Validates migration request as the remote site and sets up anything that may be needed before the migration starts.
*
* @return array
*/
function respond_to_remote_initiate_migration() {
add_filter( 'wpmdb_before_response', array( $this, 'scramble' ) );
$key_rules = array(
'action' => 'key',
'intent' => 'key',
'form_data' => 'string',
'sig' => 'string',
'site_details' => 'serialized',
);
$this->set_post_data( $key_rules );
global $wpdb;
$return = array();
$filtered_post = $this->filter_post_elements(
$this->state_data,
array(
'action',
'intent',
'form_data',
'site_details',
)
);
$filtered_post['site_details'] = stripslashes( $filtered_post['site_details'] );
if ( $this->verify_signature( $filtered_post, $this->settings['key'] ) ) {
if ( isset( $this->settings[ 'allow_' . $this->state_data['intent'] ] ) && ( true === $this->settings[ 'allow_' . $this->state_data['intent'] ] || 1 === $this->settings[ 'allow_' . $this->state_data['intent'] ] ) ) {
$return['error'] = 0;
} else {
$return['error'] = 1;
if ( $this->state_data['intent'] == 'pull' ) {
$return['message'] = __( 'The connection succeeded but the remote site is configured to reject pull connections. You can change this in the "settings" tab on the remote site. (#110)', 'wp-migrate-db' );
} else {
$return['message'] = __( 'The connection succeeded but the remote site is configured to reject push connections. You can change this in the "settings" tab on the remote site. (#110)', 'wp-migrate-db' );
}
}
} else {
$return['error'] = 1;
$error_msg = $this->invalid_content_verification_error . ' (#111)';
$this->log_error( $error_msg, $filtered_post );
$return['message'] = $error_msg;
}
// If there is an error, no need to parse args or create migration state.
if ( ! empty( $return['error'] ) ) {
$result = $this->end_ajax( serialize( $return ) );
return $result;
}
$this->log_usage( $this->state_data['intent'] . '-remote' );
$this->state_data['site_details'] = WPMDB_Utils::unserialize( $filtered_post['site_details'], __METHOD__ );
$this->form_data = $this->parse_migration_form_data( $this->state_data['form_data'] );
if ( ! empty( $this->form_data['create_backup'] ) && $this->state_data['intent'] == 'push' ) {
$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' );
}
if ( $this->state_data['intent'] == 'push' ) {
// 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;
}
$return['db_version'] = $wpdb->db_version();
$return['site_url'] = site_url();
}
// Store current migration state and return its id.
$state = array_merge( $this->state_data, $return );
$return['remote_state_id'] = $this->migration_state->id();
$return = $this->save_migration_state( $state, $return );
$result = $this->end_ajax( serialize( $return ) );
return $result;
}
/**
* No privileges AJAX endpoint for the wpmdb_verify_connection_to_remote_site action.
* Verifies that the connecting site is using the same version of WP Migrate DB as the local site.
* Verifies that the request is originating from a trusted source by verifying the request signature.
* Verifies that the local site has a valid licence.
* Verifies that the local site is allowed to perform a pull / push migration.
* If all is successful, returns an array of local site information used to complete the migration.
*
* @return mixed
*/
function respond_to_verify_connection_to_remote_site() {
$key_rules = array(
'action' => 'key',
'intent' => 'key',
'referer' => 'string',
'version' => 'string',
'sig' => 'string',
);
$this->set_post_data( $key_rules );
$return = array();
$filtered_post = $this->filter_post_elements( $this->state_data, array( 'action', 'intent', 'referer', 'version' ) );
if ( ! isset( $filtered_post['version'] ) || version_compare( $filtered_post['version'], $this->plugin_version, '!=' ) ) {
$return['error'] = 1;
$return['error_id'] = 'version_mismatch';
if ( ! isset( $filtered_post['version'] ) ) {
$return['message'] = sprintf( __( '<b>Version Mismatch</b> &mdash; We\'ve detected you have version %1$s of WP Migrate DB Pro at %2$s but are using an outdated version here. Please go to the Plugins page on both installs and check for updates.', 'wp-migrate-db' ), $GLOBALS['wpmdb_meta'][ $this->plugin_slug ]['version'], $this->get_short_home_address_from_url( home_url() ) );
} else {
$return['message'] = sprintf( __( '<b>Version Mismatch</b> &mdash; We\'ve detected you have version %1$s of WP Migrate DB Pro at %2$s but are using %3$s here. Please go to the <a href="%4$s">Plugins page</a> on both installs and check for updates.', 'wp-migrate-db' ), $GLOBALS['wpmdb_meta'][ $this->plugin_slug ]['version'], $this->get_short_home_address_from_url( home_url() ), $filtered_post['version'], '%%plugins_url%%' );
}
$this->log_error( $return['message'], $filtered_post );
$result = $this->end_ajax( serialize( $return ) );
return $result;
}
// Only scramble response once we know it can be handled.
add_filter( 'wpmdb_before_response', array( $this, 'scramble' ) );
if ( ! $this->verify_signature( $filtered_post, $this->settings['key'] ) ) {
$return['error'] = 1;
$return['message'] = $this->invalid_content_verification_error . ' (#120) <a href="#" class="try-again js-action-link">' . _x( 'Try again?', 'Asking to try and connect to remote server after verification error', 'wp-migrate-db' ) . '</a>';
$this->log_error( $this->invalid_content_verification_error . ' (#120)', $filtered_post );
$result = $this->end_ajax( serialize( $return ) );
return $result;
}
if ( ! $this->is_valid_licence() ) {
$local_host = $this->get_short_home_address_from_url( home_url() );
$remote_host = $this->state_data['referer'];
$return['error'] = 1;
$return['message'] = sprintf( __( "Activate remote license &mdash; Looks like you don't have a WP Migrate DB Pro license active at %s.", 'wp-migrate-db' ), $local_host );
$return['message'] .= ' <a href="#" class="js-action-link copy-licence-to-remote-site">';
$return['message'] .= sprintf( __( 'Copy %1$s license key to %2$s and activate it', 'wp-migrate-db' ), $remote_host, $local_host );
$return['message'] .= '</a>';
$result = $this->end_ajax( serialize( $return ) );
return $result;
}
if ( ! isset( $this->settings[ 'allow_' . $this->state_data['intent'] ] ) || $this->settings[ 'allow_' . $this->state_data['intent'] ] != true ) {
$return['error'] = 1;
if ( $this->state_data['intent'] == 'pull' ) {
$message = __( 'The connection succeeded but the remote site is configured to reject pull connections. You can change this in the "settings" tab on the remote site. (#122)', 'wp-migrate-db' );
} else {
$message = __( 'The connection succeeded but the remote site is configured to reject push connections. You can change this in the "settings" tab on the remote site. (#122)', 'wp-migrate-db' );
}
$return['message'] = $message . sprintf( ' <a href="#" class="try-again js-action-link">%s</a>', _x( 'Try again?', 'Attempt to connect to the remote server again', 'wp-migrate-db' ) );
$result = $this->end_ajax( serialize( $return ) );
return $result;
}
$site_details = $this->site_details();
$return['tables'] = $this->get_tables();
$return['prefixed_tables'] = $this->get_tables( 'prefix' );
$return['table_sizes'] = $this->get_table_sizes();
$return['table_rows'] = $this->get_table_row_count();
$return['table_sizes_hr'] = array_map( array( $this, 'format_table_sizes' ), $this->get_table_sizes() );
$return['path'] = $this->get_absolute_root_file_path();
$return['url'] = home_url();
$return['prefix'] = $site_details['prefix']; // TODO: Remove backwards compatibility.
$return['bottleneck'] = $this->get_bottleneck();
$return['delay_between_requests'] = $this->settings['delay_between_requests'];
$return['error'] = 0;
$return['plugin_version'] = $this->plugin_version;
$return['domain'] = $this->get_domain_current_site();
$return['path_current_site'] = $this->get_path_current_site();
$return['uploads_dir'] = $site_details['uploads_dir']; // TODO: Remove backwards compatibility.
$return['gzip'] = ( $this->gzip() ? '1' : '0' );
$return['post_types'] = $this->get_post_types();
// TODO: Use WP_Filesystem API.
$return['write_permissions'] = ( is_writeable( $this->get_upload_info( 'path' ) ) ? '1' : '0' );
$return['upload_dir_long'] = $this->get_upload_info( 'path' );
$return['temp_prefix'] = $this->temp_prefix;
$return['lower_case_table_names'] = $this->get_lower_case_table_names_setting();
$return['subsites'] = $site_details['subsites']; // TODO: Remove backwards compatibility.
$return['site_details'] = $this->site_details();
$return = apply_filters( 'wpmdb_establish_remote_connection_data', $return );
$result = $this->end_ajax( serialize( $return ) );
return $result;
}
function get_short_home_address_from_url( $url ) {
return untrailingslashit( str_replace( array( 'https://', 'http://', '//' ), '', $url ) );
}
/**
* Handler for a request to the remote to cancel a migration.
*
* @return bool|string
*/
function respond_to_process_push_migration_cancellation() {
add_filter( 'wpmdb_before_response', array( $this, 'scramble' ) );
$key_rules = array(
'action' => 'key',
'remote_state_id' => 'key',
'intent' => 'key',
'url' => 'url',
'form_data' => 'string',
'temp_prefix' => 'string',
'stage' => 'key',
'dump_filename' => 'string',
'sig' => 'string',
);
$this->set_post_data( $key_rules, 'remote_state_id' );
$filtered_post = $this->filter_post_elements(
$this->state_data,
array(
'action',
'remote_state_id',
'intent',
'url',
'form_data',
'temp_prefix',
'stage',
'dump_filename',
)
);
if ( ! $this->verify_signature( $filtered_post, $this->settings['key'] ) ) {
$result = $this->end_ajax( esc_html( $this->invalid_content_verification_error ) );
return $result;
}
$this->form_data = $this->parse_migration_form_data( $filtered_post['form_data'] );
if ( $filtered_post['stage'] == 'backup' && ! empty( $this->state_data['dumpfile_created'] ) ) {
$this->delete_export_file( $filtered_post['dump_filename'], true );
} else {
$this->delete_temporary_tables( $filtered_post['temp_prefix'] );
}
$result = $this->end_ajax( true );
return $result;
}
/**
* Triggers the wpmdb_migration_complete action once the migration is complete.
*
* @return bool|null
*/
function fire_migration_complete() {
$this->set_post_data();
$filtered_post = $this->filter_post_elements( $this->state_data, array( 'action', 'url' ) );
if ( ! $this->verify_signature( $filtered_post, $this->settings['key'] ) ) {
$error_msg = $this->invalid_content_verification_error . ' (#138)';
$this->log_error( $error_msg, $filtered_post );
$result = $this->end_ajax( $error_msg );
return $result;
}
do_action( 'wpmdb_migration_complete', 'pull', $this->state_data['url'] );
$result = $this->end_ajax( true );
return $result;
}
function remove_exclude_post_revision_functionality() {
$this->accepted_fields = array_diff( $this->accepted_fields, array( 'exclude_post_revisions' ) );
remove_action( 'wpmdb_advanced_options', array( $this, 'template_exclude_post_revisions' ) );
}
function mask_licence( $licence ) {
$licence_parts = explode( '-', $licence );
$i = count( $licence_parts ) - 1;
$masked_licence = '';
foreach ( $licence_parts as $licence_part ) {
if ( $i == 0 ) {
$masked_licence .= $licence_part;
continue;
}
$masked_licence .= '<span class="bull">';
$masked_licence .= str_repeat( '&bull;', strlen( $licence_part ) ) . '</span>&ndash;';
--$i;
}
return $masked_licence;
}
function get_formatted_masked_licence() {
return sprintf(
'<p class="masked-licence">%s <a href="%s">%s</a></p>',
$this->mask_licence( $this->settings['licence'] ),
network_admin_url( $this->plugin_base . '&nonce=' . wp_create_nonce( 'wpmdb-remove-licence' ) . '&wpmdb-remove-licence=1#settings' ),
_x( 'Remove', 'Delete license', 'wp-migrate-db' )
);
}
function inject_addon_install_resource( $res, $action, $args ) {
if ( 'plugin_information' != $action || empty( $args->slug ) ) {
return $res;
}
$addons = get_site_transient( 'wpmdb_addons' );
if ( ! isset( $addons[ $args->slug ] ) ) {
return $res;
}
$addon = $addons[ $args->slug ];
$required_version = $this->get_required_version( $args->slug );
$is_beta = $this->is_beta_version( $required_version ) && ! empty( $addon['beta_version'] );
$res = new stdClass();
$res->name = 'WP Migrate DB Pro ' . $addon['name'];
$res->version = $is_beta ? $addon['beta_version'] : $addon['version'];
$res->download_link = $this->get_plugin_update_download_url( $args->slug, $is_beta );
$res->tested = isset( $addon['tested'] ) ? $addon['tested'] : false;
return $res;
}
function site_transient_update_plugins( $trans ) {
$plugin_upgrade_data = $this->get_upgrade_data();
if ( false === $plugin_upgrade_data || ! isset( $plugin_upgrade_data['wp-migrate-db-pro'] ) ) {
return $trans;
}
foreach ( $plugin_upgrade_data as $plugin_slug => $upgrade_data ) {
// If pre-1.1.2 version of Media Files addon, use the slug as folder name
if ( ! isset( $GLOBALS['wpmdb_meta'][ $plugin_slug ]['folder'] ) ) {
$plugin_folder = $plugin_slug;
} else {
$plugin_folder = $GLOBALS['wpmdb_meta'][ $plugin_slug ]['folder'];
}
$plugin_basename = sprintf( '%s/%s.php', $plugin_folder, $plugin_slug );
$latest_version = $this->get_latest_version( $plugin_slug );
if ( ! isset( $GLOBALS['wpmdb_meta'][ $plugin_slug ]['version'] ) ) {
$version_file = sprintf( '%s%s/version.php', $this->plugins_dir(), $plugin_folder );
if ( file_exists( $version_file ) ) {
include_once( $version_file );
$installed_version = $GLOBALS['wpmdb_meta'][ $plugin_slug ]['version'];
} else {
$addon_file = sprintf( '%s%s/%s.php', $this->plugins_dir(), $plugin_folder, $plugin_slug );
// No addon plugin file or version.php file, bail and move on to the next addon
if ( ! file_exists( $addon_file ) ) {
continue;
}
/*
* The addon's plugin file exists but a version.php file doesn't
* We're now assuming that the addon is outdated and provide an arbitrary out-of-date version number
* This will trigger a update notice
*/
$installed_version = $GLOBALS['wpmdb_meta'][ $plugin_slug ]['version'] = '0.1';
}
} else {
$installed_version = $GLOBALS['wpmdb_meta'][ $plugin_slug ]['version'];
}
if ( isset( $installed_version ) && version_compare( $installed_version, $latest_version, '<' ) ) {
$is_beta = $this->is_beta_version( $latest_version );
$trans->response[ $plugin_basename ] = new stdClass();
$trans->response[ $plugin_basename ]->url = $this->dbrains_api_base;
$trans->response[ $plugin_basename ]->slug = $plugin_slug;
$trans->response[ $plugin_basename ]->package = $this->get_plugin_update_download_url( $plugin_slug, $is_beta );
$trans->response[ $plugin_basename ]->new_version = $latest_version;
$trans->response[ $plugin_basename ]->id = '0';
$trans->response[ $plugin_basename ]->plugin = $plugin_basename;
}
}
return $trans;
}
function enqueue_plugin_update_script( $hook ) {
if ( 'plugins.php' != $hook ) {
return;
}
$ver_string = '-' . str_replace( '.', '', $this->plugin_version );
$min = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
$src = plugins_url( "asset/dist/js/plugin-update{$ver_string}{$min}.js", dirname( __FILE__ ) );
wp_enqueue_script( 'wp-migrate-db-pro-plugin-update-script', $src, array( 'jquery' ), false, true );
wp_localize_script( 'wp-migrate-db-pro-plugin-update-script', 'wpmdb_nonces', array( 'check_licence' => wp_create_nonce( 'check-licence' ), ) );
wp_localize_script( 'wp-migrate-db-pro-plugin-update-script', 'wpmdb_update_strings', array( 'check_license_again' => __( 'Check my license again', 'wp-migrate-db' ), 'license_check_problem' => __( 'A problem occurred when trying to check the license, please try again.', 'wp-migrate-db' ), ) );
}
function add_plugin_update_styles() {
$version = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? time() : $this->plugin_version;
$plugins_url = trailingslashit( plugins_url() ) . trailingslashit( $this->plugin_folder_name );
$src = $plugins_url . 'asset/dist/css/plugin-update-styles.css';
wp_enqueue_style( 'plugin-update-styles', $src, array(), $version );
}
/**
* Appends an export of a table to a backup file as per params defined in $this->state_data.
*
* @return mixed|null
*/
function handle_table_backup() {
$this->set_post_data();
if ( empty( $this->state_data['dumpfile_created'] ) ) {
$this->state_data['dumpfile_created'] = true;
$this->save_migration_state( $this->state_data );
}
if ( isset( $this->form_data['gzip_file'] ) ) {
unset( $this->form_data['gzip_file'] );
}
$this->maximum_chunk_size = $this->get_bottleneck();
$sql_dump_file_name = $this->get_upload_info( 'path' ) . DIRECTORY_SEPARATOR;
$sql_dump_file_name .= $this->format_dump_name( $this->state_data['dump_filename'] );
$file_created = file_exists( $sql_dump_file_name );
$this->fp = $this->open( $sql_dump_file_name );
if ( $file_created == false ) {
$this->db_backup_header();
}
$result = $this->process_table( $this->state_data['table'] );
if ( isset( $this->fp ) ) {
$this->close( $this->fp );
}
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;
}
return $result;
}
/**
* AJAX handler for checking a licence.
*
* @return string (JSON)
*/
function ajax_check_licence() {
$this->check_ajax_referer( 'check-licence' );
$key_rules = array(
'action' => 'key',
'licence' => 'string',
'context' => 'key',
'nonce' => 'key',
);
$this->set_post_data( $key_rules );
$licence = ( empty( $this->state_data['licence'] ) ? $this->get_licence_key() : $this->state_data['licence'] );
$response = $this->check_licence( $licence );
$decoded_response = json_decode( $response, ARRAY_A );
$context = ( empty( $this->state_data['context'] ) ? null : $this->state_data['context'] );
if ( false == $licence ) {
$decoded_response = array( 'errors' => array() );
$decoded_response['errors'] = array( sprintf( '<div class="notification-message warning-notice inline-message invalid-licence">%s</div>', $this->get_licence_status_message() ) );
} else if ( ! empty( $decoded_response['dbrains_api_down'] ) ) {
$help_message = get_site_transient( 'wpmdb_help_message' );
if ( ! $help_message ) {
ob_start();
?>
<p><?php _e( 'If you have an <strong>active license</strong>, you may send an email to the following address.', 'wp-migrate-db' ); ?></p>
<p>
<strong><?php _e( 'Please copy the Diagnostic Info &amp; Error Log info below into a text file and attach it to your email. Do the same for any other site involved in your email.', 'wp-migrate-db' ); ?></strong>
</p>
<p class="email"><a class="button" href="mailto:wpmdb@deliciousbrains.com">wpmdb@deliciousbrains.com</a></p>
<?php
$help_message = ob_get_clean();
}
$decoded_response['message'] = $help_message;
} elseif ( ! empty( $decoded_response['errors'] ) ) {
if ( 'all' === $context && ! empty( $decoded_response['errors']['subscription_expired'] ) ) {
$decoded_response['errors']['subscription_expired'] = array();
$licence_status_messages = $this->get_licence_status_message( null, $context );
foreach ( $licence_status_messages as $frontend_context => $status_message ) {
$decoded_response['errors']['subscription_expired'][ $frontend_context ] = sprintf( '<div class="notification-message warning-notice inline-message invalid-licence">%s</div>', $status_message );
}
} else {
$decoded_response['errors'] = array( sprintf( '<div class="notification-message warning-notice inline-message invalid-licence">%s</div>', $this->get_licence_status_message( null, $context ) ) );
}
} elseif ( ! empty( $decoded_response['message'] ) && ! get_site_transient( 'wpmdb_help_message' ) ) {
set_site_transient( 'wpmdb_help_message', $decoded_response['message'], $this->transient_timeout );
}
if ( isset( $decoded_response['addon_list'] ) ) {
ob_start();
if ( empty( $decoded_response['errors'] ) ) {
$addons_available = ( $decoded_response['addons_available'] == '1' );
if ( ! $addons_available ) {
?>
<p class="inline-message warning">
<strong><?php _ex( 'Addons Unavailable', 'License does not allow use of addons', 'wp-migrate-db' ); ?></strong> &ndash; <?php printf( __( 'Addons are not included with the Personal license. Visit <a href="%s" target="_blank">My Account</a> to upgrade in just a few clicks.', 'wp-migrate-db' ), 'https://deliciousbrains.com/my-account/' ); ?>
</p>
<?php
}
}
// Save the addons list for use when installing
// Don't really need to expire it ever, but let's clean it up after 60 days
set_site_transient( 'wpmdb_addons', $decoded_response['addon_list'], HOUR_IN_SECONDS * 24 * 60 );
foreach ( $decoded_response['addon_list'] as $key => $addon ) {
$plugin_file = sprintf( '%1$s/%1$s.php', $key );
$plugin_ids = array_keys( get_plugins() );
if ( in_array( $plugin_file, $plugin_ids ) ) {
$actions = '<span class="status">' . _x( 'Installed', 'Installed on website but not activated', 'wp-migrate-db' );
if ( is_plugin_active( $plugin_file ) ) {
$actions .= ' &amp; ' . _x( 'Activated', 'Installed and activated on website', 'wp-migrate-db' ) . '</span>';
} else {
$activate_url = wp_nonce_url( network_admin_url( 'plugins.php?action=activate&amp;plugin=' . $plugin_file ), 'activate-plugin_' . $plugin_file );
$actions .= sprintf( '</span> <a class="action" href="%s">%s</a>', $activate_url, _x( 'Activate', 'Enable addon so it may be used', 'wp-migrate-db' ) );
}
} else {
$install_url = wp_nonce_url( network_admin_url( 'update.php?action=install-plugin&plugin=' . $key ), 'install-plugin_' . $key );
$actions = sprintf( '<a class="action" href="%s">%s</a>', $install_url, _x( 'Install', 'Download and activate addon', 'wp-migrate-db' ) );
}
$required_version = $this->get_required_version( $key );
$download_url = $this->get_plugin_update_download_url( $key, $this->is_beta_version( $required_version ) );
$actions .= sprintf( '<a class="action" href="%s">%s</a>', $download_url, _x( 'Download', 'Download to your computer', 'wp-migrate-db' ) ); ?>
<article class="addon <?php echo esc_attr( $key ); ?>">
<div class="desc">
<?php if ( isset( $addons_available ) && $addons_available ) : ?>
<div class="actions"><?php echo $actions; ?></div>
<?php endif; ?>
<h1><?php echo $addon['name']; ?></h1>
<p><?php echo $addon['desc']; ?></p>
</div>
</article> <?php
}
$addon_content = ob_get_clean();
$decoded_response['addon_content'] = $addon_content;
}
$response = json_encode( $decoded_response );
$result = $this->end_ajax( $response );
return $result;
}
/**
* AJAX handler for activating a licence.
*
* @return string (JSON)
*/
function ajax_activate_licence() {
$this->check_ajax_referer( 'activate-licence' );
$key_rules = array(
'action' => 'key',
'licence_key' => 'string',
'context' => 'key',
'nonce' => 'key',
);
$this->set_post_data( $key_rules );
$args = array(
'licence_key' => urlencode( $this->state_data['licence_key'] ),
'site_url' => urlencode( untrailingslashit( network_home_url( '', 'http' ) ) ),
);
$response = $this->dbrains_api_request( 'activate_licence', $args );
$decoded_response = json_decode( $response, true );
if ( empty( $decoded_response['errors'] ) && empty( $decoded_response['dbrains_api_down'] ) ) {
$this->set_licence_key( $this->state_data['licence_key'] );
$decoded_response['masked_licence'] = $this->get_formatted_masked_licence();
} else {
if ( isset( $decoded_response['errors']['activation_deactivated'] ) ) {
$this->set_licence_key( $this->state_data['licence_key'] );
} elseif ( isset( $decoded_response['errors']['subscription_expired'] ) || isset( $decoded_response['dbrains_api_down'] ) ) {
$this->set_licence_key( $this->state_data['licence_key'] );
$decoded_response['masked_licence'] = $this->get_formatted_masked_licence();
}
set_site_transient( 'wpmdb_licence_response', $response, $this->transient_timeout );
$decoded_response['errors'] = array(
sprintf( '<div class="notification-message warning-notice inline-message invalid-licence">%s</div>', $this->get_licence_status_message( $decoded_response, $this->state_data['context'] ) ),
);
if ( isset( $decoded_response['dbrains_api_down'] ) ) {
$decoded_response['errors'][] = $decoded_response['dbrains_api_down'];
}
}
$result = $this->end_ajax( json_encode( $decoded_response ) );
return $result;
}
/**
* Clear update transients when the user clicks the "Check Again" button from the update screen.
*
* @param object $current_screen
*/
function check_again_clear_transients( $current_screen ) {
if ( ! isset( $current_screen->id ) || strpos( $current_screen->id, 'update-core' ) === false || ! isset( $_GET['force-check'] ) ) {
return;
}
delete_site_transient( 'wpmdb_upgrade_data' );
delete_site_transient( 'update_plugins' );
delete_site_transient( 'wpmdb_licence_response' );
delete_site_transient( 'wpmdb_dbrains_api_down' );
}
/**
* Handler for the ajax request to process a chunk of data (e.g. SQL inserts).
*
* @return bool|null
*/
function respond_to_process_chunk() {
add_filter( 'wpmdb_before_response', array( $this, 'scramble' ) );
$key_rules = array(
'action' => 'key',
'remote_state_id' => 'key',
'table' => 'string',
'chunk_gzipped' => 'positive_int',
'sig' => 'string',
);
$this->set_post_data( $key_rules, 'remote_state_id' );
$filtered_post = $this->filter_post_elements( $this->state_data, array(
'action',
'remote_state_id',
'table',
'chunk_gzipped',
)
);
$gzip = ( isset( $this->state_data['chunk_gzipped'] ) && $this->state_data['chunk_gzipped'] );
$tmp_file_name = 'chunk.txt';
if ( $gzip ) {
$tmp_file_name .= '.gz';
}
$tmp_file_path = wp_tempnam( $tmp_file_name );
if ( ! isset( $_FILES['chunk']['tmp_name'] ) || ! move_uploaded_file( $_FILES['chunk']['tmp_name'], $tmp_file_path ) ) {
$result = $this->end_ajax( __( 'Could not upload the SQL to the server. (#135)', 'wp-migrate-db' ) );
return $result;
}
if ( false === ( $chunk = file_get_contents( $tmp_file_path ) ) ) {
$result = $this->end_ajax( __( 'Could not read the SQL file we uploaded to the server. (#136)', 'wp-migrate-db' ) );
return $result;
}
// TODO: Use WP_Filesystem API.
@unlink( $tmp_file_path );
$filtered_post['chunk'] = $chunk;
if ( ! $this->verify_signature( $filtered_post, $this->settings['key'] ) ) {
$error_msg = $this->invalid_content_verification_error . ' (#130)';
$this->log_error( $error_msg, $filtered_post );
$result = $this->end_ajax( $error_msg );
return $result;
}
if ( $this->settings['allow_push'] != true ) {
$result = $this->end_ajax( __( 'The connection succeeded but the remote site is configured to reject push connections. You can change this in the "settings" tab on the remote site. (#139)', 'wp-migrate-db' ) );
return $result;
}
if ( $gzip ) {
$filtered_post['chunk'] = gzuncompress( $filtered_post['chunk'] );
}
$process_chunk_result = $this->process_chunk( $filtered_post['chunk'] );
$result = $this->end_ajax( $process_chunk_result );
return $result;
}
function get_sensible_pull_limit() {
return apply_filters( 'wpmdb_sensible_pull_limit', min( 26214400, $this->settings['max_request'] ) );
}
/**
* Handler for ajax request to reset the secret key.
*
* @return bool|null
*/
function ajax_reset_api_key() {
$this->check_ajax_referer( 'reset-api-key' );
$key_rules = array(
'action' => 'key',
'nonce' => 'key',
);
$_POST = WPMDB_Sanitize::sanitize_data( $_POST, $key_rules, __METHOD__ );
if ( false === $_POST ) {
exit;
}
$this->settings['key'] = $this->generate_key();
update_site_option( 'wpmdb_settings', $this->settings );
$result = $this->end_ajax( sprintf( "%s\n%s", site_url( '', 'https' ), $this->settings['key'] ) );
return $result;
}
function get_plugin_title() {
return __( 'Migrate DB Pro', 'wp-migrate-db' );
}
/**
* Sends the local WP Migrate DB Pro licence to the remote machine and activates it, returns errors if applicable.
*
* @return array Empty array or an array containing an error message.
*/
function ajax_copy_licence_to_remote_site() {
$this->check_ajax_referer( 'copy-licence-to-remote-site' );
$key_rules = array(
'action' => 'key',
'url' => 'url',
'key' => 'string',
'nonce' => 'key',
);
$this->set_post_data( $key_rules );
$return = array();
$data = array(
'action' => 'wpmdb_copy_licence_to_remote_site',
'licence' => $this->get_licence_key(),
);
$data['sig'] = $this->create_signature( $data, $this->state_data['key'] );
$ajax_url = $this->ajax_url();
$serialized_response = $this->remote_post( $ajax_url, $data, __FUNCTION__, array(), true );
if ( false === $serialized_response ) {
$return = array( 'wpmdb_error' => 1, 'body' => $this->error );
$result = $this->end_ajax( json_encode( $return ) );
return $result;
}
$response = WPMDB_Utils::unserialize( $serialized_response, __METHOD__ );
if ( false === $response ) {
$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, $serialized_response );
$result = $this->end_ajax( json_encode( $return ) );
return $result;
}
if ( isset( $response['error'] ) && $response['error'] == 1 ) {
$return = array( 'wpmdb_error' => 1, 'body' => $response['message'] );
$this->log_error( $response['message'], $response );
$result = $this->end_ajax( json_encode( $return ) );
return $result;
}
$result = $this->end_ajax( json_encode( $return ) );
return $result;
}
/**
* Stores and attempts to activate the licence key received via a remote machine, returns errors if applicable.
*
* @return array Empty array or an array containing an error message.
*/
function respond_to_copy_licence_to_remote_site() {
add_filter( 'wpmdb_before_response', array( $this, 'scramble' ) );
$key_rules = array(
'action' => 'key',
'licence' => 'string',
'sig' => 'string',
);
$this->set_post_data( $key_rules );
$filtered_post = $this->filter_post_elements( $this->state_data, array( 'action', 'licence' ) );
$return = array();
if ( ! $this->verify_signature( $filtered_post, $this->settings['key'] ) ) {
$return['error'] = 1;
$return['message'] = $this->invalid_content_verification_error . ' (#142)';
$this->log_error( $return['message'], $filtered_post );
$result = $this->end_ajax( serialize( $return ) );
return $result;
}
$this->set_licence_key( trim( $this->state_data['licence'] ) );
$licence = $this->get_licence_key();
$licence_status = json_decode( $this->check_licence( $licence ), true );
if ( isset( $licence_status['errors'] ) && ! isset( $licence_status['errors']['subscription_expired'] ) ) {
$return['error'] = 1;
$return['message'] = reset( $licence_status['errors'] );
$this->log_error( $return['message'], $licence_status );
$result = $this->end_ajax( serialize( $return ) );
return $result;
}
$result = $this->end_ajax( serialize( $return ) );
return $result;
}
/**
* Attempts to reactivate this instance via the Delicious Brains API.
*
* @return array Empty array or an array containing an error message.
*/
function ajax_reactivate_licence() {
$this->check_ajax_referer( 'reactivate-licence' );
$key_rules = array(
'action' => 'key',
'nonce' => 'key',
);
$this->set_post_data( $key_rules );
$filtered_post = $this->filter_post_elements( $this->state_data, array( 'action', 'nonce' ) );
$return = array();
$args = array(
'licence_key' => urlencode( $this->get_licence_key() ),
'site_url' => urlencode( untrailingslashit( network_home_url( '', 'http' ) ) ),
);
$response = $this->dbrains_api_request( 'reactivate_licence', $args );
$decoded_response = json_decode( $response, true );
if ( isset( $decoded_response['dbrains_api_down'] ) ) {
$return['wpmdb_dbrains_api_down'] = 1;
$return['body'] = $decoded_response['dbrains_api_down'];
$result = $this->end_ajax( json_encode( $return ) );
return $result;
}
if ( isset( $decoded_response['errors'] ) ) {
$return['wpmdb_error'] = 1;
$return['body'] = reset( $decoded_response['errors'] );
$this->log_error( $return['body'], $decoded_response );
$result = $this->end_ajax( json_encode( $return ) );
return $result;
}
delete_site_transient( 'wpmdb_upgrade_data' );
delete_site_transient( 'wpmdb_licence_response' );
$result = $this->end_ajax( json_encode( array() ) );
return $result;
}
/**
* Shows a message below the plugin on the plugins page when:
* 1. the license hasn't been activated
* 2. when there's an update available but the license is expired
*
* @param string $plugin_path Path of current plugin listing relative to plugins directory
*
* @return void
*/
function plugin_row( $plugin_path, $plugin_data ) {
$plugin_title = $plugin_data['Name'];
$plugin_slug = sanitize_title( $plugin_title );
$licence = $this->get_licence_key();
$licence_response = $this->is_licence_expired();
$licence_problem = isset( $licence_response['errors'] );
$active = is_plugin_active( $plugin_path ) ? 'active' : '';
$shiny_updates = version_compare( get_bloginfo( 'version' ), '4.6-beta1-37926', '>=' );
$update_msg_classes = $shiny_updates ? 'notice inline notice-warning notice-alt post-shiny-updates' : 'pre-shiny-updates';
if ( ! isset( $GLOBALS['wpmdb_meta'][ $plugin_slug ]['version'] ) ) {
$installed_version = '0';
} else {
$installed_version = $GLOBALS['wpmdb_meta'][ $plugin_slug ]['version'];
}
$latest_version = $this->get_latest_version( $plugin_slug );
$new_version = '';
if ( version_compare( $installed_version, $latest_version, '<' ) ) {
$new_version = sprintf( __( 'There is a new version of %s available.', 'wp-migrate-db' ), $plugin_title );
$new_version .= ' <a class="thickbox" title="' . $plugin_title . '" href="plugin-install.php?tab=plugin-information&plugin=' . rawurlencode( $plugin_slug ) . '&TB_iframe=true&width=640&height=808">';
$new_version .= sprintf( __( 'View version %s details', 'wp-migrate-db' ), $latest_version ) . '</a>.';
}
if ( ! $new_version && ! empty( $licence ) ) {
return;
}
if ( empty( $licence ) ) {
$settings_link = sprintf( '<a href="%s">%s</a>', network_admin_url( $this->plugin_base ) . '#settings', _x( 'Settings', 'Plugin configuration and preferences', 'wp-migrate-db' ) );
if ( $new_version ) {
$message = sprintf( __( 'To update, go to %1$s and enter your license key. If you don\'t have a license key, you may <a href="%2$s">purchase one</a>.', 'wp-migrate-db' ), $settings_link, 'http://deliciousbrains.com/wp-migrate-db-pro/pricing/' );
} else {
$message = sprintf( __( 'To finish activating %1$s, please go to %2$s and enter your license key. If you don\'t have a license key, you may <a href="%3$s">purchase one</a>.', 'wp-migrate-db' ), $this->plugin_title, $settings_link, 'http://deliciousbrains.com/wp-migrate-db-pro/pricing/' );
}
} elseif ( $licence_problem ) {
$message = array_shift( $licence_response['errors'] ) . sprintf( ' <a href="#" class="check-my-licence-again">%s</a>', __( 'Check my license again', 'wp-migrate-db' ) );
} else {
return;
} ?>
<tr class="plugin-update-tr <?php echo $active; ?> wpmdbpro-custom">
<td colspan="3" class="plugin-update">
<div class="update-message <?php echo $update_msg_classes; ?>">
<p>
<span class="wpmdb-new-version-notice"><?php echo $new_version; ?></span>
<span class="wpmdb-licence-error-notice"><?php echo $this->get_licence_status_message( null, 'update' ); ?></span>
</p>
</div>
</td>
</tr>
<?php if ( $new_version ) { // removes the built-in plugin update message ?>
<script type="text/javascript">
(function( $ ) {
var wpmdb_row = jQuery( '[data-slug=<?php echo $plugin_slug; ?>]:first' );
// Fallback for earlier versions of WordPress.
if ( ! wpmdb_row.length ) {
wpmdb_row = jQuery( '#<?php echo $plugin_slug; ?>' );
}
var next_row = wpmdb_row.next();
// If there's a plugin update row - need to keep the original update row available so we can switch it out
// if the user has a successful response from the 'check my license again' link
if ( next_row.hasClass( 'plugin-update-tr' ) && !next_row.hasClass( 'wpmdbpro-custom' ) ) {
var original = next_row.clone();
original.add;
next_row.html( next_row.next().html() ).addClass( 'wpmdbpro-custom-visible' );
next_row.next().remove();
next_row.after( original );
original.addClass( 'wpmdb-original-update-row' );
}
})( jQuery );
</script>
<?php
}
}
/**
* Override the standard plugin information popup for each pro addon
*
* @return void
*/
function plugin_update_popup() {
if ( 'wp-migrate-db-pro' == $_GET['plugin'] ) {
$plugin_slug = 'wp-migrate-db-pro';
} elseif ( 'wp-migrate-db-pro-cli' === $_GET['plugin'] ) {
$plugin_slug = 'wp-migrate-db-pro-cli';
} elseif ( 'wp-migrate-db-pro-media-files' === $_GET['plugin'] ) {
$plugin_slug = 'wp-migrate-db-pro-media-files';
} elseif ( 'wp-migrate-db-pro-multisite-tools' === $_GET['plugin'] ) {
$plugin_slug = 'wp-migrate-db-pro-multisite-tools';
} else {
return;
}
$filename = $plugin_slug;
$latest_version = $this->get_latest_version( $plugin_slug );
if ( $this->is_beta_version( $latest_version ) ) {
$filename .= '-beta';
}
$url = $this->dbrains_api_base . '/content/themes/delicious-brains/update-popup/' . $filename . '.html';
$data = wp_remote_get( $url, array( 'timeout' => 30 ) );
if ( is_wp_error( $data ) || 200 != $data['response']['code'] ) {
echo '<p>' . __( 'Could not retrieve version details. Please try again.', 'wp-migrate-db' ) . '</p>';
} else {
echo $data['body'];
}
exit;
}
}