Ejemplo n.º 1
0
 /**
  * Post data to a remote site with WP Migrate DB Pro and check the response.
  *
  * @param string $url The URL to post to.
  * @param array $data The associative array of data to be posted to the remote.
  * @param string $scope A string to be used in error messages defining the function that initiated the remote post.
  * @param array $args An optional array of args to alter the timeout, blocking and sslverify options.
  * @param bool $expecting_serial Verify that the response is a serialized string (defaults to false).
  *
  * @return bool|string
  */
 function remote_post($url, $data, $scope, $args = array(), $expecting_serial = false)
 {
     $this->set_time_limit();
     $this->set_post_data();
     if (function_exists('fsockopen') && 0 === strpos($url, 'https://') && 'ajax_verify_connection_to_remote_site' == $scope) {
         $url_parts = $this->parse_url($url);
         $host = $url_parts['host'];
         if ($pf = @fsockopen($host, 443, $err, $err_string, 1)) {
             // worked
             fclose($pf);
         } else {
             // failed
             $url = substr_replace($url, 'http', 0, 5);
         }
     }
     $sslverify = 1 == $this->settings['verify_ssl'] ? true : false;
     $default_remote_post_timeout = apply_filters('wpmdb_default_remote_post_timeout', 60 * 20);
     $args = wp_parse_args($args, array('timeout' => $default_remote_post_timeout, 'blocking' => true, 'sslverify' => $sslverify));
     $args['method'] = 'POST';
     if (!isset($args['body'])) {
         $args['body'] = $this->array_to_multipart($data);
     }
     $args['headers']['Content-Type'] = 'multipart/form-data; boundary=' . $this->multipart_boundary;
     $args['headers']['Referer'] = $this->referer_from_url($url);
     $this->attempting_to_connect_to = $url;
     do_action('wpmdb_before_remote_post');
     $response = wp_remote_post($url, $args);
     if (!is_wp_error($response)) {
         // Every response should be scrambled, but other processes may have been applied too so we use a filter.
         add_filter('wpmdb_after_response', array($this, 'unscramble'));
         $response['body'] = apply_filters('wpmdb_after_response', trim($response['body'], ""));
         remove_filter('wpmdb_after_response', array($this, 'unscramble'));
     }
     if (is_wp_error($response)) {
         if (0 === strpos($url, 'https://') && 'ajax_verify_connection_to_remote_site' == $scope) {
             return $this->retry_remote_post($url, $data, $scope, $args, $expecting_serial);
         } elseif (isset($response->errors['http_request_failed'][0]) && strstr($response->errors['http_request_failed'][0], 'timed out')) {
             $this->error = sprintf(__('The connection to the remote server has timed out, no changes have been committed. (#134 - scope: %s)', 'wp-migrate-db'), $scope);
         } elseif (isset($response->errors['http_request_failed'][0]) && (strstr($response->errors['http_request_failed'][0], 'Could not resolve host') || strstr($response->errors['http_request_failed'][0], "Couldn't resolve host") || strstr($response->errors['http_request_failed'][0], "couldn't connect to host"))) {
             $this->error = sprintf(__('We could not find: %s. Are you sure this is the correct URL?', 'wp-migrate-db'), $this->state_data['url']);
             $url_bits = $this->parse_url($this->state_data['url']);
             if (strstr($this->state_data['url'], 'dev.') || strstr($this->state_data['url'], '.dev') || !strstr($url_bits['host'], '.')) {
                 $this->error .= '<br />';
                 if ('pull' == $this->state_data['intent']) {
                     $this->error .= __('It appears that you might be trying to pull from a local environment. This will not work if <u>this</u> website happens to be located on a remote server, it would be impossible for this server to contact your local environment.', 'wp-migrate-db');
                 } else {
                     $this->error .= __('It appears that you might be trying to push to a local environment. This will not work if <u>this</u> website happens to be located on a remote server, it would be impossible for this server to contact your local environment.', 'wp-migrate-db');
                 }
             }
         } else {
             if (defined('WP_HTTP_BLOCK_EXTERNAL') && WP_HTTP_BLOCK_EXTERNAL) {
                 $url_parts = $this->parse_url($url);
                 $host = $url_parts['host'];
                 if (!defined('WP_ACCESSIBLE_HOSTS') || defined('WP_ACCESSIBLE_HOSTS') && !in_array($host, explode(',', WP_ACCESSIBLE_HOSTS))) {
                     $this->error = sprintf(__('We\'ve detected that <code>WP_HTTP_BLOCK_EXTERNAL</code> is enabled and the host <strong>%1$s</strong> has not been added to <code>WP_ACCESSIBLE_HOSTS</code>. Please disable <code>WP_HTTP_BLOCK_EXTERNAL</code> or add <strong>%1$s</strong> to <code>WP_ACCESSIBLE_HOSTS</code> to continue. <a href="%2$s" target="_blank">More information</a>. (#147 - scope: %3$s)', 'wp-migrate-db'), esc_attr($host), 'https://deliciousbrains.com/wp-migrate-db-pro/doc/wp_http_block_external/', $scope);
                 }
             } elseif (isset($response->errors['http_request_failed'][0]) && strstr($response->errors['http_request_failed'][0], 'port 443: Connection refused')) {
                 $this->error = sprintf(__('Couldn\'t connect over HTTPS. You might want to try regular HTTP instead. (#121 - scope: %s)', 'wp-migrate-db'), $scope);
             } elseif (isset($response->errors['http_request_failed'][0]) && strstr($response->errors['http_request_failed'][0], 'SSL')) {
                 // OpenSSL/cURL/MAMP Error
                 $this->error = sprintf(__('<strong>SSL Connection error:</strong>  (#121 - scope: %s) This typically means that the version of SSL that your local site is using to connect to the remote is incompatible or, more likely, being rejected by the remote server because it\'s insecure. <a href="%s" target="_blank">See our documentation</a> for possible solutions.', 'wp-migrate-db'), $scope, 'https://deliciousbrains.com/wp-migrate-db-pro/doc/ssl-errors/');
             } else {
                 $this->error = sprintf(__('The connection failed, an unexpected error occurred, please contact support. (#121 - scope: %s)', 'wp-migrate-db'), $scope);
             }
         }
         $this->log_error($this->error, $response);
         return false;
     } elseif (200 > (int) $response['response']['code'] || 399 < (int) $response['response']['code']) {
         if (401 === (int) $response['response']['code']) {
             $this->error = __('The remote site is protected with Basic Authentication. Please enter the username and password above to continue. (401 Unauthorized)', 'wp-migrate-db');
             $this->log_error($this->error, $response);
             return false;
         } elseif (0 === strpos($url, 'https://') && 'ajax_verify_connection_to_remote_site' == $scope) {
             return $this->retry_remote_post($url, $data, $scope, $args, $expecting_serial);
         } else {
             $this->error = sprintf(__('Unable to connect to the remote server, please check the connection details - %1$s %2$s (#129 - scope: %3$s)', 'wp-migrate-db'), $response['response']['code'], $response['response']['message'], $scope);
             $this->log_error($this->error, $response);
             return false;
         }
     } elseif (empty($response['body'])) {
         if ('0' === $response['body'] && 'ajax_verify_connection_to_remote_site' == $scope) {
             if (0 === strpos($url, 'https://')) {
                 return $this->retry_remote_post($url, $data, $scope, $args, $expecting_serial);
             } else {
                 $this->error = sprintf(__('WP Migrate DB Pro does not seem to be installed or active on the remote site. (#131 - scope: %s)', 'wp-migrate-db'), $scope);
             }
         } else {
             $this->error = sprintf(__('A response was expected from the remote, instead we got nothing. (#146 - scope: %1$s) Please review %2$s for possible solutions.', 'wp-migrate-db'), $scope, sprintf('<a href="https://deliciousbrains.com/wp-migrate-db-pro/doc/a-response-was-expected-from-the-remote/" target="_blank">%1$s</a>', __('our documentation', 'wp-migrate-db')));
         }
         $this->log_error($this->error, $response);
         return false;
     } elseif ($expecting_serial && false == is_serialized($response['body'])) {
         if (0 === strpos($url, 'https://') && 'ajax_verify_connection_to_remote_site' == $scope) {
             return $this->retry_remote_post($url, $data, $scope, $args, $expecting_serial);
         }
         $this->error = __('There was a problem with the AJAX request, we were expecting a serialized response, instead we received:<br />', 'wp-migrate-db') . esc_html($response['body']);
         $this->log_error($this->error, $response);
         return false;
     } elseif ($expecting_serial && 'ajax_verify_connection_to_remote_site' == $scope) {
         $unserialized_response = WPMDB_Utils::unserialize($response['body'], __METHOD__);
         if (false !== $unserialized_response && isset($unserialized_response['error']) && '1' == $unserialized_response['error'] && 0 === strpos($url, 'https://')) {
             if (false === strpos($unserialized_response['message'], '(#122)')) {
                 return $this->retry_remote_post($url, $data, $scope, $args, $expecting_serial);
             }
         }
     }
     return trim($response['body']);
 }
