PluginProbe
WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards / 5.5.75
WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards v5.5.75
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 / Query_Builder / WPDA_Query_Builder.php

WPDA_Query_Builder.php in WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards 5.5.75, at WPDataAccess/Query_Builder/WPDA_Query_Builder.php

966 lines 39.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace WPDataAccess\Query_Builder;
4
5 use WPDataAccess\Connection\WPDADB;
6 use WPDataAccess\Data_Dictionary\WPDA_Dictionary_Lists;
7 use WPDataAccess\WPDA;
8 class WPDA_Query_Builder {
9 const QUERY_BUILDER_OPTIONS = 'wpda_query_builder';
10
11 const QUERY_BUILDER_HINTS = 'wpda_sql_hints';
12
13 const EXPLAIN_COMMANDS = array(
14 'select',
15 'delete',
16 'insert',
17 'replace',
18 'update'
19 );
20
21 const EXPLAIN_PROTECTED = array(
22 'delete',
23 'insert',
24 'replace',
25 'update'
26 );
27
28 protected $databases = array();
29
30 protected $default_database = '';
31
32 protected $wpnonce = '';
33
34 protected $sql_hints = 'off';
35
36 public function show() {
37 $dbs = WPDA_Dictionary_Lists::get_db_schemas();
38 foreach ( $dbs as $db ) {
39 $this->databases[] = $db['schema_name'];
40 }
41 $this->default_database = WPDA::get_user_default_scheme();
42 $sql_hints = get_option( self::QUERY_BUILDER_HINTS );
43 if ( false !== $sql_hints ) {
44 $this->sql_hints = $sql_hints;
45 }
46 $this->wpnonce = wp_create_nonce( 'wpda-query-builder-' . WPDA::get_current_user_id() );
47 $this->html();
48 $this->css();
49 $this->js();
50 }
51
52 protected function html() {
53 $title = 'Query Builder';
54 ?>
55 <div class="wrap">
56 <span style="float:right">
57 <label style="font-weight:normal"><input type="checkbox" id="wpda_sql_hints" <?php
58 echo ( 'on' === $this->sql_hints ? 'checked' : '' );
59 ?>> Enable SQL hints</label>
60 </span>
61 <h1 class="wp-heading-inline">
62 <?php
63 echo esc_attr( $title );
64 ?>
65 </h1>
66 <div id="wpda_query_builder_open" style="display: none">
67 <fieldset class="wpda_fieldset" style="position:relative">
68 <legend>
69 Queries stored for user <?php
70 echo esc_attr( WPDA::get_current_user_login() );
71 ?>
72 </legend>
73 <label>
74 Select
75 </label>
76 <select id="wpda_query_builder_open_select"></select>
77 <a id="wpda_query_builder_open_open"
78 href="javascript:void(0)"
79 onclick="tabOpen()"
80 class="wpda_tooltip button button-primary"
81 title="Open query in new tab">
82 <i class="fas fa-folder-open wpda_icon_on_button"></i> Open selected</a>
83 <a id="wpda_query_builder_open_openall"
84 href="javascript:void(0)"
85 onclick="tabOpenAll()"
86 class="wpda_tooltip button button-secondary"
87 title="Open all stored queries in new tabs">
88 <i class="fas fa-folder-open wpda_icon_on_button"></i> Open all</a>
89 <a id="wpda_query_builder_open_delete"
90 href="javascript:void(0)"
91 onclick="deleteQuery()"
92 class="wpda_tooltip button button-secondary"
93 title="Delete query">
94 <i class="fas fa-trash wpda_icon_on_button"></i> Delete selected</a>
95 <a href="javascript:void(0)"
96 onclick="closeQuery()"
97 class="wpda_tooltip button button-secondary"
98 title="Close panel">
99 <i class="fas fa-times-circle wpda_icon_on_button"></i> Cancel</a>
100 </fieldset>
101 </div>
102 <div id="wpda_query_builder">
103 <nav class="nav-tab-wrapper">
104 </nav>
105 </div>
106 </div>
107 <?php
108 }
109
110 protected function css() {
111 // Overwrite default style
112 ?>
113 <style>
114 .ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr, .ui-corner-left, .ui-corner-tl {
115 border-radius: 0 !important;
116 }
117 .ui-widget.ui-widget-content {
118 border: none;
119 }
120 .wpda_query_builder_tabs .ui-widget-content {
121 background: none;
122 color: inherit;
123 }
124 /*.ui-widget-header {*/
125 /* font-weight: normal;*/
126 /* background: none;*/
127 /* border: none;*/
128 /* border-bottom: 1px solid #c3c4c7;*/
129 /*}*/
130 .ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor, .ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor, .ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor {
131 cursor: pointer;
132 }
133 .ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default, .ui-button, html .ui-button.ui-state-disabled:hover, html .ui-button.ui-state-disabled:active {
134 border: 1px solid #c3c4c7;
135 font-weight: bold;
136 color: #000 !important;
137 background: #dcdcde !important;
138 }
139 .ui-state-default:hover {
140 background: #f0f0f1 !important;
141 }
142 .ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active, a.ui-button:active, .ui-button:active, .ui-button.ui-state-active:hover {
143 border: 1px solid #c3c4c7;
144 border-bottom: none;
145 font-weight: bold;
146 color: #000 !important;
147 background: #f0f0f1 !important;
148 }
149 .ui-tabs-anchor {
150 color: #50575e !important;
151 }
152 .ui-tabs-anchor span.dashicons {
153 padding-left: 5px;
154 }
155 .ui-tabs .ui-tabs-panel {
156 padding: 0;
157 font-family: inherit;
158 font-size: inherit;
159 }
160 .ui-tabs .ui-tabs-nav li {
161 margin-left: 4px;
162 }
163 .ui-tabs .ui-tabs-nav .ui-tabs-anchor {
164 line-height: 20px;
165 }
166 </style>
167 <?php
168 }
169
170 protected function js() {
171 ?>
172 <script type="application/javascript">
173 var wpda_default_database = '<?php
174 echo esc_attr( $this->default_database );
175 ?>';
176 var wpda_databases = '';
177 <?php
178 global $wpdb;
179 $database_options = '';
180 foreach ( $this->databases as $database ) {
181 if ( $wpdb->dbname === $database ) {
182 $database_printed = "WordPress database ({$database})";
183 } else {
184 $database_printed = $database;
185 }
186 $database_options .= '<option value="' . $database . '">' . $database_printed . '</option>';
187 }
188 echo "wpda_databases = '{$database_options}';";
189 // phpcs:ignore WordPress.Security.EscapeOutput
190 ?>
191 var wpda_home_url = "<?php
192 echo admin_url( 'admin.php' );
193 // phpcs:ignore WordPress.Security.EscapeOutput
194 ?>";
195 var wpda_wpnonce = "<?php
196 echo esc_attr( $this->wpnonce );
197 ?>";
198 var wpda_loader_url = "<?php
199 echo plugins_url( '../../assets/images/loading.gif', __FILE__ );
200 // phpcs:ignore WordPress.Security.EscapeOutput
201 ?>";
202 var vqbInstalled = false;
203 <?php
204 ?>
205
206 function getColumns(schema, table, activeIndex, callback, rebuild = false) {
207 const url = location.pathname + '?action=wpda_get_table_widget_info';
208 const data = {
209 wpdaschema_name: schema,
210 table_name: table,
211 wpda_wpnonce: '<?php
212 echo esc_attr( wp_create_nonce( 'wpda-getdata-access-' . WPDA::get_current_user_login() ) );
213 ?>'
214 };
215 jQuery.post(
216 url,
217 data,
218 function (data) {
219 callback(schema, table, activeIndex, JSON.parse(data), rebuild);
220 }
221 );
222 }
223
224 jQuery(
225 function() {
226 tabNew();
227 jQuery('#wpda_query_builder nav').sortable();
228 jQuery('.wpda_tooltip').tooltip();
229 jQuery("#wpda_sql_hints").on('change', function() {
230 jQuery.ajax({
231 method: 'POST',
232 url: wpda_home_url + "?action=wpda_query_builder_set_db_hints",
233 data: {
234 wpda_wpnonce: wpda_wpnonce,
235 wpda_sqlhints: jQuery(this).is(":checked") ? 'on' : 'off'
236 }
237 }).done(
238 function (msg) {}
239 ).fail(
240 function (msg) {}
241 );
242
243 });
244 }
245 );
246 </script>
247 <?php
248 }
249
250 public function execute() {
251 $response = array(
252 'tabs' => array(),
253 'status' => null,
254 );
255 WPDA::sent_header( 'application/json' );
256 ob_start();
257 // Only for admins
258 if ( WPDA::current_user_is_admin() && isset(
259 $_POST['wpda_wpnonce'],
260 $_POST['wpda_schemaname'],
261 $_POST['wpda_sqlquery'],
262 $_POST['wpda_sqllimit'],
263 $_POST['wpda_protect']
264 ) ) {
265 $wpda_wpnonce = sanitize_text_field( wp_unslash( $_POST['wpda_wpnonce'] ) );
266 // input var okay.
267 $wpda_schemaname = sanitize_text_field( wp_unslash( $_POST['wpda_schemaname'] ) );
268 // input var okay.
269 $wpda_sqlquery = html_entity_decode( wp_unslash( $_POST['wpda_sqlquery'] ), ENT_QUOTES );
270 // input var okay.
271 $wpda_sqllimit = sanitize_text_field( wp_unslash( $_POST['wpda_sqllimit'] ) );
272 // input var okay.
273 $wpda_protect = sanitize_text_field( wp_unslash( $_POST['wpda_protect'] ) );
274 // input var okay.
275 // Check query
276 if ( $this->check_query( $wpda_protect, $wpda_schemaname, $wpda_sqlquery ) ) {
277 if ( wp_verify_nonce( $wpda_wpnonce, 'wpda-query-builder-' . WPDA::get_current_user_id() ) ) {
278 // Execute query
279 $wpdadb = WPDADB::get_db_connection( $wpda_schemaname );
280 if ( null !== $wpdadb ) {
281 $wpdadb->suppress_errors( true );
282 }
283 $sqllines = explode( "\n", $wpda_sqlquery );
284 //phpcs:ignore - 8.1 proof
285 $sqlcmds = array();
286 $start_i = 0;
287 for ($i = 0; $i < count( $sqllines ); $i++) {
288 //phpcs:ignore - 8.1 proof
289 if ( '/' === trim( $sqllines[$i] ) ) {
290 $sql = '';
291 for ($j = $start_i; $j < $i; $j++) {
292 if ( '' !== trim( $sqllines[$j] ) ) {
293 $sql .= "{$sqllines[$j]} ";
294 }
295 }
296 $sqlcmds[] = $sql;
297 $start_i = $i + 1;
298 }
299 }
300 if ( count( $sqlcmds ) > 0 ) {
301 //phpcs:ignore - 8.1 proof
302 $tabs = array();
303 $vars = array();
304 $tmps = array();
305 // Process multiple SQL commands
306 for ($i = 0; $i < count( $sqlcmds ); $i++) {
307 //phpcs:ignore - 8.1 proof
308 if ( '' !== $wpda_sqllimit && 'select' === strtolower( substr( $sqlcmds[$i], 0, 6 ) ) ) {
309 $sqlcmds[$i] .= " limit {$wpda_sqllimit} ";
310 }
311 $columns = WPDA::get_columns_from_query( $wpda_schemaname, $sqlcmds[$i] );
312 // Need to reconnect when switching from local to remote and vice versa
313 $reconnected = false;
314 if ( 'use' === substr( strtolower( trim( $sqlcmds[$i] ) ), 0, 3 ) ) {
315 $use_cmd = explode( ' ', trim( $sqlcmds[$i] ) );
316 //phpcs:ignore - 8.1 proof
317 if ( 2 === count( $use_cmd ) && (strtolower( trim( $use_cmd[1] ) ) !== strtolower( trim( $wpda_schemaname ) ) && 'rdb:' === substr( strtolower( trim( $use_cmd[1] ) ), 0, 4 ) || 'rdb:' === substr( strtolower( trim( $wpda_schemaname ) ), 0, 4 )) ) {
318 $wpda_schemaname = $use_cmd[1];
319 $wpdadb = WPDADB::get_db_connection( $wpda_schemaname );
320 if ( null !== $wpdadb ) {
321 $wpdadb->suppress_errors( true );
322 }
323 $reconnected = true;
324 }
325 }
326 $exequery = true;
327 $var_name = null;
328 $wpdadb_saved = null;
329 switch ( strtolower( substr( trim( $sqlcmds[$i] ), 0, 7 ) ) ) {
330 case 'wpdavar':
331 $use_cmd = explode( ' ', trim( $sqlcmds[$i] ) );
332 //phpcs:ignore - 8.1 proof
333 $var_name = ( isset( $use_cmd[1] ) ? $use_cmd[1] : null );
334 if ( $var_name !== null ) {
335 $vars[$var_name] = $tabs;
336 $tmps[$var_name] = $this->wpdavar_table( $wpdadb, $tabs[$i - 1], $var_name );
337 $exequery = false;
338 }
339 break;
340 case 'wpdatmp':
341 $use_cmd = explode( ' ', trim( $sqlcmds[$i] ) );
342 $var_name = ( isset( $use_cmd[1] ) ? $use_cmd[1] : null );
343 if ( $var_name !== null ) {
344 $wpdadb_saved = $this->wpdatmp_table(
345 $wpdadb,
346 $tmps[$var_name],
347 $tmps[$var_name]['data'],
348 $tmps[$var_name]['table_name'],
349 $var_name
350 );
351 $exequery = false;
352 }
353 $var_name = null;
354 // reset
355 break;
356 }
357 if ( !$reconnected && $exequery && null !== $wpdadb ) {
358 $wpdadb->query( $sqlcmds[$i] );
359 }
360 if ( null === $var_name ) {
361 $status = ( null !== $wpdadb_saved ? $wpdadb_saved : (( null !== $wpdadb ? clone $wpdadb : null )) );
362 $tabs[] = array(
363 'cmd' => $sqlcmds[$i],
364 'status' => $status,
365 'columns' => $columns,
366 );
367 } else {
368 $tabs[] = array(
369 'cmd' => $sqlcmds[$i],
370 'status' => ( isset( $vars[$var_name]['status'] ) ? $vars[$var_name]['status'] : null ),
371 'wpdavar' => ( isset( $tmps[$var_name] ) ? $tmps[$var_name] : null ),
372 'columns' => null,
373 );
374 }
375 if ( null === $wpdadb || '' !== $wpdadb->last_error ) {
376 break;
377 }
378 }
379 $response['tabs'] = $tabs;
380 } else {
381 $response['columns'] = WPDA::get_columns_from_query( $wpda_schemaname, $wpda_sqlquery );
382 // Process single SQL command
383 if ( '' !== $wpda_sqllimit && 'select' === strtolower( substr( $wpda_sqlquery, 0, 6 ) ) ) {
384 $wpda_sqlquery .= " limit {$wpda_sqllimit} ";
385 }
386 if ( null !== $wpdadb ) {
387 $wpdadb->query( $wpda_sqlquery );
388 }
389 $response['cmd'] = $wpda_sqlquery;
390 $response['status'] = $wpdadb;
391 }
392 } else {
393 $response['status'] = '<strong>WP Data Access error:</strong> Token expired, please refresh page';
394 }
395 } else {
396 $response['status'] = '<strong>WP Data Access error:</strong> Query not allowed - WordPress tables are protected';
397 }
398 } else {
399 $response['status'] = '<strong>WP Data Access error:</strong> Query execution failed';
400 }
401 ob_end_clean();
402 echo json_encode( $response );
403 }
404
405 public function wpdatmp_table(
406 $wpdadb,
407 $sql,
408 $data,
409 $table_name,
410 $var_name
411 ) {
412 // Create temporary table
413 $wpdadb->query( str_ireplace( array('CREATE TABLE', $table_name), array('CREATE TEMPORARY TABLE', $var_name), $sql['create_table'] ) );
414 $wpdadb_created = clone $wpdadb;
415 // Copy data to temporary table
416 foreach ( $data as $resultset ) {
417 $column_values = array();
418 foreach ( $resultset as $key => $val ) {
419 $column_values[$key] = $val;
420 }
421 $wpdadb->insert( $var_name, $column_values );
422 }
423 return $wpdadb_created;
424 }
425
426 public function wpdavar_table( $wpdadb, $query, $var_name ) {
427 $wpdadb->query( "set sql_quote_show_create = 'ON'" );
428 if ( null === $query['status'] ) {
429 return null;
430 }
431 $explain = $wpdadb->get_results( "explain {$query['status']->last_query}", 'ARRAY_A' );
432 if ( '' !== $wpdadb->last_error ) {
433 return null;
434 }
435 $table_name = $explain[0]['table'];
436 $create_table = $wpdadb->get_results( "show create table `{$table_name}`", 'ARRAY_N' );
437 if ( '' !== $wpdadb->last_error ) {
438 return null;
439 }
440 $sql = str_replace( "\n", '', $create_table[0][1] );
441 $pos = stripos( $sql, ') ENGINE=' );
442 $tbl = ( false === $pos ? $sql : substr( $sql, 0, $pos + 1 ) );
443 return array(
444 'table_name' => $table_name,
445 'create_table' => $tbl,
446 'data' => $query['status']->last_result,
447 );
448 }
449
450 public function check_query( $wpda_protect, $wpda_schemaname, $wpda_sqlquery ) {
451 $sql_parts = explode( ' ', trim( $wpda_sqlquery ) );
452 //phpcs:ignore - 8.1 proof
453 if ( isset( $sql_parts[0] ) && isset( $sql_parts[2] ) && WPDA::is_wp_table( $sql_parts[2] ) && ('drop' === strtolower( $sql_parts[0] ) || 'alter' === strtolower( $sql_parts[0] ) || 'rename' === strtolower( $sql_parts[0] ) || 'truncate' === strtolower( $sql_parts[0] )) ) {
454 return false;
455 }
456 if ( isset( $sql_parts[0] ) && isset( $sql_parts[1] ) && WPDA::is_wp_table( $sql_parts[1] ) && 'truncate' === strtolower( $sql_parts[0] ) ) {
457 return false;
458 }
459 if ( 'false' !== $wpda_protect && isset( $sql_parts[0] ) && in_array( strtolower( $sql_parts[0] ), self::EXPLAIN_COMMANDS ) ) {
460 $wpdadb = WPDADB::get_db_connection( $wpda_schemaname );
461 $suppress = $wpdadb->suppress_errors( true );
462 $explain = $wpdadb->get_results( "explain {$wpda_sqlquery}", 'ARRAY_A' );
463 $wpdadb->suppress_errors( $suppress );
464 foreach ( $explain as $check ) {
465 if ( in_array( strtolower( $check['select_type'] ), self::EXPLAIN_PROTECTED ) && WPDA::is_wp_table( $check['table'] ) ) {
466 return false;
467 }
468 }
469 }
470 return true;
471 }
472
473 public function save() {
474 $response = array(
475 'status' => null,
476 );
477 WPDA::sent_header( 'application/json' );
478 // Only for admins
479 if ( WPDA::current_user_is_admin() && isset(
480 $_POST['wpda_wpnonce'],
481 $_POST['wpda_schemaname'],
482 $_POST['wpda_sqlqueryname'],
483 $_POST['wpda_sqlqueryname_old'],
484 $_POST['wpda_sqlquery']
485 ) ) {
486 $wpda_wpnonce = sanitize_text_field( wp_unslash( $_POST['wpda_wpnonce'] ) );
487 // input var okay.
488 $wpda_schemaname = sanitize_text_field( wp_unslash( $_POST['wpda_schemaname'] ) );
489 // input var okay.
490 $wpda_sqlqueryname = sanitize_text_field( wp_unslash( $_POST['wpda_sqlqueryname'] ) );
491 // input var okay.
492 $wpda_sqlqueryname_old = sanitize_text_field( wp_unslash( $_POST['wpda_sqlqueryname_old'] ) );
493 // input var okay.
494 $wpda_sqlquery = sanitize_textarea_field( wp_unslash( $_POST['wpda_sqlquery'] ) );
495 // input var okay.
496 $wpda_vqb = null;
497 if ( wp_verify_nonce( $wpda_wpnonce, 'wpda-query-builder-' . WPDA::get_current_user_id() ) ) {
498 // Save query
499 if ( false === $this->update_query_old(
500 $wpda_schemaname,
501 $wpda_sqlqueryname,
502 $wpda_sqlquery,
503 $wpda_sqlqueryname_old,
504 $wpda_vqb
505 ) ) {
506 $response['status'] = 'Could not save query';
507 } else {
508 $response['status'] = 'Query saved';
509 }
510 } else {
511 $response['status'] = 'Token expired, please refresh page';
512 }
513 } else {
514 $response['status'] = 'Could not save query';
515 }
516 echo json_encode( $response );
517 }
518
519 public function open() {
520 $response = array(
521 'data' => array(),
522 'status' => null,
523 );
524 WPDA::sent_header( 'application/json' );
525 // Only for admins
526 if ( WPDA::current_user_is_admin() && isset( $_POST['wpda_wpnonce'], $_POST['wpda_exclude'] ) ) {
527 $wpda_wpnonce = sanitize_text_field( wp_unslash( $_POST['wpda_wpnonce'] ) );
528 // input var okay.
529 $wpda_exclude = sanitize_text_field( wp_unslash( $_POST['wpda_exclude'] ) );
530 // input var okay.
531 if ( wp_verify_nonce( $wpda_wpnonce, 'wpda-query-builder-' . WPDA::get_current_user_id() ) ) {
532 // Send list of available queries
533 $wpda_query_builder_data = $this->get_query_list( $wpda_exclude );
534 uksort( $wpda_query_builder_data, 'strnatcasecmp' );
535 //phpcs:ignore - 8.1 proof
536 $response['data'] = $wpda_query_builder_data;
537 } else {
538 $response['status'] = 'Token expired, please refresh page';
539 }
540 } else {
541 $response['status'] = 'Query list not available';
542 }
543 echo json_encode( $response );
544 }
545
546 public function delete() {
547 $response = array(
548 'status' => null,
549 );
550 WPDA::sent_header( 'application/json' );
551 // Only for admins
552 if ( WPDA::current_user_is_admin() && isset( $_POST['wpda_wpnonce'], $_POST['wpda_sqlqueryname'] ) ) {
553 $wpda_wpnonce = sanitize_text_field( wp_unslash( $_POST['wpda_wpnonce'] ) );
554 // input var okay.
555 $wpda_sqlqueryname = sanitize_text_field( wp_unslash( $_POST['wpda_sqlqueryname'] ) );
556 // input var okay.
557 if ( wp_verify_nonce( $wpda_wpnonce, 'wpda-query-builder-' . WPDA::get_current_user_id() ) ) {
558 // Save query
559 if ( false === $this->delete_query( $wpda_sqlqueryname ) ) {
560 $response['status'] = 'Could not delete query';
561 } else {
562 $response['status'] = 'Query deleted';
563 }
564 } else {
565 $response['status'] = 'Token expired, please refresh page';
566 }
567 } else {
568 $response['status'] = 'Could not save query';
569 }
570 echo json_encode( $response );
571 }
572
573 public function get_query_list( $exclude = '', $user_id = null ) {
574 $wpda_query_builder_data = get_user_meta( ( null === $user_id ? WPDA::get_current_user_id() : $user_id ), self::QUERY_BUILDER_OPTIONS );
575 if ( is_array( $wpda_query_builder_data ) && count( $wpda_query_builder_data ) > 0 ) {
576 //phpcs:ignore - 8.1 proof
577 $queries = $wpda_query_builder_data[0];
578 if ( null !== $exclude && '' !== $exclude ) {
579 $exclude_array = explode( ',', $exclude );
580 //phpcs:ignore - 8.1 proof
581 foreach ( $exclude_array as $exclude_item ) {
582 unset($queries[$exclude_item]);
583 }
584 }
585 return $queries;
586 } else {
587 return array();
588 }
589 }
590
591 public function get_query_list_global( $exclude = '' ) {
592 $wpda_query_builder_data = get_option( self::QUERY_BUILDER_OPTIONS );
593 if ( is_array( $wpda_query_builder_data ) && count( $wpda_query_builder_data ) > 0 ) {
594 //phpcs:ignore - 8.1 proof
595 $queries = $wpda_query_builder_data;
596 if ( null !== $exclude && '' !== $exclude ) {
597 $exclude_array = explode( ',', $exclude );
598 //phpcs:ignore - 8.1 proof
599 foreach ( $exclude_array as $exclude_item ) {
600 unset($queries[$exclude_item]);
601 }
602 }
603 return $queries;
604 } else {
605 return array();
606 }
607 }
608
609 protected function update_query_list( $wpda_query_builder_data ) {
610 update_user_meta( WPDA::get_current_user_id(), self::QUERY_BUILDER_OPTIONS, $wpda_query_builder_data );
611 }
612
613 protected function update_query_list_global( $wpda_query_builder_data ) {
614 update_option( self::QUERY_BUILDER_OPTIONS, $wpda_query_builder_data );
615 }
616
617 public function get_query( $query_name, $user_id = null ) {
618 if ( null === $user_id ) {
619 $wpda_query_builder_data = $this->get_query_list();
620 } else {
621 $wpda_query_builder_data = $this->get_query_list( '', $user_id );
622 }
623 if ( is_array( $wpda_query_builder_data ) && isset( $wpda_query_builder_data[$query_name] ) ) {
624 return $wpda_query_builder_data[$query_name];
625 } else {
626 return array();
627 }
628 }
629
630 public function get_query_global( $query_name ) {
631 $wpda_query_builder_data = $this->get_query_list_global();
632 if ( is_array( $wpda_query_builder_data ) && isset( $wpda_query_builder_data[$query_name] ) ) {
633 return $wpda_query_builder_data[$query_name];
634 } else {
635 return array();
636 }
637 }
638
639 public function update_query_old(
640 $schema_name,
641 $query_name,
642 $query_sql,
643 $query_name_old,
644 $wpda_vqb = null,
645 $params = null
646 ) {
647 $wpda_query_builder_data = $this->get_query_list();
648 if ( '' !== $query_name_old && $query_name !== $query_name_old ) {
649 unset($wpda_query_builder_data[$query_name_old]);
650 }
651 $wpda_query_builder_data[$query_name] = array(
652 'schema_name' => $schema_name,
653 'query' => $query_sql,
654 'is_visual' => null !== $wpda_vqb,
655 'params' => $params,
656 );
657 $this->update_query_list( $wpda_query_builder_data );
658 }
659
660 public function update_query(
661 $schema_name,
662 $query_name,
663 $query_sql,
664 $query_name_old,
665 $is_visual,
666 $vqb,
667 $params
668 ) {
669 $wpda_query_builder_data = $this->get_query_list();
670 if ( '' !== $query_name_old && $query_name !== $query_name_old ) {
671 unset($wpda_query_builder_data[$query_name_old]);
672 }
673 $wpda_query_builder_data[$query_name] = array(
674 'schema_name' => $schema_name,
675 'query' => $query_sql,
676 'is_visual' => $is_visual,
677 'params' => $params,
678 );
679 if ( $vqb !== "" ) {
680 $wpda_query_builder_data[$query_name]['vqb'] = $vqb;
681 }
682 $this->update_query_list( $wpda_query_builder_data );
683 }
684
685 public function update_query_global(
686 $schema_name,
687 $query_name,
688 $query_sql,
689 $query_name_old,
690 $is_visual,
691 $vqb,
692 $params
693 ) {
694 $wpda_query_builder_data = $this->get_query_list_global();
695 if ( '' !== $query_name_old && $query_name !== $query_name_old ) {
696 unset($wpda_query_builder_data[$query_name_old]);
697 }
698 $wpda_query_builder_data[$query_name] = array(
699 'schema_name' => $schema_name,
700 'query' => $query_sql,
701 'is_visual' => $is_visual,
702 'params' => $params,
703 );
704 if ( $vqb !== "" ) {
705 $wpda_query_builder_data[$query_name]['vqb'] = $vqb;
706 }
707 $this->update_query_list_global( $wpda_query_builder_data );
708 }
709
710 public function delete_query( $query_name ) {
711 $wpda_query_builder_data = $this->get_query_list();
712 unset($wpda_query_builder_data[$query_name]);
713 $this->update_query_list( $wpda_query_builder_data );
714 $this->del_visual_query( $query_name );
715 }
716
717 public function delete_query_global( $query_name ) {
718 $wpda_query_builder_data = $this->get_query_list_global();
719 unset($wpda_query_builder_data[$query_name]);
720 $this->update_query_list_global( $wpda_query_builder_data );
721 $this->del_visual_query_global( $query_name );
722 }
723
724 public function get_visual_query_ajax() {
725 }
726
727 public function get_visual_query( $query_name ) {
728 return get_user_meta( WPDA::get_current_user_id(), 'wpda_query_builder_' . $this->rewrite_query_name( $query_name ), true );
729 }
730
731 public function get_visual_query_global( $query_name ) {
732 return get_option( 'wpda_query_builder_' . $this->rewrite_query_name( $query_name ), true );
733 }
734
735 public function upd_visual_query( $query_name, $wpda_vqb ) {
736 update_user_meta( WPDA::get_current_user_id(), 'wpda_query_builder_' . $this->rewrite_query_name( $query_name ), $wpda_vqb );
737 }
738
739 public function upd_visual_query_global( $query_name, $wpda_vqb ) {
740 update_option( 'wpda_query_builder_' . $this->rewrite_query_name( $query_name ), $wpda_vqb );
741 }
742
743 protected function del_visual_query( $query_name ) {
744 delete_user_meta( WPDA::get_current_user_id(), 'wpda_query_builder_' . $this->rewrite_query_name( $query_name ) );
745 }
746
747 protected function del_visual_query_global( $query_name ) {
748 delete_option( 'wpda_query_builder_' . $this->rewrite_query_name( $query_name ) );
749 }
750
751 protected function rewrite_query_name( $query_name ) {
752 return str_replace( ' ', '_', $query_name );
753 }
754
755 public function get_db_hints() {
756 $response = array(
757 'status' => 'OK',
758 );
759 WPDA::sent_header( 'application/json' );
760 if ( WPDA::current_user_is_admin() && isset( $_REQUEST['wpda_wpnonce'], $_REQUEST['wpda_schemaname'] ) ) {
761 $wpda_wpnonce = sanitize_text_field( wp_unslash( $_REQUEST['wpda_wpnonce'] ) );
762 // input var okay.
763 $wpda_schemaname = sanitize_text_field( wp_unslash( $_REQUEST['wpda_schemaname'] ) );
764 // input var okay.
765 if ( wp_verify_nonce( $wpda_wpnonce, 'wpda-query-builder-' . WPDA::get_current_user_id() ) ) {
766 $tables = WPDA_Dictionary_Lists::get_tables( true, $wpda_schemaname );
767 $hints = array();
768 foreach ( $tables as $table ) {
769 $columns = WPDA_Dictionary_Lists::get_table_columns( $table['table_name'], $wpda_schemaname );
770 $hint_cols = array();
771 foreach ( $columns as $column ) {
772 $hint_cols[] = $column['column_name'];
773 }
774 $hints[$table['table_name']] = $hint_cols;
775 }
776 $response['tables'] = $hints;
777 } else {
778 $response['status'] = 'Token expired, please refresh page';
779 }
780 } else {
781 $response['status'] = 'Invalid arguments';
782 }
783 echo json_encode( $response );
784 }
785
786 public function set_db_hints() {
787 $response = array(
788 'status' => 'OK',
789 );
790 WPDA::sent_header( 'application/json' );
791 if ( WPDA::current_user_is_admin() && isset( $_REQUEST['wpda_wpnonce'], $_REQUEST['wpda_sqlhints'] ) ) {
792 $wpda_wpnonce = sanitize_text_field( wp_unslash( $_REQUEST['wpda_wpnonce'] ) );
793 // input var okay.
794 $wpda_sqlhints = sanitize_text_field( wp_unslash( $_REQUEST['wpda_sqlhints'] ) );
795 // input var okay.
796 if ( wp_verify_nonce( $wpda_wpnonce, 'wpda-query-builder-' . WPDA::get_current_user_id() ) ) {
797 update_option( self::QUERY_BUILDER_HINTS, $wpda_sqlhints );
798 }
799 }
800 $response['hint'] = $wpda_sqlhints;
801 echo json_encode( $response );
802 }
803
804 private function substitute_sql_params( $wpdadb, $query, $params ) {
805 }
806
807 public function execute_query(
808 $dbs,
809 $query,
810 $limit,
811 $protect,
812 $params
813 ) {
814 $response = array(
815 'tabs' => array(),
816 'status' => null,
817 );
818 if ( $this->check_query( $protect, $dbs, $query ) ) {
819 // Execute query
820 $wpdadb = WPDADB::get_db_connection( $dbs );
821 if ( null !== $wpdadb ) {
822 $wpdadb->suppress_errors( true );
823 }
824 $sqllines = explode( "\n", $query );
825 //phpcs:ignore - 8.1 proof
826 $sqlcmds = array();
827 $start_i = 0;
828 for ($i = 0; $i < count( $sqllines ); $i++) {
829 //phpcs:ignore - 8.1 proof
830 if ( '/' === trim( $sqllines[$i] ) ) {
831 $sql = '';
832 for ($j = $start_i; $j < $i; $j++) {
833 if ( '' !== trim( $sqllines[$j] ) ) {
834 $sql .= "{$sqllines[$j]} ";
835 }
836 }
837 $sqlcmds[] = $sql;
838 $start_i = $i + 1;
839 }
840 }
841 if ( count( $sqlcmds ) > 0 ) {
842 //phpcs:ignore - 8.1 proof
843 $tabs = array();
844 $vars = array();
845 $tmps = array();
846 // Process multiple SQL commands
847 for ($i = 0; $i < count( $sqlcmds ); $i++) {
848 //phpcs:ignore - 8.1 proof
849 if ( '' !== $limit && 'select' === strtolower( substr( $sqlcmds[$i], 0, 6 ) ) ) {
850 $sqlcmds[$i] .= " limit {$limit} ";
851 }
852 $columns = WPDA::get_columns_from_query( $dbs, $sqlcmds[$i] );
853 // Need to reconnect when switching from local to remote and vice versa
854 $reconnected = false;
855 if ( 'use' === substr( strtolower( trim( $sqlcmds[$i] ) ), 0, 3 ) ) {
856 $use_cmd = explode( ' ', trim( $sqlcmds[$i] ) );
857 //phpcs:ignore - 8.1 proof
858 if ( 2 === count( $use_cmd ) && (strtolower( trim( $use_cmd[1] ) ) !== strtolower( trim( $dbs ) ) && 'rdb:' === substr( strtolower( trim( $use_cmd[1] ) ), 0, 4 ) || 'rdb:' === substr( strtolower( trim( $dbs ) ), 0, 4 )) ) {
859 $dbs = $use_cmd[1];
860 $wpdadb = WPDADB::get_db_connection( $dbs );
861 if ( null !== $wpdadb ) {
862 $wpdadb->suppress_errors( true );
863 }
864 $reconnected = true;
865 }
866 }
867 $exequery = true;
868 $var_name = null;
869 $wpdadb_saved = null;
870 switch ( strtolower( substr( trim( $sqlcmds[$i] ), 0, 7 ) ) ) {
871 case 'wpdavar':
872 $use_cmd = explode( ' ', trim( $sqlcmds[$i] ) );
873 //phpcs:ignore - 8.1 proof
874 $var_name = ( isset( $use_cmd[1] ) ? $use_cmd[1] : null );
875 if ( $var_name !== null ) {
876 $vars[$var_name] = $tabs;
877 $tmps[$var_name] = $this->wpdavar_table( $wpdadb, $tabs[$i - 1], $var_name );
878 $exequery = false;
879 }
880 break;
881 case 'wpdatmp':
882 $use_cmd = explode( ' ', trim( $sqlcmds[$i] ) );
883 $var_name = ( isset( $use_cmd[1] ) ? $use_cmd[1] : null );
884 if ( $var_name !== null ) {
885 $wpdadb_saved = $this->wpdatmp_table(
886 $wpdadb,
887 $tmps[$var_name],
888 $tmps[$var_name]['data'],
889 $tmps[$var_name]['table_name'],
890 $var_name
891 );
892 $exequery = false;
893 }
894 $var_name = null;
895 // reset
896 break;
897 }
898 if ( !$reconnected && $exequery && null !== $wpdadb ) {
899 $wpdadb->query( $sqlcmds[$i] );
900 }
901 if ( null === $var_name ) {
902 $status = ( null !== $wpdadb_saved ? $wpdadb_saved : (( null !== $wpdadb ? clone $wpdadb : null )) );
903 $tabs[] = array(
904 'cmd' => $sqlcmds[$i],
905 'status' => $status,
906 'columns' => $columns,
907 );
908 } else {
909 $tabs[] = array(
910 'cmd' => $sqlcmds[$i],
911 'status' => ( isset( $vars[$var_name]['status'] ) ? $vars[$var_name]['status'] : null ),
912 'wpdavar' => ( isset( $tmps[$var_name] ) ? $tmps[$var_name] : null ),
913 'columns' => null,
914 );
915 }
916 if ( null === $wpdadb || '' !== $wpdadb->last_error ) {
917 break;
918 }
919 }
920 $response['tabs'] = $tabs;
921 } else {
922 $response['columns'] = WPDA::get_columns_from_query( $dbs, $query );
923 // Process single SQL command
924 if ( '' !== $limit && 'select' === strtolower( substr( $query, 0, 6 ) ) ) {
925 $query .= " limit {$limit} ";
926 }
927 if ( null !== $wpdadb ) {
928 $wpdadb->query( $query );
929 }
930 $response['cmd'] = $query;
931 $response['status'] = clone $wpdadb;
932 }
933 } else {
934 $response['status'] = '<strong>WP Data Access error:</strong> Query not allowed - WordPress tables are protected';
935 }
936 return $response;
937 }
938
939 public function add_query( $query_name, $query ) {
940 $wpda_query_builder_data = $this->get_query_list();
941 $wpda_query_builder_data[$query_name] = $query;
942 $this->update_query_list( $wpda_query_builder_data );
943 }
944
945 public function add_query_global( $query_name, $query ) {
946 $wpda_query_builder_data = $this->get_query_list_global();
947 $wpda_query_builder_data[$query_name] = $query;
948 $this->update_query_list_global( $wpda_query_builder_data );
949 }
950
951 public function get_hints( $dbs ) {
952 $tables = WPDA_Dictionary_Lists::get_tables( true, $dbs );
953 $hints = array();
954 foreach ( $tables as $table ) {
955 $columns = WPDA_Dictionary_Lists::get_table_columns( $table['table_name'], $dbs );
956 $hint_cols = array();
957 foreach ( $columns as $column ) {
958 $hint_cols[] = $column['column_name'];
959 }
960 $hints[$table['table_name']] = $hint_cols;
961 }
962 return $hints;
963 }
964
965 }
966