PageRenderTime 62ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 1ms

/wp-content/plugins/wp-sync-db-master/class/wpsdb.php

https://gitlab.com/jessehall/hudson_alpha
PHP | 2521 lines | 2102 code | 312 blank | 107 comment | 407 complexity | 83433841bedc6559499bb5ec4eab577c MD5 | raw file
Possible License(s): GPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. class WPSDB extends WPSDB_Base {
  3. protected $fp;
  4. protected $absolute_root_file_path;
  5. protected $form_defaults;
  6. protected $accepted_fields;
  7. protected $default_profile;
  8. protected $maximum_chunk_size;
  9. protected $current_chunk = '';
  10. protected $connection_details;
  11. protected $remote_url;
  12. protected $remote_key;
  13. protected $form_data;
  14. protected $max_insert_string_len;
  15. protected $row_tracker;
  16. protected $rows_per_segment = 100;
  17. protected $create_alter_table_query;
  18. protected $alter_table_name;
  19. protected $session_salt;
  20. protected $primary_keys;
  21. function __construct( $plugin_file_path ) {
  22. parent::__construct( $plugin_file_path );
  23. $this->plugin_slug = 'wp-sync-db';
  24. $this->plugin_version = $GLOBALS['wpsdb_meta']['wp-sync-db']['version'];
  25. $this->max_insert_string_len = 50000; // 50000 is the default as defined by phphmyadmin
  26. $default_settings = array(
  27. 'key' => $this->generate_key(),
  28. 'allow_pull' => false,
  29. 'allow_push' => false,
  30. 'profiles' => array(),
  31. 'verify_ssl' => false,
  32. 'blacklist_plugins' => array(),
  33. );
  34. if( empty( $this->settings['max_request'] ) ) {
  35. $this->settings['max_request'] = min( 1024 * 1024, $this->get_bottleneck( 'max' ) );
  36. update_option( 'wpsdb_settings', $this->settings );
  37. }
  38. // if no settings exist then this is a fresh install, set up some default settings
  39. if ( empty( $this->settings ) ) {
  40. $this->settings = $default_settings;
  41. update_option( 'wpsdb_settings', $this->settings );
  42. }
  43. // When we add a new setting, an existing customer's db won't have this
  44. // new setting, so we need to add it. Otherwise, they'll see
  45. // array index errors in debug mode
  46. else {
  47. $update_settings = false;
  48. foreach ( $default_settings as $key => $value ) {
  49. if ( !isset( $this->settings[$key] ) ) {
  50. $this->settings[$key] = $value;
  51. $update_settings = true;
  52. }
  53. }
  54. if ( $update_settings ) {
  55. update_option( 'wpsdb_settings', $this->settings );
  56. }
  57. }
  58. add_filter( 'plugin_action_links_' . $this->plugin_basename, array( $this, 'plugin_action_links' ) );
  59. add_filter( 'network_admin_plugin_action_links_' . $this->plugin_basename, array( $this, 'plugin_action_links' ) );
  60. // internal AJAX handlers
  61. add_action( 'wp_ajax_wpsdb_verify_connection_to_remote_site', array( $this, 'ajax_verify_connection_to_remote_site' ) );
  62. add_action( 'wp_ajax_wpsdb_reset_api_key', array( $this, 'ajax_reset_api_key' ) );
  63. add_action( 'wp_ajax_wpsdb_delete_migration_profile', array( $this, 'ajax_delete_migration_profile' ) );
  64. add_action( 'wp_ajax_wpsdb_save_setting', array( $this, 'ajax_save_setting' ) );
  65. add_action( 'wp_ajax_wpsdb_save_profile', array( $this, 'ajax_save_profile' ) );
  66. add_action( 'wp_ajax_wpsdb_initiate_migration', array( $this, 'ajax_initiate_migration' ) );
  67. add_action( 'wp_ajax_wpsdb_migrate_table', array( $this, 'ajax_migrate_table' ) );
  68. add_action( 'wp_ajax_wpsdb_finalize_migration', array( $this, 'ajax_finalize_migration' ) );
  69. add_action( 'wp_ajax_wpsdb_clear_log', array( $this, 'ajax_clear_log' ) );
  70. add_action( 'wp_ajax_wpsdb_get_log', array( $this, 'ajax_get_log' ) );
  71. add_action( 'wp_ajax_wpsdb_fire_migration_complete', array( $this, 'fire_migration_complete' ) );
  72. add_action( 'wp_ajax_wpsdb_update_max_request_size', array( $this, 'ajax_update_max_request_size' ) );
  73. add_action( 'wp_ajax_wpsdb_plugin_compatibility', array( $this, 'ajax_plugin_compatibility' ) );
  74. add_action( 'wp_ajax_wpsdb_blacklist_plugins', array( $this, 'ajax_blacklist_plugins' ) );
  75. add_action( 'wp_ajax_wpsdb_cancel_migration', array( $this, 'ajax_cancel_migration' ) );
  76. // external AJAX handlers
  77. add_action( 'wp_ajax_nopriv_wpsdb_verify_connection_to_remote_site', array( $this, 'respond_to_verify_connection_to_remote_site' ) );
  78. add_action( 'wp_ajax_nopriv_wpsdb_remote_initiate_migration', array( $this, 'respond_to_remote_initiate_migration' ) );
  79. add_action( 'wp_ajax_nopriv_wpsdb_process_chunk', array( $this, 'ajax_process_chunk' ) );
  80. add_action( 'wp_ajax_nopriv_wpsdb_process_pull_request', array( $this, 'respond_to_process_pull_request' ) );
  81. add_action( 'wp_ajax_nopriv_wpsdb_fire_migration_complete', array( $this, 'fire_migration_complete' ) );
  82. add_action( 'wp_ajax_nopriv_wpsdb_backup_remote_table', array( $this, 'respond_to_backup_remote_table' ) );
  83. add_action( 'wp_ajax_nopriv_wpsdb_remote_finalize_migration', array( $this, 'respond_to_remote_finalize_migration' ) );
  84. add_action( 'wp_ajax_nopriv_wpsdb_process_push_migration_cancellation', array( $this, 'respond_to_process_push_migration_cancellation' ) );
  85. // Clear update transients when the user clicks the "Check Again" button from the update screen
  86. add_action( 'current_screen', array( $this, 'check_again_clear_transients' ) );
  87. $absolute_path = rtrim( ABSPATH, '\\/' );
  88. $site_url = rtrim( site_url( '', 'http' ), '\\/' );
  89. $home_url = rtrim( home_url( '', 'http' ), '\\/' );
  90. if ( $site_url != $home_url ) {
  91. $difference = str_replace( $home_url, '', $site_url );
  92. if( strpos( $absolute_path, $difference ) !== false ) {
  93. $absolute_path = rtrim( substr( $absolute_path, 0, -strlen( $difference ) ), '\\/' );
  94. }
  95. }
  96. $this->absolute_root_file_path = $absolute_path;
  97. $this->accepted_fields = array(
  98. 'action',
  99. 'save_computer',
  100. 'gzip_file',
  101. 'connection_info',
  102. 'replace_old',
  103. 'replace_new',
  104. 'table_migrate_option',
  105. 'select_tables',
  106. 'replace_guids',
  107. 'exclude_spam',
  108. 'save_migration_profile',
  109. 'save_migration_profile_option',
  110. 'create_new_profile',
  111. 'create_backup',
  112. 'remove_backup',
  113. 'keep_active_plugins',
  114. 'select_post_types',
  115. 'backup_option',
  116. 'select_backup',
  117. 'exclude_transients',
  118. 'exclude_post_types'
  119. );
  120. $this->default_profile = array(
  121. 'action' => 'savefile',
  122. 'save_computer' => '1',
  123. 'gzip_file' => '1',
  124. 'table_migrate_option' => 'migrate_only_with_prefix',
  125. 'replace_guids' => '1',
  126. 'default_profile' => true,
  127. 'name' => '',
  128. 'select_tables' => array(),
  129. 'select_post_types' => array(),
  130. 'backup_option' => 'backup_only_with_prefix',
  131. 'exclude_transients' => '1',
  132. );
  133. $this->checkbox_options = array(
  134. 'save_computer' => '0',
  135. 'gzip_file' => '0',
  136. 'replace_guids' => '0',
  137. 'exclude_spam' => '0',
  138. 'keep_active_plugins' => '0',
  139. 'create_backup' => '0',
  140. 'exclude_post_types' =>'0'
  141. );
  142. if ( is_multisite() ) {
  143. add_action( 'network_admin_menu', array( $this, 'network_admin_menu' ) );
  144. }
  145. else {
  146. add_action( 'admin_menu', array( $this, 'admin_menu' ) );
  147. }
  148. add_filter( 'admin_body_class', array( $this, 'admin_body_class' ) );
  149. // this is how many DB rows are processed at a time, allow devs to change this value
  150. $this->rows_per_segment = apply_filters( 'wpsdb_rows_per_segment', $this->rows_per_segment );
  151. if ( is_multisite() ) {
  152. add_action( 'network_admin_menu', array( $this, 'network_admin_menu' ) );
  153. $this->plugin_base = 'settings.php?page=wp-sync-db';
  154. }
  155. else {
  156. add_action( 'admin_menu', array( $this, 'admin_menu' ) );
  157. $this->plugin_base = 'tools.php?page=wp-sync-db';
  158. }
  159. }
  160. function ajax_blacklist_plugins() {
  161. $this->settings['blacklist_plugins'] = $_POST['blacklist_plugins'];
  162. update_option( 'wpsdb_settings', $this->settings );
  163. exit;
  164. }
  165. function ajax_plugin_compatibility() {
  166. $mu_dir = ( defined( 'WPMU_PLUGIN_DIR' ) && defined( 'WPMU_PLUGIN_URL' ) ) ? WPMU_PLUGIN_DIR : trailingslashit( WP_CONTENT_DIR ) . 'mu-plugins';
  167. $source = trailingslashit( $this->plugin_dir_path ) . 'compatibility/wp-sync-db-compatibility.php';
  168. $dest = trailingslashit( $mu_dir ) . 'wp-sync-db-compatibility.php';
  169. if ( '1' === trim( $_POST['install'] ) ) { // install MU plugin
  170. if ( !wp_mkdir_p( $mu_dir ) ) {
  171. _e( sprintf( 'The following directory could not be created: %s', $mu_dir ), 'wp-sync-db' );
  172. exit;
  173. }
  174. if ( !copy( $source, $dest ) ) {
  175. _e( sprintf( 'Could not copy the compatibility plugin from %1$s to %2$s', $source, $destination ), 'wp-sync-db' );
  176. exit;
  177. }
  178. } else { // uninstall MU plugin
  179. if ( file_exists( $dest ) && !unlink( $dest ) ) {
  180. _e( sprintf( 'Could not remove the compatibility plugin from %s', $dest ), 'wp-sync-db' );
  181. exit;
  182. }
  183. }
  184. exit;
  185. }
  186. function check_again_clear_transients( $current_screen ) {
  187. if( ! isset( $current_screen->id ) || strpos( $current_screen->id, 'update-core' ) === false || ! isset( $_GET['force-check'] ) ) return;
  188. delete_site_transient( 'wpsdb_upgrade_data' );
  189. delete_site_transient( 'update_plugins' );
  190. }
  191. function get_alter_table_name() {
  192. if ( ! is_null( $this->alter_table_name ) ) {
  193. return $this->alter_table_name;
  194. }
  195. global $wpdb;
  196. $this->alter_table_name = apply_filters( 'wpsdb_alter_table_name', $wpdb->prefix . 'wpsdb_alter_statements' );
  197. return $this->alter_table_name;
  198. }
  199. function get_create_alter_table_query() {
  200. if ( ! is_null( $this->create_alter_table_query ) ) {
  201. return $this->create_alter_table_query;
  202. }
  203. $alter_table_name = $this->get_alter_table_name();
  204. $this->create_alter_table_query = sprintf( "DROP TABLE IF EXISTS `%s`;\n", $alter_table_name );
  205. $this->create_alter_table_query .= sprintf( "CREATE TABLE `%s` ( `query` longtext NOT NULL );\n", $alter_table_name );
  206. $this->create_alter_table_query = apply_filters( 'wpsdb_create_alter_table_query', $this->create_alter_table_query );
  207. return $this->create_alter_table_query;
  208. }
  209. function get_short_uploads_dir() {
  210. $short_path = str_replace( $this->absolute_root_file_path, '', $this->get_upload_info( 'path' ) );
  211. return trailingslashit( substr( str_replace( '\\', '/', $short_path ), 1 ) );
  212. }
  213. function get_upload_info( $type = 'path' ) {
  214. // Let developers define their own path to for export files
  215. // Note: We require a very specific data set here, it should be similiar to the following
  216. // array(
  217. // 'path' => '/path/to/custom/uploads/directory', <- note missing end trailing slash
  218. // 'url' => 'http://yourwebsite.com/custom/uploads/directory' <- note missing end trailing slash
  219. // );
  220. $upload_info = apply_filters( 'wpsdb_upload_info', array() );
  221. if ( !empty( $upload_info ) ) {
  222. return $upload_info[$type];
  223. }
  224. $upload_dir = wp_upload_dir();
  225. $upload_info['path'] = $upload_dir['basedir'];
  226. $upload_info['url'] = $upload_dir['baseurl'];
  227. $upload_dir_name = apply_filters( 'wpsdb_upload_dir_name', 'wp-sync-db' );
  228. if( ! file_exists( $upload_dir['basedir'] . DS . $upload_dir_name ) ) {
  229. $url = wp_nonce_url( $this->plugin_base, 'wp-sync-db-nonce' );
  230. if( false === @mkdir( $upload_dir['basedir'] . DS . $upload_dir_name, 0755 ) ) {
  231. return $upload_info[$type];
  232. }
  233. $filename = $upload_dir['basedir'] . DS . $upload_dir_name . DS . 'index.php';
  234. if( false === @file_put_contents( $filename, "<?php\r\n// Silence is golden\r\n?>" ) ) {
  235. return $upload_info[$type];
  236. }
  237. }
  238. $upload_info['path'] .= DS . $upload_dir_name;
  239. $upload_info['url'] .= '/' . $upload_dir_name;
  240. return $upload_info[$type];
  241. }
  242. function ajax_update_max_request_size() {
  243. $this->check_ajax_referer( 'update-max-request-size' );
  244. $this->settings['max_request'] = (int) $_POST['max_request_size'] * 1024;
  245. update_option( 'wpsdb_settings', $this->settings );
  246. $result = $this->end_ajax();
  247. return $result;
  248. }
  249. function is_json( $string, $strict = false ) {
  250. $json = @json_decode( $string, true );
  251. if( $strict == true && ! is_array( $json ) ) return false;
  252. return ! ( $json == NULL || $json == false );
  253. }
  254. function get_sql_dump_info( $migration_type, $info_type ) {
  255. if( empty( $this->session_salt ) ) {
  256. $this->session_salt = strtolower( wp_generate_password( 5, false, false ) );
  257. }
  258. $datetime = date('YmdHis');
  259. $ds = ( $info_type == 'path' ? DS : '/' );
  260. return sprintf( '%s%s%s-%s-%s-%s.sql', $this->get_upload_info( $info_type ), $ds, sanitize_title_with_dashes( DB_NAME ), $migration_type, $datetime, $this->session_salt );
  261. }
  262. function parse_migration_form_data( $data ) {
  263. parse_str( $data, $form_data );
  264. $this->accepted_fields = apply_filters( 'wpsdb_accepted_profile_fields', $this->accepted_fields );
  265. $form_data = array_intersect_key( $form_data, array_flip( $this->accepted_fields ) );
  266. unset( $form_data['replace_old'][0] );
  267. unset( $form_data['replace_new'][0] );
  268. return $form_data;
  269. }
  270. function plugin_action_links( $links ) {
  271. $link = sprintf( '<a href="%s">%s</a>', network_admin_url( $this->plugin_base ), __( 'Settings', 'wp-sync-db' ) );
  272. array_unshift( $links, $link );
  273. return $links;
  274. }
  275. function ajax_clear_log() {
  276. $this->check_ajax_referer( 'clear-log' );
  277. delete_option( 'wpsdb_error_log' );
  278. $result = $this->end_ajax();
  279. return $result;
  280. }
  281. function ajax_get_log() {
  282. $this->check_ajax_referer( 'get-log' );
  283. ob_start();
  284. $this->output_diagnostic_info();
  285. $this->output_log_file();
  286. $return = ob_get_clean();
  287. $result = $this->end_ajax( $return );
  288. return $result;
  289. }
  290. function output_log_file() {
  291. $log = get_option( 'wpsdb_error_log' );
  292. if( $log ) {
  293. echo $log;
  294. }
  295. }
  296. function output_diagnostic_info() {
  297. global $table_prefix;
  298. global $wpdb;
  299. echo 'site_url(): ';
  300. echo site_url();
  301. echo "\r\n";
  302. echo 'home_url(): ';
  303. echo home_url();
  304. echo "\r\n";
  305. echo 'Table Prefix: ';
  306. echo $table_prefix;
  307. echo "\r\n";
  308. echo 'WordPress: ';
  309. if ( is_multisite() ) echo 'WPMU'; else echo 'WP'; echo bloginfo('version');
  310. echo "\r\n";
  311. echo 'Web Server: ';
  312. echo $_SERVER['SERVER_SOFTWARE'];
  313. echo "\r\n";
  314. echo 'PHP: ';
  315. if ( function_exists( 'phpversion' ) ) echo esc_html( phpversion() );
  316. echo "\r\n";
  317. echo 'MySQL: ';
  318. echo esc_html( empty( $wpdb->use_mysqli ) ? mysql_get_server_info() : mysqli_get_server_info( $wpdb->dbh ) );
  319. echo "\r\n";
  320. _e( 'ext/mysqli', 'wp-app-store' ); echo ': ';
  321. echo empty( $wpdb->use_mysqli ) ? 'no' : 'yes';
  322. echo "\r\n";
  323. _e( 'WP Memory Limit', 'wp-app-store' ); echo ': ';
  324. echo WP_MEMORY_LIMIT;
  325. echo "\r\n";
  326. echo 'WPSDB Bottleneck: ';
  327. echo size_format( $this->get_bottleneck() );
  328. echo "\r\n";
  329. if ( function_exists( 'ini_get' ) && $suhosin_limit = ini_get( 'suhosin.post.max_value_length' ) ) {
  330. echo 'Suhosin Post Max Value Length: ';
  331. echo is_numeric( $suhosin_limit ) ? size_format( $suhosin_limit ) : $suhosin_limit;
  332. echo "\r\n";
  333. }
  334. if ( function_exists( 'ini_get' ) && $suhosin_limit = ini_get( 'suhosin.request.max_value_length' ) ) {
  335. echo 'Suhosin Request Max Value Length: ';
  336. echo is_numeric( $suhosin_limit ) ? size_format( $suhosin_limit ) : $suhosin_limit;
  337. echo "\r\n";
  338. }
  339. echo 'Debug Mode: ';
  340. if ( defined('WP_DEBUG') && WP_DEBUG ) { echo 'Yes'; } else { echo 'No'; }
  341. echo "\r\n";
  342. echo 'WP Max Upload Size: ';
  343. echo size_format( wp_max_upload_size() );
  344. echo "\r\n";
  345. echo 'PHP Post Max Size: ';
  346. echo size_format( $this->get_post_max_size() );
  347. echo "\r\n";
  348. echo 'PHP Time Limit: ';
  349. if ( function_exists( 'ini_get' ) ) echo ini_get('max_execution_time');
  350. echo "\r\n";
  351. echo 'PHP Error Log: ';
  352. if ( function_exists( 'ini_get' ) ) echo ini_get('error_log');
  353. echo "\r\n";
  354. echo 'fsockopen: ';
  355. if ( function_exists( 'fsockopen' ) ) {
  356. echo 'Enabled';
  357. } else {
  358. echo 'Disabled';
  359. }
  360. echo "\r\n";
  361. echo 'OpenSSL: ';
  362. if ( $this->open_ssl_enabled() ) {
  363. echo OPENSSL_VERSION_TEXT;
  364. } else {
  365. echo 'Disabled';
  366. }
  367. echo "\r\n";
  368. echo 'cURL: ';
  369. if ( function_exists( 'curl_init' ) ) {
  370. echo 'Enabled';
  371. } else {
  372. echo 'Disabled';
  373. }
  374. echo "\r\n";
  375. echo "\r\n";
  376. echo "Active Plugins:\r\n";
  377. $active_plugins = (array) get_option( 'active_plugins', array() );
  378. if ( is_multisite() ) {
  379. $network_active_plugins = wp_get_active_network_plugins();
  380. $active_plugins = array_map( array( $this, 'remove_wp_plugin_dir' ), $network_active_plugins );
  381. }
  382. foreach ( $active_plugins as $plugin ) {
  383. $plugin_data = @get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
  384. if ( empty( $plugin_data['Name'] ) ) continue;
  385. printf( "%s (v%s) by %s\r\n", $plugin_data['Name'], $plugin_data['Version'], $plugin_data['AuthorName'] );
  386. }
  387. echo "\r\n";
  388. }
  389. function remove_wp_plugin_dir( $name ) {
  390. $plugin = str_replace( WP_PLUGIN_DIR, '', $name );
  391. return substr( $plugin, 1 );
  392. }
  393. function fire_migration_complete() {
  394. $filtered_post = $this->filter_post_elements( $_POST, array( 'action', 'url' ) );
  395. if ( ! $this->verify_signature( $filtered_post, $this->settings['key'] ) ) {
  396. $error_msg = $this->invalid_content_verification_error . ' (#138)';
  397. $this->log_error( $error_msg, $filtered_post );
  398. $result = $this->end_ajax( $error_msg );
  399. return $result;
  400. }
  401. do_action( 'wpsdb_migration_complete', 'pull', $_POST['url'] );
  402. $result = $this->end_ajax();
  403. return $result;
  404. }
  405. function get_alter_queries() {
  406. global $wpdb;
  407. $alter_table_name = $this->get_alter_table_name();
  408. $sql = '';
  409. $alter_queries = $wpdb->get_results( "SELECT * FROM `{$alter_table_name}`", ARRAY_A );
  410. if( ! empty( $alter_queries ) ) {
  411. foreach( $alter_queries as $alter_query ) {
  412. $sql .= $alter_query['query'];
  413. }
  414. }
  415. return $sql;
  416. }
  417. // After table migration, delete old tables and rename new tables removing the temporarily prefix
  418. function ajax_finalize_migration() {
  419. $this->check_ajax_referer( 'finalize-migration' );
  420. global $wpdb;
  421. $return = '';
  422. if ( $_POST['intent'] == 'pull' ) {
  423. $return = $this->finalize_migration();
  424. }
  425. else {
  426. do_action( 'wpsdb_migration_complete', 'push', $_POST['url'] );
  427. $data = $_POST;
  428. if ( isset( $data['nonce'] ) ) {
  429. unset( $data['nonce'] );
  430. }
  431. $data['action'] = 'wpsdb_remote_finalize_migration';
  432. $data['intent'] = 'pull';
  433. $data['prefix'] = $wpdb->prefix;
  434. $data['type'] = 'push';
  435. $data['location'] = home_url();
  436. $data['temp_prefix'] = $this->temp_prefix;
  437. $data['sig'] = $this->create_signature( $data, $data['key'] );
  438. $ajax_url = trailingslashit( $_POST['url'] ) . 'wp-admin/admin-ajax.php';
  439. $response = $this->remote_post( $ajax_url, $data, __FUNCTION__ );
  440. ob_start();
  441. echo $response;
  442. $this->display_errors();
  443. $return = ob_get_clean();
  444. }
  445. $result = $this->end_ajax( $return );
  446. return $result;
  447. }
  448. function respond_to_remote_finalize_migration() {
  449. $filtered_post = $this->filter_post_elements( $_POST, array( 'action', 'intent', 'url', 'key', 'form_data', 'prefix', 'type', 'location', 'tables', 'temp_prefix' ) );
  450. if ( ! $this->verify_signature( $filtered_post, $this->settings['key'] ) ) {
  451. $error_msg = $this->invalid_content_verification_error . ' (#123)';
  452. $this->log_error( $error_msg, $filtered_post );
  453. $result = $this->end_ajax( $error_msg );
  454. return $result;
  455. }
  456. $return = $this->finalize_migration();
  457. $result = $this->end_ajax( $return );
  458. return $result;
  459. }
  460. function finalize_migration() {
  461. global $wpdb;
  462. $tables = explode( ',', $_POST['tables'] );
  463. $temp_tables = array();
  464. foreach( $tables as $table ) {
  465. $temp_prefix = stripslashes( $_POST['temp_prefix'] );
  466. $temp_tables[] = $temp_prefix . $table;
  467. }
  468. $sql = "SET FOREIGN_KEY_CHECKS=0;\n";
  469. $preserved_options = array( 'wpsdb_settings', 'wpsdb_error_log' );
  470. $this->form_data = $this->parse_migration_form_data( $_POST['form_data'] );
  471. if( isset( $this->form_data['keep_active_plugins'] ) ) {
  472. $preserved_options[] = 'active_plugins';
  473. }
  474. $preserved_options = apply_filters( 'wpsdb_preserved_options', $preserved_options );
  475. foreach ( $temp_tables as $table ) {
  476. $sql .= 'DROP TABLE IF EXISTS ' . $this->backquote( substr( $table, strlen( $temp_prefix ) ) ) . ';';
  477. $sql .= "\n";
  478. $sql .= 'RENAME TABLE ' . $this->backquote( $table ) . ' TO ' . $this->backquote( substr( $table, strlen( $temp_prefix ) ) ) . ';';
  479. $sql .= "\n";
  480. }
  481. $preserved_options_data = $wpdb->get_results( sprintf( "SELECT * FROM %soptions WHERE `option_name` IN ('%s')", $wpdb->prefix, implode( "','", $preserved_options ) ), ARRAY_A );
  482. foreach( $preserved_options_data as $option ) {
  483. $sql .= $wpdb->prepare( "DELETE FROM `{$_POST['prefix']}options` WHERE `option_name` = %s;\n", $option['option_name'] );
  484. $sql .= $wpdb->prepare( "INSERT INTO `{$_POST['prefix']}options` ( `option_id`, `option_name`, `option_value`, `autoload` ) VALUES ( NULL , %s, %s, %s );\n", $option['option_name'], $option['option_value'], $option['autoload'] );
  485. }
  486. $alter_table_name = $this->get_alter_table_name();
  487. $sql .= $this->get_alter_queries();
  488. $sql .= "DROP TABLE IF EXISTS " . $this->backquote( $alter_table_name ) . ";\n";
  489. $process_chunk_result = $this->process_chunk( $sql );
  490. if( true !== $process_chunk_result ) {
  491. $result = $this->end_ajax( $process_chunk_result );
  492. return $result;
  493. }
  494. $type = ( isset( $_POST['type'] ) ? 'push' : 'pull' );
  495. $location = ( isset( $_POST['location'] ) ? $_POST['location'] : $_POST['url'] );
  496. if( ! isset( $_POST['location'] ) ) {
  497. $data = array();
  498. $data['action'] = 'wpsdb_fire_migration_complete';
  499. $data['url'] = home_url();
  500. $data['sig'] = $this->create_signature( $data, $_POST['key'] );
  501. $ajax_url = trailingslashit( $_POST['url'] ) . 'wp-admin/admin-ajax.php';
  502. $response = $this->remote_post( $ajax_url, $data, __FUNCTION__ );
  503. ob_start();
  504. echo $response;
  505. $this->display_errors();
  506. $maybe_errors = trim( ob_get_clean() );
  507. if( false === empty( $maybe_errors ) ) {
  508. $result = $this->end_ajax( $maybe_errors );
  509. return $result;
  510. }
  511. }
  512. // flush rewrite rules to prevent 404s and other oddities
  513. flush_rewrite_rules( true ); // true = hard refresh, recreates the .htaccess file
  514. do_action( 'wpsdb_migration_complete', $type, $location );
  515. }
  516. function ajax_process_chunk() {
  517. $filtered_post = $this->filter_post_elements( $_POST, array( 'action', 'table', 'chunk_gzipped' ) );
  518. $gzip = ( isset( $_POST['chunk_gzipped'] ) && $_POST['chunk_gzipped'] );
  519. $tmp_file_name = 'chunk.txt';
  520. if( $gzip ) {
  521. $tmp_file_name .= '.gz';
  522. }
  523. $tmp_file_path = wp_tempnam( $tmp_file_name );
  524. if ( !isset( $_FILES['chunk']['tmp_name'] ) || !move_uploaded_file( $_FILES['chunk']['tmp_name'], $tmp_file_path ) ) {
  525. $result = $this->end_ajax( __( 'Could not upload the SQL to the server. (#135)', 'wp-sync-db' ) );
  526. return $result;
  527. }
  528. if ( false === ( $chunk = file_get_contents( $tmp_file_path ) ) ) {
  529. $result = $this->end_ajax( __( 'Could not read the SQL file we uploaded to the server. (#136)', 'wp-sync-db' ) );
  530. return $result;
  531. }
  532. @unlink( $tmp_file_path );
  533. $filtered_post['chunk'] = $chunk;
  534. if ( !$this->verify_signature( $filtered_post, $this->settings['key'] ) ) {
  535. $error_msg = $this->invalid_content_verification_error . ' (#130)';
  536. $this->log_error( $error_msg, $filtered_post );
  537. $result = $this->end_ajax( $error_msg );
  538. return $result;
  539. }
  540. if ( $this->settings['allow_push'] != true ) {
  541. $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. (#133)', 'wp-sync-db' ) );
  542. return $result;
  543. }
  544. if( $gzip ) {
  545. $filtered_post['chunk'] = gzuncompress( $filtered_post['chunk'] );
  546. }
  547. $process_chunk_result = $this->process_chunk( $filtered_post['chunk'] );
  548. $result = $this->end_ajax( $process_chunk_result );
  549. return $result;
  550. }
  551. function process_chunk( $chunk ) {
  552. // prepare db
  553. global $wpdb;
  554. $this->set_time_limit();
  555. $queries = array_filter( explode( ";\n", $chunk ) );
  556. array_unshift( $queries, "SET sql_mode='NO_AUTO_VALUE_ON_ZERO';" );
  557. ob_start();
  558. $wpdb->show_errors();
  559. if( empty( $wpdb->charset ) ) {
  560. $charset = ( defined( 'DB_CHARSET' ) ? DB_CHARSET : 'utf8' );
  561. $wpdb->charset = $charset;
  562. $wpdb->set_charset( $wpdb->dbh, $wpdb->charset );
  563. }
  564. foreach( $queries as $query ) {
  565. if( false === $wpdb->query( $query ) ) {
  566. $return = ob_get_clean();
  567. $result = $this->end_ajax( $return );
  568. return $result;
  569. }
  570. }
  571. return true;
  572. }
  573. function ajax_migrate_table() {
  574. $this->check_ajax_referer( 'migrate-table' );
  575. global $wpdb;
  576. $this->form_data = $this->parse_migration_form_data( $_POST['form_data'] );
  577. $result = '';
  578. // checks if we're performing a backup, if so, continue with the backup and exit immediately after
  579. if ( $_POST['stage'] == 'backup' && $_POST['intent'] != 'savefile' ) {
  580. // if performing a push we need to backup the REMOTE machine's DB
  581. if ( $_POST['intent'] == 'push' ) {
  582. $data = $_POST;
  583. if ( isset( $data['nonce'] ) ) {
  584. unset( $data['nonce'] );
  585. }
  586. $data['action'] = 'wpsdb_backup_remote_table';
  587. $data['intent'] = 'pull';
  588. $ajax_url = trailingslashit( $_POST['url'] ) . 'wp-admin/admin-ajax.php';
  589. $data['primary_keys'] = stripslashes( $data['primary_keys'] );
  590. $data['sig'] = $this->create_signature( $data, $data['key'] );
  591. $response = $this->remote_post( $ajax_url, $data, __FUNCTION__ );
  592. ob_start();
  593. $this->display_errors();
  594. $return = ob_get_clean();
  595. $return .= $response;
  596. }
  597. else {
  598. $return = $this->handle_table_backup();
  599. }
  600. $result = $this->end_ajax( $return );
  601. return $result;
  602. }
  603. // Pull and push need to be handled differently for obvious reasons, trigger different code depending on the migration intent (push or pull)
  604. if ( $_POST['intent'] == 'push' || $_POST['intent'] == 'savefile' ) {
  605. $this->maximum_chunk_size = $this->get_bottleneck();
  606. if ( isset( $_POST['bottleneck'] ) ) {
  607. $this->maximum_chunk_size = (int) $_POST['bottleneck'];
  608. }
  609. if ( $_POST['intent'] == 'push' ) {
  610. $this->remote_key = $_POST['key'];
  611. $this->remote_url = $_POST['url'];
  612. }
  613. $sql_dump_file_name = $this->get_upload_info( 'path' ) . DS;
  614. $sql_dump_file_name .= $this->format_dump_name( $_POST['dump_filename'] );
  615. if ( $_POST['intent'] == 'savefile' ) {
  616. $this->fp = $this->open( $sql_dump_file_name );
  617. }
  618. $result = $this->export_table( $_POST['table'] );
  619. if ( $_POST['intent'] == 'savefile' ) {
  620. $this->close( $this->fp );
  621. }
  622. ob_start();
  623. $this->display_errors();
  624. $maybe_errors = trim( ob_get_clean() );
  625. if( false === empty( $maybe_errors ) ) {
  626. $result = $this->end_ajax( $maybe_errors );
  627. return $result;
  628. }
  629. return $result;
  630. }
  631. else {
  632. $data = $_POST;
  633. if ( isset( $data['nonce'] ) ) {
  634. unset( $data['nonce'] );
  635. }
  636. $data['action'] = 'wpsdb_process_pull_request';
  637. $data['pull_limit'] = $this->get_sensible_pull_limit();
  638. if( is_multisite() ) {
  639. $data['path_current_site'] = $this->get_path_current_site();
  640. $data['domain_current_site'] = $this->get_domain_current_site();
  641. }
  642. $data['prefix'] = $wpdb->prefix;
  643. if ( isset( $data['sig'] ) ) {
  644. unset( $data['sig'] );
  645. }
  646. $ajax_url = trailingslashit( $data['url'] ) . 'wp-admin/admin-ajax.php';
  647. $data['primary_keys'] = stripslashes( $data['primary_keys'] );
  648. $data['sig'] = $this->create_signature( $data, $data['key'] );
  649. $response = $this->remote_post( $ajax_url, $data, __FUNCTION__ );
  650. ob_start();
  651. $this->display_errors();
  652. $maybe_errors = trim( ob_get_clean() );
  653. if( false === empty( $maybe_errors ) ) {
  654. $result = $this->end_ajax( $maybe_errors );
  655. return $result;
  656. }
  657. if( strpos( $response, ';' ) === false ) {
  658. $result = $this->end_ajax( $response );
  659. return $result;
  660. }
  661. // returned data is just a big string like this query;query;query;33
  662. // need to split this up into a chunk and row_tracker
  663. $row_information = trim( substr( strrchr( $response, "\n" ), 1 ) );
  664. $row_information = explode( ',', $row_information );
  665. $chunk = substr( $response, 0, strrpos( $response, ";\n" ) + 1 );
  666. if ( ! empty( $chunk ) ) {
  667. $process_chunk_result = $this->process_chunk( $chunk );
  668. if( true !== $process_chunk_result ) {
  669. $result = $this->end_ajax( $process_chunk_result );
  670. return $result;
  671. }
  672. }
  673. $result = $this->end_ajax( json_encode(
  674. array(
  675. 'current_row' => $row_information[0],
  676. 'primary_keys' => $row_information[1]
  677. )
  678. ) );
  679. }
  680. return $result;
  681. }
  682. function respond_to_backup_remote_table() {
  683. $filtered_post = $this->filter_post_elements( $_POST, array( 'action', 'intent', 'url', 'key', 'table', 'form_data', 'stage', 'bottleneck', 'prefix', 'current_row', 'dump_filename', 'last_table', 'gzip', 'primary_keys', 'path_current_site', 'domain_current_site' ) );
  684. $filtered_post['primary_keys'] = stripslashes( $filtered_post['primary_keys'] );
  685. if ( ! $this->verify_signature( $filtered_post, $this->settings['key'] ) ) {
  686. $error_msg = $this->invalid_content_verification_error . ' (#137)';
  687. $this->log_error( $error_msg, $filtered_post );
  688. $result = $this->end_ajax( $error_msg );
  689. return $result;
  690. }
  691. $this->form_data = $this->parse_migration_form_data( $_POST['form_data'] );
  692. $result = $this->handle_table_backup();
  693. return $result;
  694. }
  695. function handle_table_backup() {
  696. if ( isset( $this->form_data['gzip_file'] ) ) {
  697. unset( $this->form_data['gzip_file'] );
  698. }
  699. $this->maximum_chunk_size = $this->get_bottleneck();
  700. $sql_dump_file_name = $this->get_upload_info( 'path' ) . DS;
  701. $sql_dump_file_name .= $this->format_dump_name( $_POST['dump_filename'] );
  702. $file_created = file_exists( $sql_dump_file_name );
  703. $this->fp = $this->open( $sql_dump_file_name );
  704. if ( $file_created == false ) {
  705. $this->db_backup_header();
  706. }
  707. $result = $this->export_table( $_POST['table'] );
  708. if( isset( $this->fp ) ) {
  709. $this->close( $this->fp );
  710. }
  711. ob_start();
  712. $this->display_errors();
  713. $maybe_errors = trim( ob_get_clean() );
  714. if( false === empty( $maybe_errors ) ) {
  715. $result = $this->end_ajax( $maybe_errors );
  716. return $result;
  717. }
  718. return $result;
  719. }
  720. function respond_to_process_pull_request() {
  721. $filtered_post = $this->filter_post_elements( $_POST, array( 'action', 'intent', 'url', 'key', 'table', 'form_data', 'stage', 'bottleneck', 'prefix', 'current_row', 'dump_filename', 'pull_limit', 'last_table', 'gzip', 'primary_keys', 'path_current_site', 'domain_current_site' ) );
  722. // verification will fail unless we strip slashes on primary_keys and form_data
  723. $filtered_post['primary_keys'] = stripslashes( $filtered_post['primary_keys'] );
  724. $filtered_post['form_data'] = stripslashes( $filtered_post['form_data'] );
  725. if( isset( $filtered_post['path_current_site'] ) ) {
  726. $filtered_post['path_current_site'] = stripslashes( $filtered_post['path_current_site'] );
  727. }
  728. if ( ! $this->verify_signature( $filtered_post, $this->settings['key'] ) ) {
  729. $error_msg = $this->invalid_content_verification_error . ' (#124)';
  730. $this->log_error( $error_msg, $filtered_post );
  731. $result = $this->end_ajax( $error_msg );
  732. return $result;
  733. }
  734. if ( $this->settings['allow_pull'] != true ) {
  735. $result = $this->end_ajax( __( '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. (#132)', 'wp-sync-db' ) );
  736. return $result;
  737. }
  738. $this->maximum_chunk_size = $_POST['pull_limit'];
  739. $this->export_table( $_POST['table'] );
  740. ob_start();
  741. $this->display_errors();
  742. $return = ob_get_clean();
  743. $result = $this->end_ajax( $return );
  744. return $result;
  745. }
  746. // Occurs right before the first table is migrated / backed up during the migration process
  747. // Does a quick check to make sure the verification string is valid and also opens / creates files for writing to (if required)
  748. function ajax_initiate_migration() {
  749. $this->check_ajax_referer( 'initiate-migration' );
  750. $this->form_data = $this->parse_migration_form_data( $_POST['form_data'] );
  751. if ( $_POST['intent'] == 'savefile' ) {
  752. $return = array(
  753. 'code' => 200,
  754. 'message' => 'OK',
  755. 'body' => json_encode( array( 'error' => 0 ) ),
  756. );
  757. $return['dump_filename'] = basename( $this->get_sql_dump_info( 'migrate', 'path' ) );
  758. $return['dump_url'] = $this->get_sql_dump_info( 'migrate', 'url' );
  759. $dump_filename_no_extension = substr( $return['dump_filename'], 0, -4 );
  760. $create_alter_table_query = $this->get_create_alter_table_query();
  761. // sets up our table to store 'ALTER' queries
  762. $process_chunk_result = $this->process_chunk( $create_alter_table_query );
  763. if( true !== $process_chunk_result ) {
  764. $result = $this->end_ajax( $process_chunk_result );
  765. return $result;
  766. }
  767. if ( $this->gzip() && isset( $this->form_data['gzip_file'] ) ) {
  768. $return['dump_filename'] .= '.gz';
  769. $return['dump_url'] .= '.gz';
  770. }
  771. $this->fp = $this->open( $this->get_upload_info( 'path' ) . DS . $return['dump_filename'] );
  772. $this->db_backup_header();
  773. $this->close( $this->fp );
  774. $return['dump_filename'] = $dump_filename_no_extension;
  775. }
  776. else { // does one last check that our verification string is valid
  777. $data = array(
  778. 'action' => 'wpsdb_remote_initiate_migration',
  779. 'intent' => $_POST['intent'],
  780. 'form_data' => $_POST['form_data'],
  781. );
  782. $data['sig'] = $this->create_signature( $data, $_POST['key'] );
  783. $ajax_url = trailingslashit( $_POST['url'] ) . 'wp-admin/admin-ajax.php';
  784. $response = $this->remote_post( $ajax_url, $data, __FUNCTION__ );
  785. if ( false === $response ) {
  786. $return = array( 'wpsdb_error' => 1, 'body' => $this->error );
  787. $result = $this->end_ajax( json_encode( $return ) );
  788. return $result;
  789. }
  790. $return = @unserialize( trim( $response ) );
  791. if ( false === $return ) {
  792. $error_msg = __( 'Failed attempting to unserialize the response from the remote server. Please contact support.', 'wp-sync-db' );
  793. $return = array( 'wpsdb_error' => 1, 'body' => $error_msg );
  794. $this->log_error( $error_msg, $response );
  795. $result = $this->end_ajax( json_encode( $return ) );
  796. return $result;
  797. }
  798. if ( isset( $return['error'] ) && $return['error'] == 1 ) {
  799. $return = array( 'wpsdb_error' => 1, 'body' => $return['message'] );
  800. $result = $this->end_ajax( json_encode( $return ) );
  801. return $result;
  802. }
  803. if( $_POST['intent'] == 'pull' ) {
  804. // sets up our table to store 'ALTER' queries
  805. $create_alter_table_query = $this->get_create_alter_table_query();
  806. $process_chunk_result = $this->process_chunk( $create_alter_table_query );
  807. if( true !== $process_chunk_result ) {
  808. $result = $this->end_ajax( $process_chunk_result );
  809. return $result;
  810. }
  811. }
  812. if( ! empty( $this->form_data['create_backup'] ) && $_POST['intent'] == 'pull' ) {
  813. $return['dump_filename'] = basename( $this->get_sql_dump_info( 'backup', 'path' ) );
  814. $return['dump_filename'] = substr( $return['dump_filename'], 0, -4 );
  815. $return['dump_url'] = $this->get_sql_dump_info( 'backup', 'url' );
  816. }
  817. }
  818. $return['dump_filename'] = ( empty( $return['dump_filename'] ) ) ? '' : $return['dump_filename'];
  819. $return['dump_url'] = ( empty( $return['dump_url'] ) ) ? '' : $return['dump_url'];
  820. $result = $this->end_ajax( json_encode( $return ) );
  821. return $result;
  822. }
  823. // End point for the above remote_post call, ensures that the verification string is valid before continuing with the migration
  824. function respond_to_remote_initiate_migration() {
  825. $return = array();
  826. $filtered_post = $this->filter_post_elements( $_POST, array( 'action', 'intent', 'form_data' ) );
  827. if ( $this->verify_signature( $filtered_post, $this->settings['key'] ) ) {
  828. if ( isset( $this->settings['allow_' . $_POST['intent']] ) && ( true === $this->settings['allow_' . $_POST['intent']] || 1 === $this->settings['allow_' . $_POST['intent']] ) ) {
  829. $return['error'] = 0;
  830. }
  831. else {
  832. $return['error'] = 1;
  833. if( $_POST['intent'] == 'pull' ) {
  834. $intent = __( 'pull', 'wp-sync-db' );
  835. }
  836. else {
  837. $intent = __( 'push', 'wp-sync-db' );
  838. }
  839. $return['message'] = sprintf( __( 'The connection succeeded but the remote site is configured to reject %s connections. You can change this in the "settings" tab on the remote site. (#110)', 'wp-sync-db'), $intent );
  840. }
  841. }
  842. else {
  843. $return['error'] = 1;
  844. $error_msg = $this->invalid_content_verification_error . ' (#111)';
  845. $this->log_error( $error_msg, $filtered_post );
  846. $return['message'] = $error_msg;
  847. }
  848. $this->form_data = $this->parse_migration_form_data( $_POST['form_data'] );
  849. if( ! empty( $this->form_data['create_backup'] ) && $_POST['intent'] == 'push' ) {
  850. $return['dump_filename'] = basename( $this->get_sql_dump_info( 'backup', 'path' ) );
  851. $return['dump_filename'] = substr( $return['dump_filename'], 0, -4 );
  852. $return['dump_url'] = $this->get_sql_dump_info( 'backup', 'url' );
  853. }
  854. if( $_POST['intent'] == 'push' ) {
  855. // sets up our table to store 'ALTER' queries
  856. $create_alter_table_query = $this->get_create_alter_table_query();
  857. $process_chunk_result = $this->process_chunk( $create_alter_table_query );
  858. if( true !== $process_chunk_result ) {
  859. $result = $this->end_ajax( $process_chunk_result );
  860. return $result;
  861. }
  862. }
  863. $result = $this->end_ajax( serialize( $return ) );
  864. return $result;
  865. }
  866. function ajax_save_profile() {
  867. $this->check_ajax_referer( 'save-profile' );
  868. $profile = $this->parse_migration_form_data( $_POST['profile'] );
  869. $profile = wp_parse_args( $profile, $this->checkbox_options );
  870. if ( isset( $profile['save_migration_profile_option'] ) && $profile['save_migration_profile_option'] == 'new' ) {
  871. $profile['name'] = $profile['create_new_profile'];
  872. $this->settings['profiles'][] = $profile;
  873. }
  874. else {
  875. $key = $profile['save_migration_profile_option'];
  876. $name = $this->settings['profiles'][$key]['name'];
  877. $this->settings['profiles'][$key] = $profile;
  878. $this->settings['profiles'][$key]['name'] = $name;
  879. }
  880. update_option( 'wpsdb_settings', $this->settings );
  881. end( $this->settings['profiles'] );
  882. $key = key( $this->settings['profiles'] );
  883. $result = $this->end_ajax( $key );
  884. return $result;
  885. }
  886. function ajax_save_setting() {
  887. $this->check_ajax_referer( 'save-setting' );
  888. $this->settings[$_POST['setting']] = ( $_POST['checked'] == 'false' ? false : true );
  889. update_option( 'wpsdb_settings', $this->settings );
  890. $result = $this->end_ajax();
  891. return $result;
  892. }
  893. function ajax_delete_migration_profile() {
  894. $this->check_ajax_referer( 'delete-migration-profile' );
  895. $key = absint( $_POST['profile_id'] );
  896. --$key;
  897. $return = '';
  898. if ( isset( $this->settings['profiles'][$key] ) ) {
  899. unset( $this->settings['profiles'][$key] );
  900. update_option( 'wpsdb_settings', $this->settings );
  901. }
  902. else {
  903. $return = '-1';
  904. }
  905. $result = $this->end_ajax( $return );
  906. return $result;
  907. }
  908. function ajax_reset_api_key() {
  909. $this->check_ajax_referer( 'reset-api-key' );
  910. $this->settings['key'] = $this->generate_key();
  911. update_option( 'wpsdb_settings', $this->settings );
  912. $result = $this->end_ajax( sprintf( "%s\n%s", site_url( '', 'https' ), $this->settings['key'] ) );
  913. return $result;
  914. }
  915. // AJAX endpoint for when the user pastes into the connection info box (or when they click "connect")
  916. // Responsible for contacting the remote website and retrieving info and testing the verification string
  917. function ajax_verify_connection_to_remote_site() {
  918. $this->check_ajax_referer( 'verify-connection-to-remote-site' );
  919. $data = array(
  920. 'action' => 'wpsdb_verify_connection_to_remote_site',
  921. 'intent' => $_POST['intent']
  922. );
  923. $data['sig'] = $this->create_signature( $data, $_POST['key'] );
  924. $ajax_url = trailingslashit( $_POST['url'] ) . 'wp-admin/admin-ajax.php';
  925. $timeout = apply_filters( 'wpsdb_prepare_remote_connection_timeout', 10 );
  926. $response = $this->remote_post( $ajax_url, $data, __FUNCTION__, compact( 'timeout' ), true );
  927. $url_bits = parse_url( $this->attempting_to_connect_to );
  928. $return = $response;
  929. $alt_action = '';
  930. if ( false === $response ) {
  931. $return = array( 'wpsdb_error' => 1, 'body' => $this->error );
  932. $result = $this->end_ajax( json_encode( $return ) );
  933. return $result;
  934. }
  935. $response = unserialize( trim( $response ) );
  936. if ( false === $response ) {
  937. $error_msg = __( 'Failed attempting to unserialize the response from the remote server. Please contact support.', 'wp-sync-db' );
  938. $return = array( 'wpsdb_error' => 1, 'body' => $error_msg );
  939. $this->log_error( $error_msg );
  940. $result = $this->end_ajax( json_encode( $return ) );
  941. return $result;
  942. }
  943. if ( isset( $response['error'] ) && $response['error'] == 1 ) {
  944. $return = array( 'wpsdb_error' => 1, 'body' => $response['message'] );
  945. $this->log_error( $response['message'], $response );
  946. $result = $this->end_ajax( json_encode( $return ) );
  947. return $result;
  948. }
  949. if ( isset( $_POST['convert_post_type_selection'] ) && '1' == $_POST['convert_post_type_selection'] ) {
  950. $profile = (int) $_POST['profile'];
  951. unset( $this->settings['profiles'][$profile]['post_type_migrate_option'] );
  952. $this->settings['profiles'][$profile]['exclude_post_types'] = '1';
  953. $this->settings['profiles'][$profile]['select_post_types'] = array_values( array_diff( $response['post_types'], $this->settings['profiles'][$profile]['select_post_types'] ) );
  954. $response['select_post_types'] = $this->settings['profiles'][$profile]['select_post_types'];
  955. update_option( 'wpsdb_settings', $this->settings );
  956. }
  957. $response['scheme'] = $url_bits['scheme'];
  958. $return = json_encode( $response );
  959. $result = $this->end_ajax( $return );
  960. return $result;
  961. }
  962. // End point for the above remote_post call, returns table information, absolute file path, table prefix, etc
  963. function respond_to_verify_connection_to_remote_site() {
  964. global $wpdb;
  965. $return = array();
  966. $filtered_post = $this->filter_post_elements( $_POST, array( 'action', 'intent' ) );
  967. if ( !$this->verify_signature( $filtered_post, $this->settings['key'] ) ) {
  968. $return['error'] = 1;
  969. $return['message'] = $this->invalid_content_verification_error . ' (#120) <a href="#" class="try-again js-action-link">' . __( 'Try again?', 'wp-sync-db' ) . '</a>';
  970. $this->log_error( $this->invalid_content_verification_error . ' (#120)', $filtered_post );
  971. $result = $this->end_ajax( serialize( $return ) );
  972. return $result;
  973. }
  974. if ( !isset( $this->settings['allow_' . $_POST['intent']] ) || $this->settings['allow_' . $_POST['intent']] != true ) {
  975. $return['error'] = 1;
  976. if( $_POST['intent'] == 'pull' ) {
  977. $intent = __( 'pull', 'wp-sync-db' );
  978. }
  979. else {
  980. $intent = __( 'push', 'wp-sync-db' );
  981. }
  982. $return['message'] = sprintf( __( 'The connection succeeded but the remote site is configured to reject %s connections. You can change this in the "settings" tab on the remote site. (#122) <a href="#" class="try-again js-action-link">Try again?</a>', 'wp-sync-db' ), $intent );
  983. $result = $this->end_ajax( serialize( $return ) );
  984. return $result;
  985. }
  986. $return['tables'] = $this->get_tables();
  987. $return['prefixed_tables'] = $this->get_tables( 'prefix' );
  988. $return['table_sizes'] = $this->get_table_sizes();
  989. $return['table_rows'] = $this->get_table_row_count();
  990. $return['table_sizes_hr'] = array_map( array( $this, 'format_table_sizes' ), $this->get_table_sizes() );
  991. $return['path'] = $this->absolute_root_file_path;
  992. $return['url'] = home_url();
  993. $return['prefix'] = $wpdb->prefix;
  994. $return['bottleneck'] = $this->get_bottleneck();
  995. $return['error'] = 0;
  996. $return['plugin_version'] = $this->plugin_version;
  997. $return['domain'] = $this->get_domain_current_site();
  998. $return['path_current_site'] = $this->get_path_current_site();
  999. $return['uploads_dir'] = $this->get_short_uploads_dir();
  1000. $return['gzip'] = ( $this->gzip() ? '1' : '0' );
  1001. $return['post_types'] = $this->get_post_types();
  1002. $return['write_permissions'] = ( is_writeable( $this->get_upload_info( 'path' ) ) ? '1' : '0' );
  1003. $return['upload_dir_long'] = $this->get_upload_info( 'path' );
  1004. $return['temp_prefix'] = $this->temp_prefix;
  1005. $return = apply_filters( 'wpsdb_establish_remote_connection_data', $return );
  1006. $result = $this->end_ajax( serialize( $return ) );
  1007. return $result;
  1008. }
  1009. function format_table_sizes( $size ) {
  1010. $size *= 1024;
  1011. return size_format( $size );
  1012. }
  1013. // Generates our secret key
  1014. function generate_key() {
  1015. $keyset = 'abcdefghijklmnopqrstuvqxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/';
  1016. $key = '';
  1017. for ( $i = 0; $i < 32; $i++ ) {
  1018. $key .= substr( $keyset, rand( 0, strlen( $keyset ) -1 ), 1 );
  1019. }
  1020. return $key;
  1021. }
  1022. function get_post_types() {
  1023. global $wpdb;
  1024. if( is_multisite() ) {
  1025. $tables = $this->get_tables();
  1026. $sql = "SELECT `post_type` FROM `{$wpdb->prefix}posts` ";
  1027. foreach( $tables as $table ) {
  1028. if( 0 == preg_match( '/' . $wpdb->prefix . '[0-9]+_posts/', $table ) ) continue;
  1029. $blog_id = str_replace( array( $wpdb->prefix, '_posts' ), array( '', '' ), $table );
  1030. $sql .= "UNION SELECT `post_type` FROM `{$wpdb->prefix}" . $blog_id . "_posts` ";
  1031. }
  1032. $sql .= ";";
  1033. $post_types = $wpdb->get_results( $sql, ARRAY_A );
  1034. }
  1035. else {
  1036. $post_types = $wpdb->get_results(
  1037. "SELECT DISTINCT `post_type`
  1038. FROM `{$wpdb->prefix}posts`
  1039. WHERE 1;", ARRAY_A
  1040. );
  1041. }
  1042. $return = array( 'revision' );
  1043. foreach( $post_types as $post_type ) {
  1044. $return[] = $post_type['post_type'];
  1045. }
  1046. return apply_filters( 'wpsdb_post_types', array_unique( $return ) );
  1047. }
  1048. // Retrieves the specified profile, if -1, returns the default profile
  1049. function get_profile( $profile_id ) {
  1050. --$profile_id;
  1051. if ( $profile_id == '-1' || ! isset( $this->settings['profiles'][$profile_id] ) ) {
  1052. return $this->default_profile;
  1053. }
  1054. return $this->settings['profiles'][$profile_id];
  1055. }
  1056. function get_table_row_count() {
  1057. global $wpdb;
  1058. $results = $wpdb->get_results( $wpdb->prepare(
  1059. 'SELECT table_name, TABLE_ROWS FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = %s', DB_NAME
  1060. ), ARRAY_A
  1061. );
  1062. $return = array();
  1063. foreach( $results as $results ) {
  1064. $return[$results['table_name']] = ( $results['TABLE_ROWS'] == 0 ? 1 : $results['TABLE_ROWS'] );
  1065. }
  1066. return $return;
  1067. }
  1068. function get_table_sizes( $scope = 'regular' ) {
  1069. global $wpdb;
  1070. $prefix = ( $scope == 'temp' ? $this->temp_prefix : $wpdb->prefix );
  1071. $results = $wpdb->get_results( $wpdb->prepare(
  1072. 'SELECT TABLE_NAME AS "table",
  1073. ROUND((data_length + index_length)/1024,0) AS "size"
  1074. FROM information_schema.TABLES
  1075. WHERE information_schema.TABLES.table_schema="%s"
  1076. AND information_schema.TABLES.table_type="%s"', DB_NAME, "BASE TABLE"
  1077. ), ARRAY_A
  1078. );
  1079. $return = array();
  1080. foreach ( $results as $result ) {
  1081. $return[$result['table']] = $result['size'];
  1082. }
  1083. return apply_filters( 'wpsdb_table_sizes', $return, $scope );
  1084. }
  1085. function get_post_max_size() {
  1086. $val = trim( ini_get( 'post_max_size' ) );
  1087. $last = strtolower( $val[ strlen( $val ) - 1 ] );
  1088. switch ( $last ) {
  1089. case 'g':
  1090. $val *= 1024;
  1091. case 'm':
  1092. $val *= 1024;
  1093. case 'k':
  1094. $val *= 1024;
  1095. }
  1096. return $val;
  1097. }
  1098. function get_sensible_pull_limit() {
  1099. return apply_filters( 'wpsdb_sensible_pull_limit', min( 26214400, $this->settings['max_request'] ) );
  1100. }
  1101. function get_bottleneck( $type = 'regular' ) {
  1102. $suhosin_limit = false;
  1103. $suhosin_request_limit = false;
  1104. $suhosin_post_limit = false;
  1105. if ( function_exists( 'ini_get' ) ) {
  1106. $suhosin_request_limit = $this->return_bytes( ini_get( 'suhosin.request.max_value_length' ) );
  1107. $suhosin_post_limit = $this->return_bytes( ini_get( 'suhosin.post.max_value_length' ) );
  1108. }
  1109. if ( $suhosin_request_limit && $suhosin_post_limit ) {
  1110. $suhosin_limit = min( $suhosin_request_limit, $suhosin_post_limit );
  1111. }
  1112. // we have to account for HTTP headers and other bloating, here we minus 1kb for bloat
  1113. $post_max_upper_size = apply_filters( 'wpsdb_post_max_upper_size', 26214400 );
  1114. $calculated_bottleneck = min( ( $this->get_post_max_size() - 1024 ), $post_max_upper_size );
  1115. if ( $suhosin_limit ) {
  1116. $calculated_bottleneck = min( $calculated_bottleneck, $suhosin_limit - 1024 );
  1117. }
  1118. if( $type != 'max' ) {
  1119. $calculated_bottleneck = min( $calculated_bottleneck, $this->settings['max_request'] );
  1120. }
  1121. return apply_filters( 'wpsdb_bottleneck', $calculated_bottleneck );
  1122. }
  1123. function format_dump_name( $dump_name ) {
  1124. $extension = '.sql';
  1125. $dump_name = sanitize_file_name( $dump_name );
  1126. if ( $this->gzip() && isset( $this->form_data['gzip_file'] ) ) {
  1127. $extension .= '.gz';
  1128. }
  1129. return $dump_name . $extension;
  1130. }
  1131. function options_page() {
  1132. ?>
  1133. <div class="wrap wpsdb">
  1134. <div id="icon-tools" class="icon32"><br /></div><h2>Migrate DB</h2>
  1135. <h2 class="nav-tab-wrapper"><a href="#" class="nav-tab nav-tab-active js-action-link migrate" data-div-name="migrate-tab"><?php _e( 'Migrate', 'wp-sync-db' ); ?></a><a href="#" class="nav-tab js-action-link settings" data-div-name="settings-tab"><?php _e( 'Settings', 'wp-sync-db' ); ?></a><a href="#" class="nav-tab js-action-link help" data-div-name="help-tab"><?php _e( 'Help', 'wp-sync-db' ); ?></a></h2>
  1136. <?php do_action( 'wpsdb_notices' ); ?>
  1137. <?php
  1138. $hide_warning = apply_filters( 'wpsdb_hide_outdated_addons_warning', false );
  1139. foreach( $this->addons as $addon_basename => $addon ) {
  1140. if( false == $this->is_addon_outdated( $addon_basename ) || false == is_plugin_active( $addon_basename ) ) continue;
  1141. $update_url = wp_nonce_url( network_admin_url( 'update.php?action=upgrade-plugin&plugin=' . urlencode( $addon_basename ) ), 'upgrade-plugin_' . $addon_basename );
  1142. $addon_slug = current( explode( '/', $addon_basename ) );
  1143. if ( isset( $GLOBALS['wpsdb_meta'][$addon_slug]['version'] ) ) {
  1144. $version = ' (' . $GLOBALS['wpsdb_meta'][$addon_slug]['version'] . ')';
  1145. }
  1146. else {
  1147. $version = '';
  1148. }
  1149. ?>
  1150. <div class="updated warning inline-message">
  1151. <strong>Update Required</strong> &mdash;
  1152. <?php printf( __( 'The version of the %1$s addon you have installed%2$s is out-of-date and will not work with this version WP Sync DB. <a href="%3$s">Update Now</a>', 'wp-sync-db' ), $addon['name'], $version, $update_url ); ?>
  1153. </div>
  1154. <?php
  1155. }
  1156. $hide_warning = apply_filters( 'wpsdb_hide_safe_mode_warning', false );
  1157. if ( function_exists( 'ini_get' ) && ini_get( 'safe_mode' ) && !$hide_warning ) { ?>
  1158. <div class="updated warning inline-message">
  1159. <?php
  1160. _e( "<strong>PHP Safe Mode Enabled</strong> &mdash; We do not officially sup…

Large files files are truncated, but you can click here to view the full file