PluginProbe
WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards / 5.5.79
WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards v5.5.79
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
wp-data-access / WPDataAccess / Utilities / WPDA_Export_Sql.php

WPDA_Export_Sql.php in WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards 5.5.79, at WPDataAccess/Utilities/WPDA_Export_Sql.php

892 lines 27.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Suppress "error - 0 - No summary was found for this file" on phpdoc generation
5 *
6 * @package WPDataAccess\Utilities
7 */
8
9 namespace WPDataAccess\Utilities {
10
11 use http\Encoding\Stream;
12 use WPDataAccess\Connection\WPDADB;
13 use WPDataAccess\Data_Dictionary\WPDA_Dictionary_Exist;
14 use WPDataAccess\Data_Dictionary\WPDA_List_Columns_Cache;
15 use WPDataAccess\Plugin_Table_Models\WPDA_Publisher_Model;
16 use WPDataAccess\Plugin_Table_Models\WPDA_Table_Settings_Model;
17 use WPDataAccess\WPDA;
18
19 /**
20 * Class WPDA_Export_Sql
21 *
22 * Exports tables or rows (depending on arguments)
23 *
24 * + Table export
25 * + One or more tables (batch)
26 * + Contains a create table statements for every tables exported
27 * + All records of a tables are exported as one insert statement
28 * + Contains comments (no reimport without editing possible)
29 * + Row export
30 * + All records are exported as one insert statement
31 * + Contains no comments (can be reimported without editing)
32 *
33 * @author Peter Schulz
34 * @since 1.0.0
35 */
36 class WPDA_Export_Sql {
37
38 /**
39 * Database schema name
40 *
41 * @var string
42 */
43 protected $schema_name = '';
44
45 /**
46 * Database schema name prefix used in strings
47 *
48 * @var string
49 */
50 protected $schema_name_prefix = '';
51
52 /**
53 * Table name(s) of table(s) to be exported
54 *
55 * @var string|array
56 */
57 protected $table_list = array();
58
59 /**
60 * Indicates whether to set MySQL environment
61 *
62 * @var string 'on' or 'off'
63 */
64 protected $mysql_set;
65
66 /**
67 * Indicates whether comments should be added
68 *
69 * @var string 'on' or 'off'
70 */
71 protected $show_comments;
72
73 /**
74 * Indicates whether to add a create table
75 *
76 * @var string 'on' or 'off'
77 */
78 protected $show_create;
79
80 /**
81 * Indicates whether table settings should be exported
82 *
83 * @var string 'on' or 'off'
84 */
85 protected $include_table_settings;
86
87 /**
88 * Use variable to write output
89 *
90 * @var string
91 */
92 protected $output_string;
93
94 /**
95 * Write output to stream if available
96 *
97 * @var null
98 */
99 protected $output_stream = null;
100
101 protected $export_with_prefix = false;
102
103 /**
104 * WPDA_Export constructor.
105 *
106 * Make sure the export procedure has sufficient memory.
107 *
108 * @since 2.0.11
109 */
110 public function __construct() {
111 if ( defined( 'WP_MAX_MEMORY_LIMIT' ) ) {
112 $wp_memory_limit = WP_MAX_MEMORY_LIMIT;
113 $current_memory_limit = @ini_get( 'memory_limit' );
114 if ( false === $current_memory_limit ||
115 WPDA::convert_memory_to_decimal( $current_memory_limit ) < WPDA::convert_memory_to_decimal( $wp_memory_limit )
116 ) {
117 @ini_set( 'memory_limit', $wp_memory_limit ); // phpcs:ignore
118 }
119 }
120
121 $this->export_with_prefix = 'on' === WPDA::get_option( WPDA::OPTION_BE_EXPORT_VARIABLE_PREFIX );
122 }
123
124 /**
125 * Use this method to startan export using method arguments
126 *
127 * @param string $mysql_set on|off
128 * @param string $show_comments on|off
129 * @param string $show_create on|off
130 * @param string $schema_name Database schema name
131 * @param string|array $table_names Single table name (string) | Table name list (array)
132 * @param string $export_type table|row
133 * @param string $include_table_settings on|off
134 *
135 * @since 2.0.7
136 */
137 public function export_with_arguments(
138 $mysql_set,
139 $show_comments,
140 $show_create,
141 $schema_name,
142 $table_names,
143 $export_type,
144 $include_table_settings = 'on'
145 ) {
146 $this->mysql_set = 'on' === $mysql_set ? 'on' : 'off';
147 $this->show_comments = 'on' === $show_comments ? 'on' : 'off';
148 $this->show_create = 'on' === $show_create ? 'on' : 'off';
149 $this->include_table_settings = 'on' === $include_table_settings ? 'on' : 'off';
150
151 if ( '' !== $schema_name ) {
152 $wpdadb = WPDADB::get_db_connection( $schema_name );
153 if ( null === $wpdadb ) {
154 /* translators: %s = database name */
155 die( sprintf( esc_attr__( 'ERROR - Remote database %s not available', 'wp-data-access' ), esc_attr( $this->schema_name ) ) );
156 }
157
158 $this->schema_name = $schema_name;
159 $this->schema_name_prefix = "`{$wpdadb->dbname}`.";
160 }
161
162 $this->table_list = $table_names;
163
164 if ( 'table' === $export_type ) {
165 // Table export.
166 $this->export_tables();
167 } else {
168 // Row export.
169 if ( is_array( $this->table_list ) ) {
170 // For row exports a single table name must be supplied as a string.
171 $this->wrong_arguments();
172 } else {
173 $this->export_rows();
174 }
175 }
176 }
177
178 /**
179 * Main method to start export
180 *
181 * This method checks arguments and starts the export according to the arguments provided.
182 *
183 * @since 1.0.0
184 */
185 public function export() {
186 // Check if export is allowed.
187 $table_names = isset( $_REQUEST['table_names'] ) ?
188 json_encode( WPDA::sanitize_text_field_array( $_REQUEST['table_names'] ) ) : ''; // phpcs:ignore
189 $wp_nonce = isset( $_REQUEST['_wpnonce'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['_wpnonce'] ) ) : '?'; // input var okay.
190 if (
191 ! wp_verify_nonce( $wp_nonce, "wpda-export-{$table_names}" ) &&
192 ! wp_verify_nonce( $wp_nonce, 'wpda-export-' . WPDA::get_current_user_login() )
193 ) {
194 wp_die();
195 }
196
197 // Get arguments.
198 $this->mysql_set = isset( $_REQUEST['mysql_set'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['mysql_set'] ) ) : 'on'; // input var okay.
199 $this->show_comments = isset( $_REQUEST['show_comments'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['show_comments'] ) ) : 'on'; // input var okay.
200 $this->show_create = isset( $_REQUEST['show_create'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['show_create'] ) ) : 'on'; // input var okay.
201 $this->include_table_settings = isset( $_REQUEST['include_table_settings'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['include_table_settings'] ) ) : 'off'; // input var okay.
202 $pub_id = isset( $_REQUEST['pub_id'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['pub_id'] ) ) : ''; // input var okay.
203
204 if ( isset( $_REQUEST['wpdaschema_name'] ) ) {
205 $this->schema_name = sanitize_text_field( wp_unslash( $_REQUEST['wpdaschema_name'] ) ); // input var okay.
206 } elseif ( '' !== $pub_id ) {
207 // Get schema name from publication
208 $publication = WPDA_Publisher_Model::get_publication( $pub_id );
209 if ( false === $publication ) {
210 wp_die();
211 }
212 $this->schema_name = $publication[0]['pub_schema_name'];
213 }
214
215 if ( '' !== $this->schema_name ) {
216 $wpdadb = WPDADB::get_db_connection( $this->schema_name );
217 if ( null === $wpdadb ) {
218 wp_die();
219 }
220 $this->schema_name_prefix = "`{$wpdadb->dbname}`.";
221 }
222
223 if ( isset( $_REQUEST['type'] ) && isset( $_REQUEST['table_names'] ) ) { // input var okay.
224 // Get table_name(s) from URL. Type is string for single table export and array for multi table export.
225 // Row export implies single table export.
226 $this->table_list = WPDA::sanitize_text_field_array( $_REQUEST['table_names'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
227
228 if ( 'table' === sanitize_text_field( wp_unslash( $_REQUEST['type'] ) ) ) { // input var okay.
229 // Table export.
230 $this->export_tables();
231 } else {
232 // Row export.
233 if ( is_array( $this->table_list ) ) {
234 // For row exports a single table name must be supplied as a string.
235 $this->wrong_arguments();
236 } else {
237 $this->export_rows();
238 }
239 }
240 } else {
241 $this->wrong_arguments();
242 }
243
244 if ( '' !== $pub_id ) {
245 wp_die();
246 }
247 }
248
249 /**
250 * A table export was requested
251 *
252 * @since 1.0.0
253 */
254 protected function export_tables() {
255 if ( is_array( $this->table_list ) ) {
256 // Multiple table export.
257 $this->header( 'export' );
258 $this->db_begin();
259
260 foreach ( $this->table_list as $table_name ) {
261 // Check if table exists to prevent SQL injection.
262 $wpda_dictionary_exists = new WPDA_Dictionary_Exist( $this->schema_name, $table_name );
263 if ( ! $wpda_dictionary_exists->table_exists() ) {
264 wp_die();
265 }
266
267 $this->create_table( $table_name );
268 $this->insert_rows( $table_name );
269 }
270
271 $this->db_end();
272 } else {
273 // Single table export.
274 $table_name = $this->table_list;
275
276 // Check if table exists to prevent SQL injection.
277 $wpda_dictionary_exists = new WPDA_Dictionary_Exist( $this->schema_name, $table_name );
278 if ( ! $wpda_dictionary_exists->table_exists() ) {
279 wp_die();
280 }
281
282 $this->header( $table_name );
283 $this->db_begin();
284
285 $this->create_table( $table_name );
286 $this->insert_rows( $table_name );
287
288 $this->db_end();
289 }
290 }
291
292 /**
293 * Set export header (filename)
294 *
295 * @param string $file_name Export filename.
296 *
297 * @since 1.0.0
298 */
299 protected function header( $file_name ) {
300 if ( null === $this->output_stream ) {
301 WPDA::sent_header( 'text/plain; charset=utf-8', null, "wpda_{$file_name}.sql" );
302 }
303 }
304
305 /**
306 * Set MySQL environment
307 *
308 * @since 1.0.0
309 */
310 protected function db_begin() {
311 if ( 'off' === $this->mysql_set ) {
312 return;
313 }
314
315 $wpdadb = WPDADB::get_db_connection( $this->schema_name );
316 if ( null === $wpdadb ) {
317 wp_die();
318 }
319
320 $this->output_string = '';
321
322 $this->output_string .= "/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;\n";
323 $this->output_string .= "/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;\n";
324 $this->output_string .= "/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;\n";
325 $this->output_string .= '/*!40101 SET NAMES ' . esc_attr( $wpdadb->charset ) . " */;\n\n";
326
327 $this->write_output();
328 }
329
330 /**
331 * Write create table statement
332 *
333 * @param string $table_name Database table name.
334 *
335 * @return boolean Indicates whether table exists for further processing.
336 * @since 1.0.0
337 */
338 protected function create_table( $table_name ) {
339 global $wpdb;
340 $wpdadb = WPDADB::get_db_connection( $this->schema_name );
341 if ( null === $wpdadb ) {
342 wp_die();
343 }
344
345 $save_suppress_errors = $wpdadb->suppress_errors;
346 $wpdadb->suppress_errors = true;
347
348 if ( 'off' !== $this->show_create ) {
349 $engine = WPDA::get_table_engine( $this->schema_name, $table_name );
350 if ( 'connect' === strtolower( $engine ) ) {
351 // Remove table options for CONNECT tables
352 // NO_TABLE_OPTIONS is deprecated in V8
353 // $wpdadb->query( "SET sql_mode = 'NO_TABLE_OPTIONS'" );
354 }
355 $query = "show create table {$this->schema_name_prefix}`" . str_replace( '`', '', (string) $table_name ) . '`';
356 $ctcmd = $wpdadb->get_results( $query, 'ARRAY_A' );
357 }
358
359 $this->output_string = '';
360 if ( $wpdadb->num_rows > 0 ) {
361 if ( 'off' !== $this->show_comments ) {
362 $this->output_string .= "--\n";
363 if (
364 $this->export_with_prefix &&
365 $wpdb->dbname === $this->schema_name &&
366 ( WPDA::is_wp_table( $table_name ) || WPDA::is_wpda_table( $table_name ) )
367 ) {
368 $this->output_string .= '-- Create table `{wp_prefix}' . esc_attr( substr( $table_name, strlen( $wpdb->prefix ) ) ) . "`\n";
369 } else {
370 $this->output_string .= '-- Create table `' . esc_attr( $table_name ) . "`\n";
371 }
372 $this->output_string .= "--\n";
373 }
374
375 if ( 'off' !== $this->show_create ) {
376 $create_table_statement = $ctcmd[0]['Create Table'];
377 if (
378 $this->export_with_prefix &&
379 $wpdb->dbname === $this->schema_name &&
380 ( WPDA::is_wp_table( $table_name ) || WPDA::is_wpda_table( $table_name ) )
381 ) {
382 $table_name_position = stripos( $create_table_statement, $table_name );
383 if ( $table_name_position > 0 ) {
384 $create_table_statement_saved = $create_table_statement;
385 $create_table_statement = substr( $create_table_statement, 0, $table_name_position );
386 $create_table_statement .= '{wp_prefix}' . esc_attr( substr( $table_name, strlen( $wpdb->prefix ) ) );
387 $create_table_statement .= substr( $create_table_statement_saved, $table_name_position + strlen( $table_name ) );
388 }
389 }
390 $this->output_string .= wp_kses_data( $create_table_statement ) . ";\n\n";
391 }
392
393 $table_exists = true;
394 } else {
395 if ( 'off' !== $this->show_comments ) {
396 $this->output_string .= "--\n";
397 $this->output_string .= '-- Table `' . esc_attr( $table_name ) . "` found\n";
398 $this->output_string .= "--\n\n";
399 }
400
401 $table_exists = false;
402 }
403
404 $this->write_output();
405
406 $wpdadb->suppress_errors = $save_suppress_errors;
407
408 return $table_exists;
409 }
410
411 /**
412 * Write insert into statement
413 *
414 * @param string $table_name Database table name.
415 * @param string $where Where clause.
416 * @param boolean $show_comments Argument is needed for direct call from WPDA_Repository! (do not remove).
417 *
418 * @since 1.0.0
419 */
420 public function insert_rows( $table_name, $where = '', $show_comments = true ) {
421 $wpdadb = WPDADB::get_db_connection( $this->schema_name );
422 if ( null === $wpdadb ) {
423 wp_die();
424 }
425
426 $save_suppress_errors = $wpdadb->suppress_errors;
427 $wpdadb->suppress_errors = true;
428
429 $settings_db = WPDA_Table_Settings_Model::query( $table_name, $this->schema_name );
430 if ( isset( $settings_db[0]['wpda_table_settings'] ) ) {
431 $settings_db_custom = json_decode( $settings_db[0]['wpda_table_settings'] );
432 if ( isset( $settings_db_custom->table_settings->query_buffer_size ) ) {
433 $query_buffer_size = $settings_db_custom->table_settings->query_buffer_size;
434 } else {
435 $query_buffer_size = 0;
436 }
437 } else {
438 $query_buffer_size = 0;
439 }
440
441 $this->output_string = '';
442
443 $query = "select * from {$this->schema_name_prefix}`" . str_replace( '`', '', (string) $table_name ) . "` $where";
444 if ( is_numeric( $query_buffer_size ) && $query_buffer_size > 0 ) {
445 // phpcs:disable Squiz.PHP.DiscouragedFunctions.Discouraged
446 set_time_limit(0);
447 // phpcs:enable Squiz.PHP.DiscouragedFunctions.Discouraged
448 $i = 0;
449 $sql = $query . ' limit ' . $query_buffer_size;
450 $rows = $wpdadb->get_results( $sql, 'ARRAY_A' );
451 while ( $wpdadb->num_rows > 0 ) {
452 $this->insert_rows_buffer( $rows, $table_name, $where, $show_comments );
453
454 $i++;
455 $sql = $query . ' limit ' . $query_buffer_size . ' offset ' . ( $i * $query_buffer_size );
456 $rows = $wpdadb->get_results( $sql, 'ARRAY_A' );
457 }
458
459 if ( 1 === $i && 0 == $wpdadb->num_rows ) {
460 $this->empty_table( $table_name, $show_comments );
461 }
462 } else {
463 $rows = $wpdadb->get_results( $query, 'ARRAY_A' );
464
465 if ( $wpdadb->num_rows > 0 ) {
466 $this->insert_rows_buffer( $rows, $table_name, $where, $show_comments );
467 } else {
468 $this->empty_table( $table_name, $show_comments );
469 }
470 }
471
472 if ( 'on' === $this->include_table_settings ) {
473 // Export table settings
474 $this->export_table_settings( $table_name, $show_comments );
475 }
476
477 $this->write_output();
478
479 $wpdadb->suppress_errors = $save_suppress_errors;
480 }
481
482 private function empty_table( $table_name, $show_comments ) {
483 // Empty table, nothing to export.
484 if ( $show_comments && 'off' !== $this->show_comments ) {
485 $this->output_string .= "--\n";
486 $this->output_string .= '-- No rows to export from empty table `' . esc_attr( $table_name ) . "`\n";
487 $this->output_string .= "--\n\n";
488 }
489 }
490
491 /**
492 * Write insert into statements for buffered rows
493 *
494 * @param array $rows Buffered rows
495 * @param string $table_name Database table name.
496 * @param string $where Where clause.
497 * @param boolean $show_comments Argument is needed for direct call from WPDA_Repository! (do not remove).
498 *
499 * @since 1.0.0
500 */
501 private function insert_rows_buffer( $rows, $table_name, $where, $show_comments ) {
502 global $wpdb;
503
504 $this->output_string = '';
505
506 // Prepare row export: get column names and data types.
507 $wpda_list_columns = WPDA_List_Columns_Cache::get_list_columns( $this->schema_name, $table_name );
508 $table_columns = $wpda_list_columns->get_table_columns();
509
510 // Create array for fast column_name based access.
511 $column_data_types = $this->column_data_types( $table_columns );
512
513 // Exports rows.
514 if ( $show_comments && 'off' !== $this->show_comments ) {
515 $this->output_string .= "--\n";
516 if (
517 $this->export_with_prefix &&
518 $wpdb->dbname === $this->schema_name &&
519 ( WPDA::is_wp_table( $table_name ) || WPDA::is_wpda_table( $table_name ) )
520 ) {
521 $this->output_string .= '-- Export table `{wp_prefix}' . esc_attr( substr( $table_name, strlen( $wpdb->prefix ) ) ) . "`\n";
522 } else {
523 $this->output_string .= '-- Export table `' . esc_attr( $table_name ) . "`\n";
524 }
525 $this->output_string .= "--\n";
526 }
527
528 if ( ( $show_comments && '' !== $where ) && 'off' !== $this->show_comments ) {
529 $this->output_string .= '-- Condition: `' . esc_attr( $where ) . "`\n";
530 $this->output_string .= "--\n";
531 }
532
533 $this->write_output();
534
535 if (
536 $this->export_with_prefix &&
537 ( $wpdb->dbname === $this->schema_name || '' === $this->schema_name ) &&
538 ( WPDA::is_wp_table( $table_name ) || WPDA::is_wpda_table( $table_name ) )
539 ) {
540 $insert_statement = 'INSERT INTO `{wp_prefix}' . esc_attr( substr( str_replace( '`', '', (string) $table_name ), strlen( $wpdb->prefix ) ) ) . '` ';
541 } else {
542 $insert_statement = 'INSERT INTO `' . esc_attr( str_replace( '`', '', (string) $table_name ) ) . '` ';
543 }
544
545 $process_first_row = true;
546 foreach ( $rows[0] as $column_name => $column_value ) {
547 if (
548 ! (
549 WPDA::is_wpda_table( $table_name ) &&
550 (
551 'pub_id' === $column_name ||
552 'csv_id' === $column_name ||
553 'menu_id' === $column_name ||
554 'report_id' === $column_name
555 )
556 )
557 ) {
558 $insert_statement .= $process_first_row ? '(' : ', ';
559 $insert_statement .= '`' . esc_attr( str_replace( '`', '', (string) $column_name ) ) . '`';
560
561 $process_first_row = false;
562 }
563 }
564
565 $insert_statement .= ') VALUES ';
566
567 foreach ( $rows as $row ) {
568 $this->output_string .= $insert_statement . '(';
569
570 $keys = array_keys( $row ); // phpcs:ignore -- 8.1 proof
571 $last_column = end( $keys ); // phpcs:ignore -- 8.1 proof
572 foreach ( $row as $column_name => $column_value ) {
573 if (
574 ! (
575 WPDA::is_wpda_table( $table_name ) &&
576 (
577 'pub_id' === $column_name ||
578 'csv_id' === $column_name ||
579 'menu_id' === $column_name ||
580 'report_id' === $column_name
581 )
582 )
583 ) {
584 if ( $this->is_numeric( $column_data_types[ $column_name ] ) ) {
585 if ( is_null( $column_value ) ) {
586 $this->output_string .= 'null';
587 } else {
588 $this->output_string .= esc_attr( $column_value );
589 }
590 } else {
591 if (
592 WPDA::column_is_schema_name( $table_name, $column_name ) &&
593 ( '' === $column_value || $wpdb->dbname === $column_value )
594 ) {
595 $this->output_string .= "'{wp_schema}'";
596 } else {
597 if ( is_null( $column_value ) ) {
598 $this->output_string .= 'null';
599 } else {
600 $this->output_string .= "'" . esc_sql( $column_value ) . "'";
601 }
602 }
603 }
604 if ( $column_name !== $last_column ) {
605 $this->output_string .= ',';
606 }
607 }
608 }
609
610 $this->output_string .= ");\n";
611
612 $this->write_output();
613 }
614
615 if ( 'off' !== $this->show_comments ) {
616 $this->output_string .= "\n";
617 }
618 }
619
620 /**
621 * Export table settings
622 *
623 * @param $table_name Table for which settings will be exported
624 * @param boolean $show_comments Argument is needed for direct call from WPDA_Repository! (do not remove).
625 *
626 * @since 2.6.1
627 */
628 protected function export_table_settings( $table_name, $show_comments = true ) {
629 global $wpdb;
630
631 if ( $show_comments && 'off' !== $this->show_comments ) {
632 $this->output_string .= "--\n";
633 $this->output_string .= '-- Export table settings for table `' . esc_attr( $table_name ) . "`\n";
634 $this->output_string .= "--\n";
635 }
636
637 if ( '' === $this->schema_name || $wpdb->dbname === $this->schema_name ) {
638 $schema_name = '{wp_schema}';
639 } else {
640 $schema_name = $this->schema_name;
641 }
642
643 if ( 'on' === $this->include_table_settings ) {
644 // Export column labels
645 $rows = $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- plugin table
646 $wpdb->prepare(
647 "select * from {$wpdb->prefix}wpda_table_settings where wpda_table_name = %s",
648 array(
649 $table_name,
650 )
651 ),
652 'ARRAY_A'
653 );
654 if ( 1 === $wpdb->num_rows ) {
655 $this->output_string .=
656 'DELETE FROM `{wp_prefix}wpda_table_settings` ' .
657 "WHERE `wpda_table_name` = '" . esc_attr( $table_name ) . "';";
658 $this->output_string .= "\n";
659 $this->output_string .=
660 'INSERT INTO `{wp_prefix}wpda_table_settings` ' .
661 '(`wpda_schema_name`, `wpda_table_name`, `wpda_table_settings`) ' .
662 'VALUES ' .
663 "('" . esc_sql( $schema_name ) . "', '" . esc_sql( $table_name ) . "', '" .
664 esc_sql( $rows[0]['wpda_table_settings'] ) . "');";
665 $this->output_string .= "\n";
666 }
667
668 // Export media columns
669 $rows = $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- plugin table
670 $wpdb->prepare(
671 "select * from {$wpdb->prefix}wpda_media where media_table_name = %s",
672 array(
673 $table_name,
674 )
675 ),
676 'ARRAY_A'
677 );
678 $this->output_string .=
679 'DELETE FROM `{wp_prefix}wpda_media` ' .
680 "WHERE `media_table_name` = '" . esc_attr( $table_name ) . "';";
681 $this->output_string .= "\n";
682 foreach ( $rows as $row ) {
683 $this->output_string .=
684 'INSERT INTO `{wp_prefix}wpda_media` ' .
685 '(`media_schema_name`, `media_table_name`, `media_column_name`, `media_type`, `media_activated`) ' .
686 'VALUES ' .
687 "('" . esc_sql( $schema_name ) . "', '" . esc_sql( $table_name ) . "', '" .
688 esc_sql( $row['media_column_name'] ) . "', '" . esc_sql( $row['media_type'] ) . "', '" .
689 esc_sql( $row['media_activated'] ) . "');";
690 $this->output_string .= "\n";
691 }
692
693 // Export table menus
694 $rows = $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- plugin table
695 $wpdb->prepare(
696 "select * from {$wpdb->prefix}wpda_menus where menu_table_name = %s",
697 array(
698 $table_name,
699 )
700 ),
701 'ARRAY_A'
702 );
703 $this->output_string .=
704 'DELETE FROM `{wp_prefix}wpda_menus` ' .
705 "WHERE `menu_table_name` = '" . esc_attr( $table_name ) . "';";
706 $this->output_string .= "\n";
707 foreach ( $rows as $row ) {
708 $this->output_string .=
709 'INSERT INTO `{wp_prefix}wpda_menus` ' .
710 '(`menu_schema_name`, `menu_table_name`, `menu_name`, `menu_slug`, `menu_role`) ' .
711 'VALUES ' .
712 "('" . esc_sql( $schema_name ) . "', '" . esc_sql( $table_name ) . "', '" .
713 esc_sql( $row['menu_name'] ) . "', '" . esc_sql( $row['menu_slug'] ) . "', '" .
714 esc_sql( $row['menu_role'] ) . "');";
715 $this->output_string .= "\n";
716 }
717 }
718
719 $this->output_string .= "\n";
720 }
721
722 /**
723 * Save column data types
724 *
725 * This method creates a named array for all column names of a table in form:
726 * 'column_name' => 'data_type'
727 *
728 * Argument $table_columns can be retrieved from WPDA_List_Columns->set_table_columns(). It must be prepared
729 * however with the idea that the instance of WPDA_List_Columns can be reused for best performance.
730 *
731 * In fact this is just an array conversion.
732 *
733 * @param array $table_columns Column_names and data_types of a table (table name not used here).
734 *
735 * @return array Named array 'column_name' => 'data_type' for all columns in the table.
736 * @since 1.0.0
737 */
738 protected function column_data_types( $table_columns ) {
739 $column_data_types = array();
740
741 foreach ( $table_columns as $column_value ) {
742 $column_data_types[ $column_value['column_name'] ] = $column_value['data_type'];
743 }
744
745 return $column_data_types;
746 }
747
748 /**
749 * Check if data type is numeric
750 *
751 * @param string $data_type Data type (simple).
752 *
753 * @return bool
754 * @since 1.0.0
755 */
756 protected function is_numeric( $data_type ) {
757 return ( 'number' === WPDA::get_type( $data_type ) );
758 }
759
760 /**
761 * Set back MySQL environment
762 *
763 * @since 1.0.0
764 */
765 protected function db_end() {
766 if ( 'off' === $this->mysql_set ) {
767 return;
768 }
769
770 $this->output_string = '';
771
772 $this->output_string .= "/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;\n";
773 $this->output_string .= "/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;\n";
774 $this->output_string .= "/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;\n";
775
776 $this->write_output();
777 }
778
779 /**
780 * Processing on invalid arguments
781 *
782 * @since 1.0.0
783 */
784 protected function wrong_arguments() {
785 wp_die();
786 }
787
788 /**
789 * A row export was requested
790 *
791 * @since 1.0.0
792 */
793 protected function export_rows() {
794 // Check if table exists to prevent SQL injection.
795 $wpda_dictionary_exists = new WPDA_Dictionary_Exist( $this->schema_name, $this->table_list );
796 if ( ! $wpda_dictionary_exists->table_exists() ) {
797 wp_die();
798 }
799
800 // Get table columns and data types.
801 $wpda_list_columns = WPDA_List_Columns_Cache::get_list_columns( $this->schema_name, $this->table_list );
802 $table_columns = $wpda_list_columns->get_table_columns();
803
804 // Create array for fast column_name based access.
805 $column_data_types = $this->column_data_types( $table_columns );
806
807 // Get primary key columns.
808 $table_primary_key = $wpda_list_columns->get_table_primary_key();
809
810 // Check validity request. All primary key columns must be supplied. Return error if
811 // primary key columns are missing.
812 foreach ( $table_primary_key as $key ) {
813 if ( ! isset( $key ) ) {
814 $this->wrong_arguments();
815 }
816 }
817
818 global $wpdb;
819
820 // Build where clause based on primary key.
821 $where = '';
822
823 // Use first column of the primary key to loop through arguments. Add additional arguments in the loop.
824 // A mismatch in the number of argument is possible as long as the columns match based on the first column
825 // of the primary key. Other mismatches won't be taken into account.
826 $count_pk = count( ( array ) $_REQUEST[ $table_primary_key[0] ] ); // phpcs:ignore -- 8.1 proof
827 for ( $i = 0; $i < $count_pk; $i ++ ) {
828 $and = '';
829 foreach ( $table_primary_key as $key ) {
830 $and .= '' === $and ? '(' : ' and ';
831 if ( $this->is_numeric( $column_data_types[ $key ] ) ) {
832 $and .= $wpdb->prepare(
833 '`%1s` = %d', // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders
834 array(
835 WPDA::remove_backticks( $key ),
836 sanitize_text_field( wp_unslash( $_REQUEST[ $key ][ $i ] ) ), // phpcs:ignore -- nonce veryfied in export function
837 )
838 );
839 } else {
840 $and .= $wpdb->prepare(
841 '`%1s` = %s', // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders
842 array(
843 WPDA::remove_backticks( $key ),
844 sanitize_text_field( wp_unslash( $_REQUEST[ $key ][ $i ] ) ), // phpcs:ignore -- nonce veryfied in export function
845 )
846 );
847 }
848 }
849
850 $and .= '' === $and ? '' : ')';
851
852 $where .= '' === $where ? ' where ' : ' or ';
853 $where .= $and;
854 }
855
856 $this->header( $this->table_list );
857 $this->db_begin();
858 $this->insert_rows( $this->table_list, $where );
859 $this->db_end();
860 }
861
862 /**
863 * Define output stream
864 *
865 * Used to stream an export to a file. Streaming helps to support exports of large files.
866 *
867 * @param Stream $output_stream Handle to output stream
868 *
869 * @since 2.0.13
870 */
871 public function set_output_stream( $output_stream ) {
872 $this->output_stream = $output_stream;
873 }
874
875 /**
876 * Depending on the type of export (streaming or echoing) the output is written to the export file.
877 *
878 * @since 2.0.13
879 */
880 protected function write_output() {
881 if ( null === $this->output_stream ) {
882 echo $this->output_string; // phpcs:ignore WordPress.Security.EscapeOutput
883 } else {
884 fwrite( $this->output_stream, $this->output_string ); // phpcs:ignore
885 }
886 $this->output_string = '';
887 }
888
889 }
890
891 }
892