PluginProbe
WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards / 5.5.84
WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards v5.5.84
5.5.84 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 All 160 releases
← All changes | WPDataAccess/API/WPDA_Actions.php +308 -44 5.5.45.5.84 View file →
@@ -1,14 +1,18 @@
1 1 <?php
2 2
3 3 namespace WPDataAccess\API;
4 4
5 +use PDOException;
5 6 use WPDataAccess\Connection\WPDADB;
6 7 use WPDataAccess\Plugin_Table_Models\WPDA_Media_Model;
7 8 use WPDataAccess\Plugin_Table_Models\WPDA_Table_Settings_Model;
8 9 use WPDataAccess\Plugin_Table_Models\WPDA_User_Menus_Model;
10 +use WPDataAccess\Utilities\WPDA_Mail;
9 11 use WPDataAccess\WPDA;
10 12 class WPDA_Actions extends WPDA_API_Core {
13 + const WPDA_COPY_TABLE = 'wpda_copy_table';
14 +
11 15 protected $file_pointer;
12 16
13 17 protected $file_content;
14 18
@@ -38,10 +42,27 @@
38 42 'description' => __( 'Copy data from source to destination table', 'wp-data-access' ),
39 43 'sanitize_callback' => 'sanitize_text_field',
40 44 'validate_callback' => 'rest_validate_request_arg',
41 45 ),
46 + 'copy_key' => $this->get_param( 'copy_key' ),
42 47 ),
43 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 + ) );
44 65 register_rest_route( WPDA_API::WPDA_NAMESPACE, 'action/truncate', array(
45 66 'methods' => array('POST'),
46 67 'callback' => array($this, 'action_truncate'),
47 68 'permission_callback' => '__return_true',
@@ -64,15 +85,144 @@
64 85 'methods' => array('POST'),
65 86 'callback' => array($this, 'action_import'),
66 87 'permission_callback' => '__return_true',
67 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 + ) );
68 136 }
69 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 + /* translators: %s = database name */
195 + return sprintf( __( 'Database %s not available', 'wp-data-access' ), esc_attr( $dbs ) );
196 + }
197 + $suppress_errors = $wpdadb->suppress_errors;
198 + $wpdadb->suppress_errors = true;
199 + $count = $wpdadb->get_results( $wpdadb->prepare( 'select count(*) from `%1s`', array($tbl) ), 'ARRAY_N' );
200 + $wpdadb->suppress_errors = $suppress_errors;
201 + if ( $wpdadb->last_error !== '' ) {
202 + WPDA::wpda_log_wp_error( $wpdadb->last_error );
203 + }
204 + return ( isset( $count[0][0] ) ? $count[0][0] : false );
205 + }
206 +
207 + public function action_mail( $request ) {
208 + if ( !$this->current_user_can_access() ) {
209 + return $this->unauthorized();
210 + }
211 + if ( !$this->current_user_token_valid( $request ) ) {
212 + return $this->invalid_nonce();
213 + }
214 + $to = $request['to'];
215 + $subject = $request['subject'];
216 + $message = $request['message'];
217 + return WPDA_Mail::send( $to, $subject, $message );
218 + }
219 +
70 220 public function action_import( $request ) {
71 - if ( !$this->current_user_can_access( true ) ) {
221 + if ( !$this->current_user_can_access() ) {
72 222 return $this->unauthorized();
73 223 }
74 - if ( !$this->current_user_token_valid( $request, true ) ) {
224 + if ( !$this->current_user_token_valid( $request ) ) {
75 225 return $this->invalid_nonce();
76 226 }
77 227 $dbs = $this->sanitize_db_identifier( $request->get_param( 'dbs' ) );
78 228 $files = $request->get_file_params();
@@ -81,12 +231,10 @@
81 231 if ( 0 === count( $files ) || '' === trim( $dbs ) ) {
82 232 return $this->bad_request();
83 233 } else {
84 234 foreach ( $files as $file ) {
85 - // phpcs:disable
86 235 $temp_file_name = sanitize_text_field( $file['tmp_name'] );
87 236 // For Windows: do NOT unslash!
88 - // phpcs:enable
89 237 $temp_file_type = sanitize_text_field( wp_unslash( $file['type'] ) );
90 238 $orig_file_name = sanitize_text_field( wp_unslash( $file['name'] ) );
91 239 if ( 0 === $file['error'] && is_uploaded_file( $temp_file_name ) ) {
92 240 if ( 'application/zip' === $temp_file_type || 'application/x-zip' === $temp_file_type || 'application/x-zip-compressed' === $temp_file_type ) {
@@ -102,8 +250,9 @@
102 250 $response[] = array(
103 251 $zip->getNameIndex( $i ) => array(
104 252 'status' => $status['status'],
105 253 'msg' => $status['msg'],
254 + 'errors' => $status['errors'],
106 255 ),
107 256 );
108 257 }
109 258 }
@@ -109,8 +258,9 @@
109 258 }
110 259 } else {
111 260 // Error reading ZIP file.
112 261 $errors = true;
262 + // phpcs:disable WordPress.WP.I18n.MissingTranslatorsComment
113 263 $response[] = array(
114 264 $orig_file_name => array(
115 265 'status' => 'error',
116 266 'msg' => sprintf( __( 'Import failed [error reading ZIP file `%s`]', 'wp-data-access' ), $orig_file_name ),
@@ -115,8 +265,9 @@
115 265 'status' => 'error',
116 266 'msg' => sprintf( __( 'Import failed [error reading ZIP file `%s`]', 'wp-data-access' ), $orig_file_name ),
117 267 ),
118 268 );
269 + // phpcs:enable WordPress.WP.I18n.MissingTranslatorsComment
119 270 }
120 271 } else {
121 272 // ZipArchive not installed.
122 273 $errors = true;
@@ -122,15 +273,17 @@
122 273 $errors = true;
123 274 $response[] = array(
124 275 $orig_file_name => array(
125 276 'status' => 'error',
126 - 'msg' => sprintf( __( 'Import failed - ZipArchive not installed %s', 'wp-data-access' ) ),
277 + 'msg' => __( 'Import failed - ZipArchive not installed', 'wp-data-access' ),
127 278 ),
128 279 );
129 280 }
130 281 } else {
131 282 // Process plain file.
283 + // phpcs:disable WordPress.WP.AlternativeFunctions.file_system_operations_fopen
132 284 $this->file_pointer = fopen( $temp_file_name, 'rb' );
285 + // phpcs:enable WordPress.WP.AlternativeFunctions.file_system_operations_fopen
133 286 $status = $this->import( $orig_file_name, $dbs );
134 287 if ( isset( $status['status'], $status['msg'] ) ) {
135 288 $errors = $errors || 'error' === $status['status'];
136 289 $response[] = array(
@@ -136,8 +289,9 @@
136 289 $response[] = array(
137 290 $orig_file_name => array(
138 291 'status' => $status['status'],
139 292 'msg' => $status['msg'],
293 + 'errors' => $status['errors'],
140 294 ),
141 295 );
142 296 }
143 297 }
@@ -154,12 +308,12 @@
154 308 ) );
155 309 }
156 310
157 311 public function action_drop( $request ) {
158 - if ( !$this->current_user_can_access( true ) ) {
312 + if ( !$this->current_user_can_access() ) {
159 313 return $this->unauthorized();
160 314 }
161 - if ( !$this->current_user_token_valid( $request, true ) ) {
315 + if ( !$this->current_user_token_valid( $request ) ) {
162 316 return $this->invalid_nonce();
163 317 }
164 318 $dbs = $request->get_param( 'dbs' );
165 319 $tbl = $request->get_param( 'tbl' );
@@ -185,12 +339,12 @@
185 339 }
186 340 }
187 341
188 342 public function action_truncate( $request ) {
189 - if ( !$this->current_user_can_access( true ) ) {
343 + if ( !$this->current_user_can_access() ) {
190 344 return $this->unauthorized();
191 345 }
192 - if ( !$this->current_user_token_valid( $request, true ) ) {
346 + if ( !$this->current_user_token_valid( $request ) ) {
193 347 return $this->invalid_nonce();
194 348 }
195 349 $dbs = $request->get_param( 'dbs' );
196 350 $tbl = $request->get_param( 'tbl' );
@@ -211,12 +365,12 @@
211 365 }
212 366 }
213 367
214 368 public function action_copy( $request ) {
215 - if ( !$this->current_user_can_access( true ) ) {
369 + if ( !$this->current_user_can_access() ) {
216 370 return $this->unauthorized();
217 371 }
218 - if ( !$this->current_user_token_valid( $request, true ) ) {
372 + if ( !$this->current_user_token_valid( $request ) ) {
219 373 return $this->invalid_nonce();
220 374 }
221 375 $from_dbs = $request->get_param( 'from_dbs' );
222 376 $to_dbs = $request->get_param( 'to_dbs' );
@@ -222,8 +376,9 @@
222 376 $to_dbs = $request->get_param( 'to_dbs' );
223 377 $from_tbl = $request->get_param( 'from_tbl' );
224 378 $to_tbl = $request->get_param( 'to_tbl' );
225 379 $copy_data = $request->get_param( 'copy_data' );
380 + $copy_key = $request->get_param( 'copy_key' );
226 381 if ( '' === $from_dbs || '' === $to_dbs || '' === $from_tbl || '' === $to_tbl ) {
227 382 return $this->bad_request();
228 383 }
229 384 $msg = $this->copy(
@@ -230,9 +385,10 @@
230 385 $from_dbs,
231 386 $to_dbs,
232 387 $from_tbl,
233 388 $to_tbl,
234 - $copy_data
389 + $copy_data,
390 + $copy_key
235 391 );
236 392 if ( '' === $msg ) {
237 393 return $this->WPDA_Rest_Response( __( 'Table successfully copied', 'wp-data-access' ) );
238 394 } else {
@@ -241,18 +397,55 @@
241 397 ));
242 398 }
243 399 }
244 400
401 + public function action_copy_start( $request ) {
402 + if ( !$this->current_user_can_access() ) {
403 + return $this->unauthorized();
404 + }
405 + if ( !$this->current_user_token_valid( $request ) ) {
406 + return $this->invalid_nonce();
407 + }
408 + if ( !WPDA::current_user_is_admin() ) {
409 + return $this->unauthorized();
410 + }
411 + $copy_key = $request->get_param( 'copy_key' );
412 + if ( '' === $copy_key ) {
413 + return $this->bad_request();
414 + }
415 + $this->copy_start( $copy_key );
416 + return $this->WPDA_Rest_Response( 'ok', self::copy_in_progress() );
417 + }
418 +
419 + public function action_copy_cancel( $request ) {
420 + if ( !$this->current_user_can_access() ) {
421 + return $this->unauthorized();
422 + }
423 + if ( !$this->current_user_token_valid( $request ) ) {
424 + return $this->invalid_nonce();
425 + }
426 + if ( !WPDA::current_user_is_admin() ) {
427 + return $this->unauthorized();
428 + }
429 + $copy_key = $request->get_param( 'copy_key' );
430 + if ( '' === $copy_key ) {
431 + return $this->bad_request();
432 + }
433 + $this->copy_stop( $copy_key );
434 + return $this->WPDA_Rest_Response( 'ok', self::copy_in_progress() );
435 + }
436 +
245 437 public function action_rename( $request ) {
246 - if ( !$this->current_user_can_access( true ) ) {
438 + if ( !$this->current_user_can_access() ) {
247 439 return $this->unauthorized();
248 440 }
249 - if ( !$this->current_user_token_valid( $request, true ) ) {
441 + if ( !$this->current_user_token_valid( $request ) ) {
250 442 return $this->invalid_nonce();
251 443 }
252 444 $dbs = $request->get_param( 'dbs' );
253 445 $from_tbl = $request->get_param( 'from_tbl' );
254 446 $to_tbl = $request->get_param( 'to_tbl' );
447 + $typ = $request->get_param( 'typ' );
255 448 if ( '' === $dbs || '' === $from_tbl || '' === $to_tbl ) {
256 449 return $this->bad_request();
257 450 }
258 451 if ( 'information_schema' === $dbs || 'mysql' === $dbs || 'performance_schema' === $dbs || 'sys' === $dbs || '' === $dbs ) {
@@ -277,13 +470,14 @@
277 470 }
278 471
279 472 private function rename( $dbs, $from_tbl, $to_tbl ) {
280 473 // All values have already been validated and sanitized in the rest route registration.
281 - if ( !current_user_can( 'manage_options' ) ) {
474 + if ( !WPDA::current_user_is_admin() ) {
282 475 return 'Unauthorized';
283 476 }
284 477 $wpdadb = WPDADB::get_db_connection( $dbs );
285 478 if ( null === $wpdadb ) {
479 + /* translators: %s = database name */
286 480 return sprintf( __( 'Remote database %s not available', 'wp-data-access' ), esc_attr( $dbs ) );
287 481 }
288 482 $suppress_errors = $wpdadb->suppress_errors;
289 483 $wpdadb->suppress_errors = true;
@@ -296,20 +490,23 @@
296 490 $from_dbs,
297 491 $to_dbs,
298 492 $from_tbl,
299 493 $to_tbl,
300 - $copy_data
494 + $copy_data,
495 + $copy_key
301 496 ) {
302 497 // All values have already been validated and sanitized in the rest route registration.
303 - if ( !current_user_can( 'manage_options' ) ) {
498 + if ( !WPDA::current_user_is_admin() ) {
304 499 return 'Unauthorized';
305 500 }
306 501 $wpdadb_from = WPDADB::get_db_connection( $from_dbs );
307 502 if ( null === $wpdadb_from ) {
503 + /* translators: %s = database name */
308 504 return sprintf( __( 'Remote database %s not available', 'wp-data-access' ), esc_attr( $from_dbs ) );
309 505 }
310 506 $wpdadb_to = WPDADB::get_db_connection( $to_dbs );
311 507 if ( null === $wpdadb_to ) {
508 + /* translators: %s = database name */
312 509 return sprintf( __( 'Remote database %s not available', 'wp-data-access' ), esc_attr( $to_dbs ) );
313 510 }
314 511 $suppress_errors_from = $wpdadb_from->suppress_errors;
315 512 $wpdadb_from->suppress_errors = true;
@@ -315,9 +512,10 @@
315 512 $wpdadb_from->suppress_errors = true;
316 513 $suppress_errors_to = $wpdadb_to->suppress_errors;
317 514 $wpdadb_to->suppress_errors = true;
318 515 // Get create table statement.
319 - $wpdadb_from->query( "SET sql_mode = 'NO_TABLE_OPTIONS'" );
516 + // NO_TABLE_OPTIONS is deprecated in V8
517 + // $wpdadb_from->query( "SET sql_mode = 'NO_TABLE_OPTIONS'" );
320 518 $sql_cmd = $wpdadb_from->get_results( $wpdadb_from->prepare( 'show create table `%1s`', array($from_tbl) ), 'ARRAY_A' );
321 519 // Check for errors.
322 520 if ( '' !== $wpdadb_from->last_error ) {
323 521 $wpdadb_from->suppress_errors = $suppress_errors_from;
@@ -352,41 +550,104 @@
352 550 return $wpdadb_to->last_error;
353 551 }
354 552 if ( '1' === $copy_data ) {
355 553 // Copy data from source to destination table.
554 + // Prevent time out.
555 + // phpcs:disable Squiz.PHP.DiscouragedFunctions.Discouraged
356 556 set_time_limit( 0 );
357 - // Prevent time out.
358 - // Use a cursor to process all rows and prevent exhausting memory.
359 - // Process 100 rows per batch to prevent exhausting memory.
360 - $buffer_size = 100;
557 + // phpcs:enable Squiz.PHP.DiscouragedFunctions.Discouraged
558 + // Buffer rows to prevent exhausting memory.
559 + $buffer_size = 1000;
560 + // Default buffer
561 + $settings_db = WPDA_Table_Settings_Model::query( $from_tbl, $from_dbs );
562 + if ( isset( $settings_db[0]['wpda_table_settings'] ) ) {
563 + // Convert string to JSON.
564 + $settings = json_decode( $settings_db[0]['wpda_table_settings'], true );
565 + if ( isset( $settings['table_settings']['query_buffer_size'] ) && is_numeric( $settings['table_settings']['query_buffer_size'] ) ) {
566 + $buffer_size = intval( $settings['table_settings']['query_buffer_size'] );
567 + }
568 + }
361 569 $index = 0;
362 570 $loop_done = false;
571 + $wpdadb_from->save_queries = false;
572 + $wpdadb_to->save_queries = false;
363 573 while ( !$loop_done ) {
364 574 // Get rows.
365 - $rows = $wpdadb_from->get_results( $wpdadb_from->prepare( 'select * from `%1s` limit %1s offset %1s', array($from_tbl, $buffer_size, $index * $buffer_size) ), 'ARRAY_A' );
575 + $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' );
366 576 // Process rows.
367 577 foreach ( $rows as $row ) {
368 578 $wpdadb_to->insert( $to_tbl, $row );
369 579 }
580 + // Cleanup = IMPORTANT!
581 + $wpdadb_from->flush();
582 + $wpdadb_to->flush();
583 + $wpdadb_to->queries = array();
584 + $wpdadb_to->last_query = '';
585 + $wpdadb_to->last_error = '';
586 + $wpdadb_to->result = null;
587 + $wpdadb_to->num_rows = 0;
588 + $wpdadb_to->rows_affected = 0;
589 + wp_cache_flush();
590 + if ( function_exists( 'gc_collect_cycles' ) ) {
591 + gc_collect_cycles();
592 + }
370 593 if ( 100 > count( $rows ) ) {
371 594 // No more rows to process.
372 595 $loop_done = true;
373 596 }
597 + unset($rows);
374 598 $index++;
599 + // Check if job was cancelled
600 + $in_progress = self::copy_in_progress();
601 + if ( !in_array( $copy_key, $in_progress ) ) {
602 + $loop_done = true;
603 + }
375 604 }
376 605 }
377 606 $wpdadb_from->suppress_errors = $suppress_errors_from;
378 607 $wpdadb_to->suppress_errors = $suppress_errors_to;
608 + $this->copy_stop( $copy_key );
609 + if ( '' !== $wpdadb_from->last_error ) {
610 + return $wpdadb_from->last_error;
611 + }
612 + if ( '' !== $wpdadb_to->last_error ) {
613 + return $wpdadb_to->last_error;
614 + }
379 615 return '';
380 616 }
381 617
618 + private function copy_start( $copy_key ) {
619 + $in_progress = self::copy_in_progress();
620 + $in_progress[] = $copy_key;
621 + update_user_meta( WPDA::get_current_user_id(), self::WPDA_COPY_TABLE, $in_progress );
622 + }
623 +
624 + private function copy_stop( $copy_key ) {
625 + $in_progress = self::copy_in_progress();
626 + if ( ($array_key = array_search( $copy_key, $in_progress )) !== false ) {
627 + unset($in_progress[$array_key]);
628 + $in_progress = array_values( $in_progress );
629 + // Reset indexes to start at 0
630 + }
631 + update_user_meta( WPDA::get_current_user_id(), self::WPDA_COPY_TABLE, $in_progress );
632 + }
633 +
634 + public static function copy_in_progress() {
635 + $in_progress = get_user_meta( WPDA::get_current_user_id(), self::WPDA_COPY_TABLE, true );
636 + if ( $in_progress === false || $in_progress === '' ) {
637 + return array();
638 + }
639 + return maybe_unserialize( $in_progress );
640 + }
641 +
382 642 private function truncate( $dbs, $tbl ) {
383 643 // All values have already been validated and sanitized in the rest route registration.
384 - if ( !current_user_can( 'manage_options' ) ) {
644 + if ( !WPDA::current_user_is_admin() ) {
385 645 return 'Unauthorized';
386 646 }
387 647 $wpdadb = WPDADB::get_db_connection( $dbs );
388 648 if ( null === $wpdadb ) {
649 + /* translators: %s = database name */
389 650 return sprintf( __( 'Remote database %s not available', 'wp-data-access' ), esc_attr( $dbs ) );
390 651 }
391 652 $suppress_errors = $wpdadb->suppress_errors;
392 653 $wpdadb->suppress_errors = true;
@@ -396,13 +657,14 @@
396 657 }
397 658
398 659 private function drop( $dbs, $tbl, $typ ) {
399 660 // All values have already been validated and sanitized in the rest route registration.
400 - if ( !current_user_can( 'manage_options' ) ) {
661 + if ( !WPDA::current_user_is_admin() ) {
401 662 return 'Unauthorized';
402 663 }
403 664 $wpdadb = WPDADB::get_db_connection( $dbs );
404 665 if ( null === $wpdadb ) {
666 + /* translators: %s = database name */
405 667 return sprintf( __( 'Remote database %s not available', 'wp-data-access' ), esc_attr( $dbs ) );
406 668 }
407 669 $suppress_errors = $wpdadb->suppress_errors;
408 670 $wpdadb->suppress_errors = true;
@@ -410,8 +672,11 @@
410 672 $wpdadb->query( $wpdadb->prepare( 'drop view `%1s`', array($tbl) ) );
411 673 } else {
412 674 $wpdadb->query( $wpdadb->prepare( 'drop table `%1s`', array($tbl) ) );
413 675 }
676 + if ( '' !== $wpdadb->last_error ) {
677 + return $wpdadb->last_error;
678 + }
414 679 $this->post_drop_table( $dbs, $tbl );
415 680 $wpdadb->suppress_errors = $suppress_errors;
416 681 return $wpdadb->last_error;
417 682 }
@@ -418,49 +683,42 @@
418 683
419 684 private function post_drop_table( $dbs, $tbl ) {
420 685 global $wpdb;
421 686 $suppress = $wpdb->suppress_errors( true );
687 + // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQLPlaceholders, WordPress.DB.PreparedSQLPlaceholders.UnquotedComplexPlaceholder -- plugin table
422 688 // Table settings...
423 - $wpdb->query( $wpdb->prepare(
424 - 'delete from `%1s` where wpda_schema_name = %s and wpda_table_name = %s ',
425 - // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders
426 - array(WPDA::remove_backticks( WPDA_Table_Settings_Model::get_base_table_name() ), $dbs, $tbl)
427 - ) );
689 + $wpdb->query( $wpdb->prepare( 'delete from `%1s` where wpda_schema_name = %s and wpda_table_name = %s ', array(WPDA::remove_backticks( WPDA_Table_Settings_Model::get_base_table_name() ), $dbs, $tbl) ) );
428 690 // WordPress media library columns...
429 - $wpdb->query( $wpdb->prepare(
430 - 'delete from `%1s` where media_schema_name = %s and media_table_name = %s ',
431 - // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders
432 - array(WPDA::remove_backticks( WPDA_Media_Model::get_base_table_name() ), $dbs, $tbl)
433 - ) );
691 + $wpdb->query( $wpdb->prepare( 'delete from `%1s` where media_schema_name = %s and media_table_name = %s ', array(WPDA::remove_backticks( WPDA_Media_Model::get_base_table_name() ), $dbs, $tbl) ) );
434 692 // Data menus...
435 - $wpdb->query( $wpdb->prepare(
436 - 'delete from `%1s` where menu_schema_name = %s and menu_table_name = %s ',
437 - // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders
438 - array(WPDA::remove_backticks( WPDA_User_Menus_Model::get_base_table_name() ), $dbs, $tbl)
439 - ) );
693 + $wpdb->query( $wpdb->prepare( 'delete from `%1s` where menu_schema_name = %s and menu_table_name = %s ', array(WPDA::remove_backticks( WPDA_User_Menus_Model::get_base_table_name() ), $dbs, $tbl) ) );
440 694 $wpdb->suppress_errors( $suppress );
441 695 }
442 696
443 697 private function import( $file_name, $dbs ) {
444 - if ( !current_user_can( 'manage_options' ) ) {
698 + if ( !WPDA::current_user_is_admin() ) {
445 699 return array(
446 700 'status' => 'error',
447 701 'msg' => 'Unauthorized',
448 702 );
449 703 }
450 - $result = true;
704 + $errors = array();
451 705 global $wpdb;
452 706 $wpdadb = WPDADB::get_db_connection( $dbs );
453 707 if ( null === $wpdadb ) {
708 + // phpcs:disable WordPress.WP.I18n.MissingTranslatorsComment
454 709 return array(
455 710 'status' => 'error',
456 711 'msg' => sprintf( __( 'ERROR - Remote database %s not available', 'wp-data-access' ), esc_attr( $dbs ) ),
457 712 );
713 + // phpcs:enable WordPress.WP.I18n.MissingTranslatorsComment
458 714 }
459 715 $suppress = $wpdadb->suppress_errors( true );
460 716 if ( false !== $this->file_pointer ) {
461 717 while ( !feof( $this->file_pointer ) ) {
718 + // phpcs:disable WordPress.WP.AlternativeFunctions.file_system_operations_fread
462 719 $this->file_content .= fread( $this->file_pointer, 4096 );
720 + // phpcs:enable WordPress.WP.AlternativeFunctions.file_system_operations_fread
463 721 // Replace WP prefix and WPDA prefix.
464 722 $this->file_content = str_replace( '{wp_schema}', $wpdb->dbname, $this->file_content );
465 723 $this->file_content = str_replace( '{wp_prefix}', $wpdb->prefix, $this->file_content );
466 724 $this->file_content = str_replace( '{wpda_prefix}', 'wpda', $this->file_content );
@@ -478,9 +736,11 @@
478 736 }
479 737 $sql = rtrim( substr( $this->file_content, 0, $sql_end ) );
480 738 $this->file_content = substr( $this->file_content, strpos( $this->file_content, $sql ) + strlen( $sql ) + 1 );
481 739 if ( false === $wpdadb->query( $sql ) ) {
482 - $result = false;
740 + if ( '' !== $wpdadb->last_error ) {
741 + $errors[] = $wpdadb->last_error;
742 + }
483 743 }
484 744 // Find next SQL statement.
485 745 $sql_end_unix = strpos( $this->file_content, ";\n" );
486 746 $sql_end_windows = strpos( $this->file_content, ";\r\n" );
@@ -488,12 +748,14 @@
488 748 }
489 749 }
490 750 $wpdadb->suppress_errors( $suppress );
491 751 // Process file content.
492 - if ( !$result ) {
752 + // phpcs:disable WordPress.WP.I18n.MissingTranslatorsComment
753 + if ( 0 < count( $errors ) ) {
493 754 return array(
494 755 'status' => 'error',
495 756 'msg' => sprintf( __( 'Import `%s` failed [check import file]', 'wp-data-access' ), $file_name ),
757 + 'errors' => $errors,
496 758 );
497 759 } else {
498 760 // Import succeeded.
499 761 return array(
@@ -498,9 +760,11 @@
498 760 // Import succeeded.
499 761 return array(
500 762 'status' => 'ok',
501 763 'msg' => sprintf( __( 'Import `%s` completed succesfully', 'wp-data-access' ), $file_name ),
764 + 'errors' => $errors,
502 765 );
503 766 }
767 + // phpcs:enable WordPress.WP.I18n.MissingTranslatorsComment
504 768 }
505 769
506 770 }