PluginProbe
WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards / 5.5.73
WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards v5.5.73
5.5.83 5.5.82 5.5.81 5.5.80 5.5.79 5.5.77 5.5.76 5.5.75 5.5.73 5.5.72 5.5.22 5.5.23 5.5.29 5.5.3 5.5.31 5.5.32 5.5.34 5.5.35 5.5.36 5.5.37 5.5.4 5.5.40 5.5.41 5.5.42 5.5.43 All 159 releases
wp-data-access / WPDataAccess / API / WPDA_Actions.php

WPDA_Actions.php in WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards 5.5.73, at WPDataAccess/API/WPDA_Actions.php

766 lines 34.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace WPDataAccess\API;
4
5 use PDOException;
6 use WPDataAccess\Connection\WPDADB;
7 use WPDataAccess\Plugin_Table_Models\WPDA_Media_Model;
8 use WPDataAccess\Plugin_Table_Models\WPDA_Table_Settings_Model;
9 use WPDataAccess\Plugin_Table_Models\WPDA_User_Menus_Model;
10 use WPDataAccess\Utilities\WPDA_Mail;
11 use WPDataAccess\WPDA;
12 class WPDA_Actions extends WPDA_API_Core {
13 const WPDA_COPY_TABLE = 'wpda_copy_table';
14
15 protected $file_pointer;
16
17 protected $file_content;
18
19 public function register_rest_routes() {
20 register_rest_route( WPDA_API::WPDA_NAMESPACE, 'action/rename', array(
21 'methods' => array('POST'),
22 'callback' => array($this, 'action_rename'),
23 'permission_callback' => '__return_true',
24 'args' => array(
25 'dbs' => $this->get_param( 'dbs', __( 'Local database name or remote connection string (does not accept system schemas)', 'wp-data-access' ) ),
26 'from_tbl' => $this->get_param( 'tbl', __( 'Source table name (does not rename WordPress tables)', 'wp-data-access' ) ),
27 'to_tbl' => $this->get_param( 'tbl', __( 'Destination table name (cannot overwrite existing table)', 'wp-data-access' ) ),
28 ),
29 ) );
30 register_rest_route( WPDA_API::WPDA_NAMESPACE, 'action/copy', array(
31 'methods' => array('POST'),
32 'callback' => array($this, 'action_copy'),
33 'permission_callback' => '__return_true',
34 'args' => array(
35 'from_dbs' => $this->get_param( 'dbs', __( 'Source database name or remote connection string', 'wp-data-access' ) ),
36 'to_dbs' => $this->get_param( 'dbs', __( 'Destination database name or remote connection string', 'wp-data-access' ) ),
37 'from_tbl' => $this->get_param( 'tbl', __( 'Source table name', 'wp-data-access' ) ),
38 'to_tbl' => $this->get_param( 'tbl', __( 'Destination table name', 'wp-data-access' ) ),
39 'copy_data' => array(
40 'required' => true,
41 'type' => 'boolean',
42 'description' => __( 'Copy data from source to destination table', 'wp-data-access' ),
43 'sanitize_callback' => 'sanitize_text_field',
44 'validate_callback' => 'rest_validate_request_arg',
45 ),
46 'copy_key' => $this->get_param( 'copy_key' ),
47 ),
48 ) );
49 register_rest_route( WPDA_API::WPDA_NAMESPACE, 'action/copy/start', array(
50 'methods' => array('POST'),
51 'callback' => array($this, 'action_copy_start'),
52 'permission_callback' => '__return_true',
53 'args' => array(
54 'copy_key' => $this->get_param( 'copy_key' ),
55 ),
56 ) );
57 register_rest_route( WPDA_API::WPDA_NAMESPACE, 'action/copy/cancel', array(
58 'methods' => array('POST'),
59 'callback' => array($this, 'action_copy_cancel'),
60 'permission_callback' => '__return_true',
61 'args' => array(
62 'copy_key' => $this->get_param( 'copy_key' ),
63 ),
64 ) );
65 register_rest_route( WPDA_API::WPDA_NAMESPACE, 'action/truncate', array(
66 'methods' => array('POST'),
67 'callback' => array($this, 'action_truncate'),
68 'permission_callback' => '__return_true',
69 'args' => array(
70 'dbs' => $this->get_param( 'dbs', __( 'Local database name or remote connection string (does not accept system schemas)', 'wp-data-access' ) ),
71 'tbl' => $this->get_param( 'tbl', __( 'Source table name (does not truncate WordPress tables)', 'wp-data-access' ) ),
72 ),
73 ) );
74 register_rest_route( WPDA_API::WPDA_NAMESPACE, 'action/drop', array(
75 'methods' => array('POST'),
76 'callback' => array($this, 'action_drop'),
77 'permission_callback' => '__return_true',
78 'args' => array(
79 'dbs' => $this->get_param( 'dbs', __( 'Local database name or remote connection string (does not accept system schemas)', 'wp-data-access' ) ),
80 'tbl' => $this->get_param( 'tbl', __( 'Source table name (does not drop WordPress tables)', 'wp-data-access' ) ),
81 'typ' => $this->get_param( 'typ' ),
82 ),
83 ) );
84 register_rest_route( WPDA_API::WPDA_NAMESPACE, 'action/import', array(
85 'methods' => array('POST'),
86 'callback' => array($this, 'action_import'),
87 'permission_callback' => '__return_true',
88 ) );
89 register_rest_route( WPDA_API::WPDA_NAMESPACE, 'action/mail', array(
90 'methods' => array('POST'),
91 'callback' => array($this, 'action_mail'),
92 'permission_callback' => '__return_true',
93 'args' => array(
94 'to' => array(
95 'required' => false,
96 'type' => 'string',
97 'description' => __( 'To', 'wp-data-access' ),
98 'sanitize_callback' => 'sanitize_text_field',
99 'validate_callback' => 'rest_validate_request_arg',
100 ),
101 'subject' => array(
102 'required' => false,
103 'type' => 'string',
104 'description' => __( 'Subject', 'wp-data-access' ),
105 'sanitize_callback' => 'sanitize_text_field',
106 'validate_callback' => 'rest_validate_request_arg',
107 ),
108 'message' => array(
109 'required' => false,
110 'type' => 'string',
111 'description' => __( 'Message', 'wp-data-access' ),
112 'sanitize_callback' => 'sanitize_text_field',
113 'validate_callback' => 'rest_validate_request_arg',
114 ),
115 ),
116 ) );
117 register_rest_route( WPDA_API::WPDA_NAMESPACE, 'action/get_row_count', array(
118 'methods' => array('POST'),
119 'callback' => array($this, 'action_get_row_count'),
120 'permission_callback' => '__return_true',
121 'args' => array(
122 'dbs' => $this->get_param( 'dbs', __( 'Local database name or remote connection string', 'wp-data-access' ) ),
123 'tbl' => $this->get_param( 'tbl', __( 'Table name', 'wp-data-access' ) ),
124 ),
125 ) );
126 register_rest_route( WPDA_API::WPDA_NAMESPACE, 'action/update_row_count', array(
127 'methods' => array('POST'),
128 'callback' => array($this, 'action_update_row_count'),
129 'permission_callback' => '__return_true',
130 'args' => array(
131 'dbs' => $this->get_param( 'dbs', __( 'Local database name or remote connection string', 'wp-data-access' ) ),
132 'tbl' => $this->get_param( 'tbl', __( 'Table name', 'wp-data-access' ) ),
133 'cnt' => $this->get_param( 'row_count', __( 'Hard row count estimation', 'wp-data-access' ) ),
134 ),
135 ) );
136 }
137
138 public function action_update_row_count( $request ) {
139 if ( !$this->current_user_can_access() ) {
140 return $this->unauthorized();
141 }
142 if ( !$this->current_user_token_valid( $request ) ) {
143 return $this->invalid_nonce();
144 }
145 $dbs = $request->get_param( 'dbs' );
146 $tbl = $request->get_param( 'tbl' );
147 $cnt = $request->get_param( 'cnt' );
148 // Get table settings.
149 $settings_db = WPDA_Table_Settings_Model::query( $tbl, $dbs );
150 if ( isset( $settings_db[0]['wpda_table_settings'] ) ) {
151 // Convert string to JSON.
152 $settings = json_decode( $settings_db[0]['wpda_table_settings'], true );
153 if ( isset( $settings['table_settings']['row_count_estimate_value_hard'] ) ) {
154 // Store actual row count as hard estimate.
155 $settings['table_settings']['row_count_estimate_value_hard'] = $cnt;
156 // Save new hard row count.
157 WPDA_Table_Settings_Model::update( $tbl, json_encode( $settings ), $dbs );
158 }
159 return $this->WPDA_Rest_Response( "OK" );
160 } else {
161 WPDA::wpda_log_wp_error( "Error saving hard row count. Please try again later." );
162 }
163 }
164
165 public function action_get_row_count( $request ) {
166 if ( !$this->current_user_can_access() ) {
167 return $this->unauthorized();
168 }
169 if ( !$this->current_user_token_valid( $request ) ) {
170 return $this->invalid_nonce();
171 }
172 $dbs = $request->get_param( 'dbs' );
173 $tbl = $request->get_param( 'tbl' );
174 $count = $this->get_row_count( $dbs, $tbl );
175 return $this->WPDA_Rest_Response( $count );
176 }
177
178 public function action_set_row_count( $request ) {
179 if ( !$this->current_user_can_access() ) {
180 return $this->unauthorized();
181 }
182 if ( !$this->current_user_token_valid( $request ) ) {
183 return $this->invalid_nonce();
184 }
185 $dbs = $request->get_param( 'dbs' );
186 $tbl = $request->get_param( 'tbl' );
187 $count = $this->get_row_count( $dbs, $tbl );
188 return $this->WPDA_Rest_Response( $count );
189 }
190
191 public static function get_row_count( $dbs, $tbl ) {
192 $wpdadb = WPDADB::get_db_connection( $dbs );
193 if ( null === $wpdadb ) {
194 return sprintf( __( 'Database %s not available', 'wp-data-access' ), esc_attr( $dbs ) );
195 }
196 $suppress_errors = $wpdadb->suppress_errors;
197 $wpdadb->suppress_errors = true;
198 $count = $wpdadb->get_results( $wpdadb->prepare( 'select count(*) from `%1s`', array($tbl) ), 'ARRAY_N' );
199 $wpdadb->suppress_errors = $suppress_errors;
200 if ( $wpdadb->last_error !== '' ) {
201 WPDA::wpda_log_wp_error( $wpdadb->last_error );
202 }
203 return ( isset( $count[0][0] ) ? $count[0][0] : false );
204 }
205
206 public function action_mail( $request ) {
207 if ( !$this->current_user_can_access() ) {
208 return $this->unauthorized();
209 }
210 if ( !$this->current_user_token_valid( $request ) ) {
211 return $this->invalid_nonce();
212 }
213 $to = $request['to'];
214 $subject = $request['subject'];
215 $message = $request['message'];
216 return WPDA_Mail::send( $to, $subject, $message );
217 }
218
219 public function action_import( $request ) {
220 if ( !$this->current_user_can_access() ) {
221 return $this->unauthorized();
222 }
223 if ( !$this->current_user_token_valid( $request ) ) {
224 return $this->invalid_nonce();
225 }
226 $dbs = $this->sanitize_db_identifier( $request->get_param( 'dbs' ) );
227 $files = $request->get_file_params();
228 $response = array();
229 $errors = false;
230 if ( 0 === count( $files ) || '' === trim( $dbs ) ) {
231 return $this->bad_request();
232 } else {
233 foreach ( $files as $file ) {
234 // phpcs:disable
235 $temp_file_name = sanitize_text_field( $file['tmp_name'] );
236 // For Windows: do NOT unslash!
237 // phpcs:enable
238 $temp_file_type = sanitize_text_field( wp_unslash( $file['type'] ) );
239 $orig_file_name = sanitize_text_field( wp_unslash( $file['name'] ) );
240 if ( 0 === $file['error'] && is_uploaded_file( $temp_file_name ) ) {
241 if ( 'application/zip' === $temp_file_type || 'application/x-zip' === $temp_file_type || 'application/x-zip-compressed' === $temp_file_type ) {
242 // Process ZIP file.
243 if ( class_exists( '\\ZipArchive' ) ) {
244 $zip = new \ZipArchive();
245 if ( $zip->open( $temp_file_name ) ) {
246 for ($i = 0; $i < $zip->numFiles; $i++) {
247 $this->file_pointer = $zip->getStream( $zip->getNameIndex( $i ) );
248 $status = $this->import( $zip->getNameIndex( $i ), $dbs );
249 if ( isset( $status['status'], $status['msg'] ) ) {
250 $errors = $errors || 'error' === $status['status'];
251 $response[] = array(
252 $zip->getNameIndex( $i ) => array(
253 'status' => $status['status'],
254 'msg' => $status['msg'],
255 'errors' => $status['errors'],
256 ),
257 );
258 }
259 }
260 } else {
261 // Error reading ZIP file.
262 $errors = true;
263 $response[] = array(
264 $orig_file_name => array(
265 'status' => 'error',
266 'msg' => sprintf( __( 'Import failed [error reading ZIP file `%s`]', 'wp-data-access' ), $orig_file_name ),
267 ),
268 );
269 }
270 } else {
271 // ZipArchive not installed.
272 $errors = true;
273 $response[] = array(
274 $orig_file_name => array(
275 'status' => 'error',
276 'msg' => sprintf( __( 'Import failed - ZipArchive not installed %s', 'wp-data-access' ) ),
277 ),
278 );
279 }
280 } else {
281 // Process plain file.
282 $this->file_pointer = fopen( $temp_file_name, 'rb' );
283 $status = $this->import( $orig_file_name, $dbs );
284 if ( isset( $status['status'], $status['msg'] ) ) {
285 $errors = $errors || 'error' === $status['status'];
286 $response[] = array(
287 $orig_file_name => array(
288 'status' => $status['status'],
289 'msg' => $status['msg'],
290 'errors' => $status['errors'],
291 ),
292 );
293 }
294 }
295 }
296 }
297 }
298 if ( $errors ) {
299 $msg = __( 'File(s) imported with errors', 'wp-data-access' );
300 } else {
301 $msg = __( 'File(s) successfully imported', 'wp-data-access' );
302 }
303 return $this->WPDA_Rest_Response( $msg, null, array(
304 'imported' => $response,
305 ) );
306 }
307
308 public function action_drop( $request ) {
309 if ( !$this->current_user_can_access() ) {
310 return $this->unauthorized();
311 }
312 if ( !$this->current_user_token_valid( $request ) ) {
313 return $this->invalid_nonce();
314 }
315 $dbs = $request->get_param( 'dbs' );
316 $tbl = $request->get_param( 'tbl' );
317 $typ = $request->get_param( 'typ' );
318 if ( '' === $dbs || '' === $tbl ) {
319 return $this->bad_request();
320 }
321 global $wpdb;
322 if ( $wpdb->dbname === $dbs && in_array( $tbl, $wpdb->tables() ) ) {
323 return $this->unauthorized();
324 }
325 $msg = $this->drop( $dbs, $tbl, $typ );
326 if ( '' === $msg ) {
327 if ( 1 === $typ ) {
328 return $this->WPDA_Rest_Response( __( 'View successfully dropped', 'wp-data-access' ) );
329 } else {
330 return $this->WPDA_Rest_Response( __( 'Table successfully dropped', 'wp-data-access' ) );
331 }
332 } else {
333 return new \WP_Error('error', $msg, array(
334 'status' => 403,
335 ));
336 }
337 }
338
339 public function action_truncate( $request ) {
340 if ( !$this->current_user_can_access() ) {
341 return $this->unauthorized();
342 }
343 if ( !$this->current_user_token_valid( $request ) ) {
344 return $this->invalid_nonce();
345 }
346 $dbs = $request->get_param( 'dbs' );
347 $tbl = $request->get_param( 'tbl' );
348 if ( '' === $dbs || '' === $tbl ) {
349 return $this->bad_request();
350 }
351 global $wpdb;
352 if ( $wpdb->dbname === $dbs && in_array( $tbl, $wpdb->tables() ) ) {
353 return $this->unauthorized();
354 }
355 $msg = $this->truncate( $dbs, $tbl );
356 if ( '' === $msg ) {
357 return $this->WPDA_Rest_Response( __( 'Table successfully truncated', 'wp-data-access' ) );
358 } else {
359 return new \WP_Error('error', $msg, array(
360 'status' => 403,
361 ));
362 }
363 }
364
365 public function action_copy( $request ) {
366 if ( !$this->current_user_can_access() ) {
367 return $this->unauthorized();
368 }
369 if ( !$this->current_user_token_valid( $request ) ) {
370 return $this->invalid_nonce();
371 }
372 $from_dbs = $request->get_param( 'from_dbs' );
373 $to_dbs = $request->get_param( 'to_dbs' );
374 $from_tbl = $request->get_param( 'from_tbl' );
375 $to_tbl = $request->get_param( 'to_tbl' );
376 $copy_data = $request->get_param( 'copy_data' );
377 $copy_key = $request->get_param( 'copy_key' );
378 if ( '' === $from_dbs || '' === $to_dbs || '' === $from_tbl || '' === $to_tbl ) {
379 return $this->bad_request();
380 }
381 $msg = $this->copy(
382 $from_dbs,
383 $to_dbs,
384 $from_tbl,
385 $to_tbl,
386 $copy_data,
387 $copy_key
388 );
389 if ( '' === $msg ) {
390 return $this->WPDA_Rest_Response( __( 'Table successfully copied', 'wp-data-access' ) );
391 } else {
392 return new \WP_Error('error', $msg, array(
393 'status' => 403,
394 ));
395 }
396 }
397
398 public function action_copy_start( $request ) {
399 if ( !$this->current_user_can_access() ) {
400 return $this->unauthorized();
401 }
402 if ( !$this->current_user_token_valid( $request ) ) {
403 return $this->invalid_nonce();
404 }
405 if ( !WPDA::current_user_is_admin() ) {
406 return $this->unauthorized();
407 }
408 $copy_key = $request->get_param( 'copy_key' );
409 if ( '' === $copy_key ) {
410 return $this->bad_request();
411 }
412 $this->copy_start( $copy_key );
413 return $this->WPDA_Rest_Response( 'ok', self::copy_in_progress() );
414 }
415
416 public function action_copy_cancel( $request ) {
417 if ( !$this->current_user_can_access() ) {
418 return $this->unauthorized();
419 }
420 if ( !$this->current_user_token_valid( $request ) ) {
421 return $this->invalid_nonce();
422 }
423 if ( !WPDA::current_user_is_admin() ) {
424 return $this->unauthorized();
425 }
426 $copy_key = $request->get_param( 'copy_key' );
427 if ( '' === $copy_key ) {
428 return $this->bad_request();
429 }
430 $this->copy_stop( $copy_key );
431 return $this->WPDA_Rest_Response( 'ok', self::copy_in_progress() );
432 }
433
434 public function action_rename( $request ) {
435 if ( !$this->current_user_can_access() ) {
436 return $this->unauthorized();
437 }
438 if ( !$this->current_user_token_valid( $request ) ) {
439 return $this->invalid_nonce();
440 }
441 $dbs = $request->get_param( 'dbs' );
442 $from_tbl = $request->get_param( 'from_tbl' );
443 $to_tbl = $request->get_param( 'to_tbl' );
444 $typ = $request->get_param( 'typ' );
445 if ( '' === $dbs || '' === $from_tbl || '' === $to_tbl ) {
446 return $this->bad_request();
447 }
448 if ( 'information_schema' === $dbs || 'mysql' === $dbs || 'performance_schema' === $dbs || 'sys' === $dbs || '' === $dbs ) {
449 return $this->unauthorized();
450 }
451 global $wpdb;
452 if ( $wpdb->dbname === $dbs && in_array( $from_tbl, $wpdb->tables() ) ) {
453 return $this->unauthorized();
454 }
455 $msg = $this->rename( $dbs, $from_tbl, $to_tbl );
456 if ( '' === $msg ) {
457 if ( 1 === $typ ) {
458 return $this->WPDA_Rest_Response( __( 'View successfully renamed', 'wp-data-access' ) );
459 } else {
460 return $this->WPDA_Rest_Response( __( 'Table successfully renamed', 'wp-data-access' ) );
461 }
462 } else {
463 return new \WP_Error('error', $msg, array(
464 'status' => 403,
465 ));
466 }
467 }
468
469 private function rename( $dbs, $from_tbl, $to_tbl ) {
470 // All values have already been validated and sanitized in the rest route registration.
471 if ( !WPDA::current_user_is_admin() ) {
472 return 'Unauthorized';
473 }
474 $wpdadb = WPDADB::get_db_connection( $dbs );
475 if ( null === $wpdadb ) {
476 return sprintf( __( 'Remote database %s not available', 'wp-data-access' ), esc_attr( $dbs ) );
477 }
478 $suppress_errors = $wpdadb->suppress_errors;
479 $wpdadb->suppress_errors = true;
480 $wpdadb->query( $wpdadb->prepare( 'rename table `%1s` to `%1s`', array($from_tbl, $to_tbl) ) );
481 $wpdadb->suppress_errors = $suppress_errors;
482 return $wpdadb->last_error;
483 }
484
485 private function copy(
486 $from_dbs,
487 $to_dbs,
488 $from_tbl,
489 $to_tbl,
490 $copy_data,
491 $copy_key
492 ) {
493 // All values have already been validated and sanitized in the rest route registration.
494 if ( !WPDA::current_user_is_admin() ) {
495 return 'Unauthorized';
496 }
497 $wpdadb_from = WPDADB::get_db_connection( $from_dbs );
498 if ( null === $wpdadb_from ) {
499 return sprintf( __( 'Remote database %s not available', 'wp-data-access' ), esc_attr( $from_dbs ) );
500 }
501 $wpdadb_to = WPDADB::get_db_connection( $to_dbs );
502 if ( null === $wpdadb_to ) {
503 return sprintf( __( 'Remote database %s not available', 'wp-data-access' ), esc_attr( $to_dbs ) );
504 }
505 $suppress_errors_from = $wpdadb_from->suppress_errors;
506 $wpdadb_from->suppress_errors = true;
507 $suppress_errors_to = $wpdadb_to->suppress_errors;
508 $wpdadb_to->suppress_errors = true;
509 // Get create table statement.
510 // NO_TABLE_OPTIONS is deprecated in V8
511 // $wpdadb_from->query( "SET sql_mode = 'NO_TABLE_OPTIONS'" );
512 $sql_cmd = $wpdadb_from->get_results( $wpdadb_from->prepare( 'show create table `%1s`', array($from_tbl) ), 'ARRAY_A' );
513 // Check for errors.
514 if ( '' !== $wpdadb_from->last_error ) {
515 $wpdadb_from->suppress_errors = $suppress_errors_from;
516 $wpdadb_to->suppress_errors = $suppress_errors_to;
517 return $wpdadb_from->last_error;
518 }
519 if ( !isset( $sql_cmd[0]['Create Table'] ) ) {
520 $wpdadb_from->suppress_errors = $suppress_errors_from;
521 $wpdadb_to->suppress_errors = $suppress_errors_to;
522 return 'Create command table failed';
523 }
524 // Update destination table name if applicable.
525 $create_table_statement = $sql_cmd[0]['Create Table'];
526 if ( $from_tbl !== $to_tbl ) {
527 // Modify create table statement
528 $pos = strpos( $create_table_statement, $from_tbl );
529 if ( $pos !== false ) {
530 $create_table_statement = substr_replace(
531 $create_table_statement,
532 $to_tbl,
533 $pos,
534 strlen( $from_tbl )
535 );
536 }
537 }
538 // Create new table.
539 $wpdadb_to->query( $create_table_statement );
540 // Check for errors.
541 if ( '' !== $wpdadb_to->last_error ) {
542 $wpdadb_from->suppress_errors = $suppress_errors_from;
543 $wpdadb_to->suppress_errors = $suppress_errors_to;
544 return $wpdadb_to->last_error;
545 }
546 if ( '1' === $copy_data ) {
547 // Copy data from source to destination table.
548 set_time_limit( 0 );
549 // Prevent time out.
550 // Buffer rows to prevent exhausting memory.
551 $buffer_size = 1000;
552 // Default buffer
553 $settings_db = WPDA_Table_Settings_Model::query( $from_tbl, $from_dbs );
554 if ( isset( $settings_db[0]['wpda_table_settings'] ) ) {
555 // Convert string to JSON.
556 $settings = json_decode( $settings_db[0]['wpda_table_settings'], true );
557 if ( isset( $settings['table_settings']['query_buffer_size'] ) && is_numeric( $settings['table_settings']['query_buffer_size'] ) ) {
558 $buffer_size = intval( $settings['table_settings']['query_buffer_size'] );
559 }
560 }
561 $index = 0;
562 $loop_done = false;
563 $wpdadb_from->save_queries = false;
564 $wpdadb_to->save_queries = false;
565 while ( !$loop_done ) {
566 // Get rows.
567 $rows = $wpdadb_from->get_results( $wpdadb_from->prepare( 'select * from `%1s` limit %d offset %d', array($from_tbl, $buffer_size, $index * $buffer_size) ), 'ARRAY_A' );
568 // Process rows.
569 foreach ( $rows as $row ) {
570 $wpdadb_to->insert( $to_tbl, $row );
571 }
572 // Cleanup = IMPORTANT!
573 $wpdadb_from->flush();
574 $wpdadb_to->flush();
575 $wpdadb_to->queries = array();
576 $wpdadb_to->last_query = '';
577 $wpdadb_to->last_error = '';
578 $wpdadb_to->result = null;
579 $wpdadb_to->num_rows = 0;
580 $wpdadb_to->rows_affected = 0;
581 wp_cache_flush();
582 if ( function_exists( 'gc_collect_cycles' ) ) {
583 gc_collect_cycles();
584 }
585 if ( 100 > count( $rows ) ) {
586 // No more rows to process.
587 $loop_done = true;
588 }
589 unset($rows);
590 $index++;
591 // Check if job was cancelled
592 $in_progress = self::copy_in_progress();
593 if ( !in_array( $copy_key, $in_progress ) ) {
594 $loop_done = true;
595 }
596 }
597 }
598 $wpdadb_from->suppress_errors = $suppress_errors_from;
599 $wpdadb_to->suppress_errors = $suppress_errors_to;
600 $this->copy_stop( $copy_key );
601 if ( '' !== $wpdadb_from->last_error ) {
602 return $wpdadb_from->last_error;
603 }
604 if ( '' !== $wpdadb_to->last_error ) {
605 return $wpdadb_to->last_error;
606 }
607 return '';
608 }
609
610 private function copy_start( $copy_key ) {
611 $in_progress = self::copy_in_progress();
612 $in_progress[] = $copy_key;
613 update_user_meta( WPDA::get_current_user_id(), self::WPDA_COPY_TABLE, $in_progress );
614 }
615
616 private function copy_stop( $copy_key ) {
617 $in_progress = self::copy_in_progress();
618 if ( ($array_key = array_search( $copy_key, $in_progress )) !== false ) {
619 unset($in_progress[$array_key]);
620 $in_progress = array_values( $in_progress );
621 // Reset indexes to start at 0
622 }
623 update_user_meta( WPDA::get_current_user_id(), self::WPDA_COPY_TABLE, $in_progress );
624 }
625
626 public static function copy_in_progress() {
627 $in_progress = get_user_meta( WPDA::get_current_user_id(), self::WPDA_COPY_TABLE, true );
628 if ( $in_progress === false || $in_progress === '' ) {
629 return array();
630 }
631 return maybe_unserialize( $in_progress );
632 }
633
634 private function truncate( $dbs, $tbl ) {
635 // All values have already been validated and sanitized in the rest route registration.
636 if ( !WPDA::current_user_is_admin() ) {
637 return 'Unauthorized';
638 }
639 $wpdadb = WPDADB::get_db_connection( $dbs );
640 if ( null === $wpdadb ) {
641 return sprintf( __( 'Remote database %s not available', 'wp-data-access' ), esc_attr( $dbs ) );
642 }
643 $suppress_errors = $wpdadb->suppress_errors;
644 $wpdadb->suppress_errors = true;
645 $wpdadb->query( $wpdadb->prepare( 'truncate table `%1s`', array($tbl) ) );
646 $wpdadb->suppress_errors = $suppress_errors;
647 return $wpdadb->last_error;
648 }
649
650 private function drop( $dbs, $tbl, $typ ) {
651 // All values have already been validated and sanitized in the rest route registration.
652 if ( !WPDA::current_user_is_admin() ) {
653 return 'Unauthorized';
654 }
655 $wpdadb = WPDADB::get_db_connection( $dbs );
656 if ( null === $wpdadb ) {
657 return sprintf( __( 'Remote database %s not available', 'wp-data-access' ), esc_attr( $dbs ) );
658 }
659 $suppress_errors = $wpdadb->suppress_errors;
660 $wpdadb->suppress_errors = true;
661 if ( 1 === $typ ) {
662 $wpdadb->query( $wpdadb->prepare( 'drop view `%1s`', array($tbl) ) );
663 } else {
664 $wpdadb->query( $wpdadb->prepare( 'drop table `%1s`', array($tbl) ) );
665 }
666 if ( '' !== $wpdadb->last_error ) {
667 return $wpdadb->last_error;
668 }
669 $this->post_drop_table( $dbs, $tbl );
670 $wpdadb->suppress_errors = $suppress_errors;
671 return $wpdadb->last_error;
672 }
673
674 private function post_drop_table( $dbs, $tbl ) {
675 global $wpdb;
676 $suppress = $wpdb->suppress_errors( true );
677 // Table settings...
678 $wpdb->query( $wpdb->prepare(
679 'delete from `%1s` where wpda_schema_name = %s and wpda_table_name = %s ',
680 // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders
681 array(WPDA::remove_backticks( WPDA_Table_Settings_Model::get_base_table_name() ), $dbs, $tbl)
682 ) );
683 // WordPress media library columns...
684 $wpdb->query( $wpdb->prepare(
685 'delete from `%1s` where media_schema_name = %s and media_table_name = %s ',
686 // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders
687 array(WPDA::remove_backticks( WPDA_Media_Model::get_base_table_name() ), $dbs, $tbl)
688 ) );
689 // Data menus...
690 $wpdb->query( $wpdb->prepare(
691 'delete from `%1s` where menu_schema_name = %s and menu_table_name = %s ',
692 // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders
693 array(WPDA::remove_backticks( WPDA_User_Menus_Model::get_base_table_name() ), $dbs, $tbl)
694 ) );
695 $wpdb->suppress_errors( $suppress );
696 }
697
698 private function import( $file_name, $dbs ) {
699 if ( !WPDA::current_user_is_admin() ) {
700 return array(
701 'status' => 'error',
702 'msg' => 'Unauthorized',
703 );
704 }
705 $errors = array();
706 global $wpdb;
707 $wpdadb = WPDADB::get_db_connection( $dbs );
708 if ( null === $wpdadb ) {
709 return array(
710 'status' => 'error',
711 'msg' => sprintf( __( 'ERROR - Remote database %s not available', 'wp-data-access' ), esc_attr( $dbs ) ),
712 );
713 }
714 $suppress = $wpdadb->suppress_errors( true );
715 if ( false !== $this->file_pointer ) {
716 while ( !feof( $this->file_pointer ) ) {
717 $this->file_content .= fread( $this->file_pointer, 4096 );
718 // Replace WP prefix and WPDA prefix.
719 $this->file_content = str_replace( '{wp_schema}', $wpdb->dbname, $this->file_content );
720 $this->file_content = str_replace( '{wp_prefix}', $wpdb->prefix, $this->file_content );
721 $this->file_content = str_replace( '{wpda_prefix}', 'wpda', $this->file_content );
722 // for backward compatibility
723 // Find and process SQL statements.
724 $sql_end_unix = strpos( $this->file_content, ";\n" );
725 $sql_end_windows = strpos( $this->file_content, ";\r\n" );
726 while ( false !== $sql_end_unix || false !== $sql_end_windows ) {
727 if ( false === $sql_end_unix ) {
728 $sql_end = $sql_end_windows;
729 } elseif ( false === $sql_end_windows ) {
730 $sql_end = $sql_end_unix;
731 } else {
732 $sql_end = min( $sql_end_unix, $sql_end_windows );
733 }
734 $sql = rtrim( substr( $this->file_content, 0, $sql_end ) );
735 $this->file_content = substr( $this->file_content, strpos( $this->file_content, $sql ) + strlen( $sql ) + 1 );
736 if ( false === $wpdadb->query( $sql ) ) {
737 if ( '' !== $wpdadb->last_error ) {
738 $errors[] = $wpdadb->last_error;
739 }
740 }
741 // Find next SQL statement.
742 $sql_end_unix = strpos( $this->file_content, ";\n" );
743 $sql_end_windows = strpos( $this->file_content, ";\r\n" );
744 }
745 }
746 }
747 $wpdadb->suppress_errors( $suppress );
748 // Process file content.
749 if ( 0 < count( $errors ) ) {
750 return array(
751 'status' => 'error',
752 'msg' => sprintf( __( 'Import `%s` failed [check import file]', 'wp-data-access' ), $file_name ),
753 'errors' => $errors,
754 );
755 } else {
756 // Import succeeded.
757 return array(
758 'status' => 'ok',
759 'msg' => sprintf( __( 'Import `%s` completed succesfully', 'wp-data-access' ), $file_name ),
760 'errors' => $errors,
761 );
762 }
763 }
764
765 }
766