PluginProbe
WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards / 5.5.72
WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards v5.5.72
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 / List_Table / WPDA_List_Table_Menu.php

WPDA_List_Table_Menu.php in WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards 5.5.72, at WPDataAccess/List_Table/WPDA_List_Table_Menu.php

2,641 lines 116.1 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\List_Table
7 */
8 namespace WPDataAccess\List_Table;
9
10 use WP_Data_Access_Admin;
11 use WPDataAccess\Connection\WPDADB;
12 use WPDataAccess\Data_Dictionary\WPDA_Dictionary_Access;
13 use WPDataAccess\Data_Dictionary\WPDA_Dictionary_Exist;
14 use WPDataAccess\Data_Dictionary\WPDA_Dictionary_Lists;
15 use WPDataAccess\Data_Dictionary\WPDA_List_Columns_Cache;
16 use WPDataAccess\Plugin_Table_Models\WPDA_Media_Model;
17 use WPDataAccess\Plugin_Table_Models\WPDA_Table_Settings_Model;
18 use WPDataAccess\Plugin_Table_Models\WPDA_User_Menus_Model;
19 use WPDataAccess\Utilities\WPDA_Favourites;
20 use WPDataAccess\Utilities\WPDA_Import_Multi;
21 use WPDataAccess\Utilities\WPDA_Message_Box;
22 use WPDataAccess\WPDA;
23 /**
24 * Class WPDA_List_Table_Menu
25 *
26 * This class implements the Data Explorer shown in the plugin menu.
27 *
28 * WPDA_List_Table_Menu extends WPDA_List_Table. Although both list tables basically offer the same functionality
29 * WPDA_List_Table_Menu selects data from MySQL view 'information_schema.tables', where WPDA_List_Table selects
30 * data from tables that are located in the WordPress database schema. The view that serves as the 'base table'
31 * for WPDA_List_Table_Menu is not updatable. A data entry form is therefore not available for WPDA_List_Table_Menu.
32 *
33 * Export functionality word WPDA_List_Table_Menu differs from WPDA_List_Table as well. WPDA_List_Table_Menu allows
34 * to export single tables, as well as multiple tables at once as s bulk action.
35 *
36 * When the user clicks on 'view', a list table for the selected table of view is shown.
37 *
38 * @author Peter Schulz
39 * @since 1.0.0
40 */
41 class WPDA_List_Table_Menu extends WPDA_List_Table {
42 const LOADING = 'Loading...';
43
44 const WPDACHK = 'wp-data-access-premium-data-services';
45
46 /**
47 * Holds tables marked as favourite
48 *
49 * @var array|null
50 */
51 protected $favourites = null;
52
53 /**
54 * Show, hide or empty
55 *
56 * @var string|null
57 */
58 protected $wpda_main_favourites = null;
59
60 /**
61 * Indicates whether innodb_file_per_table is enabled or disabled
62 *
63 * @var bool
64 */
65 protected $innodb_file_per_table = true;
66
67 /**
68 * Can user create database
69 *
70 * @var bool
71 */
72 protected $user_can_create_db = false;
73
74 /**
75 * Hint button create db
76 *
77 * @var string
78 */
79 protected $user_create_db_hint = '';
80
81 /**
82 * Can user drop database
83 *
84 * @var bool
85 */
86 protected $user_can_drop_db = false;
87
88 /**
89 * Hint button drop db
90 *
91 * @var string
92 */
93 protected $user_drop_db_hint = '';
94
95 /**
96 * Used to switch to another schema (after create/drop db)
97 *
98 * @var null
99 */
100 protected $switch_schema_name = null;
101
102 /**
103 * WPDA_List_Table_Menu constructor
104 *
105 * Constructor calls constructor of WPDA_List_Table. Before calling constructor of WPDA_List_Table the
106 * table name is set to {@see WPDA_List_Table::LIST_BASE_TABLE} which gives us the base table for the data
107 * explorer.
108 *
109 * Column headers and columns queried are defined hardcoded as this class handles only one base table and it's
110 * columns (table specific implementation).
111 *
112 * @param array $args See {@see WPDA_List_Table::__construct()}.
113 *
114 * @see WPDA_List_Table
115 *
116 * @since 1.0.0
117 */
118 public function __construct( $args = array() ) {
119 global $wpdb;
120 $args['table_name'] = WPDA_List_Table::LIST_BASE_TABLE;
121 // Add column labels.
122 $args['column_headers'] = self::column_headers_labels();
123 $args['title'] = 'Data Explorer';
124 $args['subtitle'] = '';
125 // Define an empty subtitle to prevent WPDA_List_Table from adding one.
126 if ( isset( $_REQUEST['action'] ) ) {
127 // Process create, drop and edit table actions before calling parent constructor to allow to redirect to
128 // another database.
129 if ( 'create_db' === $_REQUEST['action'] ) {
130 $this->process_bulk_action_create_db();
131 } elseif ( 'drop_db' === $_REQUEST['action'] ) {
132 $this->process_bulk_action_drop_db();
133 } elseif ( 'edit_db' === $_REQUEST['action'] ) {
134 $this->process_bulk_action_edit_db();
135 }
136 }
137 parent::__construct( $args );
138 $this->set_columns_queried( array(
139 'table_name AS table_name',
140 'if (find_in_set(table_name,\'' . implode( ',', WPDA::get_wp_tables() ) . '\')
141 , \'' . WPDA::get_table_type_text( WPDA::TABLE_TYPE_WP ) . '\'
142 , if (find_in_set(table_name,\'' . implode( ',', WPDA::get_wpda_tables() ) . '\')
143 , \'' . WPDA::get_table_type_text( WPDA::TABLE_TYPE_WPDA ) . '\'
144 , lower(table_type)
145 )
146 ) AS table_type',
147 'create_time AS create_time',
148 'table_rows AS table_rows',
149 'auto_increment AS auto_increment',
150 'engine AS engine',
151 'data_length+index_length AS total_size',
152 'data_length AS data_size',
153 'index_length AS index_size',
154 'data_free AS overhead',
155 'table_collation AS table_collation',
156 'table_type AS table_type_db'
157 ) );
158 $this->favourites = get_option( WPDA_Favourites::FAVOURITES_OPTION_NAME );
159 if ( null === $this->switch_schema_name ) {
160 $this->schema_name = $this->get_schema_name();
161 } else {
162 $this->schema_name = $this->switch_schema_name;
163 }
164 $this->wpda_main_favourites = $this->get_favourites();
165 // Instantiate WPDA_Import.
166 $this->wpda_import = new WPDA_Import_Multi("?page={$this->page}", $this->schema_name);
167 $wpdadb = WPDADB::get_db_connection( $this->schema_name );
168 if ( null === $wpdadb ) {
169 wp_die( sprintf( __( 'ERROR - Remote database %s not available', 'wp-data-access' ), esc_attr( $this->schema_name ) ) );
170 }
171 $result = $wpdadb->get_row( "show session variables like 'innodb_file_per_table'" );
172 if ( !empty( $result ) ) {
173 $this->innodb_file_per_table = 'ON' === $result->Value;
174 }
175 // Can user create/drop databases?
176 $this->user_can_create_db = WPDA_Dictionary_Access::can_create_db();
177 if ( $this->user_can_create_db ) {
178 $this->user_create_db_hint = __( 'Create local database/add remote database connection', 'wp-data-access' );
179 } else {
180 $this->user_create_db_hint = __( 'Add remote database connection (not authorized to create local database)', 'wp-data-access' );
181 }
182 $this->user_can_drop_db = WPDA_Dictionary_Access::can_drop_db();
183 if ( $this->user_can_drop_db ) {
184 if ( $wpdb->dbname === $this->schema_name ) {
185 $this->user_can_drop_db = false;
186 $this->user_drop_db_hint = __( 'Cannot drop WordPress database', 'wp-data-access' );
187 } elseif ( 'sys' === $this->schema_name || 'mysql' === $this->schema_name || 'information_schema' === $this->schema_name || 'performance_schema' === $this->schema_name || '' === $this->schema_name ) {
188 $this->user_can_drop_db = false;
189 $this->user_drop_db_hint = __( 'Cannot drop MySQL database', 'wp-data-access' );
190 } else {
191 if ( 'rdb:' === substr( $this->schema_name, 0, 4 ) ) {
192 $this->user_drop_db_hint = __( "Delete remote database connection.\nDoes not drop the database! Just deletes the connection definition.", 'wp-data-access' );
193 } else {
194 $this->user_drop_db_hint = __( 'Drop selected database', 'wp-data-access' );
195 }
196 }
197 } else {
198 if ( 'rdb:' === substr( $this->schema_name, 0, 4 ) ) {
199 $this->user_can_drop_db = true;
200 $this->user_drop_db_hint = __( "Delete remote database connection.\nDoes not drop the database! Just deletes the connection definition.", 'wp-data-access' );
201 } else {
202 $this->user_drop_db_hint = __( 'Cannot drop selected database [not authorized]', 'wp-data-access' );
203 }
204 }
205 }
206
207 /**
208 * Overwrite method to add structure to the row below.
209 *
210 * @param object $item Item info.
211 *
212 * @since 1.5.0
213 */
214 public function single_row( $item ) {
215 list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info();
216 //phpcs:ignore - 8.1 proof
217 $columns_not_shown = count( (array) $hidden );
218 //phpcs:ignore - 8.1 proof just to be sure
219 echo '<tr id="rownum_' . esc_attr( self::$list_number ) . '">';
220 $this->single_row_columns( $item );
221 echo '</tr>';
222 if ( $this->bulk_actions_enabled ) {
223 echo '<tr style="height:0 !important; padding: 0 !important;"><td id="rownum_' . esc_attr( self::$list_number ) . '_x1" colspan="' . esc_attr( 13 - $columns_not_shown ) . '" style="padding:0 !important;"></tr>';
224 // Fake! Maintain odd/even colors.
225 echo '<tr style="padding: 0 !important;"><td style="padding: 0 !important;"></td><td id="rownum_' . esc_attr( self::$list_number ) . '_x2" colspan="' . esc_attr( 12 - $columns_not_shown ) . '" style="padding:0 10px 10px 0 !important;">';
226 } else {
227 echo '<tr style="height:0 !important; padding: 0 !important;"><td id="rownum_' . esc_attr( self::$list_number ) . '_x1" colspan="' . esc_attr( 12 - $columns_not_shown ) . '" style="padding:0 !important;"></tr>';
228 // Fake! Maintain odd/even colors.
229 echo '<tr style="padding: 0 !important;"><td id="rownum_' . esc_attr( self::$list_number ) . '_x2" colspan="' . esc_attr( 12 - $columns_not_shown ) . '" style="padding:0 10px 10px 10px !important;">';
230 }
231 echo '<div id="wpda_admin_menu_actions_' . esc_attr( self::$list_number - 1 ) . '" style="width:100%;display:none;padding-right:20px !important;">' . esc_attr( self::LOADING ) . '</div>';
232 echo '</td></tr>';
233 }
234
235 /**
236 * Override column_default
237 *
238 * We need to override this method as our table is in fact a view and has no real columns:
239 * $this->wpda_list_columns->get_table_columns() returns no results
240 *
241 * We'll use jquery to write html forms to a container to make them accessible inside our list table.
242 * See WPDA_List_Table->column_default for further explanation.
243 *
244 * @param array $item Item info.
245 * @param string $column_name Column name.
246 *
247 * @return mixed Actions for the current row.
248 * @see WPDA_List_Table::column_default()
249 *
250 * @since 1.0.0
251 */
252 public function column_default( $item, $column_name ) {
253 if ( 'icons' === $column_name ) {
254 // Dummy column where icons are shown (favourites and row admin menu).
255 $table_name = $item['table_name'];
256 $favourite_class = 'dashicons-star-empty';
257 $favourite_title = 'Add to favourites';
258 if ( null !== $this->favourites && false !== $this->favourites ) {
259 $favourites_array = $this->favourites;
260 if ( isset( $favourites_array[$table_name] ) ) {
261 $favourite_class = 'dashicons-star-filled';
262 $favourite_title = 'Remove from favourites';
263 }
264 }
265 $favourites_menu = "<a href=\"javascript:void( 0 )\" class=\"wpda_tooltip\" title=\"{$favourite_title}\" onclick=\"wpda_list_table_favourite( '{$this->schema_name}', '{$table_name}' )\">\n\t\t\t\t\t\t<span id=\"span_favourites_{$table_name}\" class=\"dashicons {$favourite_class}\"></span>\n\t\t\t\t\t</a>";
266 return $favourites_menu;
267 }
268 if ( 'table_rows' === $column_name ) {
269 if ( is_scalar( $item['engine'] ) && is_scalar( $item['table_type'] ) && ('federated' === strtolower( $item['engine'] ) || 'connect' === strtolower( $item['engine'] ) || 'innodb' === strtolower( $item['engine'] ) || stripos( strtolower( $item['table_type'] ), 'view' ) !== false) ) {
270 $settings_db = WPDA_Table_Settings_Model::query( $item['table_name'], $this->schema_name );
271 if ( isset( $settings_db[0]['wpda_table_settings'] ) && '' !== $settings_db[0]['wpda_table_settings'] ) {
272 $settings = json_decode( $settings_db[0]['wpda_table_settings'] );
273 } else {
274 $settings = (object) null;
275 }
276 $row_count_estimate = WPDA::get_row_count_estimate( $this->schema_name, $item['table_name'], $settings );
277 if ( !$row_count_estimate['do_real_count'] ) {
278 if ( $row_count_estimate['is_estimate'] ) {
279 return stripslashes( '~' . $row_count_estimate['row_count'] );
280 } else {
281 return stripslashes( $row_count_estimate['row_count'] );
282 }
283 } else {
284 return stripslashes( $this->count_rows( $item['table_name'] ) );
285 }
286 } else {
287 return stripslashes( (string) $item[$column_name] );
288 }
289 }
290 if ( 'total_size' === $column_name || 'data_size' === $column_name || 'index_size' === $column_name ) {
291 if ( '' === stripslashes( (string) $item[$column_name] ) ) {
292 return stripslashes( (string) $item[$column_name] );
293 } else {
294 if ( $item[$column_name] / (1024 * 1024) > 1 ) {
295 return number_format(
296 stripslashes( $item[$column_name] / (1024 * 1024) ),
297 2,
298 '.',
299 ','
300 ) . ' MB';
301 } elseif ( $item[$column_name] / 1024 > 1 ) {
302 return number_format(
303 $item[$column_name] / 1024,
304 2,
305 '.',
306 ','
307 ) . ' KB';
308 }
309 return number_format(
310 stripslashes( $item[$column_name] ),
311 2,
312 '.',
313 ','
314 ) . ' bytes';
315 }
316 }
317 if ( 'overhead' === $column_name ) {
318 if ( 'InnoDB' === $item['engine'] && !$this->innodb_file_per_table ) {
319 return '-';
320 } else {
321 if ( '' === stripslashes( (string) $item[$column_name] ) ) {
322 return '';
323 } else {
324 if ( $item[$column_name] > 0 && $item['data_size'] > 0 && $item[$column_name] / $item['data_size'] > 0.2 ) {
325 $msg = __( "Fragmentation for this table is high.\nConsider: Manage>Actions>Optimize", 'wp-data-access' );
326 $approx = " <span style='font-size:15px;' class='dashicons dashicons-warning wpda_tooltip' title='{$msg}' style'cursor:pointer;'></span>";
327 } else {
328 $approx = '';
329 }
330 if ( $item[$column_name] / (1024 * 1024) > 1 ) {
331 return number_format(
332 stripslashes( $item[$column_name] / (1024 * 1024) ),
333 2,
334 '.',
335 ','
336 ) . ' MB' . $approx;
337 } elseif ( $item[$column_name] / 1024 > 1 ) {
338 return number_format(
339 stripslashes( $item[$column_name] / 1024 ),
340 2,
341 '.',
342 ','
343 ) . ' KB' . $approx;
344 }
345 return number_format(
346 stripslashes( $item[$column_name] ),
347 2,
348 '.',
349 ','
350 ) . ' bytes' . $approx;
351 }
352 }
353 }
354 if ( 'table_name' === $column_name ) {
355 // Get table name of the current row (= key).
356 $table_name = $item[$column_name];
357 $admin_actions = array();
358 // Array containing admin actions.
359 if ( WPDA::can_manage() ) {
360 // Add manage table/view line.
361 $wp_nonce_action_table_actions = "wpda-actions-{$table_name}";
362 $wp_nonce_table_actions = wp_create_nonce( $wp_nonce_action_table_actions );
363 $table_actions_title = sprintf( __( 'Table %s settings', 'wp-data-access' ), $table_name );
364 $actions['wpda_manage'] = "<a href=\"javascript:void( 0 )\" class='wpda_tooltip' title='{$table_actions_title}' onclick=\"wpda_show_table_actions( '{$this->schema_name}', '{$table_name}', '" . self::$list_number . "', '{$wp_nonce_table_actions}', '{$item['table_type_db']}', '" . self::LOADING . "' ); this.blur();\">" . '<i class="fas fa-gears wpda_icon_on_button"></i> ' . __( 'Manage', 'wp-data-access' ) . '</a>';
365 }
366 self::$list_number++;
367 // Prepare type checking for editing.
368 $check_view_access = 'true';
369 if ( 'on' === WPDA::get_option( WPDA::OPTION_BE_CONFIRM_VIEW ) ) {
370 if ( 'VIEW' !== strtoupper( $item['table_type_db'] ) && 'SYSTEM VIEW' !== strtoupper( $item['table_type_db'] ) ) {
371 if ( strtolower( WPDA::TABLE_TYPE_WP ) === strtolower( $item['table_type'] ) ) {
372 // WordPress table.
373 $msg = __( 'You are about to edit a WordPress table! Changing this table might result in corrupting the WordPress database. Are you sure you want to continue?', 'wp-data-access' );
374 } elseif ( strtolower( WPDA::TABLE_TYPE_WPDA ) === strtolower( $item['table_type'] ) ) {
375 // Plugin table.
376 $msg = __( 'You are about to edit a plugin table! Changing this table might result in corrupting the WP Data Access database. Are you sure you want to continue?', 'wp-data-access' );
377 } else {
378 // User table (other than WordPress or plugin).
379 $msg = __( 'You are about to edit a table of an external application! Changing this table might result in corrupting the external database. Are you sure you want to continue?', 'wp-data-access' );
380 }
381 $check_view_access = 'confirm(\'' . $msg . '\')';
382 }
383 }
384 $esc_attr = 'esc_attr';
385 $form_name = 'explore_' . self::$list_number;
386 $url = "?page={$this->page}";
387 $form = <<<EOT
388 \t\t\t\t<form id='{$esc_attr( $form_name )}' action='{$esc_attr( $url )}' method='post'>
389 \t\t\t\t\t<input type='hidden' name='wpdaschema_name' value='{$esc_attr( $this->schema_name )}' />
390 \t\t\t\t\t<input type='hidden' name='table_name' value='{$esc_attr( $table_name )}' />
391 \t\t\t\t\t<input type='hidden' name='action' value='listtable' />
392 \t\t\t\t</form>
393 EOT;
394 $explore = str_replace( array("\n", "\r"), '', $form );
395 ?>
396
397 <script type='text/javascript'>
398 jQuery("#wpda_invisible_container").append("<?php
399 echo $explore;
400 // phpcs:ignore WordPress.Security.EscapeOutput
401 ?>");
402 </script>
403
404 <?php
405 $action_view = ' <i class="fas fa-table-list wpda_icon_on_button"></i> ' . __( 'Explore', 'wp-data-access' );
406 $table_view_title = sprintf( __( 'Explore %s table', 'wp-data-access' ), $table_name );
407 $actions['wpda_listtable'] = sprintf(
408 '<a href="javascript:void(0)"
409 title="%s"
410 class="view wpda_tooltip"
411 onclick="if (%s) jQuery(\'#%s\').submit()">
412 %s
413 </a>',
414 $table_view_title,
415 $check_view_access,
416 $form_name,
417 $action_view
418 );
419 if ( strtolower( WPDA::TABLE_TYPE_WP ) === strtolower( $item['table_type'] ) ) {
420 ?>
421 <script type='text/javascript'>
422 wpda_bulk.push('<?php
423 echo esc_attr( $table_name );
424 ?>');
425 </script>
426 <?php
427 }
428 if ( strtolower( WPDA::TABLE_TYPE_WP ) !== strtolower( $item['table_type'] ) && strtolower( WPDA::TABLE_TYPE_WPDA ) !== strtolower( $item['table_type'] ) ) {
429 // Validate schema, table and column names
430 $warning = WPDA::validate_names( $this->schema_name, $table_name );
431 } else {
432 $warning = '';
433 }
434 return sprintf(
435 '%1$s %2$s %3$s',
436 $table_name . $warning,
437 "<span class=\"nobr\">{$this->row_actions( $actions )}</span>",
438 "<span id=\"span_admin_menu_{$table_name}\" class=\"nobr\" style=\"display:none;width:auto;float:clear;\">{$this->row_actions( $admin_actions )}</span>"
439 );
440 }
441 if ( 'create_time' === $column_name ) {
442 if ( null !== $item[$column_name] ) {
443 return date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), strtotime( $item[$column_name] ) );
444 } else {
445 return '';
446 }
447 }
448 return stripslashes( (string) $item[$column_name] );
449 }
450
451 /**
452 * Count the number of rows in a table.
453 *
454 * This method is used to get the number of rows in an InnoDB table as the table_rows column of
455 * information_schema.tables only return an estimate.
456 *
457 * @param string $table_name Database table name.
458 *
459 * @return integer|null Number of rows in $table_name.
460 * @since 1.5.1
461 */
462 protected function count_rows( $table_name ) {
463 $wpdadb = WPDADB::get_db_connection( $this->schema_name );
464 if ( null === $wpdadb ) {
465 wp_die( sprintf( __( 'ERROR - Remote database %s not available', 'wp-data-access' ), esc_attr( $this->schema_name ) ) );
466 }
467 if ( '' === $this->schema_name ) {
468 $query = "\n\t\t\t\t\tselect count(*)\n\t\t\t\t\tfrom `{$table_name}`\n\t\t\t\t";
469 } else {
470 $query = "\n\t\t\t\t\tselect count(*)\n\t\t\t\t\tfrom `{$wpdadb->dbname}`.`{$table_name}`\n\t\t\t\t";
471 }
472 $suppress = $wpdadb->suppress_errors( true );
473 $count = @$wpdadb->get_var( $query );
474 // phpcs:ignore Standard.Category.SniffName.ErrorCode
475 if ( !is_numeric( $count ) ) {
476 $count = '<span class="dashicons dashicons-flag wpda_tooltip" style="color:red;padding-left:5px" title="' . str_replace( '"', "'", $wpdadb->last_error ) . '"></span>';
477 }
478 $wpdadb->suppress_errors( $suppress );
479 return $count;
480 }
481
482 /**
483 * Override get_columns
484 *
485 * @return array
486 * @see WPDA_List_Table::get_columns()
487 *
488 * @since 1.0.0
489 */
490 public function get_columns() {
491 $columns = array();
492 if ( $this->bulk_actions_enabled ) {
493 $columns = array(
494 'cb' => '<input type="checkbox" />',
495 );
496 }
497 return array_merge( $columns, $this->column_headers );
498 //phpcs:ignore - 8.1 proof
499 }
500
501 /**
502 * Override get_sortable_columns()
503 *
504 * Type is not sortable as it is not in the view.
505 *
506 * @return array
507 * @see WPDA_List_Table::get_sortable_columns()
508 *
509 * @since 1.0.0
510 */
511 public function get_sortable_columns() {
512 $columns = array();
513 $columns['table_name'] = array('table_name', false);
514 $columns['table_type'] = array('table_type', false);
515 $columns['engine'] = array('engine', false);
516 $columns['create_time'] = array('create_time', false);
517 $columns['table_rows'] = array('table_rows', false);
518 $columns['auto_increment'] = array('auto_increment', false);
519 $columns['total_size'] = array('total_size', false);
520 $columns['data_size'] = array('data_size', false);
521 $columns['index_size'] = array('index_size', false);
522 $columns['overhead'] = array('overhead', false);
523 $columns['table_collation'] = array('table_collation', false);
524 return $columns;
525 }
526
527 /**
528 * Override column_cb
529 *
530 * @param array $item Column info.
531 *
532 * @return string
533 * @since 1.0.0
534 *
535 * @see WPDA_List_Table::column_cb()
536 */
537 public function column_cb( $item ) {
538 if ( !$this->bulk_actions_enabled ) {
539 // Bulk actions disabled.
540 return '';
541 }
542 if ( 'VIEW' === $item['table_type_db'] ) {
543 $title = 'title="Performs only drop actions on views"';
544 $class = 'class="wpda_tooltip"';
545 } else {
546 $title = '';
547 $class = '';
548 }
549 return "<input type='checkbox' name='bulk-selected[]' value='{$item['table_name']}' {$title} {$class} />";
550 }
551
552 /**
553 * Override get_bulk_actions
554 *
555 * @return array
556 * @see WPDA_List_Table::get_bulk_actions()
557 *
558 * @since 1.0.0
559 */
560 public function get_bulk_actions() {
561 if ( !$this->bulk_actions_enabled ) {
562 // Bulk actions disabled.
563 return '';
564 }
565 $actions = array();
566 $actions['bulk-export'] = __( 'Export Table(s)', 'wp-data-access' );
567 $actions['bulk-drop'] = __( 'Drop Table(s)/View(s) (does not drop WordPress tables)', 'wp-data-access' );
568 $actions['bulk-truncate'] = __( 'Truncate Table(s) (does not truncate WordPress tables)', 'wp-data-access' );
569 return $actions;
570 }
571
572 /**
573 * Override process_bulk_action()
574 *
575 * @since 1.0.0
576 *
577 * @see WPDA_List_Table::process_bulk_action()
578 */
579 public function process_bulk_action() {
580 switch ( $this->current_action() ) {
581 case 'bulk-export':
582 $this->process_bulk_action_bulk_export();
583 break;
584 case 'bulk-drop':
585 $this->process_bulk_action_bulk_drop();
586 break;
587 case 'bulk-truncate':
588 $this->process_bulk_action_bulk_truncate();
589 break;
590 case 'drop':
591 $this->process_bulk_action_drop();
592 break;
593 case 'truncate':
594 $this->process_bulk_action_truncate();
595 break;
596 case 'rename-table':
597 $this->process_bulk_action_rename_table();
598 break;
599 case 'copy-table':
600 $this->process_bulk_action_copy_table();
601 break;
602 case 'optimize-table':
603 $this->process_bulk_action_optimize_table();
604 break;
605 case 'refresh-table':
606 $this->process_bulk_action_refresh_table();
607 break;
608 case 'c2wp-table':
609 $this->process_bulk_action_c2wp_table();
610 break;
611 }
612 }
613
614 protected function process_bulk_action_refresh_table() {
615 }
616
617 protected function process_bulk_action_drop_db() {
618 if ( !$this->process_bulk_action_check_wpnonce( 'wpda-drop-db-from-data-explorer-' . WPDA::get_current_user_login(), '_wpnoncedropdb' ) ) {
619 return;
620 }
621 if ( !isset( $_REQUEST['database'] ) ) {
622 $msg = new WPDA_Message_Box(array(
623 'message_text' => sprintf( __( 'Cannot drop database [missing argument]', 'wp-data-access' ) ),
624 'message_type' => 'error',
625 'message_is_dismissible' => false,
626 ));
627 $msg->box();
628 return;
629 }
630 global $wpdb;
631 $database = str_replace( '`', '', sanitize_text_field( wp_unslash( $_REQUEST['database'] ) ) );
632 // input var okay.
633 if ( 'rdb:' === substr( $database, 0, 4 ) ) {
634 // Delete remote database
635 if ( false === WPDADB::get_remote_database( $database ) ) {
636 $msg = new WPDA_Message_Box(array(
637 'message_text' => sprintf( __( 'Cannot delete remote database connection `%s` [remote database connection not found]', 'wp-data-access' ), $database ),
638 'message_type' => 'error',
639 'message_is_dismissible' => false,
640 ));
641 $msg->box();
642 } else {
643 if ( false === WPDADB::del_remote_database( $database ) ) {
644 $msg = new WPDA_Message_Box(array(
645 'message_text' => sprintf( __( 'Cannot delete remote database connection `%s`', 'wp-data-access' ), $database ),
646 'message_type' => 'error',
647 'message_is_dismissible' => false,
648 ));
649 $msg->box();
650 } else {
651 $msg = new WPDA_Message_Box(array(
652 'message_text' => sprintf( __( 'Remove database `%s` deleted', 'wp-data-access' ), $database ),
653 ));
654 $msg->box();
655 $this->switch_schema_name = $wpdb->dbname;
656 }
657 }
658 } else {
659 // Drop local database
660 if ( $wpdb->dbname === $database ) {
661 $msg = new WPDA_Message_Box(array(
662 'message_text' => __( 'Cannot drop WordPress database', 'wp-data-access' ),
663 'message_type' => 'error',
664 'message_is_dismissible' => false,
665 ));
666 $msg->box();
667 return;
668 }
669 if ( 'sys' === $database || 'mysql' === $database || 'information_schema' === $database || 'performance_schema' === $database || '' === $database ) {
670 $msg = new WPDA_Message_Box(array(
671 'message_text' => __( 'Cannot drop MySQL database', 'wp-data-access' ),
672 'message_type' => 'error',
673 'message_is_dismissible' => false,
674 ));
675 $msg->box();
676 return;
677 }
678 if ( false === $wpdb->query( $wpdb->prepare(
679 'drop database `%1s`',
680 // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders
681 array(WPDA::remove_backticks( $database ))
682 ) ) ) {
683 // db call ok; no-cache ok.
684 $msg = new WPDA_Message_Box(array(
685 'message_text' => sprintf( __( 'Error dropping database `%s`', 'wp-data-access' ), $database ),
686 'message_type' => 'error',
687 'message_is_dismissible' => false,
688 ));
689 $msg->box();
690 } else {
691 $msg = new WPDA_Message_Box(array(
692 'message_text' => sprintf( __( 'Database `%s` dropped', 'wp-data-access' ), $database ),
693 ));
694 $msg->box();
695 $this->switch_schema_name = $wpdb->dbname;
696 }
697 }
698 }
699
700 protected function process_bulk_action_edit_db() {
701 if ( !$this->process_bulk_action_check_wpnonce( 'wpda-edit-db-from-data-explorer-' . WPDA::get_current_user_login(), '_wpnonceeditdb' ) ) {
702 return;
703 }
704 if ( !isset( $_REQUEST['edit_remote_database'] ) ) {
705 $msg = new WPDA_Message_Box(array(
706 'message_text' => sprintf( __( 'Cannot update remote database connection [missing argument]', 'wp-data-access' ) ),
707 'message_type' => 'error',
708 'message_is_dismissible' => false,
709 ));
710 $msg->box();
711 return;
712 }
713 $database = sanitize_text_field( wp_unslash( $_REQUEST['edit_remote_database'] ) );
714 // input var okay.
715 $database_old = sanitize_text_field( wp_unslash( $_REQUEST['edit_remote_database_old'] ) );
716 // input var okay.
717 if ( $database !== $database_old ) {
718 // Update database connection name
719 if ( false === WPDADB::get_remote_database( $database_old ) ) {
720 $msg = new WPDA_Message_Box(array(
721 'message_text' => sprintf( __( 'Cannot update remote database connection [remote database connection not found]', 'wp-data-access' ) ),
722 'message_type' => 'error',
723 'message_is_dismissible' => false,
724 ));
725 $msg->box();
726 return;
727 }
728 } else {
729 // Update database connection information
730 if ( false === WPDADB::get_remote_database( $database ) ) {
731 $msg = new WPDA_Message_Box(array(
732 'message_text' => sprintf( __( 'Cannot update remote database connection [remote database connection not found]', 'wp-data-access' ) ),
733 'message_type' => 'error',
734 'message_is_dismissible' => false,
735 ));
736 $msg->box();
737 return;
738 }
739 }
740 $host = ( isset( $_REQUEST['edit_remote_host'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['edit_remote_host'] ) ) : '' );
741 // input var okay.
742 $user = ( isset( $_REQUEST['edit_remote_user'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['edit_remote_user'] ) ) : '' );
743 // input var okay.
744 $passwd = ( isset( $_REQUEST['edit_remote_passwd'] ) ? wp_unslash( $_REQUEST['edit_remote_passwd'] ) : '' );
745 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
746 $port = ( isset( $_REQUEST['edit_remote_port'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['edit_remote_port'] ) ) : '' );
747 // input var okay.
748 $schema = ( isset( $_REQUEST['edit_remote_schema'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['edit_remote_schema'] ) ) : '' );
749 // input var okay.
750 $ssl = ( isset( $_REQUEST['edit_remote_ssl'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['edit_remote_ssl'] ) ) : 'off' );
751 // input var okay.
752 $ssl_key = ( isset( $_REQUEST['edit_remote_client_key'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['edit_remote_client_key'] ) ) : '' );
753 // input var okay.
754 $ssl_cert = ( isset( $_REQUEST['edit_remote_client_certificate'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['edit_remote_client_certificate'] ) ) : '' );
755 // input var okay.
756 $ssl_ca = ( isset( $_REQUEST['edit_remote_ca_certificate'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['edit_remote_ca_certificate'] ) ) : '' );
757 // input var okay.
758 $ssl_path = ( isset( $_REQUEST['edit_remote_certificate_path'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['edit_remote_certificate_path'] ) ) : '' );
759 // input var okay.
760 $ssl_cipher = ( isset( $_REQUEST['edit_remote_specified_cipher'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['edit_remote_specified_cipher'] ) ) : '' );
761 // input var okay.
762 if ( '' === $database || '' === $host || '' === $user || '' === $schema ) {
763 $msg = new WPDA_Message_Box(array(
764 'message_text' => sprintf( __( 'Cannot edit remote database connection [missing arguments]', 'wp-data-access' ) ),
765 'message_type' => 'error',
766 'message_is_dismissible' => false,
767 ));
768 $msg->box();
769 return;
770 }
771 if ( !WPDADB::upd_remote_database(
772 $database,
773 $host,
774 $user,
775 $passwd,
776 $port,
777 $schema,
778 false,
779 $database_old,
780 $ssl,
781 $ssl_key,
782 $ssl_cert,
783 $ssl_ca,
784 $ssl_path,
785 $ssl_cipher
786 ) ) {
787 $msg = new WPDA_Message_Box(array(
788 'message_text' => sprintf( __( 'Cannot update remote database connection `%s`', 'wp-data-access' ), $database ),
789 'message_type' => 'error',
790 'message_is_dismissible' => false,
791 ));
792 $msg->box();
793 } else {
794 $msg = new WPDA_Message_Box(array(
795 'message_text' => sprintf( __( 'Remote database connection `%s` updated', 'wp-data-access' ), $database ),
796 ));
797 $msg->box();
798 if ( $database !== $database_old ) {
799 $this->switch_schema_name = $database;
800 }
801 }
802 }
803
804 protected function process_bulk_action_create_db() {
805 if ( !$this->process_bulk_action_check_wpnonce( 'wpda-create-db-from-data-explorer-' . WPDA::get_current_user_login(), '_wpnoncecreatedb' ) ) {
806 return;
807 }
808 if ( isset( $_REQUEST['database_location'] ) && 'local' === $_REQUEST['database_location'] ) {
809 // Add local database
810 if ( !isset( $_REQUEST['local_database'] ) ) {
811 $msg = new WPDA_Message_Box(array(
812 'message_text' => sprintf( __( 'Cannot create database [missing argument]', 'wp-data-access' ) ),
813 'message_type' => 'error',
814 'message_is_dismissible' => false,
815 ));
816 $msg->box();
817 return;
818 }
819 $database = str_replace( '`', '', sanitize_text_field( wp_unslash( $_REQUEST['local_database'] ) ) );
820 // input var okay.
821 global $wpdb;
822 if ( false === $wpdb->query( $wpdb->prepare(
823 'create database `%1s`',
824 // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders
825 array(WPDA::remove_backticks( $database ))
826 ) ) ) {
827 // db call ok; no-cache ok.
828 $msg = new WPDA_Message_Box(array(
829 'message_text' => sprintf( __( 'Error creating database `%s`', 'wp-data-access' ), $database ),
830 'message_type' => 'error',
831 'message_is_dismissible' => false,
832 ));
833 $msg->box();
834 } else {
835 $msg = new WPDA_Message_Box(array(
836 'message_text' => sprintf( __( 'Database `%s` created', 'wp-data-access' ), $database ),
837 ));
838 $msg->box();
839 $this->switch_schema_name = $database;
840 }
841 } else {
842 // Add remote database
843 $database = ( isset( $_REQUEST['remote_database'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['remote_database'] ) ) : '' );
844 // input var okay.
845 if ( false !== WPDADB::get_remote_database( $database ) ) {
846 $msg = new WPDA_Message_Box(array(
847 'message_text' => sprintf( __( 'Remote database connection already exists', 'wp-data-access' ) ),
848 'message_type' => 'error',
849 'message_is_dismissible' => false,
850 ));
851 $msg->box();
852 return;
853 }
854 $host = ( isset( $_REQUEST['remote_host'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['remote_host'] ) ) : '' );
855 // input var okay.
856 $user = ( isset( $_REQUEST['remote_user'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['remote_user'] ) ) : '' );
857 // input var okay.
858 $passwd = ( isset( $_REQUEST['remote_passwd'] ) ? wp_unslash( $_REQUEST['remote_passwd'] ) : '' );
859 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
860 $port = ( isset( $_REQUEST['remote_port'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['remote_port'] ) ) : '' );
861 // input var okay.
862 $schema = ( isset( $_REQUEST['remote_schema'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['remote_schema'] ) ) : '' );
863 // input var okay.
864 $ssl = ( isset( $_REQUEST['remote_ssl'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['remote_ssl'] ) ) : 'off' );
865 // input var okay.
866 $ssl_key = ( isset( $_REQUEST['remote_client_key'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['remote_client_key'] ) ) : '' );
867 // input var okay.
868 $ssl_cert = ( isset( $_REQUEST['remote_client_certificate'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['remote_client_certificate'] ) ) : '' );
869 // input var okay.
870 $ssl_ca = ( isset( $_REQUEST['remote_ca_certificate'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['remote_ca_certificate'] ) ) : '' );
871 // input var okay.
872 $ssl_path = ( isset( $_REQUEST['remote_certificate_path'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['remote_certificate_path'] ) ) : '' );
873 // input var okay.
874 $ssl_cipher = ( isset( $_REQUEST['remote_specified_cipher'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['remote_specified_cipher'] ) ) : '' );
875 // input var okay.
876 if ( '' === $database || '' === $host || '' === $user || '' === $schema ) {
877 $msg = new WPDA_Message_Box(array(
878 'message_text' => sprintf( __( 'Cannot add remote database connection [missing argument]', 'wp-data-access' ) ),
879 'message_type' => 'error',
880 'message_is_dismissible' => false,
881 ));
882 $msg->box();
883 return;
884 }
885 if ( 'rdb:' === $database ) {
886 $msg = new WPDA_Message_Box(array(
887 'message_text' => sprintf( __( 'Invalid database name [enter a valid database name, for example rdb:remotedb]', 'wp-data-access' ) ),
888 'message_type' => 'error',
889 'message_is_dismissible' => false,
890 ));
891 $msg->box();
892 return;
893 }
894 if ( !WPDADB::add_remote_database(
895 $database,
896 $host,
897 $user,
898 $passwd,
899 $port,
900 $schema,
901 $ssl,
902 $ssl_key,
903 $ssl_cert,
904 $ssl_ca,
905 $ssl_path,
906 $ssl_cipher
907 ) ) {
908 $msg = new WPDA_Message_Box(array(
909 'message_text' => sprintf( __( 'Cannot add remote database connection', 'wp-data-access' ) ),
910 'message_type' => 'error',
911 'message_is_dismissible' => false,
912 ));
913 $msg->box();
914 } else {
915 $msg = new WPDA_Message_Box(array(
916 'message_text' => sprintf( __( 'Remote database connection `%s` added', 'wp-data-access' ), $database ),
917 ));
918 $msg->box();
919 $this->switch_schema_name = $database;
920 }
921 }
922 }
923
924 /**
925 * Performs optimize table.
926 */
927 protected function process_bulk_action_optimize_table() {
928 if ( isset( $_REQUEST['optimize_table_name'] ) ) {
929 $optimize_table_name = str_replace( '`', '', sanitize_text_field( wp_unslash( $_REQUEST['optimize_table_name'] ) ) );
930 // input var okay.
931 if ( $this->process_bulk_action_check_wpnonce( "wpda-optimize-{$optimize_table_name}", '_wpnonce' ) ) {
932 $dbo_type = $this->get_dbo_type( $optimize_table_name );
933 if ( false === $dbo_type || 'BASE TABLE' !== $dbo_type ) {
934 $msg = new WPDA_Message_Box(array(
935 'message_text' => sprintf( __( 'Cannot optimize `%s`', 'wp-data-access' ), $optimize_table_name ),
936 'message_type' => 'error',
937 'message_is_dismissible' => false,
938 ));
939 $msg->box();
940 } else {
941 // Optimize table.
942 $wpdadb = WPDADB::get_db_connection( $this->schema_name );
943 if ( null === $wpdadb ) {
944 wp_die( sprintf( __( 'ERROR - Remote database %s not available', 'wp-data-access' ), esc_attr( $this->schema_name ) ) );
945 }
946 $wpdadb->query( "optimize table `{$optimize_table_name}`" );
947 // db call ok; no-cache ok.
948 $msg = new WPDA_Message_Box(array(
949 'message_text' => sprintf( __( 'Table `%s` optimized', 'wp-data-access' ), $optimize_table_name ),
950 ));
951 $msg->box();
952 }
953 }
954 }
955 }
956
957 /**
958 * Performs rename table/view.
959 *
960 * @since 1.6.6
961 */
962 protected function process_bulk_action_rename_table() {
963 // Check arguments.
964 if ( !$this->process_bulk_action_check_action( 'rename_table_name_old', __( 'Missing old table name', 'wp-data-access' ) ) ) {
965 return;
966 }
967 if ( $this->process_bulk_action_check_action( 'rename_table_name_new', __( 'Missing new table name', 'wp-data-access' ) ) ) {
968 // Rename table is not allowed for WordPress tables (double check).
969 $rename_table_name_old = sanitize_text_field( wp_unslash( $_REQUEST['rename_table_name_old'] ) );
970 // input var okay.
971 $rename_table_name_new = sanitize_text_field( wp_unslash( $_REQUEST['rename_table_name_new'] ) );
972 // input var okay.
973 $err_txt = ' ' . sprintf( __( '[cannot rename WordPress table `%s`]', 'wp-data-access' ), $rename_table_name_old );
974 if ( '' === $rename_table_name_old ) {
975 $msg = new WPDA_Message_Box(array(
976 'message_text' => __( 'Missing old table name value', 'wp-data-access' ),
977 ));
978 $msg->box();
979 return;
980 }
981 if ( '' === $rename_table_name_new ) {
982 $msg = new WPDA_Message_Box(array(
983 'message_text' => __( 'Missing new table name value', 'wp-data-access' ),
984 ));
985 $msg->box();
986 return;
987 }
988 if ( $this->process_bulk_action_check_is_wp_table( $rename_table_name_old, $err_txt ) ) {
989 // Check if table exists.
990 if ( $this->process_bulk_action_check_table_exists( $rename_table_name_old ) ) {
991 // Check if rename is allowed.
992 if ( $this->process_bulk_action_check_wpnonce( "wpda-rename-{$rename_table_name_old}", '_wpnonce' ) ) {
993 $dbo_type = $this->get_dbo_type( $rename_table_name_old );
994 if ( false === $dbo_type || 'SYSTEM VIEW' === $dbo_type ) {
995 $msg = new WPDA_Message_Box(array(
996 'message_text' => sprintf( __( 'Cannot rename `%s`', 'wp-data-access' ), $rename_table_name_old ),
997 'message_type' => 'error',
998 'message_is_dismissible' => false,
999 ));
1000 $msg->box();
1001 } else {
1002 // Rename table/view.
1003 if ( false === $this->rename_table( $rename_table_name_old, $rename_table_name_new ) ) {
1004 $msg = new WPDA_Message_Box(array(
1005 'message_text' => __( 'Cannot rename', 'wp-data-access' ) . ' ' . strtolower( $dbo_type ) . ' `' . $rename_table_name_old . '`',
1006 'message_type' => 'error',
1007 'message_is_dismissible' => false,
1008 ));
1009 $msg->box();
1010 } else {
1011 $msg = new WPDA_Message_Box(array(
1012 'message_text' => strtoupper( substr( $dbo_type, 0, 1 ) ) . strtolower( substr( $dbo_type, 1 ) ) . ' `' . $rename_table_name_old . '` ' . __( 'renamed to', 'wp-data-access' ) . ' `' . $rename_table_name_new . '` ',
1013 ));
1014 $msg->box();
1015 }
1016 }
1017 }
1018 }
1019 }
1020 }
1021 }
1022
1023 /**
1024 * Rename table/view.
1025 *
1026 * @param string $rename_table_name_old Old table name.
1027 * @param string $rename_table_name_new New table name.
1028 *
1029 * @return false|int
1030 * @since 1.6.6
1031 */
1032 protected function rename_table( $rename_table_name_old, $rename_table_name_new ) {
1033 if ( WPDA::is_wp_table( $rename_table_name_old ) ) {
1034 // Never ever allow renaming a WordPress table!
1035 $msg = new WPDA_Message_Box(array(
1036 'message_text' => __( 'Not authorized [cannot rename WordPress tables]', 'wp-data-access' ),
1037 'message_type' => 'error',
1038 'message_is_dismissible' => false,
1039 ));
1040 $msg->box();
1041 return false;
1042 }
1043 $wpdadb = WPDADB::get_db_connection( $this->schema_name );
1044 if ( null === $wpdadb ) {
1045 wp_die( sprintf( __( 'ERROR - Remote database %s not available', 'wp-data-access' ), esc_attr( $this->schema_name ) ) );
1046 }
1047 return $wpdadb->query( 'rename table `' . str_replace( '`', '', $rename_table_name_old ) . '` to `' . str_replace( '`', '', $rename_table_name_new ) . '`' );
1048 // db call ok; no-cache ok.
1049 }
1050
1051 /**
1052 * Performs copying a table.
1053 *
1054 * @since 1.6.6
1055 */
1056 protected function process_bulk_action_copy_table() {
1057 // Check arguments.
1058 if ( !$this->process_bulk_action_check_action( 'copy_table_name_src', __( 'Missing source table name', 'wp-data-access' ) ) ) {
1059 return;
1060 }
1061 if ( $this->process_bulk_action_check_action( 'copy_table_name_dst', __( 'Missing destination table name', 'wp-data-access' ) ) ) {
1062 // copy table is not allowed for WordPress tables (double check).
1063 $copy_schema_name_src = sanitize_text_field( wp_unslash( $_REQUEST['copy_schema_name_src'] ) );
1064 // input var okay.
1065 $copy_table_name_src = sanitize_text_field( wp_unslash( $_REQUEST['copy_table_name_src'] ) );
1066 // input var okay.
1067 $copy_schema_name_dst = sanitize_text_field( wp_unslash( $_REQUEST['copy_schema_name_dst'] ) );
1068 // input var okay.
1069 $copy_table_name_dst = sanitize_text_field( wp_unslash( $_REQUEST['copy_table_name_dst'] ) );
1070 // input var okay.
1071 if ( '' === $copy_schema_name_src ) {
1072 $msg = new WPDA_Message_Box(array(
1073 'message_text' => __( 'Missing source schema name', 'wp-data-access' ),
1074 ));
1075 $msg->box();
1076 return;
1077 }
1078 if ( '' === $copy_table_name_src ) {
1079 $msg = new WPDA_Message_Box(array(
1080 'message_text' => __( 'Missing source table name', 'wp-data-access' ),
1081 ));
1082 $msg->box();
1083 return;
1084 }
1085 if ( '' === $copy_schema_name_dst ) {
1086 $msg = new WPDA_Message_Box(array(
1087 'message_text' => __( 'Missing destination schema name', 'wp-data-access' ),
1088 ));
1089 $msg->box();
1090 return;
1091 }
1092 if ( '' === $copy_table_name_dst ) {
1093 $msg = new WPDA_Message_Box(array(
1094 'message_text' => __( 'Missing destination table name', 'wp-data-access' ),
1095 ));
1096 $msg->box();
1097 return;
1098 }
1099 // Check if table exists.
1100 if ( $this->process_bulk_action_check_table_exists( $copy_table_name_src ) ) {
1101 // Check if copy is allowed.
1102 if ( $this->process_bulk_action_check_wpnonce( "wpda-copy-{$copy_table_name_src}", '_wpnonce' ) ) {
1103 $dbo_type = $this->get_dbo_type( $copy_table_name_src );
1104 if ( false === $dbo_type || 'SYSTEM VIEW' === $dbo_type ) {
1105 $msg = new WPDA_Message_Box(array(
1106 'message_text' => sprintf( __( 'Cannot copy `%s`', 'wp-data-access' ), $copy_table_name_src ),
1107 'message_type' => 'error',
1108 'message_is_dismissible' => false,
1109 ));
1110 $msg->box();
1111 } else {
1112 $include_data = ( isset( $_REQUEST['copy-table-data'] ) ? 'on' : 'off' );
1113 // Copy table/view.
1114 if ( false === $this->copy_table(
1115 $copy_schema_name_src,
1116 $copy_table_name_src,
1117 $copy_schema_name_dst,
1118 $copy_table_name_dst,
1119 $include_data
1120 ) ) {
1121 $msg = new WPDA_Message_Box(array(
1122 'message_text' => __( 'Cannot copy', 'wp-data-access' ) . ' ' . strtolower( $dbo_type ) . ' ' . $copy_table_name_src,
1123 'message_type' => 'error',
1124 'message_is_dismissible' => false,
1125 ));
1126 $msg->box();
1127 } else {
1128 $msg = new WPDA_Message_Box(array(
1129 'message_text' => strtoupper( substr( $dbo_type, 0, 1 ) ) . strtolower( substr( $dbo_type, 1 ) ) . " `{$copy_schema_name_src}`.`{$copy_table_name_src}` " . __( 'copied to', 'wp-data-access' ) . " `{$copy_schema_name_dst}`.`{$copy_table_name_dst}` ",
1130 ));
1131 $msg->box();
1132 }
1133 }
1134 }
1135 }
1136 }
1137 }
1138
1139 /**
1140 * Copy table.
1141 *
1142 * @param string $copy_schema_name_src Source schema name.
1143 * @param string $copy_table_name_src Source table name.
1144 * @param string $copy_schema_name_dst Destination schema name.
1145 * @param string $copy_table_name_dst Destination table name.
1146 * @param string $include_data 'on' = include data.
1147 *
1148 * @return false|int
1149 * @since 1.6.6
1150 */
1151 protected function copy_table(
1152 $copy_schema_name_src,
1153 $copy_table_name_src,
1154 $copy_schema_name_dst,
1155 $copy_table_name_dst,
1156 $include_data
1157 ) {
1158 $copy_schema_name_src = WPDA::remove_backticks( $copy_schema_name_src );
1159 $copy_table_name_src = WPDA::remove_backticks( $copy_table_name_src );
1160 $copy_schema_name_dst = WPDA::remove_backticks( $copy_schema_name_dst );
1161 $copy_table_name_dst = WPDA::remove_backticks( $copy_table_name_dst );
1162 $wpdadb_src = WPDADB::get_db_connection( $copy_schema_name_src );
1163 if ( null === $wpdadb_src ) {
1164 return false;
1165 }
1166 $wpdadb_dst = WPDADB::get_db_connection( $copy_schema_name_dst );
1167 if ( null === $wpdadb_dst ) {
1168 return false;
1169 }
1170 $suppress_wpdadb_src = $wpdadb_src->suppress_errors;
1171 $wpdadb_src->suppress_errors = true;
1172 $suppress_wpdadb_dst = $wpdadb_dst->suppress_errors;
1173 $wpdadb_dst->suppress_errors = true;
1174 // Get create table statement from $wpdadb_src.
1175 // NO_TABLE_OPTIONS is deprecated in V8
1176 // $wpdadb_src->query( "SET sql_mode = 'NO_TABLE_OPTIONS'" );
1177 $query = "show create table `{$copy_table_name_src}`";
1178 $ctcmd = $wpdadb_src->get_results( $query, 'ARRAY_A' );
1179 // phpcs:ignore Standard.Category.SniffName.ErrorCode
1180 if ( '' !== $wpdadb_src->last_error || !isset( $ctcmd[0]['Create Table'] ) ) {
1181 $wpdadb_src->suppress_errors( $suppress_wpdadb_src );
1182 $wpdadb_dst->suppress_errors( $suppress_wpdadb_dst );
1183 return false;
1184 }
1185 $create_table_statement = $ctcmd[0]['Create Table'];
1186 if ( $copy_table_name_src !== $copy_table_name_dst ) {
1187 // Modify create table statement
1188 $pos = strpos( $create_table_statement, $copy_table_name_src );
1189 if ( $pos !== false ) {
1190 $create_table_statement = substr_replace(
1191 $create_table_statement,
1192 $copy_table_name_dst,
1193 $pos,
1194 strlen( $copy_table_name_src )
1195 );
1196 }
1197 }
1198 // Create new table in $wpdadb_dst
1199 $wpdadb_dst->query( $create_table_statement );
1200 if ( '' !== $wpdadb_dst->last_error ) {
1201 $wpdadb_src->suppress_errors( $suppress_wpdadb_src );
1202 $wpdadb_dst->suppress_errors( $suppress_wpdadb_dst );
1203 return false;
1204 }
1205 if ( 'on' !== $include_data ) {
1206 return true;
1207 }
1208 if ( $copy_schema_name_src === $copy_schema_name_dst ) {
1209 // No need for buffering if source database === destination database
1210 $result = $wpdadb_dst->query( "insert `{$copy_table_name_dst}` select * from `{$copy_table_name_src}`" );
1211 // db call ok; no-cache ok.
1212 $wpdadb_src->suppress_errors( $suppress_wpdadb_src );
1213 $wpdadb_dst->suppress_errors( $suppress_wpdadb_dst );
1214 return $result;
1215 }
1216 // Check if buffering is needed for this table
1217 $settings_db = WPDA_Table_Settings_Model::query( $copy_table_name_src, $copy_schema_name_src );
1218 if ( isset( $settings_db[0]['wpda_table_settings'] ) ) {
1219 $settings_db_custom = json_decode( $settings_db[0]['wpda_table_settings'] );
1220 if ( isset( $settings_db_custom->table_settings->query_buffer_size ) ) {
1221 $query_buffer_size = $settings_db_custom->table_settings->query_buffer_size;
1222 } else {
1223 $query_buffer_size = 0;
1224 }
1225 } else {
1226 $query_buffer_size = 0;
1227 }
1228 // Copy table data from $wpdadb to $wpdb
1229 $query = "select * from `{$copy_table_name_src}`";
1230 if ( is_numeric( $query_buffer_size ) && $query_buffer_size > 0 ) {
1231 set_time_limit( 0 );
1232 ?>
1233 <p class="wpda_pds_msg_create">
1234 Copy table `<?php
1235 echo esc_attr( $copy_schema_name_src );
1236 ?>`.`<?php
1237 echo esc_attr( $copy_table_name_src );
1238 ?>`
1239 </p>
1240 <p class="wpda_pds_msg_create">
1241 To `<?php
1242 echo esc_attr( $copy_schema_name_dst );
1243 ?>`.`<?php
1244 echo esc_attr( $copy_table_name_dst );
1245 ?>`
1246 </p>
1247 <p class="wpda_pds_msg_create">
1248 Hang on...
1249 </p>
1250 <p class="wpda_pds_msg_create">
1251 Table `<?php
1252 echo esc_attr( $copy_table_name_dst );
1253 ?>` created...
1254 </p>
1255 <p class="wpda_pds_msg_create">
1256 Copying data...
1257 </p>
1258 <?php
1259 ob_flush();
1260 flush();
1261 // Create array for fast column_name based access.
1262 $wpda_list_columns = WPDA_List_Columns_Cache::get_list_columns( $copy_schema_name_src, $copy_table_name_src );
1263 $table_columns = $wpda_list_columns->get_table_columns();
1264 $column_data_types = array();
1265 foreach ( $table_columns as $column_value ) {
1266 $column_data_types[$column_value['column_name']] = $column_value['data_type'];
1267 }
1268 $i = 0;
1269 $total = 0;
1270 $sql = $query . ' limit ' . $query_buffer_size;
1271 $rows = $wpdadb_src->get_results( $sql, 'ARRAY_A' );
1272 // phpcs:ignore Standard.Category.SniffName.ErrorCode
1273 while ( $wpdadb_src->num_rows > 0 ) {
1274 $total += $wpdadb_src->num_rows;
1275 foreach ( $rows as $row ) {
1276 $wpdadb_dst->insert( $copy_table_name_dst, $row );
1277 $wpdadb_dst->flush();
1278 $wpdadb_dst->queries = null;
1279 }
1280 echo '<script>jQuery("p.wpda_pds_msg").remove();</script>';
1281 echo '<p class="wpda_pds_msg">Copied ' . number_format( $total ) . ' rows...</p>';
1282 ob_flush();
1283 flush();
1284 $i++;
1285 $wpdadb_src->flush();
1286 $wpdadb_src->queries = null;
1287 $sql = $query . ' limit ' . $query_buffer_size . ' offset ' . $i * $query_buffer_size;
1288 $rows = $wpdadb_src->get_results( $sql, 'ARRAY_A' );
1289 // phpcs:ignore Standard.Category.SniffName.ErrorCode
1290 }
1291 echo '<script>jQuery("p.wpda_pds_msg_create, p.wpda_pds_msg").css("display", "none");</script>';
1292 } else {
1293 $rows = $wpdadb_src->get_results( $query, 'ARRAY_A' );
1294 // phpcs:ignore Standard.Category.SniffName.ErrorCode
1295 foreach ( $rows as $row ) {
1296 $wpdadb_dst->insert( $copy_table_name_dst, $row );
1297 }
1298 }
1299 $wpdadb_src->suppress_errors( $suppress_wpdadb_src );
1300 $wpdadb_dst->suppress_errors( $suppress_wpdadb_dst );
1301 return true;
1302 }
1303
1304 /**
1305 * Performs bulk export.
1306 *
1307 * @since 1.5.0
1308 */
1309 protected function process_bulk_action_bulk_export() {
1310 // Check is there is anything to export.
1311 if ( $this->process_bulk_action_check_action( 'bulk-selected', __( 'Empty bulk selected', 'wp-data-access' ) ) ) {
1312 // Check if export is allowed.
1313 if ( $this->process_bulk_action_check_wpnonce( 'wpda-export-' . json_encode( $this->table_name ), '_wpnonce' ) ) {
1314 // Get arguments.
1315 $bulk_tabs = ( isset( $_REQUEST['bulk-selected'] ) ? $_REQUEST['bulk-selected'] : '' );
1316 // input var okay; sanitization okay.
1317 $wp_nonce = wp_create_nonce( 'wpda-export-' . WPDA::get_current_user_login() );
1318 $cnt = 0;
1319 $selected_tables = array();
1320 foreach ( $bulk_tabs as $table_name ) {
1321 $export_table_name = sanitize_text_field( wp_unslash( $table_name ) );
1322 // input var okay.
1323 $err_txt = ' ' . sprintf( __( '[table `%s`]', 'wp-data-access' ), $export_table_name );
1324 if ( $this->process_bulk_action_check_table_exists( $export_table_name, $err_txt ) ) {
1325 $dbo_type = $this->get_dbo_type( $export_table_name );
1326 if ( false === $dbo_type || 'VIEW' === $dbo_type || 'SYSTEM VIEW' === $dbo_type ) {
1327 $msg = new WPDA_Message_Box(array(
1328 'message_text' => sprintf( __( 'Cannot export `%s`', 'wp-data-access' ), $export_table_name ),
1329 'message_type' => 'error',
1330 'message_is_dismissible' => false,
1331 ));
1332 $msg->box();
1333 } else {
1334 $selected_tables[] = $export_table_name;
1335 $cnt++;
1336 }
1337 }
1338 }
1339 if ( 0 < $cnt ) {
1340 ?>
1341 <script type="application/javascript">
1342 jQuery(function() {
1343 wpda_main_export(
1344 '<?php
1345 echo esc_attr( $this->schema_name );
1346 ?>',
1347 '<?php
1348 echo esc_attr( $wp_nonce );
1349 ?>',
1350 '<?php
1351 echo json_encode( $selected_tables );
1352 ?>'
1353 );
1354 });
1355 </script>
1356 <?php
1357 }
1358 }
1359 }
1360 }
1361
1362 /**
1363 * Checks request argument needed for (bulk) action to be performed.
1364 *
1365 * @param string $argument_name Request argument name.
1366 * @param string $msg Message on failure.
1367 *
1368 * @return bool TRUE = argument found in request.
1369 * @since 1.5.0
1370 */
1371 protected function process_bulk_action_check_action( $argument_name, $msg ) {
1372 if ( !isset( $_REQUEST[$argument_name] ) ) {
1373 // Nothing export.
1374 $msg = new WPDA_Message_Box(array(
1375 'message_text' => $msg,
1376 ));
1377 $msg->box();
1378 return false;
1379 }
1380 return true;
1381 }
1382
1383 /**
1384 * Checks wpnonce against a specific action.
1385 *
1386 * @param string $wp_nonce_action Nonce action.
1387 * @param string $wp_nonce_arg Nonce argument.
1388 *
1389 * @return bool TRUE = action allowed.
1390 * @since 1.5.0
1391 */
1392 protected function process_bulk_action_check_wpnonce( $wp_nonce_action, $wp_nonce_arg ) {
1393 $wp_nonce = ( isset( $_REQUEST[$wp_nonce_arg] ) ? sanitize_text_field( wp_unslash( $_REQUEST[$wp_nonce_arg] ) ) : '' );
1394 // input var okay.
1395 if ( !wp_verify_nonce( $wp_nonce, $wp_nonce_action ) ) {
1396 $msg = new WPDA_Message_Box(array(
1397 'message_text' => __( 'Not authorized', 'wp-data-access' ),
1398 'message_type' => 'error',
1399 'message_is_dismissible' => false,
1400 ));
1401 $msg->box();
1402 return false;
1403 }
1404 return true;
1405 }
1406
1407 /**
1408 * Checks if table exists.
1409 *
1410 * @param string $table_name Database table name.
1411 * @param string $err_txt Additional error text/info.
1412 *
1413 * @return bool TRUE = table exists.
1414 * @since 1.5.0
1415 */
1416 protected function process_bulk_action_check_table_exists( $table_name, $err_txt = '' ) {
1417 $wpda_dictionary = new WPDA_Dictionary_Exist($this->schema_name, $table_name);
1418 if ( !$wpda_dictionary->table_exists() ) {
1419 $msg = new WPDA_Message_Box(array(
1420 'message_text' => __( 'Not authorized [table not found]', 'wp-data-access' ) . $err_txt,
1421 'message_type' => 'error',
1422 'message_is_dismissible' => false,
1423 ));
1424 $msg->box();
1425 return false;
1426 }
1427 return true;
1428 }
1429
1430 /**
1431 * Get database object type (VIEW, BASE_TABLE, SYSTEM VIEW).
1432 *
1433 * @param string $dbo_name Table or view name.
1434 *
1435 * @return string|boolean Database object type or false.
1436 * @since 1.5.0
1437 */
1438 protected function get_dbo_type( $dbo_name ) {
1439 $wpdadb = WPDADB::get_db_connection( $this->schema_name );
1440 if ( null === $wpdadb ) {
1441 return false;
1442 }
1443 $query = $wpdadb->prepare( '
1444 SELECT table_type AS table_type
1445 FROM information_schema.tables
1446 WHERE table_schema = %s
1447 AND table_name = %s
1448 ', array($wpdadb->dbname, $dbo_name) );
1449 // db call ok; no-cache ok.
1450 $result = $wpdadb->get_results( $query, 'ARRAY_A' );
1451 // phpcs:ignore Standard.Category.SniffName.ErrorCode
1452 if ( 1 === $wpdadb->num_rows ) {
1453 return $result[0]['table_type'];
1454 } else {
1455 return false;
1456 }
1457 }
1458
1459 /**
1460 * Performs a drop table or view
1461 *
1462 * Method does not drop WordPress tables.
1463 */
1464 protected function process_bulk_action_bulk_drop() {
1465 // Check is there is anything to drop.
1466 if ( $this->process_bulk_action_check_action( 'bulk-selected', __( 'Empty bulk selected', 'wp-data-access' ) ) ) {
1467 // Check if drop is allowed.
1468 if ( $this->process_bulk_action_check_wpnonce( 'wpda-drop-' . WPDA::get_current_user_login(), '_wpnonce3' ) ) {
1469 $bulk_tabs = ( isset( $_REQUEST['bulk-selected'] ) ? $_REQUEST['bulk-selected'] : '' );
1470 // input var okay; sanitization okay.
1471 foreach ( $bulk_tabs as $table_name ) {
1472 // Drop table is not allowed for WordPress tables (double check).
1473 $drop_table_name = sanitize_text_field( wp_unslash( $table_name ) );
1474 // input var okay.
1475 $err_txt = ' ' . sprintf( __( '[cannot drop WordPress table `%s`]', 'wp-data-access' ), $drop_table_name );
1476 if ( $this->process_bulk_action_check_is_wp_table( $drop_table_name, $err_txt ) ) {
1477 // Check if table exists.
1478 $err_txt = ' ' . sprintf( __( '[table `%s`]', 'wp-data-access' ), $drop_table_name );
1479 if ( $this->process_bulk_action_check_table_exists( $drop_table_name, $err_txt ) ) {
1480 $dbo_type = $this->get_dbo_type( $drop_table_name );
1481 if ( false === $dbo_type || 'SYSTEM VIEW' === $dbo_type ) {
1482 $msg = new WPDA_Message_Box(array(
1483 'message_text' => sprintf( __( 'Cannot drop `%s`', 'wp-data-access' ), $drop_table_name ),
1484 'message_type' => 'error',
1485 'message_is_dismissible' => false,
1486 ));
1487 $msg->box();
1488 } else {
1489 if ( 'VIEW' === $dbo_type ) {
1490 // Drop view.
1491 if ( $this->drop_view( $drop_table_name ) ) {
1492 $msg = new WPDA_Message_Box(array(
1493 'message_text' => sprintf( __( 'View `%s` dropped', 'wp-data-access' ), $drop_table_name ),
1494 ));
1495 $msg->box();
1496 }
1497 } else {
1498 // Drop table.
1499 if ( $this->drop_table( $drop_table_name ) ) {
1500 $msg = new WPDA_Message_Box(array(
1501 'message_text' => sprintf( __( 'Table `%s` dropped', 'wp-data-access' ), $drop_table_name ),
1502 ));
1503 $msg->box();
1504 $this->post_drop_table( $drop_table_name );
1505 }
1506 }
1507 }
1508 }
1509 }
1510 }
1511 }
1512 }
1513 }
1514
1515 /**
1516 * Silently delete table related info from repository (called after drop table)
1517 *
1518 * @param string $drop_table_name Database table name
1519 */
1520 protected function post_drop_table( $drop_table_name ) {
1521 global $wpdb;
1522 $suppress = $wpdb->suppress_errors( true );
1523 // Table settings...
1524 $wpdb->query( $wpdb->prepare(
1525 'delete from `%1s` where wpda_schema_name = %s and wpda_table_name = %s ',
1526 // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders
1527 array(WPDA::remove_backticks( WPDA_Table_Settings_Model::get_base_table_name() ), $this->schema_name, $drop_table_name)
1528 ) );
1529 // WordPress media library columns...
1530 $wpdb->query( $wpdb->prepare(
1531 'delete from `%1s` where media_schema_name = %s and media_table_name = %s ',
1532 // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders
1533 array(WPDA::remove_backticks( WPDA_Media_Model::get_base_table_name() ), $this->schema_name, $drop_table_name)
1534 ) );
1535 // Data menus...
1536 $wpdb->query( $wpdb->prepare(
1537 'delete from `%1s` where menu_schema_name = %s and menu_table_name = %s ',
1538 // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders
1539 array(WPDA::remove_backticks( WPDA_User_Menus_Model::get_base_table_name() ), $this->schema_name, $drop_table_name)
1540 ) );
1541 $wpdb->suppress_errors( $suppress );
1542 }
1543
1544 /**
1545 * Checks if table is a WordPress table.
1546 *
1547 * @param string $table_name Database table name.
1548 * @param string $err_txt Additional error text/info.
1549 *
1550 * @return bool TRUE = table is WordPress table.
1551 * @since 1.5.0
1552 */
1553 protected function process_bulk_action_check_is_wp_table( $table_name, $err_txt = '' ) {
1554 if ( WPDA::is_wp_table( $table_name ) ) {
1555 $msg = new WPDA_Message_Box(array(
1556 'message_text' => __( 'Not authorized', 'wp-data-access' ) . $err_txt,
1557 'message_type' => 'error',
1558 'message_is_dismissible' => false,
1559 ));
1560 $msg->box();
1561 return false;
1562 }
1563 return true;
1564 }
1565
1566 /**
1567 * Performs drop view.
1568 *
1569 * @param string $view_name Database view name.
1570 *
1571 * @return bool TRUE = view dropped.
1572 * @since 1.5.0
1573 */
1574 protected function drop_view( $view_name ) {
1575 $wpdadb = WPDADB::get_db_connection( $this->schema_name );
1576 if ( null === $wpdadb ) {
1577 wp_die( sprintf( __( 'ERROR - Remote database %s not available', 'wp-data-access' ), esc_attr( $this->schema_name ) ) );
1578 }
1579 return $wpdadb->query( 'drop view `' . str_replace( '`', '', $view_name ) . '`' );
1580 // db call ok; no-cache ok.
1581 }
1582
1583 /**
1584 * Performs drop table.
1585 *
1586 * @param string $table_name Database table name.
1587 *
1588 * @return bool TRUE = table dropped.
1589 * @since 1.5.0
1590 */
1591 protected function drop_table( $table_name ) {
1592 $wpdadb = WPDADB::get_db_connection( $this->schema_name );
1593 if ( null === $wpdadb ) {
1594 wp_die( sprintf( __( 'ERROR - Remote database %s not available', 'wp-data-access' ), esc_attr( $this->schema_name ) ) );
1595 }
1596 if ( WPDA::is_wp_table( $table_name ) ) {
1597 // Never ever allow dropping a WordPress table!
1598 $msg = new WPDA_Message_Box(array(
1599 'message_text' => __( 'Not authorized [cannot drop WordPress tables]', 'wp-data-access' ),
1600 'message_type' => 'error',
1601 'message_is_dismissible' => false,
1602 ));
1603 $msg->box();
1604 return false;
1605 }
1606 return $wpdadb->query( 'drop table `' . str_replace( '`', '', $table_name ) . '`' );
1607 // db call ok; no-cache ok.
1608 }
1609
1610 /**
1611 * Performs a truncate table
1612 *
1613 * Method does not truncate WordPress tables.
1614 */
1615 protected function process_bulk_action_bulk_truncate() {
1616 // Check is there is anything to truncate.
1617 if ( $this->process_bulk_action_check_action( 'bulk-selected', __( 'No table defined', 'wp-data-access' ) ) ) {
1618 // Check if truncate is allowed.
1619 if ( $this->process_bulk_action_check_wpnonce( 'wpda-truncate-' . WPDA::get_current_user_login(), '_wpnonce4' ) ) {
1620 $bulk_tabs = ( isset( $_REQUEST['bulk-selected'] ) ? $_REQUEST['bulk-selected'] : '' );
1621 // input var okay; sanitization okay.
1622 foreach ( $bulk_tabs as $table_name ) {
1623 // Truncate table is not allowed for WordPress tables (double check).
1624 $truncate_table_name = sanitize_text_field( wp_unslash( $table_name ) );
1625 // input var okay.
1626 $err_txt = ' ' . sprintf( __( '[cannot truncate WordPress table `%s`]', 'wp-data-access' ), $truncate_table_name );
1627 if ( $this->process_bulk_action_check_is_wp_table( $truncate_table_name, $err_txt ) ) {
1628 // Check if table exists.
1629 $err_txt = ' ' . sprintf( __( '[table `%s`]', 'wp-data-access' ), $truncate_table_name );
1630 if ( $this->process_bulk_action_check_table_exists( $truncate_table_name, $err_txt ) ) {
1631 $dbo_type = $this->get_dbo_type( $truncate_table_name );
1632 if ( false === $dbo_type || 'VIEW' === $dbo_type || 'SYSTEM VIEW' === $dbo_type ) {
1633 $msg = new WPDA_Message_Box(array(
1634 'message_text' => sprintf( __( 'Cannot truncate `%s`', 'wp-data-access' ), $truncate_table_name ),
1635 'message_type' => 'error',
1636 'message_is_dismissible' => false,
1637 ));
1638 $msg->box();
1639 } else {
1640 // Truncate table.
1641 if ( $this->truncate_table( $truncate_table_name ) ) {
1642 $msg = new WPDA_Message_Box(array(
1643 'message_text' => sprintf( __( 'Table `%s` truncated', 'wp-data-access' ), $truncate_table_name ),
1644 ));
1645 $msg->box();
1646 }
1647 }
1648 }
1649 }
1650 }
1651 }
1652 }
1653 }
1654
1655 /**
1656 * Performs truncate table.
1657 *
1658 * @param string $table_name Database table name.
1659 *
1660 * @return bool TRUE = table truncated.
1661 * @since 1.5.0
1662 */
1663 protected function truncate_table( $table_name ) {
1664 $wpdadb = WPDADB::get_db_connection( $this->schema_name );
1665 if ( null === $wpdadb ) {
1666 wp_die( sprintf( __( 'ERROR - Remote database %s not available', 'wp-data-access' ), esc_attr( $this->schema_name ) ) );
1667 }
1668 if ( WPDA::is_wp_table( $table_name ) ) {
1669 // Never ever allow truncating a WordPress table!
1670 $msg = new WPDA_Message_Box(array(
1671 'message_text' => __( 'Not authorized [cannot truncate WordPress tables]', 'wp-data-access' ),
1672 'message_type' => 'error',
1673 'message_is_dismissible' => false,
1674 ));
1675 $msg->box();
1676 return false;
1677 }
1678 return $wpdadb->query( $wpdadb->prepare(
1679 'truncate table `%1s`',
1680 // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders
1681 [WPDA::remove_backticks( $table_name )]
1682 ) );
1683 // db call ok; no-cache ok.
1684 }
1685
1686 /**
1687 * Processes drop table request.
1688 *
1689 * @since 1.5.0
1690 */
1691 protected function process_bulk_action_drop() {
1692 // Check is there is anything to drop.
1693 if ( $this->process_bulk_action_check_action( 'drop_table_name', __( 'No table defined', 'wp-data-access' ) ) ) {
1694 // Drop table is not allowed for WordPress tables (double check).
1695 $drop_table_name = sanitize_text_field( wp_unslash( $_REQUEST['drop_table_name'] ) );
1696 // input var okay.
1697 $err_txt = ' ' . sprintf( __( '[cannot drop WordPress table `%s`]', 'wp-data-access' ), $drop_table_name );
1698 if ( $this->process_bulk_action_check_is_wp_table( $drop_table_name, $err_txt ) ) {
1699 // Check if table exists.
1700 if ( $this->process_bulk_action_check_table_exists( $drop_table_name ) ) {
1701 // Check if drop is allowed.
1702 if ( $this->process_bulk_action_check_wpnonce( "wpda-drop-{$drop_table_name}", '_wpnonce' ) ) {
1703 $dbo_type = $this->get_dbo_type( $drop_table_name );
1704 if ( false === $dbo_type || 'SYSTEM VIEW' === $dbo_type ) {
1705 $msg = new WPDA_Message_Box(array(
1706 'message_text' => sprintf( __( 'Cannot drop `%s`', 'wp-data-access' ), $drop_table_name ),
1707 'message_type' => 'error',
1708 'message_is_dismissible' => false,
1709 ));
1710 $msg->box();
1711 } else {
1712 if ( 'VIEW' === $dbo_type ) {
1713 // Drop view.
1714 if ( $this->drop_view( $drop_table_name ) ) {
1715 $msg = new WPDA_Message_Box(array(
1716 'message_text' => sprintf( __( 'View `%s` dropped', 'wp-data-access' ), $drop_table_name ),
1717 ));
1718 $msg->box();
1719 }
1720 } else {
1721 // Drop table.
1722 if ( $this->drop_table( $drop_table_name ) ) {
1723 $msg = new WPDA_Message_Box(array(
1724 'message_text' => sprintf( __( 'Table `%s` dropped', 'wp-data-access' ), $drop_table_name ),
1725 ));
1726 $msg->box();
1727 $this->post_drop_table( $drop_table_name );
1728 }
1729 }
1730 }
1731 }
1732 }
1733 }
1734 }
1735 }
1736
1737 /**
1738 * Processes truncate table request.
1739 *
1740 * @since 1.5.0
1741 */
1742 protected function process_bulk_action_truncate() {
1743 // Check is there is anything to truncate.
1744 if ( $this->process_bulk_action_check_action( 'truncate_table_name', __( 'No table defined', 'wp-data-access' ) ) ) {
1745 // Truncate table is not allowed for WordPress tables (double check).
1746 $truncate_table_name = sanitize_text_field( wp_unslash( $_REQUEST['truncate_table_name'] ) );
1747 // input var okay.
1748 $err_txt = ' ' . sprintf( __( '[cannot truncate WordPress table `%s`]', 'wp-data-access' ), $truncate_table_name );
1749 if ( $this->process_bulk_action_check_is_wp_table( $truncate_table_name, $err_txt ) ) {
1750 // Check if table exists.
1751 if ( $this->process_bulk_action_check_table_exists( $truncate_table_name ) ) {
1752 // Check if truncate is allowed.
1753 if ( $this->process_bulk_action_check_wpnonce( "wpda-truncate-{$truncate_table_name}", '_wpnonce' ) ) {
1754 // Truncate table.
1755 if ( $this->truncate_table( $truncate_table_name ) ) {
1756 $msg = new WPDA_Message_Box(array(
1757 'message_text' => sprintf( __( 'Table `%s` truncated', 'wp-data-access' ), $truncate_table_name ),
1758 ));
1759 $msg->box();
1760 }
1761 }
1762 }
1763 }
1764 }
1765 }
1766
1767 protected function add_header_actions() {
1768 $this->add_db_containers();
1769 }
1770
1771 /**
1772 * Overwrite method: add bulk array to check ddl allowed
1773 */
1774 public function show() {
1775 ?>
1776 <script type='text/javascript'>
1777 var wpda_bulk = [];
1778
1779 function wpda_bulk_valid() {
1780 var wpda_bulk_selected_valid = true;
1781 jQuery("input[name='bulk-selected[]']:checked").each(function () {
1782 var wpda_bulk_selected = jQuery(this).val();
1783 wpda_bulk.every(function (item) {
1784 if (item === wpda_bulk_selected) {
1785 alert("Action not allowed on WordPress tables!");
1786 wpda_bulk_selected_valid = false;
1787 }
1788 });
1789 if (wpda_bulk_selected_valid === false) {
1790 return false;
1791 }
1792 });
1793 return wpda_bulk_selected_valid;
1794 }
1795
1796 function wpda_check_bulk() {
1797 action = jQuery("select[name='action']").val();
1798 action2 = jQuery("select[name='action2']").val();
1799 if (action === '-1') {
1800 if (action2 === 'bulk-drop' || action2 === 'bulk-truncate') {
1801 return wpda_bulk_valid();
1802 } else {
1803 return true;
1804 }
1805 } else {
1806 if (action === 'bulk-drop' || action === 'bulk-truncate') {
1807 return wpda_bulk_valid();
1808 } else {
1809 return true;
1810 }
1811 }
1812 }
1813 </script>
1814 <?php
1815 parent::show();
1816 ?>
1817 <script type='text/javascript'>
1818 function show_hide_column(show) {
1819 for (i = 0; i <<?php
1820 echo esc_attr( self::$list_number );
1821 ?>; i++) {
1822 if (show) {
1823 jQuery('#rownum_' + i + '_x1').attr('colspan', parseInt(jQuery('#rownum_' + i + '_x1').attr('colspan')) + 1);
1824 jQuery('#rownum_' + i + '_x2').attr('colspan', parseInt(jQuery('#rownum_' + i + '_x2').attr('colspan')) + 1);
1825 } else {
1826 jQuery('#rownum_' + i + '_x1').attr('colspan', parseInt(jQuery('#rownum_' + i + '_x1').attr('colspan')) - 1);
1827 jQuery('#rownum_' + i + '_x2').attr('colspan', parseInt(jQuery('#rownum_' + i + '_x2').attr('colspan')) - 1);
1828 }
1829 }
1830 jQuery('.wp-list-table').removeClass('fixed');
1831 }
1832
1833 jQuery(function () {
1834 jQuery("#doaction").on("click", function (e) {
1835 return wpda_check_bulk();
1836 });
1837 jQuery("#doaction2").on("click", function (e) {
1838 return wpda_check_bulk();
1839 });
1840 jQuery('#table_name-hide').on("click", function (e) {
1841 show_hide_column(jQuery('#table_name-hide').is(":checked"));
1842 });
1843 jQuery('#table_type-hide').on("click", function (e) {
1844 show_hide_column(jQuery('#table_type-hide').is(":checked"));
1845 });
1846 jQuery('#create_time-hide').on("click", function (e) {
1847 show_hide_column(jQuery('#create_time-hide').is(":checked"));
1848 });
1849 jQuery('#table_rows-hide').on("click", function (e) {
1850 show_hide_column(jQuery('#table_rows-hide').is(":checked"));
1851 });
1852 jQuery('#auto_increment-hide').on("click", function (e) {
1853 show_hide_column(jQuery('#auto_increment-hide').is(":checked"));
1854 });
1855 jQuery('#engine-hide').on("click", function (e) {
1856 show_hide_column(jQuery('#engine-hide').is(":checked"));
1857 });
1858 jQuery('#total_size-hide').on("click", function (e) {
1859 show_hide_column(jQuery('#total_size-hide').is(":checked"));
1860 });
1861 jQuery('#data_size-hide').on("click", function (e) {
1862 show_hide_column(jQuery('#data_size-hide').is(":checked"));
1863 });
1864 jQuery('#index_size-hide').on("click", function (e) {
1865 show_hide_column(jQuery('#index_size-hide').is(":checked"));
1866 });
1867 jQuery('#overhead-hide').on("click", function (e) {
1868 show_hide_column(jQuery('#overhead-hide').is(":checked"));
1869 });
1870 jQuery('#table_collation-hide').on("click", function (e) {
1871 show_hide_column(jQuery('#table_collation-hide').is(":checked"));
1872 });
1873 });
1874 </script>
1875 <?php
1876 }
1877
1878 /**
1879 * Overwrite construct_where_clause()
1880 *
1881 * @since 1.0.0
1882 *
1883 * @see WPDA_List_Table::construct_where_clause()
1884 */
1885 protected function construct_where_clause() {
1886 $wpdadb = WPDADB::get_db_connection( $this->schema_name );
1887 if ( null === $wpdadb ) {
1888 wp_die( sprintf( __( 'ERROR - Remote database %s not available', 'wp-data-access' ), esc_attr( $this->schema_name ) ) );
1889 }
1890 global $wpdb;
1891 // Make sure we're selecting only tables that are in the WordPress database.
1892 $where_or_and = ( '' === $this->where ? ' where ' : ' and ' );
1893 $this->where .= $wpdadb->prepare( " {$where_or_and} table_schema = %s ", $wpdadb->dbname );
1894 // Since we are using a view, the default behaviour of the parent will not work for us. We have to
1895 // define our where clause manually.
1896 $cols = array(array(
1897 'column_name' => 'table_name',
1898 'data_type' => 'varchar',
1899 'extra' => '',
1900 'column_type' => 'varchar(64)',
1901 'is_nullable' => 'NO',
1902 'column_default' => null,
1903 ));
1904 $where = WPDA::construct_where_clause(
1905 $this->schema_name,
1906 $this->table_name,
1907 $cols,
1908 $this->search_value
1909 );
1910 if ( '' !== $where ) {
1911 $this->where .= ' and ' . $where;
1912 }
1913 if ( $wpdb->dbname === $this->schema_name || '' === $this->schema_name ) {
1914 $table_access = WPDA::get_option( WPDA::OPTION_BE_TABLE_ACCESS );
1915 } else {
1916 $table_access = get_option( WPDA::BACKEND_OPTIONNAME_DATABASE_ACCESS . $this->schema_name );
1917 if ( false === $table_access ) {
1918 $table_access = 'show';
1919 }
1920 }
1921 if ( 'hide' === $table_access ) {
1922 // No access to WordPress tables: filter WordPress table.
1923 $this->where .= " and table_name not in ('" . implode( "','", $wpdb->tables( 'all', true ) ) . "')";
1924 } elseif ( 'select' === $table_access ) {
1925 if ( $wpdb->dbname === $this->schema_name || '' === $this->schema_name ) {
1926 $option = WPDA::get_option( WPDA::OPTION_BE_TABLE_ACCESS_SELECTED );
1927 } else {
1928 $option = get_option( WPDA::BACKEND_OPTIONNAME_DATABASE_SELECTED . $this->schema_name );
1929 if ( false === $option ) {
1930 $option = '';
1931 }
1932 }
1933 if ( '' !== $option ) {
1934 // Allow only access to selected tables.
1935 $this->where .= " and table_name in ('" . implode( "','", $option ) . "')";
1936 } else {
1937 // No tables selected: no access.
1938 $this->where .= ' and 1=2';
1939 }
1940 }
1941 if ( null != $this->wpda_main_favourites ) {
1942 if ( false === $this->favourites && 'show' === $this->wpda_main_favourites ) {
1943 $where_or_and = ( '' === $this->where ? ' where ' : ' and ' );
1944 $this->where .= " {$where_or_and} 1=2 ";
1945 } elseif ( is_array( $this->favourites ) ) {
1946 if ( 0 < count( $this->favourites ) ) {
1947 //phpcs:ignore - 8.1 proof
1948 $where_or_and = ( '' === $this->where ? ' where ' : ' and ' );
1949 $in_or_not_in = ( 'show' === $this->wpda_main_favourites ? 'in' : 'not in' );
1950 $this->where .= " {$where_or_and} table_name {$in_or_not_in} ('" . implode( "','", $this->favourites ) . "') ";
1951 }
1952 }
1953 }
1954 }
1955
1956 protected function get_order_by() {
1957 $orderby = parent::get_order_by();
1958 if ( '' !== $orderby ) {
1959 return $orderby;
1960 } else {
1961 return ' order by table_name asc ';
1962 }
1963 }
1964
1965 /**
1966 * Overwrite method: add button to design a table
1967 */
1968 protected function add_header_button() {
1969 ?>
1970 <form
1971 method="post"
1972 action="?page=<?php
1973 echo esc_attr( \WP_Data_Access_Admin::PAGE_DESIGNER );
1974 ?>"
1975 style="display: inline-block; vertical-align: baseline;"
1976 >
1977 <div>
1978 <input type="hidden" name="action" value="create_table">
1979 <input type="hidden" name="caller" value="dataexplorer">
1980 <button type="submit"
1981 class="page-title-action wpda_tooltip"
1982 title="Create a new table design"
1983 >
1984 <i class="fas fa-plus-circle wpda_icon_on_button"></i>
1985 <?php
1986 echo __( 'Design new table', 'wp-data-access' );
1987 ?>
1988 </button>
1989 </div>
1990 </form>
1991 <form id="wpda_linkto_backup" style="display: none" method="post" action="?page=<?php
1992 echo esc_attr( WP_Data_Access_Admin::PAGE_MAIN );
1993 ?>&page_action=wpda_backup">
1994 <input type="hidden" name="wpdaschema_name" value="<?php
1995 echo esc_attr( $this->schema_name );
1996 ?>">
1997 </form>
1998 <?php
1999 $this->wpda_import->add_button();
2000 }
2001
2002 /**
2003 * Add container to create new database
2004 */
2005 protected function add_db_containers() {
2006 if ( 'rdb:' === substr( $this->schema_name, 0, 4 ) ) {
2007 $rdb = WPDADB::get_remote_database( $this->schema_name );
2008 }
2009 $host = ( isset( $rdb['host'] ) ? $rdb['host'] : '' );
2010 $user = ( isset( $rdb['username'] ) ? $rdb['username'] : '' );
2011 $passwd = ( isset( $rdb['password'] ) ? $rdb['password'] : '' );
2012 $port = ( isset( $rdb['port'] ) ? $rdb['port'] : '' );
2013 $schema = ( isset( $rdb['database'] ) ? $rdb['database'] : '' );
2014 $ssl = ( isset( $rdb['ssl'] ) ? $rdb['ssl'] : '' );
2015 $ssl_key = ( isset( $rdb['ssl_key'] ) ? $rdb['ssl_key'] : '' );
2016 $ssl_cert = ( isset( $rdb['ssl_cert'] ) ? $rdb['ssl_cert'] : '' );
2017 $ssl_ca = ( isset( $rdb['ssl_ca'] ) ? $rdb['ssl_ca'] : '' );
2018 $ssl_path = ( isset( $rdb['ssl_path'] ) ? $rdb['ssl_path'] : '' );
2019 $ssl_cipher = ( isset( $rdb['ssl_cipher'] ) ? $rdb['ssl_cipher'] : '' );
2020 $readonly = '';
2021 ?>
2022 <div id="wpda_db_edit" style="display:none;padding-top:10px;">
2023 <div class="wpda_upload">
2024 <form method="post" action="?page=<?php
2025 echo esc_attr( $this->page );
2026 ?>" onsubmit="return editdb_validate_form();">
2027 <div style="height:10px;"></div>
2028 <strong><?php
2029 echo __( 'Edit Remote Database Connection', 'wp-data-access' );
2030 ?></strong>
2031 <div style="height:10px;"></div>
2032 <div>
2033 <label for="edit_remote_database" style="vertical-align:baseline;"
2034 class="database_item_label">Database name:</label>
2035 <input type="text" name="edit_remote_database" id="edit_remote_database" value="<?php
2036 echo esc_attr( $this->schema_name );
2037 ?>" <?php
2038 echo esc_attr( $readonly );
2039 ?>>
2040 <input type="hidden" name="edit_remote_database_old" value="<?php
2041 echo esc_attr( $this->schema_name );
2042 ?>">
2043 <div style="height:10px;"></div>
2044 <label for="edit_remote_host" style="vertical-align:baseline;" class="database_item_label">MySQL host:</label>
2045 <input type="text" name="edit_remote_host" id="edit_remote_host" value="<?php
2046 echo esc_attr( $host );
2047 ?>">
2048 <br/>
2049 <label for="edit_remote_user" style="vertical-align:baseline;" class="database_item_label">MySQL username:</label>
2050 <input type="text" name="edit_remote_user" id="edit_remote_user" value="<?php
2051 echo esc_attr( $user );
2052 ?>">
2053 <br/>
2054 <label for="edit_remote_passwd" style="vertical-align:baseline;" class="database_item_label" >MySQL password:</label>
2055 <input type="password" name="edit_remote_passwd" id="edit_remote_passwd" value="<?php
2056 echo esc_attr( $passwd );
2057 ?>" autocomplete="new-password">
2058 <i class="fas fa-eye" onclick="wpda_toggle_password('edit_remote_passwd', event)" style="cursor:pointer"></i>
2059 <br/>
2060 <label for="edit_remote_port" style="vertical-align:baseline;" class="database_item_label">MySQL port:</label>
2061 <input type="text" name="edit_remote_port" id="edit_remote_port" value="<?php
2062 echo esc_attr( $port );
2063 ?>">
2064 <br/>
2065 <label for="edit_remote_schema" style="vertical-align:baseline;" class="database_item_label">MySQL schema:</label>
2066 <input type="text" name="edit_remote_schema" id="edit_remote_schema" value="<?php
2067 echo esc_attr( $schema );
2068 ?>">
2069
2070 <br/>
2071 <label style="line-height:30px;" for="edit_remote_ssl" style="vertical-align:baseline;" class="database_item_label">SSL:</label>
2072 <input type="checkbox" name="edit_remote_ssl" id="edit_remote_ssl" <?php
2073 echo ( 'on' === $ssl ? 'checked' : 'unchecked' );
2074 ?> onclick="jQuery('#edit_remote_database_block_ssl').toggle()">
2075 <div id="edit_remote_database_block_ssl" <?php
2076 echo ( 'on' === $ssl ? '' : 'style="display:none;"' );
2077 ?>>
2078 <label for="edit_remote_client_key" style="vertical-align:baseline;" class="database_item_label">Client key:</label>
2079 <input type="text" name="edit_remote_client_key" id="edit_remote_client_key" value="<?php
2080 echo esc_attr( $ssl_key );
2081 ?>">
2082 <br/>
2083 <label for="edit_remote_client_certificate" style="vertical-align:baseline;" class="database_item_label">Client certificate:</label>
2084 <input type="text" name="edit_remote_client_certificate" id="edit_remote_client_certificate" value="<?php
2085 echo esc_attr( $ssl_cert );
2086 ?>">
2087 <br/>
2088 <label for="edit_remote_ca_certificate" style="vertical-align:baseline;" class="database_item_label">CA certificate:</label>
2089 <input type="text" name="edit_remote_ca_certificate" id="edit_remote_ca_certificate" value="<?php
2090 echo esc_attr( $ssl_ca );
2091 ?>">
2092 <br/>
2093 <label for="edit_remote_certificate_path" style="vertical-align:baseline;" class="database_item_label">Certificate path:</label>
2094 <input type="text" name="edit_remote_certificate_path" id="edit_remote_certificate_path" value="<?php
2095 echo esc_attr( $ssl_path );
2096 ?>">
2097 <br/>
2098 <label for="edit_remote_specified_cipher" style="vertical-align:baseline;" class="database_item_label">Specified Cipher:</label>
2099 <input type="text" name="edit_remote_specified_cipher" id="edit_remote_specified_cipher" value="<?php
2100 echo esc_attr( $ssl_cipher );
2101 ?>">
2102 </div>
2103
2104 <div style="height:10px;"></div>
2105 <label class="database_item_label"></label>
2106 <input type="button" value="Test" onclick="test_remote_connection('edit_'); return false;"
2107 id="edit_remote_test_button" class="button">
2108 <input type="button" value="Clear" onclick="test_remote_clear('edit_'); return false;"
2109 id="edit_remote_clear_button" class="button" style="display:none;">
2110 <div style="height:10px;"></div>
2111 </div>
2112 <div id="edit_remote_database_block_test" style="display:none;">
2113 <div id="edit_remote_database_block_test_content"
2114 class="remote_database_block_test_content"></div>
2115 <div style="height:10px;"></div>
2116 </div>
2117
2118 <input type="submit" class="button button-primary" value="<?php
2119 echo __( 'Save', 'wp-data-access' );
2120 ?>">
2121 <a href="javascript:void(0)"
2122 onclick="jQuery('#wpda_db_edit').hide()"
2123 class="button button-secondary"><i class="fas fa-times-circle wpda_icon_on_button"></i> <?php
2124 echo __( 'Cancel', 'wp-data-access' );
2125 ?></a>
2126 <input type="hidden" name="action" value="edit_db">
2127 <?php
2128 wp_nonce_field( 'wpda-edit-db-from-data-explorer-' . WPDA::get_current_user_login(), '_wpnonceeditdb', false );
2129 ?>
2130 </form>
2131 </div>
2132 </div>
2133
2134 <div id="wpda_db_container" style="display:none;padding-top:10px;">
2135 <div class="wpda_upload">
2136 <form method="post" action="?page=<?php
2137 echo esc_attr( $this->page );
2138 ?>" onsubmit="return createdb_validate_form();">
2139 <div style="height:10px;"></div>
2140
2141 <?php
2142 if ( $this->user_can_create_db ) {
2143 ?>
2144 <select name="database_location" id="database_location">
2145 <option value="local"
2146 selected><?php
2147 echo __( 'Create local database', 'wp-data-access' );
2148 ?></option>
2149 <option value="remote"><?php
2150 echo __( 'Add remote database connection', 'wp-data-access' );
2151 ?></option>
2152 </select>
2153
2154 <div style="height:10px;"></div>
2155
2156 <div id="local_database_block">
2157 <label for="local_database" style="vertical-align:baseline;"
2158 class="database_item_label">Database name:</label>
2159 <input type="text" name="local_database" id="local_database">
2160
2161 <div style="height:10px;"></div>
2162 </div>
2163 <?php
2164 } else {
2165 ?>
2166 <strong><?php
2167 echo __( 'Add remote database connection', 'wp-data-access' );
2168 ?></strong>
2169
2170 <div style="height:10px;"></div>
2171 <?php
2172 }
2173 ?>
2174
2175 <div id="remote_database_block"<?php
2176 echo ( $this->user_can_create_db ? 'style="display:none;"' : '' );
2177 ?>>
2178 <div>
2179 <label for="remote_database" style="vertical-align:baseline;"
2180 class="database_item_label">Database name:</label>
2181 <input type="text" name="remote_database" id="remote_database" value="rdb:">
2182 <div style="height:10px;"></div>
2183 <label for="remote_host" style="vertical-align:baseline;" class="database_item_label">MySQL host:</label>
2184 <input type="text" name="remote_host" id="remote_host">
2185 <br/>
2186 <label for="remote_user" style="vertical-align:baseline;" class="database_item_label">MySQL username:</label>
2187 <input type="text" name="remote_user" id="remote_user">
2188 <br/>
2189 <label for="remote_passwd" style="vertical-align:baseline;" class="database_item_label">MySQL password:</label>
2190 <input type="password" name="remote_passwd" id="remote_passwd" autocomplete="new-password">
2191 <i class="fas fa-eye" onclick="wpda_toggle_password('remote_passwd', event)" style="cursor:pointer"></i>
2192 <br/>
2193 <label for="remote_port" style="vertical-align:baseline;" class="database_item_label">MySQL port:</label>
2194 <input type="text" name="remote_port" id="remote_port" value="3306">
2195 <br/>
2196 <label for="remote_schema" style="vertical-align:baseline;" class="database_item_label">MySQL schema:</label>
2197 <input type="text" name="remote_schema" id="remote_schema">
2198
2199 <br/>
2200 <label style="line-height:30px;" for="remote_ssl" style="vertical-align:baseline;" class="database_item_label">SSL:</label>
2201 <input type="checkbox" name="remote_ssl" id="remote_ssl" unchecked onclick="jQuery('#remote_database_block_ssl').toggle()">
2202 <div id="remote_database_block_ssl" style="display:none;">
2203 <label for="remote_client_key" style="vertical-align:baseline;" class="database_item_label">Client key:</label>
2204 <input type="text" name="remote_client_key" id="remote_client_key">
2205 <br/>
2206 <label for="remote_client_certificate" style="vertical-align:baseline;" class="database_item_label">Client certificate:</label>
2207 <input type="text" name="remote_client_certificate" id="remote_client_certificate">
2208 <br/>
2209 <label for="remote_ca_certificate" style="vertical-align:baseline;" class="database_item_label">CA certificate:</label>
2210 <input type="text" name="remote_ca_certificate" id="remote_ca_certificate">
2211 <br/>
2212 <label for="remote_certificate_path" style="vertical-align:baseline;" class="database_item_label">Certificate path:</label>
2213 <input type="text" name="remote_certificate_path" id="remote_certificate_path">
2214 <br/>
2215 <label for="remote_specified_cipher" style="vertical-align:baseline;" class="database_item_label">Specified Cipher:</label>
2216 <input type="text" name="remote_specified_cipher" id="remote_specified_cipher">
2217 </div>
2218
2219 <div style="height:10px;"></div>
2220 <label class="database_item_label"></label>
2221 <input type="button" value="Test" onclick="test_remote_connection(); return false;"
2222 id="remote_test_button" class="button">
2223 <input type="button" value="Clear" onclick="test_remote_clear(); return false;"
2224 id="remote_clear_button" class="button" style="display:none;">
2225 <div style="height:10px;"></div>
2226 </div>
2227 <div id="remote_database_block_test" style="display:none;">
2228 <div id="remote_database_block_test_content"
2229 class="remote_database_block_test_content"></div>
2230 <div style="height:10px;"></div>
2231 </div>
2232 </div>
2233
2234 <a href="javascript:void(0)"
2235 onclick="jQuery(this).closest('form').submit()"
2236 class="button button-primary"><i class="fas fa-cloud-upload wpda_icon_on_button"></i> <?php
2237 echo __( 'Save', 'wp-data-access' );
2238 ?></a>
2239 <a href="javascript:void(0)"
2240 onclick="jQuery('#wpda_db_container').hide()"
2241 class="button button-secondary"><i class="fas fa-times-circle wpda_icon_on_button"></i> <?php
2242 echo __( 'Cancel', 'wp-data-access' );
2243 ?></a>
2244 <input type="hidden" name="action" value="create_db">
2245 <?php
2246 wp_nonce_field( 'wpda-create-db-from-data-explorer-' . WPDA::get_current_user_login(), '_wpnoncecreatedb', false );
2247 ?>
2248 </form>
2249 </div>
2250 </div>
2251
2252 <div style="display:none;">
2253 <form id="wpda_form_drop_db" method="post" action="?page=<?php
2254 echo esc_attr( $this->page );
2255 ?>">
2256 <input type="text" name="database" id="drop_database">
2257 <input type="hidden" name="action" value="drop_db">
2258 <?php
2259 wp_nonce_field( 'wpda-drop-db-from-data-explorer-' . WPDA::get_current_user_login(), '_wpnoncedropdb', false );
2260 ?>
2261 </form>
2262 </div>
2263
2264 <script type='text/javascript'>
2265 function editdb_validate_form() {
2266 if (jQuery('#edit_remote_database').val()==='' || jQuery('#edit_remote_database').val()==='rdb:') {
2267 alert('Database name must be entered');
2268 return false;
2269 }
2270 if (jQuery('#edit_remote_host').val()==='') {
2271 alert('MySQL host must be entered');
2272 return false;
2273 }
2274 if (jQuery('#edit_remote_user').val()==='') {
2275 alert('MySQL username must be entered');
2276 return false;
2277 }
2278 if (jQuery('#edit_remote_schema').val()==='') {
2279 alert('MySQL schema must be entered');
2280 return false;
2281 }
2282 return true;
2283 }
2284
2285 function createdb_validate_form() {
2286 if (jQuery('#database_location').val() === 'remote') {
2287 if (jQuery('#remote_database').val()==='' || jQuery('#remote_database').val()==='rdb:') {
2288 alert('Database name must be entered');
2289 return false;
2290 }
2291 if (jQuery('#remote_host').val()==='') {
2292 alert('MySQL host must be entered');
2293 return false;
2294 }
2295 if (jQuery('#remote_user').val()==='') {
2296 alert('MySQL username must be entered');
2297 return false;
2298 }
2299 if (jQuery('#remote_schema').val()==='') {
2300 alert('MySQL schema must be entered');
2301 return false;
2302 }
2303 } else {
2304
2305 if (jQuery('#local_database').val()==='') {
2306 alert('Database name must be entered');
2307 return false;
2308 }
2309 }
2310 return true;
2311 }
2312
2313 function test_remote_clear(mode = '') {
2314 jQuery('#' + mode + 'remote_database_block_test_content').html('');
2315 jQuery('#' + mode + 'remote_database_block_test').hide();
2316 jQuery('#' + mode + 'remote_clear_button').hide();
2317 }
2318
2319 function test_remote_connection(mode = '') {
2320 host = jQuery('#' + mode + 'remote_host').val();
2321 user = jQuery('#' + mode + 'remote_user').val();
2322 pass = jQuery('#' + mode + 'remote_passwd').val();
2323 port = jQuery('#' + mode + 'remote_port').val();
2324 dbs = jQuery('#' + mode + 'remote_schema').val();
2325 ssl = jQuery('#' + mode + 'remote_ssl').val();
2326 ssl_key = jQuery('#' + mode + 'remote_client_key').val();
2327 ssl_cert = jQuery('#' + mode + 'remote_client_certificate').val();
2328 ssl_ca = jQuery('#' + mode + 'remote_ca_certificate').val();
2329 ssl_path = jQuery('#' + mode + 'remote_certificate_path').val();
2330 ssl_cipher = jQuery('#' + mode + 'remote_specified_cipher').val();
2331
2332 url = '//' + window.location.host + window.location.pathname +
2333 '?action=wpda_check_remote_database_connection';
2334
2335 jQuery('#' + mode + 'remote_test_button').val('Testing...');
2336
2337 jQuery.ajax({
2338 method: 'POST',
2339 url: url,
2340 data: {
2341 host: host,
2342 user: user,
2343 passwd: pass,
2344 port: port,
2345 schema: dbs,
2346 ssl: ssl,
2347 ssl_key: ssl_key,
2348 ssl_cert: ssl_cert,
2349 ssl_ca: ssl_ca,
2350 ssl_path: ssl_path,
2351 ssl_cipher: ssl_cipher
2352 }
2353 }).done(
2354 function (msg) {
2355 jQuery('#' + mode + 'remote_database_block_test_content').html(msg);
2356 jQuery('#' + mode + 'remote_database_block_test').show();
2357 }
2358 ).fail(
2359 function () {
2360 jQuery('#' + mode + 'remote_database_block_test_content').html('Preparing connection...<br/>Establishing connection...<br/><br/><strong>Remote database connection invalid</strong>');
2361 jQuery('#' + mode + 'remote_database_block_test').show();
2362 }
2363 ).always(
2364 function () {
2365 jQuery('#' + mode + 'remote_test_button').val('Test');
2366 jQuery('#' + mode + 'remote_clear_button').show();
2367 }
2368 );
2369 }
2370
2371 jQuery(function () {
2372 jQuery('#database_location').on('change', function () {
2373 if (jQuery(this).val() === 'remote') {
2374 jQuery('#local_database_block').hide();
2375 jQuery('#remote_database_block').show();
2376 } else {
2377 jQuery('#remote_database_block').hide();
2378 jQuery('#local_database_block').show();
2379 }
2380 });
2381 jQuery('#remote_database, #edit_remote_database').keydown(function(e) {
2382 var field = this;
2383 setTimeout(function () {
2384 if (field.value.indexOf('rdb:') !== 0) {
2385 jQuery(field).val('rdb:');
2386 }
2387 }, 1);
2388 });
2389 });
2390 </script>
2391 <?php
2392 }
2393
2394 /**
2395 * Display the search box
2396 *
2397 * @param string $text The 'submit' button label.
2398 * @param string $input_id ID attribute value for the search input field.
2399 *
2400 * @since 1.6.0
2401 */
2402 public function search_box( $text, $input_id ) {
2403 global $wpdb;
2404 $input_id = $input_id . '-search-input';
2405 $schemas = WPDA_Dictionary_Lists::get_db_schemas();
2406 ?>
2407 <div style="padding-top:10px;padding-bottom:0;">
2408 <span style="font-weight: bold;"><?php
2409 echo __( 'Database', 'wp-data-access' );
2410 ?>:</span>
2411 <select id="wpda_main_db_schema_list">
2412 <?php
2413 foreach ( $schemas as $schema ) {
2414 if ( $this->schema_name === $schema['schema_name'] ) {
2415 $selected = ' selected';
2416 } else {
2417 $selected = '';
2418 }
2419 if ( $wpdb->dbname === $schema['schema_name'] ) {
2420 $printed_schema_name = "WordPress database ({$schema['schema_name']})";
2421 } else {
2422 $printed_schema_name = $schema['schema_name'];
2423 }
2424 ?>
2425 <option value="<?php
2426 echo esc_attr( $schema['schema_name'] );
2427 ?>" <?php
2428 echo esc_attr( $selected );
2429 ?>>
2430 <?php
2431 echo esc_attr( $printed_schema_name );
2432 ?>
2433 </option>
2434 <?php
2435 }
2436 ?>
2437 </select>
2438 <a class="dashicons dashicons-edit wpda_tooltip" href="javascript:void(0)"
2439 <?php
2440 if ( 'rdb:' === substr( $this->schema_name, 0, 4 ) ) {
2441 ?>
2442 onclick="jQuery('#wpda_db_edit').show();"
2443 <?php
2444 }
2445 ?>
2446 style="<?php
2447 echo ( 'rdb:' === substr( $this->schema_name, 0, 4 ) ? '' : 'color:grey;cursor:default;' );
2448 ?>vertical-align:middle;"
2449 title="<?php
2450 echo ( 'rdb:' === substr( $this->schema_name, 0, 4 ) ? __( 'Edit remote database connection', 'wp-data-access' ) : __( 'Not available for local database', 'wp-data-access' ) );
2451 ?>">&nbsp;</a>
2452 <a class="dashicons dashicons-plus-alt wpda_tooltip" href="javascript:void(0)"
2453 onclick="jQuery('#wpda_db_container').show(); jQuery('#local_database').focus();"
2454 style="vertical-align:middle;"
2455 title="<?php
2456 echo esc_attr( $this->user_create_db_hint );
2457 ?>">&nbsp;</a>
2458 <a class="dashicons dashicons-dismiss wpda_tooltip" id="wpda_drop_database" href="javascript:void(0)"
2459 <?php
2460 if ( $this->user_can_drop_db ) {
2461 if ( 'rdb:' === substr( $this->schema_name, 0, 4 ) ) {
2462 $msg = __( 'Delete remote database connection?\\nDoes not drop the database! Only deletes the remote database connection definition.', 'wp-data-access' );
2463 } else {
2464 $msg = __( 'Drop selected database?', 'wp-data-access' );
2465 }
2466 ?>
2467 onclick="if (confirm('<?php
2468 echo $msg;
2469 // phpcs:ignore WordPress.Security.EscapeOutput
2470 ?>')) { jQuery('#drop_database').val(jQuery('#wpda_main_db_schema_list').val()); jQuery('#wpda_form_drop_db').submit(); }"
2471 <?php
2472 }
2473 ?>
2474 style="<?php
2475 echo ( $this->user_can_drop_db ? 'color:#a00;' : 'color:grey;cursor:default;' );
2476 ?>vertical-align:middle;"
2477 title="<?php
2478 echo esc_attr( $this->user_drop_db_hint );
2479 ?>">&nbsp;</a>
2480 <a class="dashicons dashicons-admin-plugins wpda_tooltip"
2481 href="javascript:void(0)"
2482 onclick="wpda_dbinit_admin( '<?php
2483 echo esc_attr( $this->schema_name );
2484 ?>', '<?php
2485 echo wp_create_nonce( 'wpda_dbinit_admin_' . WPDA::get_current_user_login() );
2486 ?>' )"
2487 style="vertical-align:middle;"
2488 title="<?php
2489 echo __( "Create function wpda_get_wp_user_id() to access the WordPress user ID from database views", 'wp-data-access' );
2490 ?>">&nbsp;</a>
2491 &nbsp;<span style="font-weight: bold;"><?php
2492 echo __( 'Favourites', 'wp-data-access' );
2493 // phpcs:ignore WordPress.Security.EscapeOutput
2494 ?>:</span>
2495 <select id="wpda_main_favourites_list">
2496 <option value="" <?php
2497 echo ( '' === $this->wpda_main_favourites ? 'selected' : '' );
2498 ?>>Show all
2499 </option>
2500 <option value="show" <?php
2501 echo ( 'show' === $this->wpda_main_favourites ? 'selected' : '' );
2502 ?>>Show
2503 favourites only
2504 </option>
2505 <option value="hide" <?php
2506 echo ( 'hide' === $this->wpda_main_favourites ? 'selected' : '' );
2507 ?>>Hide
2508 favourites
2509 </option>
2510 </select>
2511 <?php
2512 if ( !(null === $this->search_value && !$this->has_items()) ) {
2513 ?>
2514 <p class="search-box">
2515 <input type="search" id="<?php
2516 echo esc_attr( $input_id );
2517 ?>"
2518 name="<?php
2519 echo esc_attr( $this->search_item_name );
2520 ?>"
2521 value="<?php
2522 echo esc_attr( $this->search_value );
2523 ?>"/>
2524 <?php
2525 submit_button(
2526 $text,
2527 '',
2528 '',
2529 false,
2530 array(
2531 'id' => 'search-submit',
2532 )
2533 );
2534 ?>
2535 <input type="hidden" name="<?php
2536 echo esc_attr( $this->search_item_name );
2537 ?>_old_value"
2538 value="<?php
2539 echo esc_attr( $this->search_value );
2540 ?>"/>
2541 </p>
2542 <?php
2543 }
2544 ?>
2545 </div>
2546 <script type='text/javascript'>
2547 jQuery(function () {
2548 jQuery("#wpda_main_db_schema_list").on("change", function () {
2549 jQuery("#wpda_main_db_schema").val(jQuery(this).val());
2550 jQuery("#wpda_main_form :input[name='action']").val('-1');
2551 jQuery("#wpda_main_form :input[name='action2']").val('-1');
2552 jQuery("#wpda_main_form").submit();
2553 });
2554 jQuery("#wpda_main_favourites_list").on("change", function () {
2555 jQuery("#wpda_main_favourites").val(jQuery(this).val());
2556 jQuery("#wpda_main_form :input[name='action']").val('-1');
2557 jQuery("#wpda_main_form :input[name='action2']").val('-1');
2558 jQuery("#wpda_main_form").submit();
2559 });
2560 });
2561 </script>
2562 <?php
2563 }
2564
2565 /**
2566 * Get schema name from cookie or list
2567 *
2568 * @return null|string
2569 * @since 1.6.0
2570 */
2571 protected function get_schema_name() {
2572 $cookie_name = $this->page . '_schema_name';
2573 $wpda_main_db_schema = null;
2574 if ( isset( $_REQUEST['wpda_main_db_schema'] ) && '' !== $_REQUEST['wpda_main_db_schema'] ) {
2575 $wpda_main_db_schema = sanitize_text_field( wp_unslash( $_REQUEST['wpda_main_db_schema'] ) );
2576 // input var okay.
2577 } elseif ( isset( $_COOKIE[$cookie_name] ) ) {
2578 $wpda_main_db_schema = sanitize_text_field( wp_unslash( $_COOKIE[$cookie_name] ) );
2579 // input var okay.
2580 }
2581 if ( null !== $wpda_main_db_schema ) {
2582 if ( '' !== $wpda_main_db_schema && 'rdb:' !== substr( $wpda_main_db_schema, 0, 4 ) ) {
2583 if ( !WPDA_Dictionary_Exist::schema_exists( $wpda_main_db_schema ) ) {
2584 return WPDA::get_user_default_scheme();
2585 }
2586 }
2587 if ( WPDA::schema_disabled( $wpda_main_db_schema ) ) {
2588 return WPDA::get_user_default_scheme();
2589 }
2590 if ( WPDA::schema_exists( $wpda_main_db_schema ) ) {
2591 return $wpda_main_db_schema;
2592 }
2593 echo '<p><strong>' . sprintf( __( 'ERROR - Remote database %s not available', 'wp-data-access' ), esc_attr( $wpda_main_db_schema ) ) . '</strong></p>';
2594 }
2595 return WPDA::get_user_default_scheme();
2596 }
2597
2598 /**
2599 * Get favourite selection from cookie or list
2600 *
2601 * @return null|string
2602 * @since 1.6.0
2603 */
2604 protected function get_favourites() {
2605 $cookie_name = $this->page . '_favourites';
2606 if ( isset( $_REQUEST['wpda_main_favourites'] ) ) {
2607 return sanitize_text_field( wp_unslash( $_REQUEST['wpda_main_favourites'] ) );
2608 // input var okay.
2609 } elseif ( isset( $_COOKIE[$cookie_name] ) ) {
2610 return sanitize_text_field( wp_unslash( $_COOKIE[$cookie_name] ) );
2611 } else {
2612 return null;
2613 }
2614 }
2615
2616 /**
2617 * Add labels to static function to make it available to class WPDA_List _View. Allowing to hide columns in
2618 * Data Explorer main page.
2619 *
2620 * @return array
2621 * @since 2.0.3
2622 */
2623 public static function column_headers_labels() {
2624 return array(
2625 'table_name' => __( 'Name', 'wp-data-access' ),
2626 'icons' => '',
2627 'table_type' => __( 'Type', 'wp-data-access' ),
2628 'create_time' => __( 'Creation Date', 'wp-data-access' ),
2629 'table_rows' => __( '#Rows', 'wp-data-access' ),
2630 'auto_increment' => __( 'Increment', 'wp-data-access' ),
2631 'engine' => __( 'Engine', 'wp-data-access' ),
2632 'total_size' => __( 'Size', 'wp-data-access' ),
2633 'data_size' => __( 'Data Size', 'wp-data-access' ),
2634 'index_size' => __( 'Index Size', 'wp-data-access' ),
2635 'overhead' => __( 'Overhead', 'wp-data-access' ),
2636 'table_collation' => __( 'Collation', 'wp-data-access' ),
2637 );
2638 }
2639
2640 }
2641