PluginProbe
WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards / 5.5.22
WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards v5.5.22
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.22, at WPDataAccess/Utilities/WPDA_Export_Sql.php

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