PageRenderTime 55ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 1ms

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

https://gitlab.com/mattswann/launch-housing
PHP | 399 lines | 334 code | 60 blank | 5 comment | 97 complexity | 86af381dae73802b5ea4545a43b44ea9 MD5 | raw file
  1. <?php
  2. class WPSDB_Base {
  3. protected $settings;
  4. protected $plugin_file_path;
  5. protected $plugin_dir_path;
  6. protected $plugin_slug;
  7. protected $plugin_folder_name;
  8. protected $plugin_basename;
  9. protected $plugin_base;
  10. protected $plugin_version;
  11. protected $template_dir;
  12. protected $plugin_title;
  13. protected $transient_timeout;
  14. protected $transient_retry_timeout;
  15. protected $multipart_boundary = 'bWH4JVmYCnf6GfXacrcc';
  16. protected $attempting_to_connect_to;
  17. protected $error;
  18. protected $temp_prefix = '_mig_';
  19. protected $invalid_content_verification_error;
  20. protected $addons;
  21. protected $doing_cli_migration = false;
  22. function __construct( $plugin_file_path ) {
  23. $this->settings = get_option( 'wpsdb_settings' );
  24. $this->addons = array(
  25. 'wp-sync-db-media-files/wp-sync-db-media-files.php' => array(
  26. 'name' => 'Media Files',
  27. 'required_version' => '1.1.4b1',
  28. ),
  29. 'wp-sync-db-cli/wp-sync-db-cli.php' => array(
  30. 'name' => 'CLI',
  31. 'required_version' => '1.0b1',
  32. )
  33. );
  34. $this->invalid_content_verification_error = __( 'Invalid content verification signature, please verify the connection information on the remote site and try again.', 'wp-sync-db' );
  35. $this->transient_timeout = 60 * 60 * 12;
  36. $this->transient_retry_timeout = 60 * 60 * 2;
  37. $this->plugin_file_path = $plugin_file_path;
  38. $this->plugin_dir_path = plugin_dir_path( $plugin_file_path );
  39. $this->plugin_folder_name = basename( $this->plugin_dir_path );
  40. $this->plugin_basename = plugin_basename( $plugin_file_path );
  41. $this->template_dir = $this->plugin_dir_path . 'template' . DS;
  42. $this->plugin_title = ucwords( str_ireplace( '-', ' ', basename( $plugin_file_path ) ) );
  43. $this->plugin_title = str_ireplace( array( 'db', 'wp', '.php' ), array( 'DB', 'WP', '' ), $this->plugin_title );
  44. if ( is_multisite() ) {
  45. $this->plugin_base = 'settings.php?page=wp-sync-db';
  46. }
  47. else {
  48. $this->plugin_base = 'tools.php?page=wp-sync-db';
  49. }
  50. // allow devs to change the temporary prefix applied to the tables
  51. $this->temp_prefix = apply_filters( 'wpsdb_temporary_prefix', $this->temp_prefix );
  52. }
  53. function template( $template ) {
  54. include $this->template_dir . $template . '.php';
  55. }
  56. function open_ssl_enabled() {
  57. if ( defined( 'OPENSSL_VERSION_TEXT' ) ) {
  58. return true;
  59. }
  60. else {
  61. return false;
  62. }
  63. }
  64. function set_time_limit() {
  65. if ( !function_exists( 'ini_get' ) || !ini_get( 'safe_mode' ) ) {
  66. @set_time_limit( 0 );
  67. }
  68. }
  69. function remote_post( $url, $data, $scope, $args = array(), $expecting_serial = false ) {
  70. $this->set_time_limit();
  71. if( function_exists( 'fsockopen' ) && strpos( $url, 'https://' ) === 0 && $scope == 'ajax_verify_connection_to_remote_site' ) {
  72. $url_parts = parse_url( $url );
  73. $host = $url_parts['host'];
  74. if( $pf = @fsockopen( $host, 443, $err, $err_string, 1 ) ) {
  75. // worked
  76. fclose( $pf );
  77. }
  78. else {
  79. // failed
  80. $url = substr_replace( $url, 'http', 0, 5 );
  81. }
  82. }
  83. $sslverify = ( $this->settings['verify_ssl'] == 1 ? true : false );
  84. $default_remote_post_timeout = apply_filters( 'wpsdb_default_remote_post_timeout', 60 * 20 );
  85. $args = wp_parse_args( $args, array(
  86. 'timeout' => $default_remote_post_timeout,
  87. 'blocking' => true,
  88. 'sslverify' => $sslverify,
  89. ) );
  90. $args['method'] = 'POST';
  91. if( ! isset( $args['body'] ) ) {
  92. $args['body'] = $this->array_to_multipart( $data );
  93. }
  94. $args['headers']['Content-Type'] = 'multipart/form-data; boundary=' . $this->multipart_boundary;
  95. $args['headers']['Referer'] = network_admin_url( 'admin-ajax.php' );
  96. $this->attempting_to_connect_to = $url;
  97. $response = wp_remote_post( $url, $args );
  98. if ( ! is_wp_error( $response ) ) {
  99. $response['body'] = trim( $response['body'], "\xef\xbb\xbf" );
  100. }
  101. if ( is_wp_error( $response ) ) {
  102. if( strpos( $url, 'https://' ) === 0 && $scope == 'ajax_verify_connection_to_remote_site' ) {
  103. return $this->retry_remote_post( $url, $data, $scope, $args, $expecting_serial );
  104. }
  105. else if( isset( $response->errors['http_request_failed'][0] ) && strstr( $response->errors['http_request_failed'][0], 'timed out' ) ) {
  106. $this->error = sprintf( __( 'The connection to the remote server has timed out, no changes have been committed. (#134 - scope: %s)', 'wp-sync-db' ), $scope );
  107. }
  108. else if ( 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 connect to host' ) ) ) {
  109. $this->error = sprintf( __( 'We could not find: %s. Are you sure this is the correct URL?', 'wp-sync-db' ), $_POST['url'] );
  110. $url_bits = parse_url( $_POST['url'] );
  111. if( strstr( $_POST['url'], 'dev.' ) || strstr( $_POST['url'], '.dev' ) || ! strstr( $url_bits['host'], '.' ) ) {
  112. $this->error .= '<br />';
  113. if( $_POST['intent'] == 'pull' ) {
  114. $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-sync-db' );
  115. }
  116. else {
  117. $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-sync-db' );
  118. }
  119. }
  120. }
  121. else {
  122. $this->error = sprintf( __( 'The connection failed, an unexpected error occurred, please contact support. (#121 - scope: %s)', 'wp-sync-db' ), $scope );
  123. }
  124. $this->log_error( $this->error, $response );
  125. return false;
  126. }
  127. elseif ( (int) $response['response']['code'] < 200 || (int) $response['response']['code'] > 399 ) {
  128. if( strpos( $url, 'https://' ) === 0 && $scope == 'ajax_verify_connection_to_remote_site' ) {
  129. return $this->retry_remote_post( $url, $data, $scope, $args, $expecting_serial );
  130. }
  131. else if( $response['response']['code'] == '401' ) {
  132. $this->error = __( 'The remote site is protected with Basic Authentication. Please enter the username and password above to continue. (401 Unauthorized)', 'wp-sync-db' );
  133. $this->log_error( $this->error, $response );
  134. return false;
  135. }
  136. else {
  137. $this->error = sprintf( __( 'Unable to connect to the remote server, please check the connection details - %1$s %2$s (#129 - scope: %3$s)', 'wp-sync-db' ), $response['response']['code'], $response['response']['message'], $scope );
  138. $this->log_error( $this->error, $response );
  139. return false;
  140. }
  141. }
  142. elseif ( $expecting_serial && is_serialized( $response['body'] ) == false ) {
  143. if( strpos( $url, 'https://' ) === 0 && $scope == 'ajax_verify_connection_to_remote_site' ) {
  144. return $this->retry_remote_post( $url, $data, $scope, $args, $expecting_serial );
  145. }
  146. $this->error = __( 'There was a problem with the AJAX request, we were expecting a serialized response, instead we received:<br />', 'wp-sync-db' ) . htmlentities( $response['body'] );
  147. $this->log_error( $this->error, $response );
  148. return false;
  149. }
  150. elseif ( $response['body'] === '0' ) {
  151. if( strpos( $url, 'https://' ) === 0 && $scope == 'ajax_verify_connection_to_remote_site' ) {
  152. return $this->retry_remote_post( $url, $data, $scope, $args, $expecting_serial );
  153. }
  154. $this->error = sprintf( __( 'WP Sync DB does not seem to be installed or active on the remote site. (#131 - scope: %s)', 'wp-sync-db' ), $scope );
  155. $this->log_error( $this->error, $response );
  156. return false;
  157. }
  158. elseif ( $expecting_serial && is_serialized( $response['body'] ) == true && $scope == 'ajax_verify_connection_to_remote_site' ) {
  159. $unserialized_response = unserialize( $response['body'] );
  160. if ( isset( $unserialized_response['error'] ) && '1' == $unserialized_response['error'] && strpos( $url, 'https://' ) === 0 ) {
  161. return $this->retry_remote_post( $url, $data, $scope, $args, $expecting_serial );
  162. }
  163. }
  164. return $response['body'];
  165. }
  166. function retry_remote_post( $url, $data, $scope, $args = array(), $expecting_serial = false ) {
  167. $url = substr_replace( $url, 'http', 0, 5 );
  168. if( $response = $this->remote_post( $url, $data, $scope, $args, $expecting_serial ) ) {
  169. return $response;
  170. }
  171. return false;
  172. }
  173. function array_to_multipart( $data ) {
  174. if ( !$data || !is_array( $data ) ) {
  175. return $data;
  176. }
  177. $result = '';
  178. foreach ( $data as $key => $value ) {
  179. $result .= '--' . $this->multipart_boundary . "\r\n" .
  180. sprintf( 'Content-Disposition: form-data; name="%s"', $key );
  181. if ( 'chunk' == $key ) {
  182. if ( $data['chunk_gzipped'] ) {
  183. $result .= "; filename=\"chunk.txt.gz\"\r\nContent-Type: application/x-gzip";
  184. }
  185. else {
  186. $result .= "; filename=\"chunk.txt\"\r\nContent-Type: text/plain;";
  187. }
  188. }
  189. else {
  190. $result .= "\r\nContent-Type: text/plain; charset=" . get_option( 'blog_charset' );
  191. }
  192. $result .= "\r\n\r\n" . $value . "\r\n";
  193. }
  194. $result .= "--" . $this->multipart_boundary . "--\r\n";
  195. return $result;
  196. }
  197. function file_to_multipart( $file ) {
  198. $result = '';
  199. if( false == file_exists( $file ) ) return false;
  200. $filetype = wp_check_filetype( $file );
  201. $contents = file_get_contents( $file );
  202. $result .= '--' . $this->multipart_boundary . "\r\n" .
  203. sprintf( 'Content-Disposition: form-data; name="media[]"; filename="%s"', basename( $file ) );
  204. $result .= sprintf( "\r\nContent-Type: %s", $filetype['type'] );
  205. $result .= "\r\n\r\n" . $contents . "\r\n";
  206. $result .= "--" . $this->multipart_boundary . "--\r\n";
  207. return $result;
  208. }
  209. function log_error( $wpsdb_error, $additional_error_var = false ){
  210. $error_header = "********************************************\n****** Log date: " . date( 'Y/m/d H:i:s' ) . " ******\n********************************************\n\n";
  211. $error = $error_header . "WPSDB Error: " . $wpsdb_error . "\n\n";
  212. if( ! empty( $this->attempting_to_connect_to ) ) {
  213. $error .= "Attempted to connect to: " . $this->attempting_to_connect_to . "\n\n";
  214. }
  215. if( $additional_error_var !== false ){
  216. $error .= print_r( $additional_error_var, true ) . "\n\n";
  217. }
  218. $log = get_option( 'wpsdb_error_log' );
  219. if( $log ) {
  220. $log = $log . $error;
  221. }
  222. else {
  223. $log = $error;
  224. }
  225. update_option( 'wpsdb_error_log', $log );
  226. }
  227. function display_errors() {
  228. if ( ! empty( $this->error ) ) {
  229. echo $this->error;
  230. $this->error = '';
  231. return true;
  232. }
  233. return false;
  234. }
  235. function filter_post_elements( $post_array, $accepted_elements ) {
  236. if ( isset( $post_array['form_data'] ) ) {
  237. $post_array['form_data'] = stripslashes( $post_array['form_data'] );
  238. }
  239. $accepted_elements[] = 'sig';
  240. return array_intersect_key( $post_array, array_flip( $accepted_elements ) );
  241. }
  242. function create_signature( $data, $key ) {
  243. if ( isset( $data['sig'] ) ) {
  244. unset( $data['sig'] );
  245. }
  246. $flat_data = implode( '', $data );
  247. return base64_encode( hash_hmac( 'sha1', $flat_data, $key, true ) );
  248. }
  249. function verify_signature( $data, $key ) {
  250. if( empty( $data['sig'] ) ) {
  251. return false;
  252. }
  253. if ( isset( $data['nonce'] ) ) {
  254. unset( $data['nonce'] );
  255. }
  256. $temp = $data;
  257. $computed_signature = $this->create_signature( $temp, $key );
  258. return $computed_signature === $data['sig'];
  259. }
  260. function diverse_array( $vector ) {
  261. $result = array();
  262. foreach( $vector as $key1 => $value1 )
  263. foreach( $value1 as $key2 => $value2 )
  264. $result[$key2][$key1] = $value2;
  265. return $result;
  266. }
  267. function set_time_limit_available() {
  268. if ( ! function_exists( 'set_time_limit' ) || ! function_exists( 'ini_get' ) ) return false;
  269. $current_max_execution_time = ini_get( 'max_execution_time' );
  270. $proposed_max_execution_time = ( $current_max_execution_time == 30 ) ? 31 : 30;
  271. @set_time_limit( $proposed_max_execution_time );
  272. $current_max_execution_time = ini_get( 'max_execution_time' );
  273. return ( $proposed_max_execution_time == $current_max_execution_time );
  274. }
  275. function get_plugin_name( $plugin = false ) {
  276. if ( !is_admin() ) return false;
  277. $plugin_basename = ( false !== $plugin ? $plugin : $this->plugin_basename );
  278. $plugins = get_plugins();
  279. if ( !isset( $plugins[$plugin_basename]['Name'] ) ) {
  280. return false;
  281. }
  282. return $plugins[$plugin_basename]['Name'];
  283. }
  284. function get_class_props() {
  285. return get_object_vars( $this );
  286. }
  287. // Get only the table beginning with our DB prefix or temporary prefix, also skip views
  288. function get_tables( $scope = 'regular' ) {
  289. global $wpdb;
  290. $prefix = ( $scope == 'temp' ? $this->temp_prefix : $wpdb->prefix );
  291. $tables = $wpdb->get_results( 'SHOW FULL TABLES', ARRAY_N );
  292. foreach ( $tables as $table ) {
  293. if ( ( ( $scope == 'temp' || $scope == 'prefix' ) && 0 !== strpos( $table[0], $prefix ) ) || $table[1] == 'VIEW' ) {
  294. continue;
  295. }
  296. $clean_tables[] = $table[0];
  297. }
  298. return apply_filters( 'wpsdb_tables', $clean_tables, $scope );
  299. }
  300. function plugins_dir() {
  301. $path = untrailingslashit( $this->plugin_dir_path );
  302. return substr( $path, 0, strrpos( $path, DS ) ) . DS;
  303. }
  304. function is_addon_outdated( $addon_basename ) {
  305. $addon_slug = current( explode( '/', $addon_basename ) );
  306. // If pre-1.1.2 version of Media Files addon, then it is outdated
  307. if ( ! isset( $GLOBALS['wpsdb_meta'][$addon_slug]['version'] ) ) return true;
  308. $installed_version = $GLOBALS['wpsdb_meta'][$addon_slug]['version'];
  309. $required_version = $this->addons[$addon_basename]['required_version'];
  310. return version_compare( $installed_version, $required_version, '<' );
  311. }
  312. function get_plugin_file_path() {
  313. return $this->plugin_file_path;
  314. }
  315. function set_cli_migration() {
  316. $this->doing_cli_migration = true;
  317. }
  318. function end_ajax( $return = false ) {
  319. if( defined( 'DOING_WPSDB_TESTS' ) || $this->doing_cli_migration ) {
  320. return ( false === $return ) ? NULL : $return;
  321. }
  322. echo ( false === $return ) ? '' : $return;
  323. exit;
  324. }
  325. function check_ajax_referer( $action ) {
  326. if ( defined( 'DOING_WPSDB_TESTS' ) || $this->doing_cli_migration ) return;
  327. $result = check_ajax_referer( $action, 'nonce', false );
  328. if ( false === $result ) {
  329. $return = array( 'wpsdb_error' => 1, 'body' => sprintf( __( 'Invalid nonce for: %s', 'wp-sync-db' ), $action ) );
  330. $this->end_ajax( json_encode( $return ) );
  331. }
  332. $cap = ( is_multisite() ) ? 'manage_network_options' : 'export';
  333. $cap = apply_filters( 'wpsdb_ajax_cap', $cap );
  334. if ( !current_user_can( $cap ) ) {
  335. $return = array( 'wpsdb_error' => 1, 'body' => sprintf( __( 'Access denied for: %s', 'wp-sync-db' ), $action ) );
  336. $this->end_ajax( json_encode( $return ) );
  337. }
  338. }
  339. }