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

889 lines 27.8 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 // NO_TABLE_OPTIONS is deprecated in V8
352 // $wpdadb->query( "SET sql_mode = 'NO_TABLE_OPTIONS'" );
353 }
354 $query = "show create table {$this->schema_name_prefix}`" . str_replace( '`', '', (string) $table_name ) . '`';
355 $ctcmd = $wpdadb->get_results( $query, 'ARRAY_A' ); // phpcs:ignore Standard.Category.SniffName.ErrorCode
356 }
357
358 $this->output_string = '';
359 if ( $wpdadb->num_rows > 0 ) {
360 if ( 'off' !== $this->show_comments ) {
361 $this->output_string .= "--\n";
362 if (
363 $this->export_with_prefix &&
364 $wpdb->dbname === $this->schema_name &&
365 ( WPDA::is_wp_table( $table_name ) || WPDA::is_wpda_table( $table_name ) )
366 ) {
367 $this->output_string .= '-- Create table `{wp_prefix}' . esc_attr( substr( $table_name, strlen( $wpdb->prefix ) ) ) . "`\n";
368 } else {
369 $this->output_string .= '-- Create table `' . esc_attr( $table_name ) . "`\n";
370 }
371 $this->output_string .= "--\n";
372 }
373
374 if ( 'off' !== $this->show_create ) {
375 $create_table_statement = $ctcmd[0]['Create Table'];
376 if (
377 $this->export_with_prefix &&
378 $wpdb->dbname === $this->schema_name &&
379 ( WPDA::is_wp_table( $table_name ) || WPDA::is_wpda_table( $table_name ) )
380 ) {
381 $table_name_position = stripos( $create_table_statement, $table_name );
382 if ( $table_name_position > 0 ) {
383 $create_table_statement_saved = $create_table_statement;
384 $create_table_statement = substr( $create_table_statement, 0, $table_name_position );
385 $create_table_statement .= '{wp_prefix}' . esc_attr( substr( $table_name, strlen( $wpdb->prefix ) ) );
386 $create_table_statement .= substr( $create_table_statement_saved, $table_name_position + strlen( $table_name ) );
387 }
388 }
389 $this->output_string .= wp_kses_data( $create_table_statement ) . ";\n\n";
390 }
391
392 $table_exists = true;
393 } else {
394 if ( 'off' !== $this->show_comments ) {
395 $this->output_string .= "--\n";
396 $this->output_string .= '-- Table `' . esc_attr( $table_name ) . "` found\n";
397 $this->output_string .= "--\n\n";
398 }
399
400 $table_exists = false;
401 }
402
403 $this->write_output();
404
405 $wpdadb->suppress_errors = $save_suppress_errors;
406
407 return $table_exists;
408 }
409
410 /**
411 * Write insert into statement
412 *
413 * @param string $table_name Database table name.
414 * @param string $where Where clause.
415 * @param boolean $show_comments Argument is needed for direct call from WPDA_Repository! (do not remove).
416 *
417 * @since 1.0.0
418 */
419 public function insert_rows( $table_name, $where = '', $show_comments = true ) {
420 $wpdadb = WPDADB::get_db_connection( $this->schema_name );
421 if ( null === $wpdadb ) {
422 wp_die();
423 }
424
425 $save_suppress_errors = $wpdadb->suppress_errors;
426 $wpdadb->suppress_errors = true;
427
428 $settings_db = WPDA_Table_Settings_Model::query( $table_name, $this->schema_name );
429 if ( isset( $settings_db[0]['wpda_table_settings'] ) ) {
430 $settings_db_custom = json_decode( $settings_db[0]['wpda_table_settings'] );
431 if ( isset( $settings_db_custom->table_settings->query_buffer_size ) ) {
432 $query_buffer_size = $settings_db_custom->table_settings->query_buffer_size;
433 } else {
434 $query_buffer_size = 0;
435 }
436 } else {
437 $query_buffer_size = 0;
438 }
439
440 $this->output_string = '';
441
442 $query = "select * from {$this->schema_name_prefix}`" . str_replace( '`', '', (string) $table_name ) . "` $where";
443 if ( is_numeric( $query_buffer_size ) && $query_buffer_size > 0 ) {
444 set_time_limit(0);
445 $i = 0;
446 $sql = $query . ' limit ' . $query_buffer_size;
447 $rows = $wpdadb->get_results( $sql, 'ARRAY_A' ); // phpcs:ignore Standard.Category.SniffName.ErrorCode
448 while ( $wpdadb->num_rows > 0 ) {
449 $this->insert_rows_buffer( $rows, $table_name, $where, $show_comments );
450
451 $i++;
452 $sql = $query . ' limit ' . $query_buffer_size . ' offset ' . ( $i * $query_buffer_size );
453 $rows = $wpdadb->get_results( $sql, 'ARRAY_A' ); // phpcs:ignore Standard.Category.SniffName.ErrorCode
454 }
455
456 if ( 1 === $i && 0 == $wpdadb->num_rows ) {
457 $this->empty_table( $table_name, $show_comments );
458 }
459 } else {
460 $rows = $wpdadb->get_results( $query, 'ARRAY_A' ); // phpcs:ignore Standard.Category.SniffName.ErrorCode
461
462 if ( $wpdadb->num_rows > 0 ) {
463 $this->insert_rows_buffer( $rows, $table_name, $where, $show_comments );
464 } else {
465 $this->empty_table( $table_name, $show_comments );
466 }
467 }
468
469 if ( 'on' === $this->include_table_settings ) {
470 // Export table settings
471 $this->export_table_settings( $table_name, $show_comments );
472 }
473
474 $this->write_output();
475
476 $wpdadb->suppress_errors = $save_suppress_errors;
477 }
478
479 private function empty_table( $table_name, $show_comments ) {
480 // Empty table, nothing to export.
481 if ( $show_comments && 'off' !== $this->show_comments ) {
482 $this->output_string .= "--\n";
483 $this->output_string .= '-- No rows to export from empty table `' . esc_attr( $table_name ) . "`\n";
484 $this->output_string .= "--\n\n";
485 }
486 }
487
488 /**
489 * Write insert into statements for buffered rows
490 *
491 * @param array $rows Buffered rows
492 * @param string $table_name Database table name.
493 * @param string $where Where clause.
494 * @param boolean $show_comments Argument is needed for direct call from WPDA_Repository! (do not remove).
495 *
496 * @since 1.0.0
497 */
498 private function insert_rows_buffer( $rows, $table_name, $where, $show_comments ) {
499 global $wpdb;
500
501 $this->output_string = '';
502
503 // Prepare row export: get column names and data types.
504 $wpda_list_columns = WPDA_List_Columns_Cache::get_list_columns( $this->schema_name, $table_name );
505 $table_columns = $wpda_list_columns->get_table_columns();
506
507 // Create array for fast column_name based access.
508 $column_data_types = $this->column_data_types( $table_columns );
509
510 // Exports rows.
511 if ( $show_comments && 'off' !== $this->show_comments ) {
512 $this->output_string .= "--\n";
513 if (
514 $this->export_with_prefix &&
515 $wpdb->dbname === $this->schema_name &&
516 ( WPDA::is_wp_table( $table_name ) || WPDA::is_wpda_table( $table_name ) )
517 ) {
518 $this->output_string .= '-- Export table `{wp_prefix}' . esc_attr( substr( $table_name, strlen( $wpdb->prefix ) ) ) . "`\n";
519 } else {
520 $this->output_string .= '-- Export table `' . esc_attr( $table_name ) . "`\n";
521 }
522 $this->output_string .= "--\n";
523 }
524
525 if ( ( $show_comments && '' !== $where ) && 'off' !== $this->show_comments ) {
526 $this->output_string .= '-- Condition: `' . esc_attr( $where ) . "`\n";
527 $this->output_string .= "--\n";
528 }
529
530 $this->write_output();
531
532 if (
533 $this->export_with_prefix &&
534 ( $wpdb->dbname === $this->schema_name || '' === $this->schema_name ) &&
535 ( WPDA::is_wp_table( $table_name ) || WPDA::is_wpda_table( $table_name ) )
536 ) {
537 $insert_statement = 'INSERT INTO `{wp_prefix}' . esc_attr( substr( str_replace( '`', '', (string) $table_name ), strlen( $wpdb->prefix ) ) ) . '` ';
538 } else {
539 $insert_statement = 'INSERT INTO `' . esc_attr( str_replace( '`', '', (string) $table_name ) ) . '` ';
540 }
541
542 $process_first_row = true;
543 foreach ( $rows[0] as $column_name => $column_value ) {
544 if (
545 ! (
546 WPDA::is_wpda_table( $table_name ) &&
547 (
548 'pub_id' === $column_name ||
549 'csv_id' === $column_name ||
550 'menu_id' === $column_name ||
551 'report_id' === $column_name
552 )
553 )
554 ) {
555 $insert_statement .= $process_first_row ? '(' : ', ';
556 $insert_statement .= '`' . esc_attr( str_replace( '`', '', (string) $column_name ) ) . '`';
557
558 $process_first_row = false;
559 }
560 }
561
562 $insert_statement .= ') VALUES ';
563
564 foreach ( $rows as $row ) {
565 $this->output_string .= $insert_statement . '(';
566
567 $keys = array_keys( $row );//phpcs:ignore - 8.1 proof
568 $last_column = end( $keys );//phpcs:ignore - 8.1 proof
569 foreach ( $row as $column_name => $column_value ) {
570 if (
571 ! (
572 WPDA::is_wpda_table( $table_name ) &&
573 (
574 'pub_id' === $column_name ||
575 'csv_id' === $column_name ||
576 'menu_id' === $column_name ||
577 'report_id' === $column_name
578 )
579 )
580 ) {
581 if ( $this->is_numeric( $column_data_types[ $column_name ] ) ) {
582 if ( is_null( $column_value ) ) {
583 $this->output_string .= 'null';
584 } else {
585 $this->output_string .= esc_attr( $column_value );
586 }
587 } else {
588 if (
589 WPDA::column_is_schema_name( $table_name, $column_name ) &&
590 ( '' === $column_value || $wpdb->dbname === $column_value )
591 ) {
592 $this->output_string .= "'{wp_schema}'";
593 } else {
594 if ( is_null( $column_value ) ) {
595 $this->output_string .= 'null';
596 } else {
597 $this->output_string .= "'" . esc_sql( $column_value ) . "'";
598 }
599 }
600 }
601 if ( $column_name !== $last_column ) {
602 $this->output_string .= ',';
603 }
604 }
605 }
606
607 $this->output_string .= ");\n";
608
609 $this->write_output();
610 }
611
612 if ( 'off' !== $this->show_comments ) {
613 $this->output_string .= "\n";
614 }
615 }
616
617 /**
618 * Export table settings
619 *
620 * @param $table_name Table for which settings will be exported
621 * @param boolean $show_comments Argument is needed for direct call from WPDA_Repository! (do not remove).
622 *
623 * @since 2.6.1
624 */
625 protected function export_table_settings( $table_name, $show_comments = true ) {
626 global $wpdb;
627
628 if ( $show_comments && 'off' !== $this->show_comments ) {
629 $this->output_string .= "--\n";
630 $this->output_string .= '-- Export table settings for table `' . esc_attr( $table_name ) . "`\n";
631 $this->output_string .= "--\n";
632 }
633
634 if ( '' === $this->schema_name || $wpdb->dbname === $this->schema_name ) {
635 $schema_name = '{wp_schema}';
636 } else {
637 $schema_name = $this->schema_name;
638 }
639
640 if ( 'on' === $this->include_table_settings ) {
641 // Export column labels
642 $rows = $wpdb->get_results(
643 $wpdb->prepare(
644 "select * from {$wpdb->prefix}wpda_table_settings where wpda_table_name = %s",
645 array(
646 $table_name,
647 )
648 ),
649 'ARRAY_A'
650 ); // phpcs:ignore Standard.Category.SniffName.ErrorCode
651 if ( 1 === $wpdb->num_rows ) {
652 $this->output_string .=
653 'DELETE FROM `{wp_prefix}wpda_table_settings` ' .
654 "WHERE `wpda_table_name` = '" . esc_attr( $table_name ) . "';";
655 $this->output_string .= "\n";
656 $this->output_string .=
657 'INSERT INTO `{wp_prefix}wpda_table_settings` ' .
658 '(`wpda_schema_name`, `wpda_table_name`, `wpda_table_settings`) ' .
659 'VALUES ' .
660 "('" . esc_sql( $schema_name ) . "', '" . esc_sql( $table_name ) . "', '" .
661 esc_sql( $rows[0]['wpda_table_settings'] ) . "');";
662 $this->output_string .= "\n";
663 }
664
665 // Export media columns
666 $rows = $wpdb->get_results(
667 $wpdb->prepare(
668 "select * from {$wpdb->prefix}wpda_media where media_table_name = %s",
669 array(
670 $table_name,
671 )
672 ),
673 'ARRAY_A'
674 ); // phpcs:ignore Standard.Category.SniffName.ErrorCode
675 $this->output_string .=
676 'DELETE FROM `{wp_prefix}wpda_media` ' .
677 "WHERE `media_table_name` = '" . esc_attr( $table_name ) . "';";
678 $this->output_string .= "\n";
679 foreach ( $rows as $row ) {
680 $this->output_string .=
681 'INSERT INTO `{wp_prefix}wpda_media` ' .
682 '(`media_schema_name`, `media_table_name`, `media_column_name`, `media_type`, `media_activated`) ' .
683 'VALUES ' .
684 "('" . esc_sql( $schema_name ) . "', '" . esc_sql( $table_name ) . "', '" .
685 esc_sql( $row['media_column_name'] ) . "', '" . esc_sql( $row['media_type'] ) . "', '" .
686 esc_sql( $row['media_activated'] ) . "');";
687 $this->output_string .= "\n";
688 }
689
690 // Export table menus
691 $rows = $wpdb->get_results(
692 $wpdb->prepare(
693 "select * from {$wpdb->prefix}wpda_menus where menu_table_name = %s",
694 array(
695 $table_name,
696 )
697 ),
698 'ARRAY_A'
699 ); // phpcs:ignore Standard.Category.SniffName.ErrorCode
700 $this->output_string .=
701 'DELETE FROM `{wp_prefix}wpda_menus` ' .
702 "WHERE `menu_table_name` = '" . esc_attr( $table_name ) . "';";
703 $this->output_string .= "\n";
704 foreach ( $rows as $row ) {
705 $this->output_string .=
706 'INSERT INTO `{wp_prefix}wpda_menus` ' .
707 '(`menu_schema_name`, `menu_table_name`, `menu_name`, `menu_slug`, `menu_role`) ' .
708 'VALUES ' .
709 "('" . esc_sql( $schema_name ) . "', '" . esc_sql( $table_name ) . "', '" .
710 esc_sql( $row['menu_name'] ) . "', '" . esc_sql( $row['menu_slug'] ) . "', '" .
711 esc_sql( $row['menu_role'] ) . "');";
712 $this->output_string .= "\n";
713 }
714 }
715
716 $this->output_string .= "\n";
717 }
718
719 /**
720 * Save column data types
721 *
722 * This method creates a named array for all column names of a table in form:
723 * 'column_name' => 'data_type'
724 *
725 * Argument $table_columns can be retrieved from WPDA_List_Columns->set_table_columns(). It must be prepared
726 * however with the idea that the instance of WPDA_List_Columns can be reused for best performance.
727 *
728 * In fact this is just an array conversion.
729 *
730 * @param array $table_columns Column_names and data_types of a table (table name not used here).
731 *
732 * @return array Named array 'column_name' => 'data_type' for all columns in the table.
733 * @since 1.0.0
734 */
735 protected function column_data_types( $table_columns ) {
736 $column_data_types = array();
737
738 foreach ( $table_columns as $column_value ) {
739 $column_data_types[ $column_value['column_name'] ] = $column_value['data_type'];
740 }
741
742 return $column_data_types;
743 }
744
745 /**
746 * Check if data type is numeric
747 *
748 * @param string $data_type Data type (simple).
749 *
750 * @return bool
751 * @since 1.0.0
752 */
753 protected function is_numeric( $data_type ) {
754 return ( 'number' === WPDA::get_type( $data_type ) );
755 }
756
757 /**
758 * Set back MySQL environment
759 *
760 * @since 1.0.0
761 */
762 protected function db_end() {
763 if ( 'off' === $this->mysql_set ) {
764 return;
765 }
766
767 $this->output_string = '';
768
769 $this->output_string .= "/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;\n";
770 $this->output_string .= "/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;\n";
771 $this->output_string .= "/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;\n";
772
773 $this->write_output();
774 }
775
776 /**
777 * Processing on invalid arguments
778 *
779 * @since 1.0.0
780 */
781 protected function wrong_arguments() {
782 wp_die();
783 }
784
785 /**
786 * A row export was requested
787 *
788 * @since 1.0.0
789 */
790 protected function export_rows() {
791 // Check if table exists to prevent SQL injection.
792 $wpda_dictionary_exists = new WPDA_Dictionary_Exist( $this->schema_name, $this->table_list );
793 if ( ! $wpda_dictionary_exists->table_exists() ) {
794 wp_die();
795 }
796
797 // Get table columns and data types.
798 $wpda_list_columns = WPDA_List_Columns_Cache::get_list_columns( $this->schema_name, $this->table_list );
799 $table_columns = $wpda_list_columns->get_table_columns();
800
801 // Create array for fast column_name based access.
802 $column_data_types = $this->column_data_types( $table_columns );
803
804 // Get primary key columns.
805 $table_primary_key = $wpda_list_columns->get_table_primary_key();
806
807 // Check validity request. All primary key columns must be supplied. Return error if
808 // primary key columns are missing.
809 foreach ( $table_primary_key as $key ) {
810 if ( ! isset( $key ) ) {
811 $this->wrong_arguments();
812 }
813 }
814
815 global $wpdb;
816
817 // Build where clause based on primary key.
818 $where = '';
819
820 // Use first column of the primary key to loop through arguments. Add additional arguments in the loop.
821 // A mismatch in the number of argument is possible as long as the columns match based on the first column
822 // of the primary key. Other mismatches won't be taken into account.
823 $count_pk = count( ( array ) $_REQUEST[ $table_primary_key[0] ] );//phpcs:ignore - 8.1 proof
824 for ( $i = 0; $i < $count_pk; $i ++ ) {
825 $and = '';
826 foreach ( $table_primary_key as $key ) {
827 $and .= '' === $and ? '(' : ' and ';
828 if ( $this->is_numeric( $column_data_types[ $key ] ) ) {
829 $and .= $wpdb->prepare(
830 '`%1s` = %d', // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders
831 array(
832 WPDA::remove_backticks( $key ),
833 sanitize_text_field( wp_unslash( $_REQUEST[ $key ][ $i ] ) ),
834 )
835 ); // phpcs:ignore Standard.Category.SniffName.ErrorCode
836 } else {
837 $and .= $wpdb->prepare(
838 '`%1s` = %s', // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders
839 array(
840 WPDA::remove_backticks( $key ),
841 sanitize_text_field( wp_unslash( $_REQUEST[ $key ][ $i ] ) ),
842 )
843 ); // phpcs:ignore Standard.Category.SniffName.ErrorCode
844 }
845 }
846
847 $and .= '' === $and ? '' : ')';
848
849 $where .= '' === $where ? ' where ' : ' or ';
850 $where .= $and;
851 }
852
853 $this->header( $this->table_list );
854 $this->db_begin();
855 $this->insert_rows( $this->table_list, $where );
856 $this->db_end();
857 }
858
859 /**
860 * Define output stream
861 *
862 * Used to stream an export to a file. Streaming helps to support exports of large files.
863 *
864 * @param Stream $output_stream Handle to output stream
865 *
866 * @since 2.0.13
867 */
868 public function set_output_stream( $output_stream ) {
869 $this->output_stream = $output_stream;
870 }
871
872 /**
873 * Depending on the type of export (streaming or echoing) the output is written to the export file.
874 *
875 * @since 2.0.13
876 */
877 protected function write_output() {
878 if ( null === $this->output_stream ) {
879 echo $this->output_string; // phpcs:ignore WordPress.Security.EscapeOutput
880 } else {
881 fwrite( $this->output_stream, $this->output_string );
882 }
883 $this->output_string = '';
884 }
885
886 }
887
888 }
889