Ejemplo n.º 2
0
 /**
  * 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;
 }
Ejemplo n.º 3
0
 /**
  * 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;
 }
Ejemplo n.º 4
0
 /**
  * Take a serialized array and unserialize it replacing elements as needed and
  * unserialising any subordinate arrays and performing the replace on those too.
  *
  * Mostly from https://github.com/interconnectit/Search-Replace-DB
  *
  * @param mixed $data Used to pass any subordinate arrays back to in.
  * @param bool $serialized Does the array passed via $data need serialising.
  * @param bool $parent_serialized Passes whether the original data passed in was serialized
  * @param bool $filtered Should we apply before and after filters successively
  *
  * @return mixed    The original array with all elements replaced as needed.
  */
 function recursive_unserialize_replace($data, $serialized = false, $parent_serialized = false, $filtered = true)
 {
     $pre = apply_filters('wpmdb_pre_recursive_unserialize_replace', false, $data, $this);
     if (false !== $pre) {
         return $pre;
     }
     $is_json = false;
     $before_fired = false;
     $successive_filter = $filtered;
     if (true === $filtered) {
         list($data, $before_fired, $successive_filter) = apply_filters('wpmdb_before_replace_custom_data', array($data, $before_fired, $successive_filter), $this);
     }
     // some unserialized data cannot be re-serialized eg. SimpleXMLElements
     try {
         if (is_string($data) && ($unserialized = WPMDB_Utils::unserialize($data, __METHOD__)) !== false) {
             // PHP currently has a bug that doesn't allow you to clone the DateInterval / DatePeriod classes.
             // We skip them here as they probably won't need data to be replaced anyway
             if (is_object($unserialized)) {
                 if ($unserialized instanceof DateInterval || $unserialized instanceof DatePeriod) {
                     return $data;
                 }
             }
             $data = $this->recursive_unserialize_replace($unserialized, true, true, $successive_filter);
         } elseif (is_array($data)) {
             $_tmp = array();
             foreach ($data as $key => $value) {
                 $_tmp[$key] = $this->recursive_unserialize_replace($value, false, $parent_serialized, $successive_filter);
             }
             $data = $_tmp;
             unset($_tmp);
         } elseif (is_object($data)) {
             // Submitted by Tina Matter
             $_tmp = clone $data;
             foreach ($data as $key => $value) {
                 // Integer properties are crazy and the best thing we can do is to just ignore them.
                 // see http://stackoverflow.com/a/10333200 and https://github.com/deliciousbrains/wp-migrate-db-pro/issues/853
                 if (is_int($key)) {
                     continue;
                 }
                 $_tmp->{$key} = $this->recursive_unserialize_replace($value, false, $parent_serialized, $successive_filter);
             }
             $data = $_tmp;
             unset($_tmp);
         } elseif ($this->wpmdb->is_json($data, true)) {
             $_tmp = array();
             $data = json_decode($data, true);
             foreach ($data as $key => $value) {
                 $_tmp[$key] = $this->recursive_unserialize_replace($value, false, $parent_serialized, $successive_filter);
             }
             $data = $_tmp;
             unset($_tmp);
             $is_json = true;
         } elseif (is_string($data)) {
             list($data, $do_replace) = apply_filters('wpmdb_replace_custom_data', array($data, true), $this);
             if ($do_replace) {
                 $data = $this->apply_replaces($data);
             }
         }
         if ($is_json) {
             $data = json_encode($data);
         }
         if ($serialized) {
             $data = serialize($data);
         }
     } catch (Exception $error) {
         $error_msg = __('Failed attempting to do the recursive unserialize replace. Please contact support.', 'wp-migrate-db');
         $error_details = $error->getMessage() . "\n\n";
         $error_details .= var_export($data, true);
         $this->wpmdb->log_error($error_msg, $error_details);
     }
     if (true === $filtered) {
         $data = apply_filters('wpmdb_after_replace_custom_data', $data, $before_fired, $this);
     }
     return $data;
 }
