PluginProbe
WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards / 5.5.22
WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards v5.5.22
5.5.84 5.5.83 5.5.82 5.5.81 5.5.80 5.5.79 5.5.77 5.5.76 5.5.75 5.5.73 5.5.72 5.5.22 5.5.23 5.5.29 5.5.3 5.5.31 5.5.32 5.5.34 5.5.35 5.5.36 5.5.37 5.5.4 5.5.40 5.5.41 5.5.42 All 160 releases
wp-data-access / WPDataAccess / 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.22, at WPDataAccess/List_Table/WPDA_List_Table_Menu.php

2,649 lines 116.4 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 $wpdadb_src->query( "SET sql_mode = 'NO_TABLE_OPTIONS'" );
1176 $query = "show create table `{$copy_table_name_src}`";
1177 $ctcmd = $wpdadb_src->get_results( $query, 'ARRAY_A' );
1178 // phpcs:ignore Standard.Category.SniffName.ErrorCode
1179 if ( '' !== $wpdadb_src->last_error || !isset( $ctcmd[0]['Create Table'] ) ) {
1180 $wpdadb_src->suppress_errors( $suppress_wpdadb_src );
1181 $wpdadb_dst->suppress_errors( $suppress_wpdadb_dst );
1182 return false;
1183 }
1184 $create_table_statement = $ctcmd[0]['Create Table'];
1185 if ( $copy_table_name_src !== $copy_table_name_dst ) {
1186 // Modify create table statement
1187 $pos = strpos( $create_table_statement, $copy_table_name_src );
1188 if ( $pos !== false ) {
1189 $create_table_statement = substr_replace(
1190 $create_table_statement,
1191 $copy_table_name_dst,
1192 $pos,
1193 strlen( $copy_table_name_src )
1194 );
1195 }
1196 }
1197 // Create new table in $wpdadb_dst
1198 $wpdadb_dst->query( $create_table_statement );
1199 if ( '' !== $wpdadb_dst->last_error ) {
1200 $wpdadb_src->suppress_errors( $suppress_wpdadb_src );
1201 $wpdadb_dst->suppress_errors( $suppress_wpdadb_dst );
1202 return false;
1203 }
1204 if ( 'on' !== $include_data ) {
1205 return true;
1206 }
1207 if ( $copy_schema_name_src === $copy_schema_name_dst ) {
1208 // No need for buffering if source database === destination database
1209 $result = $wpdadb_dst->query( "insert `{$copy_table_name_dst}` select * from `{$copy_table_name_src}`" );
1210 // db call ok; no-cache ok.
1211 $wpdadb_src->suppress_errors( $suppress_wpdadb_src );
1212 $wpdadb_dst->suppress_errors( $suppress_wpdadb_dst );
1213 return $result;
1214 }
1215 // Check if buffering is needed for this table
1216 $settings_db = WPDA_Table_Settings_Model::query( $copy_table_name_src, $copy_schema_name_src );
1217 if ( isset( $settings_db[0]['wpda_table_settings'] ) ) {
1218 $settings_db_custom = json_decode( $settings_db[0]['wpda_table_settings'] );
1219 if ( isset( $settings_db_custom->table_settings->query_buffer_size ) ) {
1220 $query_buffer_size = $settings_db_custom->table_settings->query_buffer_size;
1221 } else {
1222 $query_buffer_size = 0;
1223 }
1224 } else {
1225 $query_buffer_size = 0;
1226 }
1227 // Copy table data from $wpdadb to $wpdb
1228 $query = "select * from `{$copy_table_name_src}`";
1229 if ( is_numeric( $query_buffer_size ) && $query_buffer_size > 0 ) {
1230 set_time_limit( 0 );
1231 ?>
1232 <p class="wpda_pds_msg_create">
1233 Copy table `<?php
1234 echo esc_attr( $copy_schema_name_src );
1235 ?>`.`<?php
1236 echo esc_attr( $copy_table_name_src );
1237 ?>`
1238 </p>
1239 <p class="wpda_pds_msg_create">
1240 To `<?php
1241 echo esc_attr( $copy_schema_name_dst );
1242 ?>`.`<?php
1243 echo esc_attr( $copy_table_name_dst );
1244 ?>`
1245 </p>
1246 <p class="wpda_pds_msg_create">
1247 Hang on...
1248 </p>
1249 <p class="wpda_pds_msg_create">
1250 Table `<?php
1251 echo esc_attr( $copy_table_name_dst );
1252 ?>` created...
1253 </p>
1254 <p class="wpda_pds_msg_create">
1255 Copying data...
1256 </p>
1257 <?php
1258 ob_flush();
1259 flush();
1260 // Create array for fast column_name based access.
1261 $wpda_list_columns = WPDA_List_Columns_Cache::get_list_columns( $copy_schema_name_src, $copy_table_name_src );
1262 $table_columns = $wpda_list_columns->get_table_columns();
1263 $column_data_types = array();
1264 foreach ( $table_columns as $column_value ) {
1265 $column_data_types[$column_value['column_name']] = $column_value['data_type'];
1266 }
1267 $i = 0;
1268 $total = 0;
1269 $sql = $query . ' limit ' . $query_buffer_size;
1270 $rows = $wpdadb_src->get_results( $sql, 'ARRAY_A' );
1271 // phpcs:ignore Standard.Category.SniffName.ErrorCode
1272 while ( $wpdadb_src->num_rows > 0 ) {
1273 $total += $wpdadb_src->num_rows;
1274 foreach ( $rows as $row ) {
1275 $wpdadb_dst->insert( $copy_table_name_dst, $row );
1276 $wpdadb_dst->flush();
1277 $wpdadb_dst->queries = null;
1278 }
1279 echo '<script>jQuery("p.wpda_pds_msg").remove();</script>';
1280 echo '<p class="wpda_pds_msg">Copied ' . number_format( $total ) . ' rows...</p>';
1281 ob_flush();
1282 flush();
1283 $i++;
1284 $wpdadb_src->flush();
1285 $wpdadb_src->queries = null;
1286 $sql = $query . ' limit ' . $query_buffer_size . ' offset ' . $i * $query_buffer_size;
1287 $rows = $wpdadb_src->get_results( $sql, 'ARRAY_A' );
1288 // phpcs:ignore Standard.Category.SniffName.ErrorCode
1289 }
1290 echo '<script>jQuery("p.wpda_pds_msg_create, p.wpda_pds_msg").css("display", "none");</script>';
1291 } else {
1292 $rows = $wpdadb_src->get_results( $query, 'ARRAY_A' );
1293 // phpcs:ignore Standard.Category.SniffName.ErrorCode
1294 foreach ( $rows as $row ) {
1295 $wpdadb_dst->insert( $copy_table_name_dst, $row );
1296 }
1297 }
1298 $wpdadb_src->suppress_errors( $suppress_wpdadb_src );
1299 $wpdadb_dst->suppress_errors( $suppress_wpdadb_dst );
1300 return true;
1301 }
1302
1303 /**
1304 * Performs bulk export.
1305 *
1306 * @since 1.5.0
1307 */
1308 protected function process_bulk_action_bulk_export() {
1309 // Check is there is anything to export.
1310 if ( $this->process_bulk_action_check_action( 'bulk-selected', __( 'Empty bulk selected', 'wp-data-access' ) ) ) {
1311 // Check if export is allowed.
1312 if ( $this->process_bulk_action_check_wpnonce( 'wpda-export-' . json_encode( $this->table_name ), '_wpnonce' ) ) {
1313 // Get arguments.
1314 $bulk_tabs = ( isset( $_REQUEST['bulk-selected'] ) ? $_REQUEST['bulk-selected'] : '' );
1315 // input var okay; sanitization okay.
1316 $wp_nonce = wp_create_nonce( 'wpda-export-' . WPDA::get_current_user_login() );
1317 $cnt = 0;
1318 $selected_tables = array();
1319 foreach ( $bulk_tabs as $table_name ) {
1320 $export_table_name = sanitize_text_field( wp_unslash( $table_name ) );
1321 // input var okay.
1322 $err_txt = ' ' . sprintf( __( '[table `%s`]', 'wp-data-access' ), $export_table_name );
1323 if ( $this->process_bulk_action_check_table_exists( $export_table_name, $err_txt ) ) {
1324 $dbo_type = $this->get_dbo_type( $export_table_name );
1325 if ( false === $dbo_type || 'VIEW' === $dbo_type || 'SYSTEM VIEW' === $dbo_type ) {
1326 $msg = new WPDA_Message_Box(array(
1327 'message_text' => sprintf( __( 'Cannot export `%s`', 'wp-data-access' ), $export_table_name ),
1328 'message_type' => 'error',
1329 'message_is_dismissible' => false,
1330 ));
1331 $msg->box();
1332 } else {
1333 $selected_tables[] = $export_table_name;
1334 $cnt++;
1335 }
1336 }
1337 }
1338 if ( 0 < $cnt ) {
1339 ?>
1340 <script type="application/javascript">
1341 jQuery(function() {
1342 wpda_main_export(
1343 '<?php
1344 echo esc_attr( $this->schema_name );
1345 ?>',
1346 '<?php
1347 echo esc_attr( $wp_nonce );
1348 ?>',
1349 '<?php
1350 echo json_encode( $selected_tables );
1351 ?>'
1352 );
1353 });
1354 </script>
1355 <?php
1356 }
1357 }
1358 }
1359 }
1360
1361 /**
1362 * Checks request argument needed for (bulk) action to be performed.
1363 *
1364 * @param string $argument_name Request argument name.
1365 * @param string $msg Message on failure.
1366 *
1367 * @return bool TRUE = argument found in request.
1368 * @since 1.5.0
1369 */
1370 protected function process_bulk_action_check_action( $argument_name, $msg ) {
1371 if ( !isset( $_REQUEST[$argument_name] ) ) {
1372 // Nothing export.
1373 $msg = new WPDA_Message_Box(array(
1374 'message_text' => $msg,
1375 ));
1376 $msg->box();
1377 return false;
1378 }
1379 return true;
1380 }
1381
1382 /**
1383 * Checks wpnonce against a specific action.
1384 *
1385 * @param string $wp_nonce_action Nonce action.
1386 * @param string $wp_nonce_arg Nonce argument.
1387 *
1388 * @return bool TRUE = action allowed.
1389 * @since 1.5.0
1390 */
1391 protected function process_bulk_action_check_wpnonce( $wp_nonce_action, $wp_nonce_arg ) {
1392 $wp_nonce = ( isset( $_REQUEST[$wp_nonce_arg] ) ? sanitize_text_field( wp_unslash( $_REQUEST[$wp_nonce_arg] ) ) : '' );
1393 // input var okay.
1394 if ( !wp_verify_nonce( $wp_nonce, $wp_nonce_action ) ) {
1395 $msg = new WPDA_Message_Box(array(
1396 'message_text' => __( 'Not authorized', 'wp-data-access' ),
1397 'message_type' => 'error',
1398 'message_is_dismissible' => false,
1399 ));
1400 $msg->box();
1401 return false;
1402 }
1403 return true;
1404 }
1405
1406 /**
1407 * Checks if table exists.
1408 *
1409 * @param string $table_name Database table name.
1410 * @param string $err_txt Additional error text/info.
1411 *
1412 * @return bool TRUE = table exists.
1413 * @since 1.5.0
1414 */
1415 protected function process_bulk_action_check_table_exists( $table_name, $err_txt = '' ) {
1416 $wpda_dictionary = new WPDA_Dictionary_Exist($this->schema_name, $table_name);
1417 if ( !$wpda_dictionary->table_exists() ) {
1418 $msg = new WPDA_Message_Box(array(
1419 'message_text' => __( 'Not authorized [table not found]', 'wp-data-access' ) . $err_txt,
1420 'message_type' => 'error',
1421 'message_is_dismissible' => false,
1422 ));
1423 $msg->box();
1424 return false;
1425 }
1426 return true;
1427 }
1428
1429 /**
1430 * Get database object type (VIEW, BASE_TABLE, SYSTEM VIEW).
1431 *
1432 * @param string $dbo_name Table or view name.
1433 *
1434 * @return string|boolean Database object type or false.
1435 * @since 1.5.0
1436 */
1437 protected function get_dbo_type( $dbo_name ) {
1438 $wpdadb = WPDADB::get_db_connection( $this->schema_name );
1439 if ( null === $wpdadb ) {
1440 return false;
1441 }
1442 $query = $wpdadb->prepare( '
1443 SELECT table_type AS table_type
1444 FROM information_schema.tables
1445 WHERE table_schema = %s
1446 AND table_name = %s
1447 ', array($wpdadb->dbname, $dbo_name) );
1448 // db call ok; no-cache ok.
1449 $result = $wpdadb->get_results( $query, 'ARRAY_A' );
1450 // phpcs:ignore Standard.Category.SniffName.ErrorCode
1451 if ( 1 === $wpdadb->num_rows ) {
1452 return $result[0]['table_type'];
1453 } else {
1454 return false;
1455 }
1456 }
1457
1458 /**
1459 * Performs a drop table or view
1460 *
1461 * Method does not drop WordPress tables.
1462 */
1463 protected function process_bulk_action_bulk_drop() {
1464 // Check is there is anything to drop.
1465 if ( $this->process_bulk_action_check_action( 'bulk-selected', __( 'Empty bulk selected', 'wp-data-access' ) ) ) {
1466 // Check if drop is allowed.
1467 if ( $this->process_bulk_action_check_wpnonce( 'wpda-drop-' . WPDA::get_current_user_login(), '_wpnonce3' ) ) {
1468 $bulk_tabs = ( isset( $_REQUEST['bulk-selected'] ) ? $_REQUEST['bulk-selected'] : '' );
1469 // input var okay; sanitization okay.
1470 foreach ( $bulk_tabs as $table_name ) {
1471 // Drop table is not allowed for WordPress tables (double check).
1472 $drop_table_name = sanitize_text_field( wp_unslash( $table_name ) );
1473 // input var okay.
1474 $err_txt = ' ' . sprintf( __( '[cannot drop WordPress table `%s`]', 'wp-data-access' ), $drop_table_name );
1475 if ( $this->process_bulk_action_check_is_wp_table( $drop_table_name, $err_txt ) ) {
1476 // Check if table exists.
1477 $err_txt = ' ' . sprintf( __( '[table `%s`]', 'wp-data-access' ), $drop_table_name );
1478 if ( $this->process_bulk_action_check_table_exists( $drop_table_name, $err_txt ) ) {
1479 $dbo_type = $this->get_dbo_type( $drop_table_name );
1480 if ( false === $dbo_type || 'SYSTEM VIEW' === $dbo_type ) {
1481 $msg = new WPDA_Message_Box(array(
1482 'message_text' => sprintf( __( 'Cannot drop `%s`', 'wp-data-access' ), $drop_table_name ),
1483 'message_type' => 'error',
1484 'message_is_dismissible' => false,
1485 ));
1486 $msg->box();
1487 } else {
1488 if ( 'VIEW' === $dbo_type ) {
1489 // Drop view.
1490 if ( $this->drop_view( $drop_table_name ) ) {
1491 $msg = new WPDA_Message_Box(array(
1492 'message_text' => sprintf( __( 'View `%s` dropped', 'wp-data-access' ), $drop_table_name ),
1493 ));
1494 $msg->box();
1495 }
1496 } else {
1497 // Drop table.
1498 if ( $this->drop_table( $drop_table_name ) ) {
1499 $msg = new WPDA_Message_Box(array(
1500 'message_text' => sprintf( __( 'Table `%s` dropped', 'wp-data-access' ), $drop_table_name ),
1501 ));
1502 $msg->box();
1503 $this->post_drop_table( $drop_table_name );
1504 }
1505 }
1506 }
1507 }
1508 }
1509 }
1510 }
1511 }
1512 }
1513
1514 /**
1515 * Silently delete table related info from repository (called after drop table)
1516 *
1517 * @param string $drop_table_name Database table name
1518 */
1519 protected function post_drop_table( $drop_table_name ) {
1520 global $wpdb;
1521 $suppress = $wpdb->suppress_errors( true );
1522 // Table settings...
1523 $wpdb->query( $wpdb->prepare(
1524 'delete from `%1s` where wpda_schema_name = %s and wpda_table_name = %s ',
1525 // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders
1526 array(WPDA::remove_backticks( WPDA_Table_Settings_Model::get_base_table_name() ), $this->schema_name, $drop_table_name)
1527 ) );
1528 // WordPress media library columns...
1529 $wpdb->query( $wpdb->prepare(
1530 'delete from `%1s` where media_schema_name = %s and media_table_name = %s ',
1531 // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders
1532 array(WPDA::remove_backticks( WPDA_Media_Model::get_base_table_name() ), $this->schema_name, $drop_table_name)
1533 ) );
1534 // Data menus...
1535 $wpdb->query( $wpdb->prepare(
1536 'delete from `%1s` where menu_schema_name = %s and menu_table_name = %s ',
1537 // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders
1538 array(WPDA::remove_backticks( WPDA_User_Menus_Model::get_base_table_name() ), $this->schema_name, $drop_table_name)
1539 ) );
1540 $wpdb->suppress_errors( $suppress );
1541 }
1542
1543 /**
1544 * Checks if table is a WordPress table.
1545 *
1546 * @param string $table_name Database table name.
1547 * @param string $err_txt Additional error text/info.
1548 *
1549 * @return bool TRUE = table is WordPress table.
1550 * @since 1.5.0
1551 */
1552 protected function process_bulk_action_check_is_wp_table( $table_name, $err_txt = '' ) {
1553 if ( WPDA::is_wp_table( $table_name ) ) {
1554 $msg = new WPDA_Message_Box(array(
1555 'message_text' => __( 'Not authorized', 'wp-data-access' ) . $err_txt,
1556 'message_type' => 'error',
1557 'message_is_dismissible' => false,
1558 ));
1559 $msg->box();
1560 return false;
1561 }
1562 return true;
1563 }
1564
1565 /**
1566 * Performs drop view.
1567 *
1568 * @param string $view_name Database view name.
1569 *
1570 * @return bool TRUE = view dropped.
1571 * @since 1.5.0
1572 */
1573 protected function drop_view( $view_name ) {
1574 $wpdadb = WPDADB::get_db_connection( $this->schema_name );
1575 if ( null === $wpdadb ) {
1576 wp_die( sprintf( __( 'ERROR - Remote database %s not available', 'wp-data-access' ), esc_attr( $this->schema_name ) ) );
1577 }
1578 return $wpdadb->query( 'drop view `' . str_replace( '`', '', $view_name ) . '`' );
1579 // db call ok; no-cache ok.
1580 }
1581
1582 /**
1583 * Performs drop table.
1584 *
1585 * @param string $table_name Database table name.
1586 *
1587 * @return bool TRUE = table dropped.
1588 * @since 1.5.0
1589 */
1590 protected function drop_table( $table_name ) {
1591 $wpdadb = WPDADB::get_db_connection( $this->schema_name );
1592 if ( null === $wpdadb ) {
1593 wp_die( sprintf( __( 'ERROR - Remote database %s not available', 'wp-data-access' ), esc_attr( $this->schema_name ) ) );
1594 }
1595 if ( WPDA::is_wp_table( $table_name ) ) {
1596 // Never ever allow dropping a WordPress table!
1597 $msg = new WPDA_Message_Box(array(
1598 'message_text' => __( 'Not authorized [cannot drop WordPress tables]', 'wp-data-access' ),
1599 'message_type' => 'error',
1600 'message_is_dismissible' => false,
1601 ));
1602 $msg->box();
1603 return false;
1604 }
1605 return $wpdadb->query( 'drop table `' . str_replace( '`', '', $table_name ) . '`' );
1606 // db call ok; no-cache ok.
1607 }
1608
1609 /**
1610 * Performs a truncate table
1611 *
1612 * Method does not truncate WordPress tables.
1613 */
1614 protected function process_bulk_action_bulk_truncate() {
1615 // Check is there is anything to truncate.
1616 if ( $this->process_bulk_action_check_action( 'bulk-selected', __( 'No table defined', 'wp-data-access' ) ) ) {
1617 // Check if truncate is allowed.
1618 if ( $this->process_bulk_action_check_wpnonce( 'wpda-truncate-' . WPDA::get_current_user_login(), '_wpnonce4' ) ) {
1619 $bulk_tabs = ( isset( $_REQUEST['bulk-selected'] ) ? $_REQUEST['bulk-selected'] : '' );
1620 // input var okay; sanitization okay.
1621 foreach ( $bulk_tabs as $table_name ) {
1622 // Truncate table is not allowed for WordPress tables (double check).
1623 $truncate_table_name = sanitize_text_field( wp_unslash( $table_name ) );
1624 // input var okay.
1625 $err_txt = ' ' . sprintf( __( '[cannot truncate WordPress table `%s`]', 'wp-data-access' ), $truncate_table_name );
1626 if ( $this->process_bulk_action_check_is_wp_table( $truncate_table_name, $err_txt ) ) {
1627 // Check if table exists.
1628 $err_txt = ' ' . sprintf( __( '[table `%s`]', 'wp-data-access' ), $truncate_table_name );
1629 if ( $this->process_bulk_action_check_table_exists( $truncate_table_name, $err_txt ) ) {
1630 $dbo_type = $this->get_dbo_type( $truncate_table_name );
1631 if ( false === $dbo_type || 'VIEW' === $dbo_type || 'SYSTEM VIEW' === $dbo_type ) {
1632 $msg = new WPDA_Message_Box(array(
1633 'message_text' => sprintf( __( 'Cannot truncate `%s`', 'wp-data-access' ), $truncate_table_name ),
1634 'message_type' => 'error',
1635 'message_is_dismissible' => false,
1636 ));
1637 $msg->box();
1638 } else {
1639 // Truncate table.
1640 if ( $this->truncate_table( $truncate_table_name ) ) {
1641 $msg = new WPDA_Message_Box(array(
1642 'message_text' => sprintf( __( 'Table `%s` truncated', 'wp-data-access' ), $truncate_table_name ),
1643 ));
1644 $msg->box();
1645 }
1646 }
1647 }
1648 }
1649 }
1650 }
1651 }
1652 }
1653
1654 /**
1655 * Performs truncate table.
1656 *
1657 * @param string $table_name Database table name.
1658 *
1659 * @return bool TRUE = table truncated.
1660 * @since 1.5.0
1661 */
1662 protected function truncate_table( $table_name ) {
1663 $wpdadb = WPDADB::get_db_connection( $this->schema_name );
1664 if ( null === $wpdadb ) {
1665 wp_die( sprintf( __( 'ERROR - Remote database %s not available', 'wp-data-access' ), esc_attr( $this->schema_name ) ) );
1666 }
1667 if ( WPDA::is_wp_table( $table_name ) ) {
1668 // Never ever allow truncating a WordPress table!
1669 $msg = new WPDA_Message_Box(array(
1670 'message_text' => __( 'Not authorized [cannot truncate WordPress tables]', 'wp-data-access' ),
1671 'message_type' => 'error',
1672 'message_is_dismissible' => false,
1673 ));
1674 $msg->box();
1675 return false;
1676 }
1677 return $wpdadb->query( $wpdadb->prepare(
1678 'truncate table `%1s`',
1679 // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders
1680 [WPDA::remove_backticks( $table_name )]
1681 ) );
1682 // db call ok; no-cache ok.
1683 }
1684
1685 /**
1686 * Processes drop table request.
1687 *
1688 * @since 1.5.0
1689 */
1690 protected function process_bulk_action_drop() {
1691 // Check is there is anything to drop.
1692 if ( $this->process_bulk_action_check_action( 'drop_table_name', __( 'No table defined', 'wp-data-access' ) ) ) {
1693 // Drop table is not allowed for WordPress tables (double check).
1694 $drop_table_name = sanitize_text_field( wp_unslash( $_REQUEST['drop_table_name'] ) );
1695 // input var okay.
1696 $err_txt = ' ' . sprintf( __( '[cannot drop WordPress table `%s`]', 'wp-data-access' ), $drop_table_name );
1697 if ( $this->process_bulk_action_check_is_wp_table( $drop_table_name, $err_txt ) ) {
1698 // Check if table exists.
1699 if ( $this->process_bulk_action_check_table_exists( $drop_table_name ) ) {
1700 // Check if drop is allowed.
1701 if ( $this->process_bulk_action_check_wpnonce( "wpda-drop-{$drop_table_name}", '_wpnonce' ) ) {
1702 $dbo_type = $this->get_dbo_type( $drop_table_name );
1703 if ( false === $dbo_type || 'SYSTEM VIEW' === $dbo_type ) {
1704 $msg = new WPDA_Message_Box(array(
1705 'message_text' => sprintf( __( 'Cannot drop `%s`', 'wp-data-access' ), $drop_table_name ),
1706 'message_type' => 'error',
1707 'message_is_dismissible' => false,
1708 ));
1709 $msg->box();
1710 } else {
1711 if ( 'VIEW' === $dbo_type ) {
1712 // Drop view.
1713 if ( $this->drop_view( $drop_table_name ) ) {
1714 $msg = new WPDA_Message_Box(array(
1715 'message_text' => sprintf( __( 'View `%s` dropped', 'wp-data-access' ), $drop_table_name ),
1716 ));
1717 $msg->box();
1718 }
1719 } else {
1720 // Drop table.
1721 if ( $this->drop_table( $drop_table_name ) ) {
1722 $msg = new WPDA_Message_Box(array(
1723 'message_text' => sprintf( __( 'Table `%s` dropped', 'wp-data-access' ), $drop_table_name ),
1724 ));
1725 $msg->box();
1726 $this->post_drop_table( $drop_table_name );
1727 }
1728 }
1729 }
1730 }
1731 }
1732 }
1733 }
1734 }
1735
1736 /**
1737 * Processes truncate table request.
1738 *
1739 * @since 1.5.0
1740 */
1741 protected function process_bulk_action_truncate() {
1742 // Check is there is anything to truncate.
1743 if ( $this->process_bulk_action_check_action( 'truncate_table_name', __( 'No table defined', 'wp-data-access' ) ) ) {
1744 // Truncate table is not allowed for WordPress tables (double check).
1745 $truncate_table_name = sanitize_text_field( wp_unslash( $_REQUEST['truncate_table_name'] ) );
1746 // input var okay.
1747 $err_txt = ' ' . sprintf( __( '[cannot truncate WordPress table `%s`]', 'wp-data-access' ), $truncate_table_name );
1748 if ( $this->process_bulk_action_check_is_wp_table( $truncate_table_name, $err_txt ) ) {
1749 // Check if table exists.
1750 if ( $this->process_bulk_action_check_table_exists( $truncate_table_name ) ) {
1751 // Check if truncate is allowed.
1752 if ( $this->process_bulk_action_check_wpnonce( "wpda-truncate-{$truncate_table_name}", '_wpnonce' ) ) {
1753 // Truncate table.
1754 if ( $this->truncate_table( $truncate_table_name ) ) {
1755 $msg = new WPDA_Message_Box(array(
1756 'message_text' => sprintf( __( 'Table `%s` truncated', 'wp-data-access' ), $truncate_table_name ),
1757 ));
1758 $msg->box();
1759 }
1760 }
1761 }
1762 }
1763 }
1764 }
1765
1766 protected function add_header_actions() {
1767 $this->add_db_containers();
1768 }
1769
1770 /**
1771 * Overwrite method: add bulk array to check ddl allowed
1772 */
1773 public function show() {
1774 ?>
1775 <script type='text/javascript'>
1776 var wpda_bulk = [];
1777
1778 function wpda_bulk_valid() {
1779 var wpda_bulk_selected_valid = true;
1780 jQuery("input[name='bulk-selected[]']:checked").each(function () {
1781 var wpda_bulk_selected = jQuery(this).val();
1782 wpda_bulk.every(function (item) {
1783 if (item === wpda_bulk_selected) {
1784 alert("Action not allowed on WordPress tables!");
1785 wpda_bulk_selected_valid = false;
1786 }
1787 });
1788 if (wpda_bulk_selected_valid === false) {
1789 return false;
1790 }
1791 });
1792 return wpda_bulk_selected_valid;
1793 }
1794
1795 function wpda_check_bulk() {
1796 action = jQuery("select[name='action']").val();
1797 action2 = jQuery("select[name='action2']").val();
1798 if (action === '-1') {
1799 if (action2 === 'bulk-drop' || action2 === 'bulk-truncate') {
1800 return wpda_bulk_valid();
1801 } else {
1802 return true;
1803 }
1804 } else {
1805 if (action === 'bulk-drop' || action === 'bulk-truncate') {
1806 return wpda_bulk_valid();
1807 } else {
1808 return true;
1809 }
1810 }
1811 }
1812 </script>
1813 <?php
1814 parent::show();
1815 ?>
1816 <script type='text/javascript'>
1817 function show_hide_column(show) {
1818 for (i = 0; i <<?php
1819 echo esc_attr( self::$list_number );
1820 ?>; i++) {
1821 if (show) {
1822 jQuery('#rownum_' + i + '_x1').attr('colspan', parseInt(jQuery('#rownum_' + i + '_x1').attr('colspan')) + 1);
1823 jQuery('#rownum_' + i + '_x2').attr('colspan', parseInt(jQuery('#rownum_' + i + '_x2').attr('colspan')) + 1);
1824 } else {
1825 jQuery('#rownum_' + i + '_x1').attr('colspan', parseInt(jQuery('#rownum_' + i + '_x1').attr('colspan')) - 1);
1826 jQuery('#rownum_' + i + '_x2').attr('colspan', parseInt(jQuery('#rownum_' + i + '_x2').attr('colspan')) - 1);
1827 }
1828 }
1829 jQuery('.wp-list-table').removeClass('fixed');
1830 }
1831
1832 jQuery(function () {
1833 jQuery("#doaction").on("click", function (e) {
1834 return wpda_check_bulk();
1835 });
1836 jQuery("#doaction2").on("click", function (e) {
1837 return wpda_check_bulk();
1838 });
1839 jQuery('#table_name-hide').on("click", function (e) {
1840 show_hide_column(jQuery('#table_name-hide').is(":checked"));
1841 });
1842 jQuery('#table_type-hide').on("click", function (e) {
1843 show_hide_column(jQuery('#table_type-hide').is(":checked"));
1844 });
1845 jQuery('#create_time-hide').on("click", function (e) {
1846 show_hide_column(jQuery('#create_time-hide').is(":checked"));
1847 });
1848 jQuery('#table_rows-hide').on("click", function (e) {
1849 show_hide_column(jQuery('#table_rows-hide').is(":checked"));
1850 });
1851 jQuery('#auto_increment-hide').on("click", function (e) {
1852 show_hide_column(jQuery('#auto_increment-hide').is(":checked"));
1853 });
1854 jQuery('#engine-hide').on("click", function (e) {
1855 show_hide_column(jQuery('#engine-hide').is(":checked"));
1856 });
1857 jQuery('#total_size-hide').on("click", function (e) {
1858 show_hide_column(jQuery('#total_size-hide').is(":checked"));
1859 });
1860 jQuery('#data_size-hide').on("click", function (e) {
1861 show_hide_column(jQuery('#data_size-hide').is(":checked"));
1862 });
1863 jQuery('#index_size-hide').on("click", function (e) {
1864 show_hide_column(jQuery('#index_size-hide').is(":checked"));
1865 });
1866 jQuery('#overhead-hide').on("click", function (e) {
1867 show_hide_column(jQuery('#overhead-hide').is(":checked"));
1868 });
1869 jQuery('#table_collation-hide').on("click", function (e) {
1870 show_hide_column(jQuery('#table_collation-hide').is(":checked"));
1871 });
1872 });
1873 </script>
1874 <?php
1875 }
1876
1877 /**
1878 * Overwrite construct_where_clause()
1879 *
1880 * @since 1.0.0
1881 *
1882 * @see WPDA_List_Table::construct_where_clause()
1883 */
1884 protected function construct_where_clause() {
1885 $wpdadb = WPDADB::get_db_connection( $this->schema_name );
1886 if ( null === $wpdadb ) {
1887 wp_die( sprintf( __( 'ERROR - Remote database %s not available', 'wp-data-access' ), esc_attr( $this->schema_name ) ) );
1888 }
1889 global $wpdb;
1890 // Make sure we're selecting only tables that are in the WordPress database.
1891 $where_or_and = ( '' === $this->where ? ' where ' : ' and ' );
1892 $this->where .= $wpdadb->prepare( " {$where_or_and} table_schema = %s ", $wpdadb->dbname );
1893 // Since we are using a view, the default behaviour of the parent will not work for us. We have to
1894 // define our where clause manually.
1895 $cols = array(array(
1896 'column_name' => 'table_name',
1897 'data_type' => 'varchar',
1898 'extra' => '',
1899 'column_type' => 'varchar(64)',
1900 'is_nullable' => 'NO',
1901 'column_default' => null,
1902 ));
1903 $where = WPDA::construct_where_clause(
1904 $this->schema_name,
1905 $this->table_name,
1906 $cols,
1907 $this->search_value
1908 );
1909 if ( '' !== $where ) {
1910 $this->where .= ' and ' . $where;
1911 }
1912 if ( $wpdb->dbname === $this->schema_name || '' === $this->schema_name ) {
1913 $table_access = WPDA::get_option( WPDA::OPTION_BE_TABLE_ACCESS );
1914 } else {
1915 $table_access = get_option( WPDA::BACKEND_OPTIONNAME_DATABASE_ACCESS . $this->schema_name );
1916 if ( false === $table_access ) {
1917 $table_access = 'show';
1918 }
1919 }
1920 if ( 'hide' === $table_access ) {
1921 // No access to WordPress tables: filter WordPress table.
1922 $this->where .= " and table_name not in ('" . implode( "','", $wpdb->tables( 'all', true ) ) . "')";
1923 } elseif ( 'select' === $table_access ) {
1924 if ( $wpdb->dbname === $this->schema_name || '' === $this->schema_name ) {
1925 $option = WPDA::get_option( WPDA::OPTION_BE_TABLE_ACCESS_SELECTED );
1926 } else {
1927 $option = get_option( WPDA::BACKEND_OPTIONNAME_DATABASE_SELECTED . $this->schema_name );
1928 if ( false === $option ) {
1929 $option = '';
1930 }
1931 }
1932 if ( '' !== $option ) {
1933 // Allow only access to selected tables.
1934 $this->where .= " and table_name in ('" . implode( "','", $option ) . "')";
1935 } else {
1936 // No tables selected: no access.
1937 $this->where .= ' and 1=2';
1938 }
1939 }
1940 if ( null != $this->wpda_main_favourites ) {
1941 if ( false === $this->favourites && 'show' === $this->wpda_main_favourites ) {
1942 $where_or_and = ( '' === $this->where ? ' where ' : ' and ' );
1943 $this->where .= " {$where_or_and} 1=2 ";
1944 } elseif ( is_array( $this->favourites ) ) {
1945 if ( 0 < count( $this->favourites ) ) {
1946 //phpcs:ignore - 8.1 proof
1947 $where_or_and = ( '' === $this->where ? ' where ' : ' and ' );
1948 $in_or_not_in = ( 'show' === $this->wpda_main_favourites ? 'in' : 'not in' );
1949 $this->where .= " {$where_or_and} table_name {$in_or_not_in} ('" . implode( "','", $this->favourites ) . "') ";
1950 }
1951 }
1952 }
1953 }
1954
1955 protected function get_order_by() {
1956 $orderby = parent::get_order_by();
1957 if ( '' !== $orderby ) {
1958 return $orderby;
1959 } else {
1960 return ' order by table_name asc ';
1961 }
1962 }
1963
1964 /**
1965 * Overwrite method: add button to design a table
1966 */
1967 protected function add_header_button() {
1968 ?>
1969 <form
1970 method="post"
1971 action="?page=<?php
1972 echo esc_attr( \WP_Data_Access_Admin::PAGE_DESIGNER );
1973 ?>"
1974 style="display: inline-block; vertical-align: baseline;"
1975 >
1976 <div>
1977 <input type="hidden" name="action" value="create_table">
1978 <input type="hidden" name="caller" value="dataexplorer">
1979 <button type="submit"
1980 class="page-title-action wpda_tooltip"
1981 title="Create a new table design"
1982 >
1983 <i class="fas fa-plus-circle wpda_icon_on_button"></i>
1984 <?php
1985 echo __( 'Design new table', 'wp-data-access' );
1986 ?>
1987 </button>
1988 </div>
1989 </form>
1990 <form id="wpda_linkto_backup" style="display: none" method="post" action="?page=<?php
1991 echo esc_attr( WP_Data_Access_Admin::PAGE_MAIN );
1992 ?>&page_action=wpda_backup">
1993 <input type="hidden" name="wpdaschema_name" value="<?php
1994 echo esc_attr( $this->schema_name );
1995 ?>">
1996 </form>
1997 <?php
1998 $this->wpda_import->add_button();
1999 ?>
2000 <a href="javascript:void(0)"
2001 onclick="jQuery('#wpda_linkto_backup').submit()"
2002 class="page-title-action wpda_tooltip"
2003 title="Create unattended export jobs"
2004 ><i class="fas fa-cloud-download wpda_icon_on_button"></i> <?php
2005 echo __( 'Data Backup' );
2006 ?></a>
2007 <?php
2008 }
2009
2010 /**
2011 * Add container to create new database
2012 */
2013 protected function add_db_containers() {
2014 if ( 'rdb:' === substr( $this->schema_name, 0, 4 ) ) {
2015 $rdb = WPDADB::get_remote_database( $this->schema_name );
2016 }
2017 $host = ( isset( $rdb['host'] ) ? $rdb['host'] : '' );
2018 $user = ( isset( $rdb['username'] ) ? $rdb['username'] : '' );
2019 $passwd = ( isset( $rdb['password'] ) ? $rdb['password'] : '' );
2020 $port = ( isset( $rdb['port'] ) ? $rdb['port'] : '' );
2021 $schema = ( isset( $rdb['database'] ) ? $rdb['database'] : '' );
2022 $ssl = ( isset( $rdb['ssl'] ) ? $rdb['ssl'] : '' );
2023 $ssl_key = ( isset( $rdb['ssl_key'] ) ? $rdb['ssl_key'] : '' );
2024 $ssl_cert = ( isset( $rdb['ssl_cert'] ) ? $rdb['ssl_cert'] : '' );
2025 $ssl_ca = ( isset( $rdb['ssl_ca'] ) ? $rdb['ssl_ca'] : '' );
2026 $ssl_path = ( isset( $rdb['ssl_path'] ) ? $rdb['ssl_path'] : '' );
2027 $ssl_cipher = ( isset( $rdb['ssl_cipher'] ) ? $rdb['ssl_cipher'] : '' );
2028 $readonly = '';
2029 ?>
2030 <div id="wpda_db_edit" style="display:none;padding-top:10px;">
2031 <div class="wpda_upload">
2032 <form method="post" action="?page=<?php
2033 echo esc_attr( $this->page );
2034 ?>" onsubmit="return editdb_validate_form();">
2035 <div style="height:10px;"></div>
2036 <strong><?php
2037 echo __( 'Edit Remote Database Connection', 'wp-data-access' );
2038 ?></strong>
2039 <div style="height:10px;"></div>
2040 <div>
2041 <label for="edit_remote_database" style="vertical-align:baseline;"
2042 class="database_item_label">Database name:</label>
2043 <input type="text" name="edit_remote_database" id="edit_remote_database" value="<?php
2044 echo esc_attr( $this->schema_name );
2045 ?>" <?php
2046 echo esc_attr( $readonly );
2047 ?>>
2048 <input type="hidden" name="edit_remote_database_old" value="<?php
2049 echo esc_attr( $this->schema_name );
2050 ?>">
2051 <div style="height:10px;"></div>
2052 <label for="edit_remote_host" style="vertical-align:baseline;" class="database_item_label">MySQL host:</label>
2053 <input type="text" name="edit_remote_host" id="edit_remote_host" value="<?php
2054 echo esc_attr( $host );
2055 ?>">
2056 <br/>
2057 <label for="edit_remote_user" style="vertical-align:baseline;" class="database_item_label">MySQL username:</label>
2058 <input type="text" name="edit_remote_user" id="edit_remote_user" value="<?php
2059 echo esc_attr( $user );
2060 ?>">
2061 <br/>
2062 <label for="edit_remote_passwd" style="vertical-align:baseline;" class="database_item_label" >MySQL password:</label>
2063 <input type="password" name="edit_remote_passwd" id="edit_remote_passwd" value="<?php
2064 echo esc_attr( $passwd );
2065 ?>" autocomplete="new-password">
2066 <i class="fas fa-eye" onclick="wpda_toggle_password('edit_remote_passwd', event)" style="cursor:pointer"></i>
2067 <br/>
2068 <label for="edit_remote_port" style="vertical-align:baseline;" class="database_item_label">MySQL port:</label>
2069 <input type="text" name="edit_remote_port" id="edit_remote_port" value="<?php
2070 echo esc_attr( $port );
2071 ?>">
2072 <br/>
2073 <label for="edit_remote_schema" style="vertical-align:baseline;" class="database_item_label">MySQL schema:</label>
2074 <input type="text" name="edit_remote_schema" id="edit_remote_schema" value="<?php
2075 echo esc_attr( $schema );
2076 ?>">
2077
2078 <br/>
2079 <label style="line-height:30px;" for="edit_remote_ssl" style="vertical-align:baseline;" class="database_item_label">SSL:</label>
2080 <input type="checkbox" name="edit_remote_ssl" id="edit_remote_ssl" <?php
2081 echo ( 'on' === $ssl ? 'checked' : 'unchecked' );
2082 ?> onclick="jQuery('#edit_remote_database_block_ssl').toggle()">
2083 <div id="edit_remote_database_block_ssl" <?php
2084 echo ( 'on' === $ssl ? '' : 'style="display:none;"' );
2085 ?>>
2086 <label for="edit_remote_client_key" style="vertical-align:baseline;" class="database_item_label">Client key:</label>
2087 <input type="text" name="edit_remote_client_key" id="edit_remote_client_key" value="<?php
2088 echo esc_attr( $ssl_key );
2089 ?>">
2090 <br/>
2091 <label for="edit_remote_client_certificate" style="vertical-align:baseline;" class="database_item_label">Client certificate:</label>
2092 <input type="text" name="edit_remote_client_certificate" id="edit_remote_client_certificate" value="<?php
2093 echo esc_attr( $ssl_cert );
2094 ?>">
2095 <br/>
2096 <label for="edit_remote_ca_certificate" style="vertical-align:baseline;" class="database_item_label">CA certificate:</label>
2097 <input type="text" name="edit_remote_ca_certificate" id="edit_remote_ca_certificate" value="<?php
2098 echo esc_attr( $ssl_ca );
2099 ?>">
2100 <br/>
2101 <label for="edit_remote_certificate_path" style="vertical-align:baseline;" class="database_item_label">Certificate path:</label>
2102 <input type="text" name="edit_remote_certificate_path" id="edit_remote_certificate_path" value="<?php
2103 echo esc_attr( $ssl_path );
2104 ?>">
2105 <br/>
2106 <label for="edit_remote_specified_cipher" style="vertical-align:baseline;" class="database_item_label">Specified Cipher:</label>
2107 <input type="text" name="edit_remote_specified_cipher" id="edit_remote_specified_cipher" value="<?php
2108 echo esc_attr( $ssl_cipher );
2109 ?>">
2110 </div>
2111
2112 <div style="height:10px;"></div>
2113 <label class="database_item_label"></label>
2114 <input type="button" value="Test" onclick="test_remote_connection('edit_'); return false;"
2115 id="edit_remote_test_button" class="button">
2116 <input type="button" value="Clear" onclick="test_remote_clear('edit_'); return false;"
2117 id="edit_remote_clear_button" class="button" style="display:none;">
2118 <div style="height:10px;"></div>
2119 </div>
2120 <div id="edit_remote_database_block_test" style="display:none;">
2121 <div id="edit_remote_database_block_test_content"
2122 class="remote_database_block_test_content"></div>
2123 <div style="height:10px;"></div>
2124 </div>
2125
2126 <input type="submit" class="button button-primary" value="<?php
2127 echo __( 'Save', 'wp-data-access' );
2128 ?>">
2129 <a href="javascript:void(0)"
2130 onclick="jQuery('#wpda_db_edit').hide()"
2131 class="button button-secondary"><i class="fas fa-times-circle wpda_icon_on_button"></i> <?php
2132 echo __( 'Cancel', 'wp-data-access' );
2133 ?></a>
2134 <input type="hidden" name="action" value="edit_db">
2135 <?php
2136 wp_nonce_field( 'wpda-edit-db-from-data-explorer-' . WPDA::get_current_user_login(), '_wpnonceeditdb', false );
2137 ?>
2138 </form>
2139 </div>
2140 </div>
2141
2142 <div id="wpda_db_container" style="display:none;padding-top:10px;">
2143 <div class="wpda_upload">
2144 <form method="post" action="?page=<?php
2145 echo esc_attr( $this->page );
2146 ?>" onsubmit="return createdb_validate_form();">
2147 <div style="height:10px;"></div>
2148
2149 <?php
2150 if ( $this->user_can_create_db ) {
2151 ?>
2152 <select name="database_location" id="database_location">
2153 <option value="local"
2154 selected><?php
2155 echo __( 'Create local database', 'wp-data-access' );
2156 ?></option>
2157 <option value="remote"><?php
2158 echo __( 'Add remote database connection', 'wp-data-access' );
2159 ?></option>
2160 </select>
2161
2162 <div style="height:10px;"></div>
2163
2164 <div id="local_database_block">
2165 <label for="local_database" style="vertical-align:baseline;"
2166 class="database_item_label">Database name:</label>
2167 <input type="text" name="local_database" id="local_database">
2168
2169 <div style="height:10px;"></div>
2170 </div>
2171 <?php
2172 } else {
2173 ?>
2174 <strong><?php
2175 echo __( 'Add remote database connection', 'wp-data-access' );
2176 ?></strong>
2177
2178 <div style="height:10px;"></div>
2179 <?php
2180 }
2181 ?>
2182
2183 <div id="remote_database_block"<?php
2184 echo ( $this->user_can_create_db ? 'style="display:none;"' : '' );
2185 ?>>
2186 <div>
2187 <label for="remote_database" style="vertical-align:baseline;"
2188 class="database_item_label">Database name:</label>
2189 <input type="text" name="remote_database" id="remote_database" value="rdb:">
2190 <div style="height:10px;"></div>
2191 <label for="remote_host" style="vertical-align:baseline;" class="database_item_label">MySQL host:</label>
2192 <input type="text" name="remote_host" id="remote_host">
2193 <br/>
2194 <label for="remote_user" style="vertical-align:baseline;" class="database_item_label">MySQL username:</label>
2195 <input type="text" name="remote_user" id="remote_user">
2196 <br/>
2197 <label for="remote_passwd" style="vertical-align:baseline;" class="database_item_label">MySQL password:</label>
2198 <input type="password" name="remote_passwd" id="remote_passwd" autocomplete="new-password">
2199 <i class="fas fa-eye" onclick="wpda_toggle_password('remote_passwd', event)" style="cursor:pointer"></i>
2200 <br/>
2201 <label for="remote_port" style="vertical-align:baseline;" class="database_item_label">MySQL port:</label>
2202 <input type="text" name="remote_port" id="remote_port" value="3306">
2203 <br/>
2204 <label for="remote_schema" style="vertical-align:baseline;" class="database_item_label">MySQL schema:</label>
2205 <input type="text" name="remote_schema" id="remote_schema">
2206
2207 <br/>
2208 <label style="line-height:30px;" for="remote_ssl" style="vertical-align:baseline;" class="database_item_label">SSL:</label>
2209 <input type="checkbox" name="remote_ssl" id="remote_ssl" unchecked onclick="jQuery('#remote_database_block_ssl').toggle()">
2210 <div id="remote_database_block_ssl" style="display:none;">
2211 <label for="remote_client_key" style="vertical-align:baseline;" class="database_item_label">Client key:</label>
2212 <input type="text" name="remote_client_key" id="remote_client_key">
2213 <br/>
2214 <label for="remote_client_certificate" style="vertical-align:baseline;" class="database_item_label">Client certificate:</label>
2215 <input type="text" name="remote_client_certificate" id="remote_client_certificate">
2216 <br/>
2217 <label for="remote_ca_certificate" style="vertical-align:baseline;" class="database_item_label">CA certificate:</label>
2218 <input type="text" name="remote_ca_certificate" id="remote_ca_certificate">
2219 <br/>
2220 <label for="remote_certificate_path" style="vertical-align:baseline;" class="database_item_label">Certificate path:</label>
2221 <input type="text" name="remote_certificate_path" id="remote_certificate_path">
2222 <br/>
2223 <label for="remote_specified_cipher" style="vertical-align:baseline;" class="database_item_label">Specified Cipher:</label>
2224 <input type="text" name="remote_specified_cipher" id="remote_specified_cipher">
2225 </div>
2226
2227 <div style="height:10px;"></div>
2228 <label class="database_item_label"></label>
2229 <input type="button" value="Test" onclick="test_remote_connection(); return false;"
2230 id="remote_test_button" class="button">
2231 <input type="button" value="Clear" onclick="test_remote_clear(); return false;"
2232 id="remote_clear_button" class="button" style="display:none;">
2233 <div style="height:10px;"></div>
2234 </div>
2235 <div id="remote_database_block_test" style="display:none;">
2236 <div id="remote_database_block_test_content"
2237 class="remote_database_block_test_content"></div>
2238 <div style="height:10px;"></div>
2239 </div>
2240 </div>
2241
2242 <a href="javascript:void(0)"
2243 onclick="jQuery(this).closest('form').submit()"
2244 class="button button-primary"><i class="fas fa-cloud-upload wpda_icon_on_button"></i> <?php
2245 echo __( 'Save', 'wp-data-access' );
2246 ?></a>
2247 <a href="javascript:void(0)"
2248 onclick="jQuery('#wpda_db_container').hide()"
2249 class="button button-secondary"><i class="fas fa-times-circle wpda_icon_on_button"></i> <?php
2250 echo __( 'Cancel', 'wp-data-access' );
2251 ?></a>
2252 <input type="hidden" name="action" value="create_db">
2253 <?php
2254 wp_nonce_field( 'wpda-create-db-from-data-explorer-' . WPDA::get_current_user_login(), '_wpnoncecreatedb', false );
2255 ?>
2256 </form>
2257 </div>
2258 </div>
2259
2260 <div style="display:none;">
2261 <form id="wpda_form_drop_db" method="post" action="?page=<?php
2262 echo esc_attr( $this->page );
2263 ?>">
2264 <input type="text" name="database" id="drop_database">
2265 <input type="hidden" name="action" value="drop_db">
2266 <?php
2267 wp_nonce_field( 'wpda-drop-db-from-data-explorer-' . WPDA::get_current_user_login(), '_wpnoncedropdb', false );
2268 ?>
2269 </form>
2270 </div>
2271
2272 <script type='text/javascript'>
2273 function editdb_validate_form() {
2274 if (jQuery('#edit_remote_database').val()==='' || jQuery('#edit_remote_database').val()==='rdb:') {
2275 alert('Database name must be entered');
2276 return false;
2277 }
2278 if (jQuery('#edit_remote_host').val()==='') {
2279 alert('MySQL host must be entered');
2280 return false;
2281 }
2282 if (jQuery('#edit_remote_user').val()==='') {
2283 alert('MySQL username must be entered');
2284 return false;
2285 }
2286 if (jQuery('#edit_remote_schema').val()==='') {
2287 alert('MySQL schema must be entered');
2288 return false;
2289 }
2290 return true;
2291 }
2292
2293 function createdb_validate_form() {
2294 if (jQuery('#database_location').val() === 'remote') {
2295 if (jQuery('#remote_database').val()==='' || jQuery('#remote_database').val()==='rdb:') {
2296 alert('Database name must be entered');
2297 return false;
2298 }
2299 if (jQuery('#remote_host').val()==='') {
2300 alert('MySQL host must be entered');
2301 return false;
2302 }
2303 if (jQuery('#remote_user').val()==='') {
2304 alert('MySQL username must be entered');
2305 return false;
2306 }
2307 if (jQuery('#remote_schema').val()==='') {
2308 alert('MySQL schema must be entered');
2309 return false;
2310 }
2311 } else {
2312
2313 if (jQuery('#local_database').val()==='') {
2314 alert('Database name must be entered');
2315 return false;
2316 }
2317 }
2318 return true;
2319 }
2320
2321 function test_remote_clear(mode = '') {
2322 jQuery('#' + mode + 'remote_database_block_test_content').html('');
2323 jQuery('#' + mode + 'remote_database_block_test').hide();
2324 jQuery('#' + mode + 'remote_clear_button').hide();
2325 }
2326
2327 function test_remote_connection(mode = '') {
2328 host = jQuery('#' + mode + 'remote_host').val();
2329 user = jQuery('#' + mode + 'remote_user').val();
2330 pass = jQuery('#' + mode + 'remote_passwd').val();
2331 port = jQuery('#' + mode + 'remote_port').val();
2332 dbs = jQuery('#' + mode + 'remote_schema').val();
2333 ssl = jQuery('#' + mode + 'remote_ssl').val();
2334 ssl_key = jQuery('#' + mode + 'remote_client_key').val();
2335 ssl_cert = jQuery('#' + mode + 'remote_client_certificate').val();
2336 ssl_ca = jQuery('#' + mode + 'remote_ca_certificate').val();
2337 ssl_path = jQuery('#' + mode + 'remote_certificate_path').val();
2338 ssl_cipher = jQuery('#' + mode + 'remote_specified_cipher').val();
2339
2340 url = '//' + window.location.host + window.location.pathname +
2341 '?action=wpda_check_remote_database_connection';
2342
2343 jQuery('#' + mode + 'remote_test_button').val('Testing...');
2344
2345 jQuery.ajax({
2346 method: 'POST',
2347 url: url,
2348 data: {
2349 host: host,
2350 user: user,
2351 passwd: pass,
2352 port: port,
2353 schema: dbs,
2354 ssl: ssl,
2355 ssl_key: ssl_key,
2356 ssl_cert: ssl_cert,
2357 ssl_ca: ssl_ca,
2358 ssl_path: ssl_path,
2359 ssl_cipher: ssl_cipher
2360 }
2361 }).done(
2362 function (msg) {
2363 jQuery('#' + mode + 'remote_database_block_test_content').html(msg);
2364 jQuery('#' + mode + 'remote_database_block_test').show();
2365 }
2366 ).fail(
2367 function () {
2368 jQuery('#' + mode + 'remote_database_block_test_content').html('Preparing connection...<br/>Establishing connection...<br/><br/><strong>Remote database connection invalid</strong>');
2369 jQuery('#' + mode + 'remote_database_block_test').show();
2370 }
2371 ).always(
2372 function () {
2373 jQuery('#' + mode + 'remote_test_button').val('Test');
2374 jQuery('#' + mode + 'remote_clear_button').show();
2375 }
2376 );
2377 }
2378
2379 jQuery(function () {
2380 jQuery('#database_location').on('change', function () {
2381 if (jQuery(this).val() === 'remote') {
2382 jQuery('#local_database_block').hide();
2383 jQuery('#remote_database_block').show();
2384 } else {
2385 jQuery('#remote_database_block').hide();
2386 jQuery('#local_database_block').show();
2387 }
2388 });
2389 jQuery('#remote_database, #edit_remote_database').keydown(function(e) {
2390 var field = this;
2391 setTimeout(function () {
2392 if (field.value.indexOf('rdb:') !== 0) {
2393 jQuery(field).val('rdb:');
2394 }
2395 }, 1);
2396 });
2397 });
2398 </script>
2399 <?php
2400 }
2401
2402 /**
2403 * Display the search box
2404 *
2405 * @param string $text The 'submit' button label.
2406 * @param string $input_id ID attribute value for the search input field.
2407 *
2408 * @since 1.6.0
2409 */
2410 public function search_box( $text, $input_id ) {
2411 global $wpdb;
2412 $input_id = $input_id . '-search-input';
2413 $schemas = WPDA_Dictionary_Lists::get_db_schemas();
2414 ?>
2415 <div style="padding-top:10px;padding-bottom:0;">
2416 <span style="font-weight: bold;"><?php
2417 echo __( 'Database', 'wp-data-access' );
2418 ?>:</span>
2419 <select id="wpda_main_db_schema_list">
2420 <?php
2421 foreach ( $schemas as $schema ) {
2422 if ( $this->schema_name === $schema['schema_name'] ) {
2423 $selected = ' selected';
2424 } else {
2425 $selected = '';
2426 }
2427 if ( $wpdb->dbname === $schema['schema_name'] ) {
2428 $printed_schema_name = "WordPress database ({$schema['schema_name']})";
2429 } else {
2430 $printed_schema_name = $schema['schema_name'];
2431 }
2432 ?>
2433 <option value="<?php
2434 echo esc_attr( $schema['schema_name'] );
2435 ?>" <?php
2436 echo esc_attr( $selected );
2437 ?>>
2438 <?php
2439 echo esc_attr( $printed_schema_name );
2440 ?>
2441 </option>
2442 <?php
2443 }
2444 ?>
2445 </select>
2446 <a class="dashicons dashicons-edit wpda_tooltip" href="javascript:void(0)"
2447 <?php
2448 if ( 'rdb:' === substr( $this->schema_name, 0, 4 ) ) {
2449 ?>
2450 onclick="jQuery('#wpda_db_edit').show();"
2451 <?php
2452 }
2453 ?>
2454 style="<?php
2455 echo ( 'rdb:' === substr( $this->schema_name, 0, 4 ) ? '' : 'color:grey;cursor:default;' );
2456 ?>vertical-align:middle;"
2457 title="<?php
2458 echo ( 'rdb:' === substr( $this->schema_name, 0, 4 ) ? __( 'Edit remote database connection', 'wp-data-access' ) : __( 'Not available for local database', 'wp-data-access' ) );
2459 ?>">&nbsp;</a>
2460 <a class="dashicons dashicons-plus-alt wpda_tooltip" href="javascript:void(0)"
2461 onclick="jQuery('#wpda_db_container').show(); jQuery('#local_database').focus();"
2462 style="vertical-align:middle;"
2463 title="<?php
2464 echo esc_attr( $this->user_create_db_hint );
2465 ?>">&nbsp;</a>
2466 <a class="dashicons dashicons-dismiss wpda_tooltip" id="wpda_drop_database" href="javascript:void(0)"
2467 <?php
2468 if ( $this->user_can_drop_db ) {
2469 if ( 'rdb:' === substr( $this->schema_name, 0, 4 ) ) {
2470 $msg = __( 'Delete remote database connection?\\nDoes not drop the database! Only deletes the remote database connection definition.', 'wp-data-access' );
2471 } else {
2472 $msg = __( 'Drop selected database?', 'wp-data-access' );
2473 }
2474 ?>
2475 onclick="if (confirm('<?php
2476 echo $msg;
2477 // phpcs:ignore WordPress.Security.EscapeOutput
2478 ?>')) { jQuery('#drop_database').val(jQuery('#wpda_main_db_schema_list').val()); jQuery('#wpda_form_drop_db').submit(); }"
2479 <?php
2480 }
2481 ?>
2482 style="<?php
2483 echo ( $this->user_can_drop_db ? 'color:#a00;' : 'color:grey;cursor:default;' );
2484 ?>vertical-align:middle;"
2485 title="<?php
2486 echo esc_attr( $this->user_drop_db_hint );
2487 ?>">&nbsp;</a>
2488 <a class="dashicons dashicons-admin-plugins wpda_tooltip"
2489 href="javascript:void(0)"
2490 onclick="wpda_dbinit_admin( '<?php
2491 echo esc_attr( $this->schema_name );
2492 ?>', '<?php
2493 echo wp_create_nonce( 'wpda_dbinit_admin_' . WPDA::get_current_user_login() );
2494 ?>' )"
2495 style="vertical-align:middle;"
2496 title="<?php
2497 echo __( "Create function wpda_get_wp_user_id()\nto get access to the WordPress user ID from database views", 'wp-data-access' );
2498 ?>">&nbsp;</a>
2499 &nbsp;<span style="font-weight: bold;"><?php
2500 echo __( 'Favourites', 'wp-data-access' );
2501 // phpcs:ignore WordPress.Security.EscapeOutput
2502 ?>:</span>
2503 <select id="wpda_main_favourites_list">
2504 <option value="" <?php
2505 echo ( '' === $this->wpda_main_favourites ? 'selected' : '' );
2506 ?>>Show all
2507 </option>
2508 <option value="show" <?php
2509 echo ( 'show' === $this->wpda_main_favourites ? 'selected' : '' );
2510 ?>>Show
2511 favourites only
2512 </option>
2513 <option value="hide" <?php
2514 echo ( 'hide' === $this->wpda_main_favourites ? 'selected' : '' );
2515 ?>>Hide
2516 favourites
2517 </option>
2518 </select>
2519 <?php
2520 if ( !(null === $this->search_value && !$this->has_items()) ) {
2521 ?>
2522 <p class="search-box">
2523 <input type="search" id="<?php
2524 echo esc_attr( $input_id );
2525 ?>"
2526 name="<?php
2527 echo esc_attr( $this->search_item_name );
2528 ?>"
2529 value="<?php
2530 echo esc_attr( $this->search_value );
2531 ?>"/>
2532 <?php
2533 submit_button(
2534 $text,
2535 '',
2536 '',
2537 false,
2538 array(
2539 'id' => 'search-submit',
2540 )
2541 );
2542 ?>
2543 <input type="hidden" name="<?php
2544 echo esc_attr( $this->search_item_name );
2545 ?>_old_value"
2546 value="<?php
2547 echo esc_attr( $this->search_value );
2548 ?>"/>
2549 </p>
2550 <?php
2551 }
2552 ?>
2553 </div>
2554 <script type='text/javascript'>
2555 jQuery(function () {
2556 jQuery("#wpda_main_db_schema_list").on("change", function () {
2557 jQuery("#wpda_main_db_schema").val(jQuery(this).val());
2558 jQuery("#wpda_main_form :input[name='action']").val('-1');
2559 jQuery("#wpda_main_form :input[name='action2']").val('-1');
2560 jQuery("#wpda_main_form").submit();
2561 });
2562 jQuery("#wpda_main_favourites_list").on("change", function () {
2563 jQuery("#wpda_main_favourites").val(jQuery(this).val());
2564 jQuery("#wpda_main_form :input[name='action']").val('-1');
2565 jQuery("#wpda_main_form :input[name='action2']").val('-1');
2566 jQuery("#wpda_main_form").submit();
2567 });
2568 });
2569 </script>
2570 <?php
2571 }
2572
2573 /**
2574 * Get schema name from cookie or list
2575 *
2576 * @return null|string
2577 * @since 1.6.0
2578 */
2579 protected function get_schema_name() {
2580 $cookie_name = $this->page . '_schema_name';
2581 $wpda_main_db_schema = null;
2582 if ( isset( $_REQUEST['wpda_main_db_schema'] ) && '' !== $_REQUEST['wpda_main_db_schema'] ) {
2583 $wpda_main_db_schema = sanitize_text_field( wp_unslash( $_REQUEST['wpda_main_db_schema'] ) );
2584 // input var okay.
2585 } elseif ( isset( $_COOKIE[$cookie_name] ) ) {
2586 $wpda_main_db_schema = sanitize_text_field( wp_unslash( $_COOKIE[$cookie_name] ) );
2587 // input var okay.
2588 }
2589 if ( null !== $wpda_main_db_schema ) {
2590 if ( '' !== $wpda_main_db_schema && 'rdb:' !== substr( $wpda_main_db_schema, 0, 4 ) ) {
2591 if ( !WPDA_Dictionary_Exist::schema_exists( $wpda_main_db_schema ) ) {
2592 return WPDA::get_user_default_scheme();
2593 }
2594 }
2595 if ( WPDA::schema_disabled( $wpda_main_db_schema ) ) {
2596 return WPDA::get_user_default_scheme();
2597 }
2598 if ( WPDA::schema_exists( $wpda_main_db_schema ) ) {
2599 return $wpda_main_db_schema;
2600 }
2601 echo '<p><strong>' . sprintf( __( 'ERROR - Remote database %s not available', 'wp-data-access' ), esc_attr( $wpda_main_db_schema ) ) . '</strong></p>';
2602 }
2603 return WPDA::get_user_default_scheme();
2604 }
2605
2606 /**
2607 * Get favourite selection from cookie or list
2608 *
2609 * @return null|string
2610 * @since 1.6.0
2611 */
2612 protected function get_favourites() {
2613 $cookie_name = $this->page . '_favourites';
2614 if ( isset( $_REQUEST['wpda_main_favourites'] ) ) {
2615 return sanitize_text_field( wp_unslash( $_REQUEST['wpda_main_favourites'] ) );
2616 // input var okay.
2617 } elseif ( isset( $_COOKIE[$cookie_name] ) ) {
2618 return sanitize_text_field( wp_unslash( $_COOKIE[$cookie_name] ) );
2619 } else {
2620 return null;
2621 }
2622 }
2623
2624 /**
2625 * Add labels to static function to make it available to class WPDA_List _View. Allowing to hide columns in
2626 * Data Explorer main page.
2627 *
2628 * @return array
2629 * @since 2.0.3
2630 */
2631 public static function column_headers_labels() {
2632 return array(
2633 'table_name' => __( 'Name', 'wp-data-access' ),
2634 'icons' => '',
2635 'table_type' => __( 'Type', 'wp-data-access' ),
2636 'create_time' => __( 'Creation Date', 'wp-data-access' ),
2637 'table_rows' => __( '#Rows', 'wp-data-access' ),
2638 'auto_increment' => __( 'Increment', 'wp-data-access' ),
2639 'engine' => __( 'Engine', 'wp-data-access' ),
2640 'total_size' => __( 'Size', 'wp-data-access' ),
2641 'data_size' => __( 'Data Size', 'wp-data-access' ),
2642 'index_size' => __( 'Index Size', 'wp-data-access' ),
2643 'overhead' => __( 'Overhead', 'wp-data-access' ),
2644 'table_collation' => __( 'Collation', 'wp-data-access' ),
2645 );
2646 }
2647
2648 }
2649