PluginProbe
WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards / 5.5.43
WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards v5.5.43
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 5.5.43 All 159 releases
wp-data-access / WPDataAccess / API / WPDA_Table.php

WPDA_Table.php in WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards 5.5.43, at WPDataAccess/API/WPDA_Table.php

1,386 lines 54.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace WPDataAccess\API;
4
5 use stdClass;
6 use WPDataAccess\Connection\WPDADB;
7 use WPDataAccess\Data_Dictionary\WPDA_Dictionary_Access;
8 use WPDataAccess\Data_Dictionary\WPDA_List_Columns_Cache;
9 use WPDataAccess\Plugin_Table_Models\WPDA_Table_Settings_Model;
10 use WPDataAccess\Utilities\WPDA_WP_Media;
11 use WPDataAccess\WPDA;
12 class WPDA_Table extends WPDA_API_Core {
13 const WPDA_SEARCH_MODES = array(
14 'contains',
15 'startsWith',
16 'endsWith',
17 'equals',
18 'notEquals',
19 'empty',
20 'notEmpty',
21 'between',
22 'betweenInclusive',
23 'greaterThan',
24 'greaterThanOrEqualTo',
25 'lessThan',
26 'lessThanOrEqualTo'
27 );
28
29 const RELATIONTABLEPREFIX = 'relationTableColumn___';
30
31 public function register_rest_routes() {
32 register_rest_route( WPDA_API::WPDA_NAMESPACE, 'table/meta', array(
33 'methods' => array('POST'),
34 'callback' => array($this, 'table_meta'),
35 'permission_callback' => '__return_true',
36 'args' => array(
37 'dbs' => $this->get_param( 'dbs' ),
38 'tbl' => $this->get_param( 'tbl' ),
39 'waa' => array(
40 'required' => false,
41 'type' => 'boolean',
42 'description' => __( 'With admin actions (to support table exports)', 'wp-data-access' ),
43 ),
44 ),
45 ) );
46 register_rest_route( WPDA_API::WPDA_NAMESPACE, 'table/select', array(
47 'methods' => array('GET', 'POST'),
48 'callback' => array($this, 'table_select'),
49 'permission_callback' => '__return_true',
50 'args' => array(
51 'dbs' => $this->get_param( 'dbs' ),
52 'tbl' => $this->get_param( 'tbl' ),
53 'col' => $this->get_param( 'cols' ),
54 'page_index' => $this->get_param( 'page_index' ),
55 'page_size' => $this->get_param( 'page_size' ),
56 'search' => $this->get_param( 'search' ),
57 'search_columns' => $this->get_param( 'search_columns' ),
58 'search_column_fns' => $this->get_param( 'search_column_fns' ),
59 'sorting' => $this->get_param( 'sorting' ),
60 'row_count' => $this->get_param( 'row_count' ),
61 'row_count_estimate' => $this->get_param( 'row_count_estimate' ),
62 'media' => $this->get_param( 'media' ),
63 'client_side' => $this->get_param( 'client_side' ),
64 ),
65 ) );
66 register_rest_route( WPDA_API::WPDA_NAMESPACE, 'table/get', array(
67 'methods' => array('GET', 'POST'),
68 'callback' => array($this, 'table_get'),
69 'permission_callback' => '__return_true',
70 'args' => array(
71 'dbs' => $this->get_param( 'dbs' ),
72 'tbl' => $this->get_param( 'tbl' ),
73 'key' => $this->get_param( 'key' ),
74 'media' => $this->get_param( 'media' ),
75 ),
76 ) );
77 register_rest_route( WPDA_API::WPDA_NAMESPACE, 'table/insert', array(
78 'methods' => array('GET', 'POST'),
79 'callback' => array($this, 'table_insert'),
80 'permission_callback' => '__return_true',
81 'args' => array(
82 'dbs' => $this->get_param( 'dbs' ),
83 'tbl' => $this->get_param( 'tbl' ),
84 'val' => $this->get_param( 'val' ),
85 ),
86 ) );
87 register_rest_route( WPDA_API::WPDA_NAMESPACE, 'table/update', array(
88 'methods' => array('GET', 'POST'),
89 'callback' => array($this, 'table_update'),
90 'permission_callback' => '__return_true',
91 'args' => array(
92 'dbs' => $this->get_param( 'dbs' ),
93 'tbl' => $this->get_param( 'tbl' ),
94 'key' => $this->get_param( 'key' ),
95 'val' => $this->get_param( 'val' ),
96 ),
97 ) );
98 register_rest_route( WPDA_API::WPDA_NAMESPACE, 'table/delete', array(
99 'methods' => array('GET', 'POST'),
100 'callback' => array($this, 'table_delete'),
101 'permission_callback' => '__return_true',
102 'args' => array(
103 'dbs' => $this->get_param( 'dbs' ),
104 'tbl' => $this->get_param( 'tbl' ),
105 'key' => $this->get_param( 'key' ),
106 ),
107 ) );
108 register_rest_route( WPDA_API::WPDA_NAMESPACE, 'table/lov', array(
109 'methods' => array('GET', 'POST'),
110 'callback' => array($this, 'table_lov'),
111 'permission_callback' => '__return_true',
112 'args' => array(
113 'dbs' => $this->get_param( 'dbs' ),
114 'tbl' => $this->get_param( 'tbl' ),
115 'col' => $this->get_param( 'col' ),
116 ),
117 ) );
118 }
119
120 /**
121 * Get table meta info.
122 *
123 * @param WP_REST_Request $request Rest API request.
124 * @return \WP_Error|\WP_REST_Response
125 */
126 public function table_meta( $request ) {
127 $dbs = $request->get_param( 'dbs' );
128 $tbl = $request->get_param( 'tbl' );
129 $waa = $request->get_param( 'waa' );
130 if ( $this->check_table_access(
131 $dbs,
132 $tbl,
133 $request,
134 'select',
135 $msg
136 ) ) {
137 return $this->WPDA_Rest_Response( '', $this->get_table_meta_data( $dbs, $tbl, $waa ) );
138 } else {
139 if ( 'rest_cookie_invalid_nonce' === $msg ) {
140 return $this->invalid_nonce();
141 } else {
142 return new \WP_Error('error', $msg, array(
143 'status' => 401,
144 ));
145 }
146 }
147 }
148
149 /**
150 * Database table query using the full primary key. Must return exactly one row.
151 *
152 * @param WP_REST_Request $request Rest API request.
153 * @return \WP_Error|\WP_REST_Response
154 */
155 public function table_get( $request ) {
156 $dbs = $request->get_param( 'dbs' );
157 $tbl = $request->get_param( 'tbl' );
158 $key = $request->get_param( 'key' );
159 $media = $request->get_param( 'media' );
160 if ( $this->check_table_access(
161 $dbs,
162 $tbl,
163 $request,
164 'select',
165 $msg
166 ) ) {
167 return $this->get(
168 $dbs,
169 $tbl,
170 $key,
171 $media
172 );
173 } else {
174 if ( 'rest_cookie_invalid_nonce' === $msg ) {
175 return $this->invalid_nonce();
176 } else {
177 return new \WP_Error('error', $msg, array(
178 'status' => 401,
179 ));
180 }
181 }
182 }
183
184 /**
185 * Insert one row.
186 *
187 * @param WP_REST_Request $request Rest API request.
188 * @return \WP_Error|\WP_REST_Response
189 */
190 public function table_insert( $request ) {
191 $dbs = $request->get_param( 'dbs' );
192 $tbl = $request->get_param( 'tbl' );
193 $val = $request->get_param( 'val' );
194 if ( $this->check_table_access(
195 $dbs,
196 $tbl,
197 $request,
198 'insert',
199 $msg
200 ) ) {
201 return $this->insert( $dbs, $tbl, $val );
202 } else {
203 if ( 'rest_cookie_invalid_nonce' === $msg ) {
204 return $this->invalid_nonce();
205 } else {
206 return new \WP_Error('error', $msg, array(
207 'status' => 401,
208 ));
209 }
210 }
211 }
212
213 /**
214 * Update uses primary key. Must return exactly one row.
215 *
216 * @param WP_REST_Request $request Rest API request.
217 * @return \WP_Error|\WP_REST_Response
218 */
219 public function table_update( $request ) {
220 $dbs = $request->get_param( 'dbs' );
221 $tbl = $request->get_param( 'tbl' );
222 $key = $request->get_param( 'key' );
223 $val = $request->get_param( 'val' );
224 if ( $this->check_table_access(
225 $dbs,
226 $tbl,
227 $request,
228 'update',
229 $msg
230 ) ) {
231 return $this->update(
232 $dbs,
233 $tbl,
234 $key,
235 $val
236 );
237 } else {
238 if ( 'rest_cookie_invalid_nonce' === $msg ) {
239 return $this->invalid_nonce();
240 } else {
241 return new \WP_Error('error', $msg, array(
242 'status' => 401,
243 ));
244 }
245 }
246 }
247
248 /**
249 * Delete uses primary key. Must return exactly one row.
250 *
251 * @param WP_REST_Request $request Rest API request.
252 * @return \WP_Error|\WP_REST_Response
253 */
254 public function table_delete( $request ) {
255 $dbs = $request->get_param( 'dbs' );
256 $tbl = $request->get_param( 'tbl' );
257 $key = $request->get_param( 'key' );
258 if ( $this->check_table_access(
259 $dbs,
260 $tbl,
261 $request,
262 'delete',
263 $msg
264 ) ) {
265 return $this->delete( $dbs, $tbl, $key );
266 } else {
267 if ( 'rest_cookie_invalid_nonce' === $msg ) {
268 return $this->invalid_nonce();
269 } else {
270 return new \WP_Error('error', $msg, array(
271 'status' => 401,
272 ));
273 }
274 }
275 }
276
277 /**
278 * Database table query to populate a list of values for a specific table/column.
279 *
280 * @param WP_REST_Request $request Rest API request.
281 * @return \WP_Error|\WP_REST_Response
282 */
283 public function table_lov( $request ) {
284 }
285
286 /**
287 * Database table query.
288 *
289 * Supports: searching, ordering and pagination.
290 *
291 * @param WP_REST_Request $request Rest API request.
292 * @return \WP_Error|\WP_REST_Response
293 */
294 public function table_select( $request ) {
295 $dbs = $request->get_param( 'dbs' );
296 $tbl = $request->get_param( 'tbl' );
297 $col = $request->get_param( 'col' );
298 $page_index = $request->get_param( 'page_index' );
299 $page_size = $request->get_param( 'page_size' );
300 $search = $request->get_param( 'search' );
301 $search_columns = $request->get_param( 'search_columns' );
302 $search_column_fns = $request->get_param( 'search_column_fns' );
303 $search_data_types = $request->get_param( 'search_data_types' );
304 $sorting = $request->get_param( 'sorting' );
305 $row_count = $request->get_param( 'row_count' );
306 $row_count_estimate = $request->get_param( 'row_count_estimate' );
307 $media = $request->get_param( 'media' );
308 $client_side = '1' === $request->get_param( 'client_side' );
309 if ( $this->check_table_access(
310 $dbs,
311 $tbl,
312 $request,
313 'select',
314 $msg
315 ) ) {
316 return $this->select(
317 $dbs,
318 $tbl,
319 $col,
320 $page_index,
321 $page_size,
322 $search,
323 $search_columns,
324 $search_column_fns,
325 $sorting,
326 $row_count,
327 $row_count_estimate,
328 $media,
329 '',
330 '',
331 array(),
332 array(),
333 array(),
334 $search_data_types,
335 $client_side
336 );
337 } else {
338 if ( 'rest_cookie_invalid_nonce' === $msg ) {
339 return $this->invalid_nonce();
340 } else {
341 return new \WP_Error('error', $msg, array(
342 'status' => 401,
343 ));
344 }
345 }
346 }
347
348 /**
349 * Perform query and return result as JSON response.
350 *
351 * @param string $dbs Schema name (database).
352 * @param string $tbl Table Name.
353 * @param array $column_name Column name.
354 * @param array $search Global search.
355 * @param array $search_columns Column filters.
356 * @param array $search_column_fns Column filter fns.
357 * @return \WP_Error|\WP_REST_Response
358 */
359 public function lov(
360 $dbs,
361 $tbl,
362 $column_name,
363 $cascade = false,
364 $default_where = '',
365 $search = '',
366 $column_names = array(),
367 $search_columns = array(),
368 $search_column_fns = array(),
369 $lookups = array(),
370 $md = array(),
371 $m2m_relationship = array(),
372 $search_data_types = array()
373 ) {
374 }
375
376 public function lookup(
377 $dbs,
378 $tbl,
379 $column_key,
380 $column_value,
381 $column_dynamic_values,
382 $default_where,
383 $cascade = false,
384 $cascade_table = '',
385 $cascade_column = '',
386 $cascade_where = '',
387 $search = '',
388 $column_names = array(),
389 $search_columns = array(),
390 $search_column_fns = array(),
391 $lookups = array(),
392 $md = array(),
393 $m2m_relationship = array(),
394 $search_data_types = array()
395 ) {
396 $wpdadb = WPDADB::get_db_connection( $dbs );
397 if ( null === $wpdadb ) {
398 // Error connecting.
399 return new \WP_Error('error', "Error connecting to database {$dbs}", array(
400 'status' => 420,
401 ));
402 } else {
403 // Connected, perform queries.
404 $suppress = $wpdadb->suppress_errors( true );
405 $subquery = '';
406 $where = '';
407 if ( '' !== trim( $default_where ) ) {
408 if ( 'where' !== strtolower( substr( trim( $default_where ), 0, 5 ) ) ) {
409 $where = "where {$default_where}";
410 } else {
411 $where = $default_where;
412 }
413 }
414 $dynamic_where = array();
415 if ( is_array( $column_dynamic_values ) && 0 < count( $column_dynamic_values ) ) {
416 foreach ( $column_dynamic_values as $key => $value ) {
417 $dynamic_where[] = $wpdadb->prepare( " `{$key}` = %s ", $value );
418 }
419 $where .= (( '' === $where ? ' where ' : ' and ' )) . ' (' . implode( ' and ', $dynamic_where ) . ') ';
420 }
421 if ( strpos( $column_value, ',' ) !== false ) {
422 $columns = explode( ',', $column_value );
423 $sql = $wpdadb->prepare( "\n\t\t\t\t\t\t\tselect distinct `%1s` as 'key'\n\t\t\t\t\t\t\t, `%1s`\n\t\t\t\t\t\t\tfrom `%1s`\n\t\t\t\t\t\t", array($column_key, implode( '`,`', $columns ), $tbl) );
424 } else {
425 $sql = $wpdadb->prepare( "\n\t\t\t\t\t\t\tselect distinct `%1s` as 'key'\n\t\t\t\t\t\t\t, `%1s` as 'value' \n\t\t\t\t\t\t\tfrom `%1s`\n\t\t\t\t\t\t", array($column_key, $column_value, $tbl) );
426 }
427 $sql .= " {$where} order by 2 ";
428 // $where already sanitized
429 $dataset = $wpdadb->get_results( $sql, 'OBJECT' );
430 $wpdadb->suppress_errors( $suppress );
431 // Send response.
432 if ( '' === $wpdadb->last_error ) {
433 // Prepare debug info.
434 if ( 'on' === WPDA::get_option( WPDA::OPTION_PLUGIN_DEBUG ) ) {
435 $debug = array(
436 'debug' => array(
437 'sql' => preg_replace( "/\\s+/", " ", $sql ),
438 'where' => $where ?? '',
439 ),
440 );
441 } else {
442 $debug = null;
443 }
444 // Add context node to response.
445 $context = array();
446 if ( isset( $debug['debug'] ) && 'on' === WPDA::get_option( WPDA::OPTION_PLUGIN_DEBUG ) ) {
447 $context['debug'] = $debug['debug'];
448 }
449 return $this->WPDA_Rest_Response( '', $dataset, $context );
450 } else {
451 return new \WP_Error('error', $wpdadb->last_error, array(
452 'status' => 420,
453 ));
454 }
455 }
456 }
457
458 /**
459 * Perform query and return result as JSON response.
460 *
461 * @param string $dbs Schema name (database).
462 * @param string $tbl Table Name.
463 * @param array $primary Primary (key|value pairs.
464 * @param array $media_columns Media columns.
465 * @param array $column_names Just a plain array containing the column names.
466 * @return \WP_Error|\WP_REST_Response
467 */
468 public function get(
469 $dbs,
470 $tbl,
471 $primary_key,
472 $media_columns = array(),
473 $column_names = array(),
474 $default_where = ''
475 ) {
476 $wpdadb = WPDADB::get_db_connection( $dbs );
477 if ( null === $wpdadb ) {
478 // Error connecting.
479 return new \WP_Error('error', "Error connecting to database {$dbs}", array(
480 'status' => 420,
481 ));
482 } else {
483 // Connected, perform queries.
484 $suppress = $wpdadb->suppress_errors( true );
485 $where = '';
486 foreach ( $primary_key as $primary_key_column => $primary_key_value ) {
487 $where = ( '' === $where ? ' where ' : $where . ' and ' );
488 $where .= $wpdadb->prepare( " `%1s` = %s ", array($primary_key_column, $primary_key_value) );
489 }
490 if ( '' !== $default_where ) {
491 if ( '' === $where ) {
492 $where = $default_where;
493 } else {
494 $where .= " and {$default_where} ";
495 }
496 }
497 // Get table column data types
498 $column_list = WPDA_List_Columns_Cache::get_list_columns( $dbs, $tbl );
499 $table_columns = $column_list->get_table_columns();
500 // Prepare selected column list
501 $columns_selected = array();
502 $search_data_types = array();
503 foreach ( $table_columns as $table_column ) {
504 $columns_selected[$table_column['column_name']] = true;
505 $search_data_types[$table_column['column_name']] = $table_column['data_type'];
506 }
507 $selected_columns = $this->get_selected_columns( $columns_selected, $search_data_types );
508 $sql = $wpdadb->prepare( "\n select {$selected_columns}\n from `%1s`\n {$where}\n ", array($tbl) );
509 $dataset = $wpdadb->get_results( $sql, 'ARRAY_A' );
510 // Prepare debug info.
511 if ( 'on' === WPDA::get_option( WPDA::OPTION_PLUGIN_DEBUG ) ) {
512 $debug = array(
513 'debug' => array(
514 'sql' => $sql,
515 'where' => $where,
516 ),
517 );
518 } else {
519 $debug = null;
520 }
521 $wpdadb->suppress_errors( $suppress );
522 // Send response.
523 $media = array();
524 if ( is_array( $media_columns ) && 0 < count( $media_columns ) ) {
525 foreach ( $media_columns as $media_column_name => $media_column_type ) {
526 if ( isset( $dataset[0][$media_column_name] ) ) {
527 if ( in_array( $media_column_type, [
528 'WP-Image',
529 'WP-Attachment',
530 'WP-Audio',
531 'WP-Video'
532 ] ) ) {
533 $media[$media_column_name] = WPDA_WP_Media::get_media_url( $dataset[0][$media_column_name] );
534 }
535 }
536 }
537 }
538 $context = array();
539 $context['media'] = $media;
540 if ( isset( $debug['debug'] ) && 'on' === WPDA::get_option( WPDA::OPTION_PLUGIN_DEBUG ) ) {
541 $context['debug'] = $debug['debug'];
542 }
543 if ( 0 === count( $dataset ) ) {
544 return $this->WPDA_Rest_Response( 'No data found', $dataset, array(
545 'debug' => $debug['debug'],
546 ) );
547 } else {
548 if ( 1 === count( $dataset ) ) {
549 return $this->WPDA_Rest_Response( '', $dataset, $context );
550 } else {
551 return $this->WPDA_Rest_Response( 'Query returned more than one row', $dataset, array(
552 'debug' => $debug['debug'],
553 ) );
554 }
555 }
556 }
557 }
558
559 public function insert( $dbs, $tbl, $column_values ) {
560 $wpdadb = WPDADB::get_db_connection( $dbs );
561 if ( null === $wpdadb ) {
562 // Error connecting.
563 return new \WP_Error('error', "Error connecting to database {$dbs}", array(
564 'status' => 420,
565 ));
566 } else {
567 // Get column default values
568 $column_list = WPDA_List_Columns_Cache::get_list_columns( $dbs, $tbl );
569 $table_columns = $column_list->get_table_columns();
570 foreach ( $table_columns as $table_column_type ) {
571 if ( isset( $column_values[$table_column_type['column_name']] ) && $column_values[$table_column_type['column_name']] === $table_column_type['column_default'] ) {
572 // Remove default values if send values equals column default to support defaults using functions
573 unset($column_values[$table_column_type['column_name']]);
574 }
575 }
576 // Sanitize column names and values.
577 $sanitized_column_values = self::sanitize_column_values( $dbs, $tbl, $column_values );
578 if ( false === $sanitized_column_values ) {
579 return new \WP_Error('error', "Invalid arguments", array(
580 'status' => 420,
581 ));
582 }
583 // Insert row.
584 $rows_inserted = $wpdadb->insert( $tbl, $sanitized_column_values );
585 // Send response.
586 if ( 1 === $rows_inserted ) {
587 return $this->WPDA_Rest_Response( __( 'Row successfully inserted', 'wp-data-access' ), null, array(
588 'insert_id' => $wpdadb->insert_id,
589 ) );
590 } else {
591 if ( '' !== $wpdadb->last_error ) {
592 return new \WP_Error('error', $wpdadb->last_error, array(
593 'status' => 420,
594 ));
595 } else {
596 return new \WP_Error('error', 'Insert failed', array(
597 'status' => 420,
598 ));
599 }
600 }
601 }
602 }
603
604 public function update(
605 $dbs,
606 $tbl,
607 $primary_key,
608 $column_values,
609 $column_names = array(),
610 $code_columns = array(),
611 $html_columns = array()
612 ) {
613 $wpdadb = WPDADB::get_db_connection( $dbs );
614 if ( null === $wpdadb ) {
615 // Error connecting.
616 return new \WP_Error('error', "Error connecting to database {$dbs}", array(
617 'status' => 420,
618 ));
619 } else {
620 // Sanitize column names and values.
621 $sanitized_column_values = self::sanitize_column_values(
622 $dbs,
623 $tbl,
624 $column_values,
625 $code_columns,
626 $html_columns
627 );
628 if ( false === $sanitized_column_values ) {
629 return new \WP_Error('error', "Invalid arguments", array(
630 'status' => 420,
631 ));
632 }
633 // Update row.
634 $rows_inserted = $wpdadb->update( $tbl, $sanitized_column_values, $primary_key );
635 // Send response.
636 if ( 0 === $rows_inserted ) {
637 return $this->WPDA_Rest_Response_Info( 'Nothing to update' );
638 } elseif ( 1 === $rows_inserted ) {
639 $context = null;
640 if ( 0 < count( $column_names ) ) {
641 // Return updated values
642 $updated_row = $this->get(
643 $dbs,
644 $tbl,
645 $primary_key,
646 $column_names
647 );
648 if ( isset( $updated_row->data['data'][0] ) ) {
649 $updated_values = $updated_row->data['data'][0];
650 $updated_context = array();
651 foreach ( $updated_values as $key => $value ) {
652 if ( !isset( $column_values[$key] ) ) {
653 $updated_context[$key] = $value;
654 }
655 }
656 if ( 0 < count( $updated_context ) ) {
657 $context = array(
658 'updated' => $updated_context,
659 );
660 }
661 }
662 }
663 return $this->WPDA_Rest_Response( __( 'Row successfully updated', 'wp-data-access' ), null, $context );
664 } else {
665 if ( '' !== $wpdadb->last_error ) {
666 return new \WP_Error('error', $wpdadb->last_error, array(
667 'status' => 420,
668 ));
669 } else {
670 return new \WP_Error('error', 'Update failed', array(
671 'status' => 420,
672 ));
673 }
674 }
675 }
676 }
677
678 public function delete( $dbs, $tbl, $primary_key ) {
679 $wpdadb = WPDADB::get_db_connection( $dbs );
680 if ( null === $wpdadb ) {
681 // Error connecting.
682 return new \WP_Error('error', "Error connecting to database {$dbs}", array(
683 'status' => 420,
684 ));
685 } else {
686 // Delete row.
687 $rows_deleted = $wpdadb->delete( $tbl, $primary_key );
688 // Send response.
689 if ( 0 === $rows_deleted ) {
690 return $this->WPDA_Rest_Response_Info( __( 'No data found', 'wp-data-access' ) );
691 } elseif ( 1 === $rows_deleted ) {
692 return $this->WPDA_Rest_Response( __( 'Row successfully deleted', 'wp-data-access' ) );
693 } else {
694 if ( '' !== $wpdadb->last_error ) {
695 return new \WP_Error('error', $wpdadb->last_error, array(
696 'status' => 420,
697 ));
698 } else {
699 return new \WP_Error('error', 'Delete failed', array(
700 'status' => 420,
701 ));
702 }
703 }
704 }
705 }
706
707 private function generate_lookup_condition(
708 $wpdadb,
709 $lookups,
710 $column_name,
711 $search_values,
712 $search_column_fns,
713 $filter_mode = null,
714 $filter_key = false
715 ) {
716 $lookup = $lookups[$column_name];
717 $lookup_table = $lookup['tbl'];
718 $lookup_key = $lookup['key'];
719 $lookup_columns = explode( ',', $lookup['value'] );
720 $lookup_where = array();
721 if ( $filter_key ) {
722 $filter_columns = array($lookup_key);
723 } else {
724 $filter_columns = $lookup_columns;
725 }
726 foreach ( $filter_columns as $lookup_column ) {
727 foreach ( $search_values as $search_value ) {
728 $lookup_where[] = $this->add_filter(
729 $wpdadb,
730 $lookup_column,
731 ( $filter_mode !== null ? $filter_mode : $search_column_fns[$column_name] ),
732 $search_value
733 );
734 }
735 }
736 if ( 0 < count( $lookup_where ) ) {
737 return $wpdadb->prepare( ' `%1s` in ( select `%1s` from `%1s` where (' . implode( ' or ', $lookup_where ) . ') ) ', array(
738 $column_name,
739 $lookup_key,
740 $lookup_table,
741 $lookup_columns[0],
742 "%{$search_values[0]}%"
743 ) );
744 } else {
745 return null;
746 }
747 }
748
749 public static function remove_where_from_sql( $sql ) {
750 if ( 'where' === substr( trim( $sql ), 0, 5 ) ) {
751 $pos = strpos( $sql, 'where' );
752 if ( false !== $pos ) {
753 $sql = substr_replace(
754 $sql,
755 '',
756 $pos,
757 5
758 );
759 }
760 }
761 return $sql;
762 }
763
764 private function get_md( $md, $wpdadb, $m2m_relationship ) {
765 }
766
767 private function get_global_filter(
768 $wpdadb,
769 $search,
770 $column_names,
771 $lookups,
772 $m2m_relationship
773 ) {
774 $where_global = array();
775 if ( null !== $search && "" !== $search ) {
776 foreach ( $column_names as $column_name => $queryable ) {
777 if ( $queryable ) {
778 if ( isset( $lookups[$column_name] ) ) {
779 // Perform look search.
780 $condition = $this->generate_lookup_condition(
781 $wpdadb,
782 $lookups,
783 $column_name,
784 array($search),
785 array(),
786 'contains'
787 );
788 if ( null !== $condition ) {
789 $where_global[] = $condition;
790 }
791 } else {
792 $where_global[] = $wpdadb->prepare( " `%1s` like '%s' ", array($this->convert_column_name( $m2m_relationship, $column_name ), '%' . esc_sql( $search ) . '%') );
793 }
794 }
795 }
796 }
797 return $where_global;
798 }
799
800 private function get_column_filters(
801 $wpdadb,
802 $search_columns,
803 $search_column_fns,
804 $lookups,
805 $m2m_relationship,
806 $search_data_types
807 ) {
808 }
809
810 private function get_where(
811 $wpdadb,
812 $default_where,
813 $md,
814 $m2m_relationship,
815 $search,
816 $column_names,
817 $lookups,
818 $search_columns,
819 $search_column_fns,
820 $search_data_types,
821 $geo_radius = array()
822 ) {
823 // Default where.
824 if ( '' !== trim( $default_where ) && 'where' !== strtolower( substr( trim( $default_where ), 0, 5 ) ) ) {
825 $where = "where {$default_where}";
826 } else {
827 $where = $default_where;
828 }
829 // Global filter.
830 $where_global = $this->get_global_filter(
831 $wpdadb,
832 $search,
833 $column_names,
834 $lookups,
835 $m2m_relationship
836 );
837 if ( 0 < count( $where_global ) ) {
838 $where .= (( '' === trim( $where ) ? ' where ' : ' and ' )) . $this->add_condition( $where_global, 'or' );
839 }
840 if ( is_array( $geo_radius ) && 0 < count( $geo_radius ) ) {
841 // Add geo radius to query
842 // Variable $geo_radius already sanitized in REST API
843 $unit = ( "km" == $geo_radius['unit'] ? 1000 : 1609.344 );
844 // km versus miles
845 if ( $geo_radius['col']['lat'] === $geo_radius['col']['lng'] ) {
846 // Location stored in GEOMETRY or POINT data type
847 $geocol = $geo_radius['col']['lat'];
848 $geo_where = " ( st_distance_sphere(point(st_y(`{$geocol}`), st_x(`{$geocol}`)), point({$geo_radius['loc']['lng']}, {$geo_radius['loc']['lat']})) / {$unit} ) < {$geo_radius['radius']} ";
849 } else {
850 // Latitude and longitude stored separately
851 $geo_where = " ( st_distance_sphere(point(`{$geo_radius['col']['lng']}`, `{$geo_radius['col']['lat']}`), point({$geo_radius['loc']['lng']}, {$geo_radius['loc']['lat']})) / {$unit} ) < {$geo_radius['radius']} ";
852 }
853 if ( '' === $where ) {
854 $where = " where {$geo_where} ";
855 } else {
856 $where .= " and {$geo_where} ";
857 }
858 }
859 return $where;
860 }
861
862 private function get_selected_columns( $column_names, $search_data_types ) {
863 if ( !is_array( $column_names ) ) {
864 return '*';
865 // select all columns
866 }
867 // Check for geo columns
868 $geometryColumns = array();
869 if ( is_array( $search_data_types ) ) {
870 foreach ( $search_data_types as $column_name => $search_data_type ) {
871 if ( 'geometry' === strtolower( $search_data_type ) || 'point' === strtolower( $search_data_type ) ) {
872 $geometryColumns[] = $column_name;
873 }
874 }
875 }
876 return implode( ",", array_map( function ( $column_name ) use($geometryColumns) {
877 if ( in_array( $column_name, $geometryColumns ) ) {
878 return 'ST_AsText(`' . WPDA::remove_backticks( $column_name ) . '`) ' . " as `{$column_name}` ";
879 // Convert geo data to string
880 } else {
881 return '`' . WPDA::remove_backticks( $column_name ) . '`';
882 }
883 }, array_keys( $column_names ) ) );
884 }
885
886 /**
887 * Perform query and return result as JSON response.
888 *
889 * @param string $dbs Schema name (database).
890 * @param string $tbl Table Name.
891 * @param string $column_names Column Names.
892 * @param string $page_index Page number.
893 * @param string $page_size Rows per page.
894 * @param string $search Filter.
895 * @param string $search_columns Column search filters.
896 * @param string $search_column_fns Column search filter modes.
897 * @param string $Sorting Order by.
898 * @param integer $last_row_count Row count previous request.
899 * @param string $row_count_estimate Indicates if row count estimate should be used.
900 * @param string $media_columns Media columns.
901 * @param string $default_where Defaul where clause
902 * @param string $default_orderby Defaul order by clause
903 * @return \WP_Error|\WP_REST_Response
904 */
905 public function select(
906 $dbs,
907 $tbl,
908 $column_names,
909 $page_index,
910 $page_size,
911 $search,
912 $search_columns,
913 $search_column_fns,
914 $sorting,
915 $last_row_count,
916 $row_count_estimate,
917 $media_columns = array(),
918 $default_where = '',
919 $default_orderby = '',
920 $lookups = array(),
921 $md = array(),
922 $m2m_relationship = array(),
923 $search_data_types = array(),
924 $client_side = false,
925 $geo_radius = array()
926 ) {
927 $wpdadb = WPDADB::get_db_connection( $dbs );
928 if ( null === $wpdadb ) {
929 // Error connecting.
930 return new \WP_Error('error', "Error connecting to database {$dbs}", array(
931 'status' => 420,
932 ));
933 } else {
934 $suppress = $wpdadb->suppress_errors( true );
935 // Build where clause.
936 $where = $this->get_where(
937 $wpdadb,
938 $default_where,
939 $md,
940 $m2m_relationship,
941 $search,
942 $column_names,
943 $lookups,
944 $search_columns,
945 $search_column_fns,
946 $search_data_types,
947 $geo_radius
948 );
949 // Build order by.
950 $sqlorder = '';
951 if ( is_array( $sorting ) && 0 < count( $sorting ) ) {
952 foreach ( $sorting as $sort ) {
953 if ( '' === $sqlorder ) {
954 $sqlorder = 'order by ';
955 } else {
956 $sqlorder .= ',';
957 }
958 $sqlorder .= '`' . $this->convert_column_name( $m2m_relationship, $sort['id'] ) . '` ' . (( $sort['desc'] ? 'desc' : 'asc' ));
959 }
960 }
961 if ( '' === $sqlorder && '' !== trim( $default_orderby ) ) {
962 $sqlorder = $default_orderby;
963 }
964 // Add pagination.
965 if ( !is_numeric( $page_size ) ) {
966 $page_size = 10;
967 }
968 $offset = $page_index * $page_size;
969 // Calculate offset.
970 if ( !is_numeric( $offset ) ) {
971 $offset = 0;
972 }
973 // Prepare query.
974 $sql = "\n\t\t\t\t\tselect " . $this->get_selected_columns( $column_names, $search_data_types ) . "\n\t\t\t\t\tfrom `%1s`\n\t\t\t\t\t{$where}\n\t\t\t\t\t{$sqlorder}\n\t\t\t\t";
975 $sql_tables = array($tbl);
976 // Perpare query.
977 $sql = $wpdadb->prepare( ( true === $client_side ? $sql : $sql . (( 0 < $page_size ? " limit {$page_size} offset {$offset} " : '' )) ), $sql_tables );
978 // Prepare debug info.
979 if ( 'on' === WPDA::get_option( WPDA::OPTION_PLUGIN_DEBUG ) ) {
980 $debug = array(
981 'sql' => preg_replace( "/\\s+/", " ", $sql ),
982 'where' => $where,
983 'order by' => $sqlorder,
984 );
985 } else {
986 $debug = null;
987 }
988 // Perform query.
989 $dataset = $wpdadb->get_results( $sql, 'ARRAY_A' );
990 if ( $wpdadb->last_error ) {
991 // Handle SQL errors.
992 return new \WP_Error('error', $wpdadb->last_error, array(
993 'status' => 420,
994 'debug' => $debug,
995 ));
996 }
997 if ( is_numeric( $last_row_count ) and 0 <= $last_row_count ) {
998 // Prevents additional unnecessary queries.
999 $rowcount = $last_row_count;
1000 } else {
1001 if ( true === $client_side ) {
1002 $rowcount = 0;
1003 } else {
1004 $estimate = false;
1005 if ( '1' === $row_count_estimate && '' === $where ) {
1006 // Perform row count estimate
1007 $countrows = $wpdadb->get_results( $wpdadb->prepare( "\n\t\t\t\t\t\t\t\t\tselect table_rows as rowcount\n\t\t\t\t\t\t\t\t\t from information_schema.tables\n\t\t\t\t\t\t\t\t\twhere table_schema = %s\n\t\t\t\t\t\t\t\t\t and table_name = %s\n\t\t\t\t\t\t\t\t", [$wpdadb->dbname, $tbl] ), 'ARRAY_A' );
1008 if ( isset( $countrows[0]['rowcount'] ) && 0 != $countrows[0]['rowcount'] ) {
1009 $estimate = true;
1010 }
1011 }
1012 if ( !$estimate ) {
1013 if ( !$estimate ) {
1014 // (Re)Count rows.
1015 $countrows = $wpdadb->get_results( $wpdadb->prepare( "\n\t\t\t\t\t\t\t\t\t\tselect count(1) as rowcount\n\t\t\t\t\t\t\t\t\t\tfrom `%1s`\n\t\t\t\t\t\t\t\t\t\t{$where}\n\t\t\t\t\t\t\t\t\t", array($tbl) ), 'ARRAY_A' );
1016 }
1017 }
1018 if ( $wpdadb->last_error ) {
1019 // Handle SQL errors.
1020 return new \WP_Error('error', $wpdadb->last_error, array(
1021 'status' => 420,
1022 ));
1023 }
1024 if ( isset( $countrows[0]['rowcount'] ) ) {
1025 $rowcount = $countrows[0]['rowcount'];
1026 } else {
1027 $rowcount = 0;
1028 }
1029 }
1030 }
1031 // Add context node to response
1032 $context = array();
1033 if ( 'on' === WPDA::get_option( WPDA::OPTION_PLUGIN_DEBUG ) ) {
1034 $context['debug'] = $debug;
1035 }
1036 if ( is_array( $media_columns ) && 0 < count( $media_columns ) ) {
1037 // Handle WP media library
1038 $media = array();
1039 for ($i = 0; $i < count( $dataset ); $i++) {
1040 $media_row = array();
1041 foreach ( $media_columns as $media_column_name => $media_column_type ) {
1042 if ( isset( $dataset[$i][$media_column_name] ) ) {
1043 $media_row[$media_column_name] = WPDA_WP_Media::get_media_url( $dataset[$i][$media_column_name] );
1044 }
1045 }
1046 $media[] = $media_row;
1047 }
1048 // Add media to context node
1049 $context['media'] = $media;
1050 }
1051 $wpdadb->suppress_errors( $suppress );
1052 // Send response.
1053 $response = $this->WPDA_Rest_Response(
1054 '',
1055 $dataset,
1056 $context,
1057 array(
1058 'rowCount' => $rowcount,
1059 )
1060 );
1061 $response->header( 'X-WP-Total', $rowcount );
1062 // Total rows for this query.
1063 if ( 0 < $page_size ) {
1064 $pagecount = floor( $rowcount / $page_size );
1065 if ( $pagecount != $rowcount / $page_size ) {
1066 // phpcs:ignore WordPress.PHP.StrictComparisons
1067 $pagecount++;
1068 }
1069 } else {
1070 // Prevent division by zero
1071 $pagecount = 0;
1072 }
1073 $response->header( 'X-WP-TotalPages', $pagecount );
1074 // Total pages for this query.
1075 return $response;
1076 }
1077 }
1078
1079 private function convert_column_name( $m2m_relationship, $column_name ) {
1080 // Return plain column name.
1081 return $this->sanitize_db_identifier( $column_name );
1082 }
1083
1084 private function map_columns( $prefix, $column_names ) {
1085 return implode( ",", array_map( function ( $v ) use($prefix) {
1086 $c = $this->sanitize_db_identifier( $v );
1087 $r = ( 'd' === $prefix ? static::RELATIONTABLEPREFIX . $c : $c );
1088 return "`{$prefix}`.`{$c}` as \"{$r}\"";
1089 }, array_keys( $column_names ) ) );
1090 }
1091
1092 public function add_filter(
1093 $wpdadb,
1094 $search_column,
1095 $search_column_fns,
1096 $search_value,
1097 $m2m_relationship = array(),
1098 $search_data_types = array()
1099 ) {
1100 }
1101
1102 public static function add_condition( $where_lines, $operand = 'and' ) {
1103 if ( 0 < count( array_filter( $where_lines ) ) ) {
1104 // Apply all searches.
1105 return ' ( (' . implode( ") {$operand} (", array_filter( $where_lines ) ) . ') ) ';
1106 } else {
1107 return "";
1108 }
1109 }
1110
1111 /**
1112 * Get table meta data.
1113 *
1114 * @param string $dbs Database schema name.
1115 * @param string $tbl Database table name.
1116 * @param string $waa With admin actions.
1117 * @return array\object
1118 */
1119 public function get_table_meta_data( $dbs, $tbl, $waa ) {
1120 $sql_create_table = '';
1121 if ( WPDA::current_user_is_admin() ) {
1122 // Admin user has access to all resources
1123 $access = array(
1124 'select' => array('POST'),
1125 'insert' => array('POST'),
1126 'update' => array('POST'),
1127 'delete' => array('POST'),
1128 );
1129 // Get create table script
1130 $wpdadb = WPDADB::get_db_connection( $dbs );
1131 if ( null !== $wpdadb ) {
1132 $suppress_errors = $wpdadb->suppress_errors;
1133 $wpdadb->suppress_errors = true;
1134 // NO_TABLE_OPTIONS is deprecated in V8
1135 // $wpdadb->query( "SET sql_mode = 'NO_TABLE_OPTIONS'" );
1136 $sql = $wpdadb->get_results( $wpdadb->prepare( 'show create table `%1s`', array($tbl) ), 'ARRAY_N' );
1137 if ( isset( $sql[0][1] ) ) {
1138 $sql_create_table = $sql[0][1];
1139 }
1140 $wpdadb->suppress_errors = $suppress_errors;
1141 }
1142 } else {
1143 $access = $this->get_table_access( $dbs, $tbl );
1144 }
1145 $settings = new stdClass();
1146 if ( null !== $access ) {
1147 $columns = WPDA_List_Columns_Cache::get_list_columns( $dbs, $tbl );
1148 $settings_db = WPDA_Table_Settings_Model::query( $tbl, $dbs );
1149 if ( isset( $settings_db[0]['wpda_table_settings'] ) ) {
1150 $settings = json_decode( $settings_db[0]['wpda_table_settings'] );
1151 // Remove old settings from response.
1152 unset($settings->form_labels);
1153 unset($settings->list_labels);
1154 unset($settings->custom_settings);
1155 unset($settings->search_settings);
1156 }
1157 $settings->ui = WPDA_Settings::get_admin_settings( $dbs, $tbl );
1158 $rest_api = get_option( WPDA_API::WPDA_REST_API_TABLE_ACCESS );
1159 if ( isset( $rest_api[$dbs][$tbl] ) ) {
1160 $settings->rest_api = $rest_api[$dbs][$tbl];
1161 }
1162 $settings->env = $this->get_env();
1163 $wp_nonce_action_alter = "wpda-alter-{$tbl}";
1164 $wp_nonce_alter = wp_create_nonce( $wp_nonce_action_alter );
1165 $wp_nonce_refresh = null;
1166 $connect = null;
1167 global $wpdb;
1168 $settings->wp = [
1169 'roles' => $this->get_wp_roles(),
1170 'users' => $this->get_wp_users(),
1171 'home' => admin_url( 'admin.php' ),
1172 'homea' => admin_url( 'admin-ajax.php' ),
1173 'tables' => array_values( $wpdb->tables() ),
1174 'date_format' => get_option( 'date_format' ),
1175 'time_format' => get_option( 'time_format' ),
1176 'alter' => $wp_nonce_alter,
1177 'refresh' => $wp_nonce_refresh,
1178 'connect' => $connect,
1179 ];
1180 if ( true === $waa ) {
1181 $settings->wp['aonce'] = implode( '-', array(
1182 wp_create_nonce( 'wpda-export-' . json_encode( $tbl ) ),
1183 // Table export
1184 wp_create_nonce( 'wpda-rename-' . $tbl ),
1185 ) );
1186 }
1187 $table_columns = $columns->get_table_columns();
1188 $media = $this->get_media( $dbs, $tbl, $table_columns );
1189 $columns_sorted = array();
1190 foreach ( $table_columns as $column ) {
1191 if ( isset( $column['column_name'] ) ) {
1192 $columns_sorted[$column['column_name']] = $column;
1193 }
1194 }
1195 }
1196 return array(
1197 'columns' => $table_columns,
1198 'columns_sorted' => $columns_sorted,
1199 'table_labels' => $columns->get_table_header_labels(),
1200 'form_labels' => $columns->get_table_column_headers(),
1201 'primary_key' => $columns->get_table_primary_key(),
1202 'access' => $access,
1203 'settings' => $settings,
1204 'media' => $media['media'],
1205 'wp_media' => $media['wp_media'],
1206 'table_info' => $this->get_table_info( $dbs, $tbl ),
1207 'create' => $sql_create_table,
1208 );
1209 }
1210
1211 private function get_table_access( $dbs, $tbl ) {
1212 if ( current_user_can( 'manage_options' ) ) {
1213 // Check administrator rights
1214 if ( is_admin() ) {
1215 $access = WPDA_Dictionary_Access::check_table_access_backend( $dbs, $tbl, $done );
1216 } else {
1217 $access = WPDA_Dictionary_Access::check_table_access_frontend( $dbs, $tbl, $done );
1218 }
1219 if ( $access ) {
1220 // Administrator access granted
1221 return array(
1222 'select' => array('POST'),
1223 'insert' => array('POST'),
1224 'update' => array('POST'),
1225 'delete' => array('POST'),
1226 );
1227 }
1228 }
1229 $tables = get_option( WPDA_API::WPDA_REST_API_TABLE_ACCESS );
1230 if ( false !== $tables && isset( $tables[$dbs][$tbl] ) && is_array( $tables[$dbs][$tbl] ) ) {
1231 $table = $tables[$dbs][$tbl];
1232 $table_access = new \stdClass();
1233 $table_access->select = $this->get_table_access_action( $table, 'select' );
1234 $table_access->insert = $this->get_table_access_action( $table, 'insert' );
1235 $table_access->update = $this->get_table_access_action( $table, 'update' );
1236 $table_access->delete = $this->get_table_access_action( $table, 'delete' );
1237 return $table_access;
1238 }
1239 return false;
1240 }
1241
1242 private function get_table_access_action( $table, $action ) {
1243 if ( isset( $table[$action]['authorization'], $table[$action]['methods'] ) && is_array( $table[$action]['methods'] ) && 0 < count( $table[$action]['methods'] ) ) {
1244 if ( 'anonymous' === $table[$action]['authorization'] ) {
1245 return $table[$action]['methods'];
1246 } else {
1247 // Check authorized users
1248 if ( isset( $table[$action]['authorized_users'] ) && is_array( $table[$action]['authorized_users'] ) && 0 < count( $table[$action]['authorized_users'] ) && in_array( (string) $this->get_user_login(), $table[$action]['authorized_users'] ) ) {
1249 return $table[$action]['methods'];
1250 }
1251 // Check authorized roles
1252 if ( isset( $table[$action]['authorized_roles'] ) && is_array( $table[$action]['authorized_roles'] ) && 0 < count( $table[$action]['authorized_roles'] ) && 0 < count( array_intersect( $this->get_user_roles(), $table[$action]['authorized_roles'] ) ) ) {
1253 return $table[$action]['methods'];
1254 }
1255 }
1256 }
1257 return array();
1258 }
1259
1260 /**
1261 * Check if access is grant for requested database/table.
1262 *
1263 * @param string $dbs Remote or local database connection string.
1264 * @param string $tbl Database table name.
1265 * @param onject $request Request object.
1266 * @param string $action Possible values: select, insert, update, delete.
1267 * @return bool
1268 */
1269 private function check_table_access(
1270 $dbs,
1271 $tbl,
1272 $request,
1273 $action,
1274 &$msg = ''
1275 ) {
1276 if ( WPDA::current_user_is_admin() ) {
1277 // Grant access to administrators always.
1278 return true;
1279 }
1280 $tables = get_option( WPDA_API::WPDA_REST_API_TABLE_ACCESS );
1281 if ( false === $tables ) {
1282 // No tables.
1283 $msg = __( 'Unauthorized', 'wp-data-access' );
1284 return false;
1285 }
1286 if ( !(isset( $tables[$dbs][$tbl][$action]['methods'] ) && is_array( $tables[$dbs][$tbl][$action]['methods'] )) ) {
1287 // No methods.
1288 $msg = __( 'Unauthorized', 'wp-data-access' );
1289 return false;
1290 } else {
1291 if ( !in_array( $request->get_method(), $tables[$dbs][$tbl][$action]['methods'] ) ) {
1292 //phpcs:ignore - 8.1 proof
1293 $msg = __( 'Unauthorized', 'wp-data-access' );
1294 return false;
1295 }
1296 }
1297 if ( !isset( $tables[$dbs][$tbl][$action]['authorization'] ) ) {
1298 // No authorization.
1299 $msg = __( 'Unauthorized', 'wp-data-access' );
1300 return false;
1301 } else {
1302 if ( 'anonymous' === $tables[$dbs][$tbl][$action]['authorization'] ) {
1303 // Access granted to all users.
1304 return true;
1305 }
1306 }
1307 global $wp_rest_auth_cookie;
1308 if ( true !== $wp_rest_auth_cookie ) {
1309 // No anonymous access.
1310 $msg = __( 'Unauthorized', 'wp-data-access' );
1311 return false;
1312 } else {
1313 if ( 'authorized' !== $tables[$dbs][$tbl][$action]['authorization'] ) {
1314 // Authorization check.
1315 $msg = __( 'Unauthorized', 'wp-data-access' );
1316 return false;
1317 }
1318 // Authorized access requires a valid nonce.
1319 if ( !wp_verify_nonce( $request->get_header( 'X-WP-Nonce' ), 'wp_rest' ) ) {
1320 $msg = 'rest_cookie_invalid_nonce';
1321 return false;
1322 }
1323 if ( !(isset( $tables[$dbs][$tbl][$action]['authorized_users'] ) && is_array( $tables[$dbs][$tbl][$action]['authorized_users'] )) ) {
1324 // No users.
1325 $msg = __( 'Unauthorized', 'wp-data-access' );
1326 return false;
1327 } else {
1328 $requesting_user_login = $this->get_user_login();
1329 if ( 0 < count( $tables[$dbs][$tbl][$action]['authorized_users'] ) && in_array( $requesting_user_login, $tables[$dbs][$tbl][$action]['authorized_users'] ) ) {
1330 return true;
1331 }
1332 }
1333 if ( !(isset( $tables[$dbs][$tbl][$action]['authorized_roles'] ) && is_array( $tables[$dbs][$tbl][$action]['authorized_roles'] )) ) {
1334 // No roles.
1335 $msg = __( 'Unauthorized', 'wp-data-access' );
1336 return false;
1337 } else {
1338 $requesting_user_roles = $this->get_user_roles();
1339 if ( false === $requesting_user_roles ) {
1340 $requesting_user_roles = array();
1341 }
1342 if ( 0 < count( $tables[$dbs][$tbl][$action]['authorized_roles'] ) && 0 < count( array_intersect( $requesting_user_roles, $tables[$dbs][$tbl][$action]['authorized_roles'] ) ) ) {
1343 return true;
1344 }
1345 }
1346 $msg = __( 'Unauthorized', 'wp-data-access' );
1347 return false;
1348 }
1349 }
1350
1351 private function sanitize_column_values(
1352 $dbs,
1353 $tbl,
1354 $column_values,
1355 $code_columns = array(),
1356 $html_columns = array()
1357 ) {
1358 $wpda_list_columns = WPDA_List_Columns_Cache::get_list_columns( $dbs, $tbl );
1359 $sanitized_column_values = [];
1360 foreach ( $column_values as $column_name => $column_value ) {
1361 $column_value = $column_values[$column_name];
1362 switch ( $wpda_list_columns->get_column_data_type( $column_name ) ) {
1363 case 'tinytext':
1364 case 'text':
1365 case 'mediumtext':
1366 case 'longtext':
1367 if ( null !== $column_value ) {
1368 if ( in_array( $column_name, $html_columns ) ) {
1369 $column_value = sanitize_textarea_field( $column_value );
1370 } else {
1371 $column_value = wp_kses_post( $column_value );
1372 }
1373 }
1374 break;
1375 default:
1376 if ( null !== $column_value ) {
1377 $column_value = sanitize_text_field( $column_value );
1378 }
1379 }
1380 $sanitized_column_values[$this->sanitize_db_identifier( $column_name )] = $column_value;
1381 }
1382 return $sanitized_column_values;
1383 }
1384
1385 }
1386