Ejemplo n.º 5
0
 /**
  * Taken partially from phpMyAdmin and partially from
  * Alain Wolf, Zurich - Switzerland
  * Website: http://restkultur.ch/personal/wolf/scripts/db_backup/
  * Modified by Scott Merrill (http://www.skippy.net/)
  * to use the WordPress $wpdb object
  *
  * @param string $table
  * @param string $db_version
  *
  * @return mixed
  */
 function export_table($table, $db_version = '')
 {
     global $wpdb;
     $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']);
     }
     $temp_prefix = isset($this->state_data['temp_prefix']) ? $this->state_data['temp_prefix'] : $this->temp_prefix;
     $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 false;
     }
     $table_name = $table;
     $site_details = empty($this->state_data['site_details']) ? array() : $this->state_data['site_details'];
     $target_table_name = apply_filters('wpmdb_target_table_name', $table_name, $this->form_data['action'], $this->state_data['stage'], $site_details);
     $table_name = $target_table_name;
     if ('savefile' !== $this->form_data['action'] && 'backup' !== $this->state_data['stage']) {
         $table_name = $temp_prefix . $table_name;
     }
     $current_row = -1;
     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;
         }
     }
     if ($current_row == -1) {
         // Don't stow data until after `wpmdb_create_table_query` filter is applied as mysql_compat_filter() can return an error
         $stow = '';
         // Add SQL statement to drop existing table
         if ($this->form_data['action'] == 'savefile' || $this->state_data['stage'] == 'backup') {
             $stow .= "\n\n";
             $stow .= "#\n";
             $stow .= '# ' . sprintf(__('Delete any existing table %s', 'wp-migrate-db'), $this->backquote($table_name)) . "\n";
             $stow .= "#\n";
             $stow .= "\n";
         }
         $stow .= 'DROP TABLE IF EXISTS ' . $this->backquote($table_name) . ";\n";
         // Table structure
         // Comment in SQL-file
         if ($this->form_data['action'] == 'savefile' || $this->state_data['stage'] == 'backup') {
             $stow .= "\n\n";
             $stow .= "#\n";
             $stow .= '# ' . sprintf(__('Table structure of table %s', 'wp-migrate-db'), $this->backquote($table_name)) . "\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_name . '`', $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_name, $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 ($this->form_data['action'] == 'savefile' || $this->state_data['stage'] == '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_name, $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 ('savefile' == $this->form_data['action'] || 'backup' == $this->state_data['stage']) {
                 $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 ($this->form_data['action'] == 'savefile' || $this->state_data['stage'] == 'backup') {
             $this->stow("\n\n");
             $this->stow("#\n");
             $this->stow('# ' . sprintf(__('Data contents of table %s', 'wp-migrate-db'), $this->backquote($table_name)) . "\n");
             $this->stow("#\n");
         }
     }
     // $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();
     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';
         }
     }
     // Batch by $row_inc
     $row_inc = $this->rows_per_segment;
     $row_start = 0;
     if ($current_row != -1) {
         $row_start = $current_row;
     }
     $this->row_tracker = $row_start;
     // \x08\\x09, not required
     $multibyte_search = array("", "\n", "\r", "");
     $multibyte_replace = array('\\0', '\\n', '\\r', '\\Z');
     $query_size = 0;
     $this->primary_keys = array();
     $field_set = array();
     $use_primary_keys = true;
     foreach ($table_structure as $col) {
         $field_set[] = $this->backquote($col->Field);
         if ($col->Key == 'PRI' && true == $use_primary_keys) {
             if (false === strpos($col->Type, 'int')) {
                 $use_primary_keys = false;
                 $this->primary_keys = array();
                 continue;
             }
             $this->primary_keys[$col->Field] = 0;
         }
     }
     $first_select = true;
     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'])) {
             $first_select = false;
         }
     }
     $fields = implode(', ', $field_set);
     $insert_buffer = $insert_query_template = 'INSERT INTO ' . $this->backquote($table_name) . ' ( ' . $fields . ") VALUES\n";
     do {
         $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}, {$row_inc}";
         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 {$row_inc}";
             if (false == $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) . ' )';
             }
             $first_select = false;
         }
         $sel = $this->backquote($table) . '.*';
         if (!empty($bins)) {
             foreach ($bins as $key => $bin) {
                 $hex_key = strtolower($key) . '__hex';
                 $sel .= ', HEX(' . $this->backquote($key) . ') as ' . $this->backquote($hex_key);
             }
         }
         if (!empty($bits)) {
             foreach ($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);
         $table_data = $wpdb->get_results($sql);
         if ($table_data) {
             $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' => $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));
             foreach ($table_data as $row) {
                 $skip_row = false;
                 if (!apply_filters('wpmdb_table_row', $row, $table, $this->form_data['action'], $this->state_data['stage'])) {
                     $skip_row = true;
                 }
                 if (!$skip_row) {
                     $replacer->set_row($row);
                     $values = array();
                     foreach ($row as $key => $value) {
                         $replacer->set_column($key);
                         if (isset($ints[strtolower($key)]) && $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 ? $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($bins[strtolower($key)]) && $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($bits[strtolower($key)]) && $bits[strtolower($key)] && isset($row->{$bit_key})) {
                             $value = "b'" . $row->{$bit_key} . "'";
                             $values[] = $value;
                             unset($row->{$bit_key});
                             continue;
                         }
                         if (is_multisite() && 'path' == $key && $this->state_data['stage'] != 'backup' && ($wpdb->site == $table || $wpdb->blogs == $table)) {
                             $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 (is_multisite() && 'domain' == $key && $this->state_data['stage'] != 'backup' && ($wpdb->site == $table || $wpdb->blogs == $table)) {
                             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);
                             }
                         }
                         $value = $this->sql_addslashes($value);
                         $value = str_replace($multibyte_search, $multibyte_replace, $value);
                         $values[] = "'" . $value . "'";
                     }
                     $insert_line = '(' . implode(', ', $values) . '),';
                     $insert_line .= "\n";
                 } else {
                     $insert_line = '';
                 }
                 if (strlen($this->current_chunk) + strlen($insert_line) + strlen($insert_buffer) + 30 > $this->maximum_chunk_size) {
                     if ($insert_buffer == $insert_query_template) {
                         $insert_buffer .= $insert_line;
                         ++$this->row_tracker;
                         if (!empty($this->primary_keys)) {
                             foreach ($this->primary_keys as $primary_key => $value) {
                                 $this->primary_keys[$primary_key] = $row->{$primary_key};
                             }
                         }
                     }
                     $insert_buffer = rtrim($insert_buffer, "\n,");
                     $insert_buffer .= " ;\n";
                     $this->stow($insert_buffer);
                     $insert_buffer = $insert_query_template;
                     $query_size = 0;
                     return $this->transfer_chunk();
                 }
                 if ($query_size + strlen($insert_line) > $this->max_insert_string_len && $insert_buffer != $insert_query_template) {
                     $insert_buffer = rtrim($insert_buffer, "\n,");
                     $insert_buffer .= " ;\n";
                     $this->stow($insert_buffer);
                     $insert_buffer = $insert_query_template;
                     $query_size = 0;
                 }
                 $insert_buffer .= $insert_line;
                 $query_size += strlen($insert_line);
                 ++$this->row_tracker;
                 if (!empty($this->primary_keys)) {
                     foreach ($this->primary_keys as $primary_key => $value) {
                         $this->primary_keys[$primary_key] = $row->{$primary_key};
                     }
                 }
             }
             $row_start += $row_inc;
             if ($insert_buffer != $insert_query_template) {
                 $insert_buffer = rtrim($insert_buffer, "\n,");
                 $insert_buffer .= " ;\n";
                 $this->stow($insert_buffer);
                 $insert_buffer = $insert_query_template;
                 $query_size = 0;
             }
         }
     } while (count($table_data) > 0);
     // Create footer/closing comment in SQL-file
     if ('savefile' == $this->form_data['action'] || 'backup' == $this->state_data['stage']) {
         $this->stow("\n");
         $this->stow("#\n");
         $this->stow('# ' . sprintf(__('End of data contents of table %s', 'wp-migrate-db'), $this->backquote($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;
                 }
             }
         }
     }
     $this->row_tracker = -1;
     return $this->transfer_chunk();
 }