PluginProbe
WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards / 5.2
WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards v5.2
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 / WPDA.php

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

1,534 lines 46.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Suppress "error - 0 - No summary was found for this file" on phpdoc generation
5 *
6 * @package WPDataAccess
7 */
8
9 namespace WPDataAccess {
10
11 use WP_Data_Access_Admin;
12 use WPDataAccess\Connection\WPDADB;
13 use WPDataAccess\Data_Dictionary\WPDA_Dictionary_Lists;
14 use WPDataAccess\Data_Dictionary\WPDA_List_Columns_Cache;
15 use WPDataAccess\Utilities\WPDA_Message_Box;
16 use WPDataProjects\WPDP;
17
18 /**
19 * Class WPDA
20 *
21 * Plugin default values and settings are managed through this class. Every plugin option has a default value
22 * which is maintained in an array together with the option name. Options are only saved in $wpdb->options when
23 * they are changed. Otherwise the default values are used. After reading option values from $wpdb->options the
24 * values are cached as many of them are used in multiple
25 * values are cached as many of them are used in multiple
26 * places during the processing of a request.
27 *
28 * @author Peter Schulz
29 * @since 1.0.0
30 */
31 class WPDA {
32
33 // SAVING SPACE - According to the plugin guideliness it is allowed to include external fonts:
34 // https://developer.wordpress.org/plugins/wordpress-org/detailed-plugin-guidelines/#8-plugins-may-not-send-executable-code-via-third-party-systems
35 const CDN_FONTAWESOME = 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/';
36 const GOOGLE_CHARTS = 'https://www.gstatic.com/charts/loader.js';
37
38 /**
39 * Label for WordPress tables
40 */
41 const TABLE_TYPE_WP = 'wordpress table';
42 /**
43 * Label for WPDA plugin tables
44 */
45 const TABLE_TYPE_WPDA = 'plugin table';
46
47 // Options are stored in arrays (OPTION_ARRAYS):
48 // [0] = option name (as saved in wp_options).
49 // [1] = default value (used if option is not available in wp_options).
50 // Application options.
51 /**
52 * Option wpda_version and it's default value
53 */
54 const OPTION_WPDA_VERSION = [ 'wpda_version', '5.2' ];
55 /**
56 * Option wpda_setup_error and it's default value
57 */
58 const OPTION_WPDA_SETUP_ERROR = [
59 'wpda_setup_error',
60 ''
61 ]; // Values: off = do not display setup errors, other = show.
62 /**
63 * Option wpda_show_whats_new and it's default value
64 */
65 const OPTION_WPDA_SHOW_WHATS_NEW = [
66 'wpda_show_whats_new',
67 'off'
68 ]; // Values: off = hide link to what's new page, other = show.
69 /**
70 * Option wpda_uninstall_tables and it's default value
71 */
72 const OPTION_WPDA_UNINSTALL_TABLES = [ 'wpda_uninstall_tables', 'off' ]; // On uninstall drop WPDA tables.
73 /**
74 * Option wpda_uninstall_options and it's default value
75 */
76 const OPTION_WPDA_UNINSTALL_OPTIONS = [ 'wpda_uninstall_options', 'off' ]; // On uninstall delety WPDA options.
77 /**
78 * Option wpda_datatables_version and it's default value
79 */
80 const OPTION_WPDA_DATATABLES_VERSION = [ 'wpda_datatables_version', '1.11.3' ];
81 /**
82 * Option wpda_datatables_responsive_version and it's default value
83 */
84 const OPTION_WPDA_DATATABLES_RESPONSIVE_VERSION = [ 'wpda_datatables_responsive_version', '2.2.9' ];
85
86 const OPTION_PLUGIN_NAVIGATION = [ 'wpda_plugin_navigation', 'dashboard' ];
87 const OPTION_PLUGIN_NAVIGATION_DEFAULT_PAGE = [ 'wpda_plugin_navigation_default_page', 'wpda' ];
88
89 const OPTION_PLUGIN_HIDE_NOTICES = [ 'wpda_plugin_hide_notices', 'on' ];
90
91 const OPTION_PLUGIN_HIDE_ADMIN_MENU = [ 'wpda_plugin_hide_admin_menu', 'off' ];
92
93 const OPTION_PLUGIN_PANEL_COOKIES = [ 'wpda_plugin_panel_cookies', 'clear' ];
94
95 const OPTION_PLUGIN_SECRET_KEY_DEFAULT = 'enter-your-secret-key-here';
96 const OPTION_PLUGIN_SECRET_IV_DEFAULT = 'enter-your-secret-iv-here';
97
98 const OPTION_PLUGIN_SECRET_KEY = [ 'wpda_plugin_secret_key', self::OPTION_PLUGIN_SECRET_KEY_DEFAULT ];
99 const OPTION_PLUGIN_SECRET_IV = [ 'wpda_plugin_secret_iv', self::OPTION_PLUGIN_SECRET_IV_DEFAULT ];
100
101 const OPTION_PLUGIN_SONCE_SEED = [ 'wpda_plugin_sonce_seed', 'ALSKDFHIUWEALDSKNCNKSDJAKDJHSFAKSDFGFKOJHORITIHGMRTGHMHL' ];
102
103 const OPTION_PLUGIN_WPDATAACCESS_POST = [ 'wpda_plugin_wpdataaccess_post', 'on' ];
104 const OPTION_PLUGIN_WPDATAACCESS_PAGE = [ 'wpda_plugin_wpdataaccess_page', 'on' ];
105 const OPTION_PLUGIN_WPDADIEHARD_POST = [ 'wpda_plugin_wpdadiehard_post', 'on' ];
106 const OPTION_PLUGIN_WPDADIEHARD_PAGE = [ 'wpda_plugin_wpdadiehard_page', 'on' ];
107 const OPTION_PLUGIN_WPDADATAFORMS_POST = [ 'wpda_plugin_wpdadataforms_post', 'on' ];
108 const OPTION_PLUGIN_WPDADATAFORMS_PAGE = [ 'wpda_plugin_wpdadataforms_page', 'on' ];
109 const OPTION_PLUGIN_WPDADATAFORMS_ALLOW_ANONYMOUS_ACCESS = [ 'wpda_plugin_wpdadataforms_allow_anonymous_access', 'off' ];
110 const OPTION_PLUGIN_WPDAREPORT_POST = [ 'wpda_plugin_wpdareport_post', 'on' ];
111 const OPTION_PLUGIN_WPDAREPORT_PAGE = [ 'wpda_plugin_wpdareport_page', 'on' ];
112
113 // MySQL date and time formats
114 const DB_DATE_FORMAT = 'Y-m-d';
115 const DB_TIME_FORMAT = 'H:i:s';
116 const DB_DATETIME_FORMAT = 'Y-m-d H:i:s';
117
118 // Plugin options. (date and time settings)
119 const OPTION_PLUGIN_DATE_FORMAT = [ 'wpda_plugin_date_format', 'Y-m-d' ];
120 const OPTION_PLUGIN_DATE_PLACEHOLDER = [ 'wpda_plugin_date_placeholder', 'yyyy-mm-dd' ];
121 const OPTION_PLUGIN_TIME_FORMAT = [ 'wpda_plugin_time_format', 'H:i' ];
122 const OPTION_PLUGIN_TIME_PLACEHOLDER = [ 'wpda_plugin_time_placeholder', 'hh:mi' ];
123 const OPTION_PLUGIN_SET_FORMAT = [ 'wpda_plugin_set_format', 'csv' ];
124
125 // Plugin debug mode
126 const OPTION_PLUGIN_DEBUG = [ 'wpda_plugin_debug', 'off' ];
127
128 // Back-end options.
129 /**
130 * Option wpda_be_load_datatables and it's default value
131 */
132 const OPTION_BE_LOAD_DATATABLES = [ 'wpda_be_load_datatables', 'on' ];
133 /**
134 * Option wpda_be_load_datatables_response and it's default value
135 */
136 const OPTION_BE_LOAD_DATATABLES_RESPONSE = [ 'wpda_be_load_datatables_response', 'on' ];
137 /**
138 * Option wpda_be_table_access and it's default value
139 */
140 const OPTION_BE_TABLE_ACCESS = [ 'wpda_be_table_access', 'show' ]; // Values: show, hide and select.
141 /**
142 * Option wpda_be_table_access_selected and it's default value
143 */
144 const OPTION_BE_TABLE_ACCESS_SELECTED = [ 'wpda_be_table_access_selected', '' ]; // Tables authorized in WPDA.
145 /**
146 * Option wpda_be_view_link and it's default value
147 */
148 const OPTION_BE_VIEW_LINK = [ 'wpda_be_view_link', 'on' ]; // Show view link in list table.
149 /**
150 * Option wpda_be_allow_insert and it's default value
151 */
152 const OPTION_BE_ALLOW_INSERT = [
153 'wpda_be_allow_insert',
154 'on'
155 ]; // Show insert link in list table (simple form).
156 /**
157 * Option wpda_be_allow_update and it's default value
158 */
159 const OPTION_BE_ALLOW_UPDATE = [
160 'wpda_be_allow_update',
161 'on'
162 ]; // Show update link in list table (simple form).
163 /**
164 * Option wpda_be_allow_delete and it's default value
165 */
166 const OPTION_BE_ALLOW_DELETE = [ 'wpda_be_allow_delete', 'on' ]; // Show delete link in list table.
167 /**
168 * Option wpda_be_wpda_export_rows and it's default value
169 */
170 const OPTION_BE_EXPORT_ROWS = [
171 'wpda_be_wpda_export_rows',
172 'on'
173 ]; // Show export link in list table (row export).
174 /**
175 * Option wpda_be_wpda_export_variable_prefix and it's default value
176 */
177 const OPTION_BE_EXPORT_VARIABLE_PREFIX = [
178 'wpda_be_wpda_export_variable_prefix',
179 'on'
180 ]; // Allows to import into repository with different wpdb prefix.
181 /**
182 * Option wpda_be_wpda_allow_imports and it's default value
183 */
184 const OPTION_BE_ALLOW_IMPORTS = [ 'wpda_be_wpda_allow_imports', 'on' ]; // Allow to import data (main only).
185 /**
186 * Option wpda_be_confirm_export and it's default value
187 */
188 const OPTION_BE_CONFIRM_EXPORT = [ 'wpda_be_confirm_export', 'off' ]; // Ask for confirmation before exporting.
189 /**
190 * Option wpda_be_confirm_view and it's default value
191 */
192 const OPTION_BE_CONFIRM_VIEW = [ 'wpda_be_confirm_view', 'off' ]; // Ask for confirmation before viewing.
193 /**
194 * Option wpda_be_pagination and it's default value
195 */
196 const OPTION_BE_PAGINATION = [ 'wpda_be_pagination', '10' ];
197 /**
198 * Option wpda_be_remember_search and it's default value
199 */
200 const OPTION_BE_REMEMBER_SEARCH = [ 'wpda_be_remember_search', 'on' ];
201 /**
202 * Option wpda_be_innodb_count and it's default value
203 */
204 const OPTION_BE_INNODB_COUNT = [ 'wpda_be_innodb_count', 100000 ];
205 /**
206 * Option wpda_be_design_mode and it's default value
207 */
208 const OPTION_BE_DESIGN_MODE = [ 'wpda_be_design_mode', 'advanced' ]; // Default design mode (basic/advanced).
209 /**
210 * Option wpda_be_text_wrap_switch and it's default value
211 */
212 const OPTION_BE_TEXT_WRAP_SWITCH = [ 'wpda_be_text_wrap_switch', 'off' ];
213 /**
214 * Option wpda_be_text_wrap and it's default value
215 */
216 const OPTION_BE_TEXT_WRAP = [ 'wpda_be_text_wrap', 400 ];
217 /**
218 * Option wpda_be_hide_button_icons and it's default value
219 */
220 const OPTION_BE_HIDE_BUTTON_ICONS = [ 'wpda_be_hide_button_icons', 'off' ];
221
222 // Front-end options.
223 /**
224 * Option wpda_fe_load_datatables and it's default value
225 */
226 const OPTION_FE_LOAD_DATATABLES = [ 'wpda_fe_load_datatables', 'on' ];
227 /**
228 * Option wpda_fe_load_datatables_response and it's default value
229 */
230 const OPTION_FE_LOAD_DATATABLES_RESPONSE = [ 'wpda_fe_load_datatables_response', 'on' ];
231 /**
232 * Option wpda_fe_table_access and it's default value
233 */
234 const OPTION_FE_TABLE_ACCESS = [ 'wpda_fe_table_access', 'select' ]; // Values: hide, show, select.
235 /**
236 * Option wpda_fe_table_access_selected and it's default value
237 */
238 const OPTION_FE_TABLE_ACCESS_SELECTED = [ 'wpda_fe_table_access_selected', '' ]; // Tables authorized in WPDA.
239 /**
240 * Option wpda_fe_pagination and it's default value
241 */
242 const OPTION_FE_PAGINATION = [ 'wpda_fe_pagination', '10' ];
243 const OPTION_FE_ADD_PROJECTS_TO_TOOLBAR = [ 'wpda_fe_add_projects_to_toolbar', 'on' ];
244
245 // Manage Repository options.
246 /**
247 * Option wpda_mr_keep_backup_tables and it's default value
248 */
249 const OPTION_MR_KEEP_BACKUP_TABLES = [ 'wpda_mr_keep_backup_tables', 'on' ];
250 const OPTION_MR_BACKUP_TABLES_KEPT_DEFAULT = '3';
251 const OPTION_MR_BACKUP_TABLES_KEPT = [ 'wpda_mr_backup_tables_kept', self::OPTION_MR_BACKUP_TABLES_KEPT_DEFAULT ];
252
253 // Data Backup options.
254 /**
255 * Option wpda_db_local_path and it's default value
256 */
257 const OPTION_DB_LOCAL_PATH = [ 'wpda_db_local_path', '' ];
258 /**
259 * Option wpda_db_dropbox_path and it's default value
260 */
261 const OPTION_DB_DROPBOX_PATH = [ 'wpda_db_dropbox_path', '' ];
262
263 // Data Publisher options.
264 /**
265 * Option wpda_dp_publication_roles and it's default value
266 */
267 const OPTION_DP_PUBLICATION_ROLES = [ 'wpda_dp_publication_roles', '' ];
268 const OPTION_DP_LANGUAGE = [ 'wpda_dp_language', 'English' ];
269 const OPTION_DP_JSON_EDITING = [ 'wpda_dp_json_editing', 'validate' ];
270 const OPTION_DP_STYLE = [ 'wpda_dp_style', 'default' ];
271
272 // Role Management
273 const OPTION_WPDA_ENABLE_ROLE_MANAGEMENT = [ 'wpda_rm_enable_role_management', 'off' ];
274 const OPTION_WPDA_USE_ROLES_IN_SHORTCODE = [ 'wpda_rm_use_roles_in_shortcode', 'off' ];
275
276 // Prefixes to store backend access for non WP databases
277 const BACKEND_OPTIONNAME_DATABASE_ACCESS = 'WPDA_BE_TABLE_ACCESS_';
278 const BACKEND_OPTIONNAME_DATABASE_SELECTED = 'WPDA_BE_TABLE_SELECTED_';
279
280 // Prefixes to store frontend access for non WP databases
281 const FRONTEND_OPTIONNAME_DATABASE_ACCESS = 'WPDA_FE_TABLE_ACCESS_';
282 const FRONTEND_OPTIONNAME_DATABASE_SELECTED = 'WPDA_FE_TABLE_SELECTED_';
283
284 const WPDA_DT_UI_THEME_DEFAULT = [ 'wpda_dt_ui_theme_default', 'smoothness' ];
285
286 /**
287 * List of plugin tables
288 */
289 const WPDA_TABLES = [
290 'wpda_logging' => true,
291 'wpda_menus' => true,
292 'wpda_table_settings' => true,
293 'wpda_table_design' => true,
294 'wpda_publisher' => true,
295 'wpda_media' => true,
296 'wpda_project' => true,
297 'wpda_project_page' => true,
298 'wpda_project_table' => true,
299 'wpda_csv_uploads' => true,
300 'wpda_pro_reports' => true,
301 ];
302
303 /**
304 * List containing all plugin tables
305 *
306 * @var array
307 */
308 static protected $wpda_tables = [];
309
310 // Option values once queried from wp_options are stored in an array for re-use during request to prevent
311 // executing same query on wp_options multiple times.
312 /**
313 * Options cache array
314 *
315 * @var array
316 */
317 static protected $option_cache = [];
318
319 /**
320 * List containing all WordPress tables
321 *
322 * @var array
323 */
324 static protected $wp_tables = [];
325
326 static protected $plugin_pages = [
327 WP_Data_Access_Admin::PAGE_MAIN,
328 WP_Data_Access_Admin::PAGE_DASHBOARD,
329 WP_Data_Access_Admin::PAGE_SETTINGS,
330 WP_Data_Access_Admin::PAGE_EXPLORER,
331 WP_Data_Access_Admin::PAGE_QUERY_BUILDER,
332 WP_Data_Access_Admin::PAGE_PUBLISHER,
333 WP_Data_Access_Admin::PAGE_DESIGNER,
334 WP_Data_Access_Admin::PAGE_MY_TABLES,
335 WP_Data_Access_Admin::PAGE_CHARTS,
336 WPDP::PAGE_MAIN,
337 WPDP::PAGE_TEMPLATES,
338 ];
339
340 public static function is_plugin_page( $page ) {
341 return (
342 'wpda_wpdp_' === substr( $page, 0, 10 ) ||
343 WP_Data_Access_Admin::PAGE_EXPLORER === substr( $page, 0, 13 ) ||
344 in_array( $page, self::$plugin_pages)
345 );
346 }
347
348 /**
349 * Translated table label
350 *
351 * Returns a translated table label. The label depends on the type of table. Provided through a function to
352 * support internationalization.
353 *
354 * @param string $table_type Table type (use WPDA constants).
355 *
356 * @return string Translated table type.
357 * @since 1.0.0
358 *
359 */
360 public static function get_table_type_text( $table_type ) {
361
362 switch ( $table_type ) {
363
364 case self::TABLE_TYPE_WP:
365 return __( 'WordPress table', 'wp-data-access' );
366
367 case self::TABLE_TYPE_WPDA:
368 return __( 'plugin table', 'wp-data-access' );
369
370 default:
371 return $table_type;
372
373 }
374
375 }
376
377 /**
378 * Get plugin option values
379 *
380 * Get value for pluginoption saved in wp_options. If option is not found in $wpdb->options the default value
381 * for that option is returned. Option values once taken from $wpdb->options are cached to prevent execution
382 * of the same query multiple times during teh processing of a request.
383 *
384 * @param array $option OPTION_ARRAY (use class constants).
385 *
386 * @return mixed Value for OPTION_ARRAY ($option): (1) cached value (2) wp_options value (3) default value.
387 * @since 1.0.0
388 *
389 */
390 public static function get_option( $option ) {
391
392 if ( isset( self::$option_cache[ $option[0] ] ) ) {
393 return self::$option_cache[ $option[0] ]; // Re-use cached value.
394 }
395
396 $option_value = get_option( $option[0] );
397 if ( ! $option_value ) {
398 // Option not found in wp_options: save default value for re-use.
399 self::$option_cache[ $option[0] ] = $option[1];
400 } else {
401 // Option found in wp_options: save for re-use.
402 self::$option_cache[ $option[0] ] = $option_value;
403 }
404
405 return self::$option_cache[ $option[0] ]; // Return saved value.
406
407 }
408
409 /**
410 * Delete all plugin options from table wp_options
411 *
412 * @since 1.0.0
413 */
414 public static function clear_all_options() {
415
416 global $wpdb;
417
418 $wpdb->query(
419 "
420 DELETE FROM wp_options
421 WHERE option_name LIKE 'wpda_%'
422 "
423 ); // db call ok; no-cache ok.
424
425 self::$option_cache = []; // Reset cache.
426
427 }
428
429 /**
430 * Load all WordPress tables
431 *
432 * @since 1.1.0
433 */
434 public static function load_wp_tables() {
435
436 if ( 0 === count( self::$wp_tables ) ) {
437 try {
438 global $wpdb;
439
440 if ( ! is_multisite() ) {
441 foreach ( $wpdb->tables( 'all', true ) as $table ) {
442 self::$wp_tables[ $table ] = $table;
443 }
444 } else {
445 $query = "select blog_id from {$wpdb->blogs}";
446 $blogs = $wpdb->get_results( $query, 'ARRAY_N' );
447 foreach ( $blogs as $blog ) {
448 foreach ( $wpdb->tables( $blog === reset( $blogs ) ? 'all' : 'blog', true, $blog[0] ) as $table ) {
449 self::$wp_tables[ $table ] = $table;
450 }
451 }
452 }
453
454 return true;
455 } catch ( \Exception $e ) {
456 wp_die( 'ERROR: ' . $e->getMessage() );
457 }
458 }
459
460 }
461
462 /**
463 * Checks if a table is a WordPress table
464 *
465 * @param string $table_name Table name.
466 *
467 * @return bool TRUE = WordPress table
468 * @since 1.1.0
469 *
470 */
471 public static function is_wp_table( $table_name ) {
472
473 self::load_wp_tables();
474
475 if ( 0 === count( self::$wp_tables ) ) {
476 return false;
477 }
478
479 return isset( self::$wp_tables[ $table_name ] );
480
481 }
482
483 /**
484 * List containing all WordPress tables
485 *
486 * @return array
487 * @since 1.1.0
488 *
489 */
490 public static function get_wp_tables() {
491
492 self::load_wp_tables();
493
494 if ( 0 === count( self::$wp_tables ) ) {
495 wp_die( __( 'ERROR: No WordPress table found', 'wp-data-access' ) );
496 }
497
498 return self::$wp_tables;
499
500 }
501
502 /**
503 * Returns a list of all plugin tables
504 *
505 * @return array List of plugin tables
506 * @since 1.0.0
507 *
508 */
509 public static function get_wpda_tables() {
510
511 global $wpdb;
512 $wpda_tables = [];
513
514 foreach ( self::WPDA_TABLES as $key => $value ) {
515 $wpda_tables[] = $wpdb->prefix . $key;
516 }
517
518 return $wpda_tables;
519
520 }
521
522 /**
523 * Check if repository column represents a schema name
524 *
525 * @param string $table_name Table name
526 * @param string $column_name Column name
527 *
528 * @return bool
529 */
530 public static function column_is_schema_name( $table_name, $column_name ) {
531 if ( 0 === sizeof( self::$wpda_tables ) ) {
532 // Cache schema names
533 global $wpdb;
534 self::$wpda_tables[$wpdb->prefix . 'wpda_media.media_schema_name' ] = true;
535 self::$wpda_tables[$wpdb->prefix . 'wpda_project_page.page_schema_name' ] = true;
536 self::$wpda_tables[$wpdb->prefix . 'wpda_menus.menu_schema_name' ] = true;
537 self::$wpda_tables[$wpdb->prefix . 'wpda_project_table.wpda_schema_name' ] = true;
538 self::$wpda_tables[$wpdb->prefix . 'wpda_publisher.pub_schema_name' ] = true;
539 self::$wpda_tables[$wpdb->prefix . 'wpda_table_design.wpda_schema_name' ] = true;
540 self::$wpda_tables[$wpdb->prefix . 'wpda_table_settings.wpda_schema_name' ] = true;
541 }
542
543 return isset( self::$wpda_tables[ "{$table_name}.{$column_name}" ] );
544 }
545
546 /**
547 * Return the default value for a plugin option
548 *
549 * @param array $option OPTION_ARRAY (use class constants).
550 *
551 * @return mixed Default value for OPTION_ARRAY ($option).
552 * @since 1.0.0
553 *
554 */
555 public static function get_option_default( $option ) {
556
557 return $option[1]; // Default option value.
558
559 }
560
561 /**
562 * Checks if table is plugin table
563 *
564 * NOTE
565 * Variable $phpdoc_supported_solution is a temporary variable that does not add any functionality to this
566 * function. It only serves the purpose to get class WPDA in the documentation!!! If the isset statement in
567 * the return is performed directly on self::WPDA_TABLES, class WPDA will not appear in the phpdoc generated
568 * documentation. To avoid class WPDA to be undocumented, we use $phpdoc_supported_solution.
569 *
570 * @param string $real_table_name Table name to be checked.
571 *
572 * @return bool TRUE = $table_name is a WPDA table, FALSE = $table_name is not a WPDA table.
573 * @since 1.0.0
574 *
575 */
576 public static function is_wpda_table( $real_table_name ) {
577 if ( null === $real_table_name ) {
578 return false;
579 }
580
581 global $wpdb;
582
583 $phpdoc_supported_solution = self::WPDA_TABLES; // DO NOT DELETE THIS TO MAKE THE CODE SIMPLER!!! (read).
584
585 return
586 (
587 isset(
588 $phpdoc_supported_solution[ substr( $real_table_name, strlen( $wpdb->prefix ) ) ]
589 ) && (
590 $wpdb->prefix === substr( $real_table_name, 0, strlen( $wpdb->prefix ) )
591 )
592 );
593 }
594
595 /**
596 * Save plugin option
597 *
598 * Saves a plugin option in $wpdb->options.
599 *
600 * @param array $option OPTION_ARRAYS (use class constants).
601 * @param mixed $value Value to be saved for $option. If null set to default.
602 *
603 * @since 1.0.0
604 *
605 */
606 public static function set_option( $option, $value = null ) {
607
608 try {
609
610 if ( is_null( $value ) ) {
611 $option_value = $option[1]; // Set option to default.
612 } else {
613 $option_value = $value; // Set option value.
614 }
615
616 update_option( $option[0], $option_value ); // Save option value in wp_options.
617
618 self::$option_cache[ $option[0] ] = $option_value; // Save for re-use.
619
620 } catch ( \Exception $e ) {
621
622 die( 'ERROR: ' . esc_html( $e->errorMessage() ) );
623
624 }
625
626 }
627
628 /**
629 * Simplify data type for simple forms
630 *
631 * Data types used in plugin a re simplified for simple form usage.
632 *
633 * @param string $arg Data type as known to the MySQL database.
634 *
635 * @return string Simplified data type (mainly used to recognize when to use quotes).
636 * @since 1.0.0
637 *
638 * @see \WPDataAccess\Simple_Form\WPDA_Simple_Form
639 *
640 */
641 public static function get_type( $arg ) {
642 $type = trim( str_replace( 'unsigned', '', $arg ) );
643 if ( false !== ( $index = strpos( $type, '(' ) ) ) {
644 $type = substr( $type, 0, $index );
645 }
646 switch ( $type ) {
647 case 'tinyint':
648 case 'smallint':
649 case 'mediumint':
650 case 'int':
651 case 'bigint':
652 case 'float':
653 case 'double':
654 case 'decimal':
655 case 'year':
656 return 'number';
657 case 'date':
658 case 'datetime':
659 case 'timestamp':
660 return 'date';
661 case 'time':
662 return 'time';
663 case 'enum':
664 return 'enum';
665 case 'set':
666 return 'set';
667 default:
668 return 'string';
669 }
670 }
671
672 public static function get_sb_type( $arg ) {
673 $type = trim( str_replace( 'unsigned', '', $arg ) );
674 if ( false !== ( $index = strpos( $type, '(' ) ) ) {
675 $type = substr( $type, 0, $index );
676 }
677 switch ( $type ) {
678 case 'tinyint':
679 case 'smallint':
680 case 'mediumint':
681 case 'int':
682 case 'bigint':
683 case 'float':
684 case 'double':
685 case 'decimal':
686 case 'year':
687 return 'num';
688 case 'date':
689 case 'datetime':
690 case 'timestamp':
691 return 'date';
692 default:
693 return 'string';
694 }
695 }
696
697 /**
698 * Insert a value or key/value pair after a specific key in an array. If key doesn't exist, value is appended
699 * to the end of the array.
700 *
701 * Source: https://gist.github.com/wpscholar/0deadce1bbfa4adb4e4c
702 *
703 * @param array $array
704 * @param string $key
705 * @param array $new
706 *
707 * @return array
708 */
709 public static function array_insert_after( $array, $key, $new ) {
710 $keys = array_keys( $array );
711 $index = array_search( $key, $keys );
712 $pos = false === $index ? count( $array ) : $index + 1;
713
714 return array_merge( array_slice( $array, 0, $pos ), $new, array_slice( $array, $pos ) );
715 }
716
717 /**
718 * Log a message in the database
719 *
720 * Use this method to log messages to the database.
721 *
722 * NOTE Don't use $wpdb->insert! You'll miss a lot of information...
723 *
724 * @param $log_id string Id to identify/find logged data.
725 * @param $log_type string Possible values: 'FATAL', 'ERROR', 'WARN', 'INFO', 'DEBUG', 'TRACE'
726 * @param $log_msg string Any text (max length 4096kb).
727 *
728 * @since 2.0.7
729 *
730 */
731 public static function log( $log_id, $log_type, $log_msg ) {
732 global $wpdb;
733
734 $sql =
735 $wpdb->prepare(
736 'INSERT INTO ' . $wpdb->prefix .
737 'wpda_logging (log_time, log_id, log_type, log_msg) VALUES (now(), %s, %s, %s)'
738 , $log_id
739 , $log_type
740 , $log_msg
741 );
742 $wpdb->query( $sql );
743
744 }
745
746 /**
747 * Get user role
748 *
749 * @return mixed Current user roles or FALSE if not logged in.
750 * @since 2.0.8
751 *
752 */
753 public static function get_current_user_roles() {
754 if ( is_user_logged_in() ) {
755 $user = wp_get_current_user();
756 if ( ! is_array( $user->roles ) ) {
757 return ( array ) $user->roles;
758 } else {
759 return $user->roles;
760 }
761 } else {
762 return false;
763 }
764 }
765
766 /**
767 * Get user capability
768 *
769 * @return mixed Current users first capability or FALSE if not logged in.
770 * @since 2.0.8
771 *
772 */
773 public static function get_current_user_capability() {
774 if ( is_user_logged_in() ) {
775 $user = wp_get_current_user();
776 $allcaps = [];
777 foreach ( $user->allcaps as $key => $val ) {
778 array_push( $allcaps, $key );
779 }
780
781 return $allcaps[0];
782 } else {
783 return false;
784 }
785 }
786
787 /**
788 * Convert memory value to integer.
789 *
790 * @param $memory_value string Memory value (eg 128M)
791 *
792 * @return integer Converted value in decimal
793 * @since 2.0.8
794 *
795 */
796 public static function convert_memory_to_decimal( $memory_value ) {
797 if ( preg_match( '/^(\d+)(.)$/', $memory_value, $matches ) ) {
798 if ( $matches[2] == 'G' ) {
799 return $matches[1] * 1024 * 1024 * 1024;
800 } else if ( $matches[2] == 'M' ) {
801 return $matches[1] * 1024 * 1024;
802 } else if ( $matches[2] == 'K' ) {
803 return $matches[1] * 1024;
804 }
805 }
806 }
807
808 public static function get_current_user_id( $is_anonymous = false ) {
809 if ( $is_anonymous ) {
810 return -1;
811 }
812
813 global $current_user;
814 if ( isset( $current_user->ID ) ) {
815 return $current_user->ID;
816 } else {
817 if ( function_exists('wp_get_current_user') ) {
818 $wp_user = wp_get_current_user();
819 if ( isset( $wp_user->ID ) ) {
820 return $wp_user->ID;
821 } else {
822 return - 1;
823 }
824 } else {
825 return - 1;
826 }
827 }
828 }
829
830 public static function get_current_user_login() {
831 global $current_user;
832 if ( isset( $current_user->user_login ) ) {
833 return $current_user->user_login;
834 } else {
835 if ( function_exists('wp_get_current_user') ) {
836 $wp_user = wp_get_current_user();
837 if ( isset( $wp_user->data->user_login ) ) {
838 return $wp_user->data->user_login;
839 } else {
840 return 'anonymous';
841 }
842 } else {
843 return 'anonymous';
844 }
845 }
846 }
847
848 public static function get_current_user_email() {
849 global $current_user;
850 if ( isset( $current_user->user_email ) ) {
851 return $current_user->user_email;
852 } else {
853 $wp_user = wp_get_current_user();
854 if ( isset( $wp_user->data->user_email ) ) {
855 return $wp_user->data->user_email;
856 } else {
857 return 'anonymous';
858 }
859 }
860 }
861
862 /**
863 * Replaces environment variables in where clause with appropriate values
864 *
865 * @param $where_clause
866 *
867 * @return string
868 */
869 public static function substitute_environment_vars( $where_clause ) {
870 if ( strpos( $where_clause, '$$USERID$$' ) ) {
871 $user_id = WPDA::get_current_user_id();
872 $where_clause = str_replace( '$$USERID$$', $user_id, $where_clause );
873 }
874
875 if ( strpos( $where_clause, '$$USER$$' ) ) {
876 $user_login = WPDA::get_current_user_login();
877 $where_clause = str_replace( '$$USER$$', "'" . $user_login . "'", $where_clause );
878 }
879
880 if ( strpos( $where_clause, '$$EMAIL$$' ) ) {
881 $user_email = WPDA::get_current_user_email();
882 $where_clause = str_replace( '$$EMAIL$$', $user_email, $where_clause );
883 }
884
885 return $where_clause;
886 }
887
888 /**
889 * Where clause construction (use filter if applied)
890 *
891 * Param $columns = associative array containing the following column info taken from the data dictionary:
892 * $columns['column_name'] => information_schema.tables.column_name
893 * $columns['data_type'] => information_schema.tables.data_type
894 * $columns['extra'] => information_schema.tables.extra
895 * $columns['column_type' => information_schema.tables.column_type
896 * $columns['is_nullable' => information_schema.tables.is_nullable
897 * $columns['column_default'] => information_schema.tables.column_default
898 *
899 * @param string $schema_name Schema name (optional)
900 * @param string $table_name Table name (optional)
901 * @param string $columns Array containing table columns
902 * @param string $search Search string entered by user
903 *
904 * @return string Where clause between ()
905 */
906 public static function construct_where_clause( $schema_name, $table_name, $columns, $search ) {
907 $where_search_args = self::add_wpda_search_args( $columns );
908
909 if ( has_filter('wpda_construct_where_clause') ) {
910 global $wpda_search_args;
911 $wpda_search_args = $where_search_args;
912
913 // Use search filter
914 $filter = apply_filters(
915 'wpda_construct_where_clause',
916 '',
917 $schema_name,
918 $table_name,
919 $columns,
920 $search
921 );
922 if ( null !== $filter ) {
923 if ( '' === $where_search_args ) {
924 return $filter;
925 } else {
926 if ( '' === $filter ) {
927 return $where_search_args;
928 } else {
929 return "{$filter} and {$where_search_args}";
930 }
931 }
932 }
933 }
934
935 // Default search behaviour
936 if ( '' === $search || null === $search || ! is_array( $columns ) ) {
937 return $where_search_args;
938 }
939
940 global $wpdb;
941 $where_columns = [];
942
943 foreach ( $columns as $column ) {
944 if ( 'string' === WPDA::get_type( $column['data_type'] ) ) {
945 $where_columns[] = $wpdb->prepare( "`" . str_replace( '`', '', $column['column_name'] ) . "` like '%s'", '%' . esc_sql( $search ) . '%' ); // phpcs:ignore Standard.Category.SniffName.ErrorCode
946 }
947 }
948
949 if ( 0 === count( $where_columns ) ) {
950 return '' === $where_search_args ? ' (1=2) ' : $where_search_args;
951 }
952
953 if ( '' === $where_search_args ) {
954 return ' (' . implode( ' or ', $where_columns ) . ') ';
955 } else {
956 return ' (' . implode( ' or ', $where_columns ) . ') ' . "and {$where_search_args}";
957 }
958 }
959
960 public static function add_wpda_search_args( $columns ) {
961 $where_columns = [];
962
963 if ( is_array( $columns ) ) {
964 global $wpdb;
965 $request = array_change_key_case( $_REQUEST );
966 foreach ( $columns as $column ) {
967 $column_name = str_replace( '`', '', $column['column_name'] );
968 $column_name_lwr = strtolower( $column_name );
969 if ( isset( $request["wpda_search_column_{$column_name_lwr}"] ) ) {
970 if ( is_array( $request["wpda_search_column_{$column_name_lwr}"] ) ) {
971 // Handle multiple values for same column with OR
972 $where_columns_arr = [];
973 foreach ( $request["wpda_search_column_{$column_name_lwr}"] as $value ) {
974 $column_date_type = $column['data_type'];
975 $column_value = wp_strip_all_tags( wp_unslash( $value ) ); // input var okay.
976 if ( '' !== $column_value ) {
977 if ( 'string' === WPDA::get_type( $column_date_type ) ) {
978 $where_columns_arr[] = $wpdb->prepare( "`{$column_name}` like '%s'", esc_sql( $column_value ) ); // phpcs:ignore Standard.Category.SniffName.ErrorCode
979 } elseif ( 'number' === WPDA::get_type( $column_date_type ) ) {
980 $where_columns_arr[] = $wpdb->prepare( "`{$column_name}` = '%d'", esc_sql( $column_value ) ); // phpcs:ignore Standard.Category.SniffName.ErrorCode
981 }
982 }
983 }
984 if ( sizeof( $where_columns_arr ) > 0 ) {
985 $where_columns[] = ' (' . implode( ' or ', $where_columns_arr ) . ') ';
986 }
987 } else {
988 // Handle single value
989 $column_date_type = $column['data_type'];
990 $column_value = wp_strip_all_tags( wp_unslash( $request[ "wpda_search_column_{$column_name_lwr}" ] ) );
991 if ( '' !== $column_value ) {
992 if ( 'string' === WPDA::get_type( $column_date_type ) ) {
993 $where_columns[] = $wpdb->prepare( "`{$column_name}` like '%s'", esc_sql( $column_value ) ); // phpcs:ignore Standard.Category.SniffName.ErrorCode
994 } elseif ( 'number' === WPDA::get_type( $column_date_type ) ) {
995 $where_columns[] = $wpdb->prepare( "`{$column_name}` = '%d'", esc_sql( $column_value ) ); // phpcs:ignore Standard.Category.SniffName.ErrorCode
996 }
997 }
998 }
999 }
1000 }
1001 }
1002
1003 if ( 0 === count( $where_columns ) ) {
1004 return '';
1005 } else {
1006 $operator =
1007 isset( $_REQUEST['wpda_search_column_operator'] ) &&
1008 'or' === strtolower( $_REQUEST['wpda_search_column_operator'] )
1009 ? 'or' : 'and';
1010 return ' (' . implode( " $operator ", $where_columns ) . ') ';
1011 }
1012 }
1013
1014 public static function schema_disabled( $schema_name ) {
1015 if ( 'rdb:' === substr( $schema_name, 0, 4) ) {
1016 $rdb = WPDADB::get_remote_database( $schema_name, true );
1017 if ( false === $rdb ) {
1018 return false;
1019 }
1020 return true === $rdb[ 'disabled' ];
1021 }
1022 return false;
1023 }
1024
1025 /**
1026 * Check if database schema exists (local and remote databases)
1027 *
1028 * @param string $schema_name Database schema
1029 *
1030 * @return bool Exists?
1031 */
1032 public static function schema_exists( $schema_name ) {
1033 if ( self::schema_disabled( $schema_name ) ) {
1034 return false;
1035 }
1036
1037 $wpdadb = WPDADB::get_db_connection( $schema_name );
1038 if ( null === $wpdadb ) {
1039 return false;
1040 }
1041 if ( method_exists( $wpdadb, 'is_connected' ) ) {
1042 if ( ! $wpdadb->is_connected() ) {
1043 $msg = new WPDA_Message_Box(
1044 [
1045 'message_text' => __( "Remote database '{$schema_name}' not available [check connection: Settings > WP Data Access]", 'wp-data-access' ),
1046 'message_type' => 'error',
1047 'message_is_dismissible' => false,
1048 ]
1049 );
1050 $msg->box();
1051
1052 return false;
1053 }
1054 }
1055
1056 $wpdadb->query(
1057 $wpdadb->prepare( '
1058 SELECT TRUE FROM information_schema.schemata WHERE schema_name = %s
1059 ',
1060 [
1061 $wpdadb->dbname,
1062 ]
1063 )
1064 ); // db call ok; no-cache ok.
1065 $wpdadb->get_results(); // phpcs:ignore Standard.Category.SniffName.ErrorCode
1066
1067 return 1 === $wpdadb->num_rows;
1068 }
1069
1070 public static function get_user_default_scheme() {
1071 $default_databases = get_option('wpda_default_database');
1072 if ( false !== $default_databases ) {
1073 $user_id = get_current_user_id();
1074 if (
1075 $user_id > 0 &&
1076 isset( $default_databases[ $user_id ] ) &&
1077 self::schema_exists( $default_databases[ $user_id ] )
1078 ) {
1079 return $default_databases[ $user_id ];
1080 }
1081 }
1082
1083 global $wpdb;
1084 return $wpdb->dbname;
1085 }
1086
1087 public static function shortcode_popup() {
1088 ?>
1089 <script type="text/javascript">
1090 jQuery(function() {
1091 var clipboard = new ClipboardJS('.wpda_shortcode_clipboard');
1092 });
1093 </script>
1094 <style type="text/css">
1095 .wpda_shortcode_text {
1096 text-align: center;
1097 font-size: 105%;
1098 white-space: nowrap;
1099 }
1100 .wpda_shortcode_buttons {
1101 text-align: center;
1102 }
1103 .button.wpda_shortcode_button {
1104 width: 100px !important;
1105 }
1106 .wpda_shortcode_link {
1107 text-decoration: none;
1108 font-weight: bold;
1109 }
1110 </style>
1111 <?php
1112 }
1113
1114 public static function is_editing_post() {
1115 global $pagenow;
1116 if ( $pagenow === 'post.php' || $pagenow === 'edit.php' || $pagenow === 'post-new.php' ) {
1117 // Editing post in classic editor
1118 return '';
1119 }
1120
1121 if ( isset( $_SERVER["CONTENT_TYPE"] ) && 'application/json' === $_SERVER["CONTENT_TYPE"] ) {
1122 // Editing post in Gutenberg editor
1123 return null;
1124 }
1125
1126 return false;
1127 }
1128
1129 /**
1130 * Get all available post types.
1131 *
1132 * @return array
1133 */
1134 public static function get_post_types() {
1135 global $wpdb;
1136 $rows = $wpdb->get_results(
1137 "select distinct post_type from {$wpdb->posts}",
1138 'ARRAY_N'
1139 );
1140
1141 $cpts = [];
1142 foreach ( $rows as $row ) {
1143 $cpts[] = $row[0];
1144 }
1145
1146 return $cpts;
1147 }
1148
1149 public static function get_table_engine( $schema_name, $table_name ) {
1150 $table_info = WPDA::get_table_values( $schema_name, $table_name );
1151 return (
1152 1 === sizeof( $table_info ) &&
1153 'connect' === strtolower( $table_info[0]['engine'] )
1154 ) ? 'connect' : '';
1155 }
1156
1157 public static function get_table_values( $schema_name, $table_name ) {
1158 $wpdadb = WPDADB::get_db_connection( $schema_name );
1159 return $wpdadb->get_results(
1160 $wpdadb->prepare(
1161 "
1162 select engine as engine,
1163 table_rows as table_rows,
1164 table_type as table_type
1165 from information_schema.tables
1166 where table_schema = %s
1167 and table_name = %s
1168 ",
1169 [
1170 $wpdadb->dbname,
1171 $table_name
1172 ]
1173 ),
1174 'ARRAY_A'
1175 );
1176 }
1177
1178 /**
1179 * Get estimated number of rows in a table
1180 *
1181 * @param $schema_name Schema name
1182 * @param $table_name Table name
1183 * @param $wpda_table_settings Table settings (query WPDA_Table_Settings_Model)
1184 *
1185 * @return int row count estimate or -1 if no estimate available
1186 */
1187 public static function get_row_count_estimate( $schema_name, $table_name, $wpda_table_settings ) {
1188 $row_count = null;
1189 $is_estimate = null;
1190 $do_real_count = null;
1191 $table_info = self::get_table_values( $schema_name, $table_name );
1192 if ( 1 === sizeof( $table_info ) ) {
1193 $row_count = $table_info[0]['table_rows'];
1194
1195 $system_row_count_estimate = null;
1196 $row_count_estimate_value = null;
1197 $row_count_estimate_value_hard = null;
1198
1199 if ( isset( $wpda_table_settings->table_settings->row_count_estimate ) ) {
1200 $system_row_count_estimate = $wpda_table_settings->table_settings->row_count_estimate;
1201 }
1202
1203 if ( isset( $wpda_table_settings->table_settings->row_count_estimate_value ) ) {
1204 $row_count_estimate_value = $wpda_table_settings->table_settings->row_count_estimate_value;
1205 }
1206 if ( isset( $wpda_table_settings->table_settings->row_count_estimate_value_hard ) ) {
1207 $row_count_estimate_value_hard = $wpda_table_settings->table_settings->row_count_estimate_value_hard;
1208 }
1209
1210 if (
1211 'federated' === strtolower( $table_info[0]['engine'] ) ||
1212 'innodb' === strtolower( $table_info[0]['engine'] ) ||
1213 stripos( strtolower( $table_info[0]['table_type'] ), 'view' ) !== false
1214 ) {
1215 // Handle InnoDB tables, views and system views
1216 $wpdadb = WPDADB::get_db_connection( $schema_name );
1217 $view_explain = $wpdadb->get_results(
1218 'explain select count(*) from `' . str_replace( '`', '', $table_name ) . '`',
1219 'ARRAY_A'
1220 );
1221
1222 if ( isset( $view_explain[0]['rows'] ) ) {
1223 $row_count = $view_explain[0]['rows'];
1224 } elseif ( isset( $view_explain[0]['ROWS'] ) ) {
1225 $row_count = $view_explain[0]['ROWS'];
1226 }
1227
1228 if ( true === $system_row_count_estimate ) {
1229 if ( 'hard' === $row_count_estimate_value && null !== $row_count_estimate_value_hard ) {
1230 $row_count = $row_count_estimate_value_hard;
1231 }
1232 $is_estimate = true;
1233 $do_real_count = false;
1234 } elseif ( false === $system_row_count_estimate ) {
1235 $is_estimate = false;
1236 $do_real_count = true;
1237 } else {
1238 if ( intval( $row_count ) > intval( WPDA::get_option( WPDA::OPTION_BE_INNODB_COUNT ) ) ) {
1239 $is_estimate = true;
1240 $do_real_count = false;
1241 } else {
1242 $is_estimate = false;
1243 $do_real_count = true;
1244 }
1245 }
1246 } elseif ( 'connect' === strtolower( $table_info[0]['engine'] ) ) {
1247 $getpk = WPDA_List_Columns_Cache::get_list_columns( $schema_name, $table_name );
1248 $pk = $getpk->get_table_primary_key();
1249 if ( is_array( $pk ) && sizeof( $pk ) > 0 ) {
1250 $sql_rowcount_sql =
1251 'select count(*) from `' . str_replace( '`', '', $table_name ) .
1252 '` where `' . $pk[0] . '` not in ' .
1253 '(select null from `' . str_replace( '`', '', $table_name ) . '` where 1=2)';
1254 $wpdadb = WPDADB::get_db_connection( $schema_name );
1255 $sql_rowcount = $wpdadb->get_results( $sql_rowcount_sql, 'ARRAY_N' );
1256 if ( sizeof( $sql_rowcount ) === 1 ) {
1257 $row_count = $sql_rowcount[0][0];
1258 $is_estimate = false;
1259 $do_real_count = false;
1260 } else {
1261 $is_estimate = false;
1262 $do_real_count = true;
1263 }
1264 } else {
1265 $is_estimate = false;
1266 $do_real_count = true;
1267 }
1268 } else {
1269 // Handle other table types (MyISAM and NDB)
1270 $is_estimate = false;
1271 $do_real_count = false;
1272 }
1273 }
1274
1275 return [
1276 'row_count' => $row_count,
1277 'is_estimate' => $is_estimate,
1278 'do_real_count' => $do_real_count
1279 ];
1280 }
1281
1282 public static function validate_names( $schema_name, $table_name, $column_names = null ) {
1283 if ( ! self::validate_name( $table_name ) ) {
1284 return self::validate_name_failed();
1285 }
1286
1287 if ( 'rdb:' === substr( $schema_name, 0, 4 ) ) {
1288 $wpdadb = WPDADB::get_db_connection( $schema_name );
1289 if ( $wpdadb === null ) {
1290 return self::validate_name_np();
1291 } else {
1292 if ( ! self::validate_name( $wpdadb->dbname ) ) {
1293 return self::validate_name_failed();
1294 }
1295 }
1296 } else {
1297 // Added prefix to schema validation: allowing database names to start with a number
1298 if ( ! self::validate_name( 'prefix_' . $schema_name ) ) {
1299 return self::validate_name_failed();
1300 }
1301 }
1302
1303 if ( null === $column_names ) {
1304 $columns = WPDA_Dictionary_Lists::get_table_columns( $table_name, $schema_name );
1305 $column_names = array_column( $columns, 'column_name' );
1306 }
1307 if ( sizeof( $column_names ) === 0 ) {
1308 return self::validate_name_np();
1309 }
1310
1311 $is_valid = true;
1312 foreach ( $column_names as $column_name ) {
1313 if ( ! self::validate_name( $column_name ) ) {
1314 $is_valid = false;
1315 break;
1316 }
1317 }
1318
1319 return $is_valid ? '' : self::validate_name_failed();
1320 }
1321
1322 public static function validate_name( $item_name ) {
1323 if (
1324 ! ctype_alpha( substr( $item_name, 0, 1 ) ) ||
1325 ! preg_match("/^[_a-zA-Z0-9]+$/", $item_name)
1326 ){
1327 return false;
1328 }
1329
1330 return true;
1331 }
1332
1333 public static function validate_name_failed() {
1334 $title = __( 'Schema, table or column name(s) restricting plugin features (click to read more and fix)', 'wp-data-access' );
1335 $warning = "
1336 <a href='https://wpdataaccess.com/docs/documentation/data-explorer/naming-conventions/' target='_blank' style='text-decoration:none'>
1337 <span class='dashicons dashicons-flag wpda_tooltip' style='color:red;padding-left:5px' title='$title'></span>
1338 </a>";
1339 return $warning;
1340 }
1341
1342 public static function validate_name_np() {
1343 $title = __( 'Schema, table or column name validation not possible (click to read more and fix)', 'wp-data-access' );
1344 $warning = "
1345 <a href='https://wpdataaccess.com/docs/documentation/data-explorer/naming-conventions/' target='_blank'>
1346 <span class='dashicons dashicons-warning wpda_tooltip' style='padding-left:5px' title='$title'></span>
1347 </a>";
1348 return $warning;
1349 }
1350
1351 public static function get_dbms_var( $var_name = null, $schema_name = null ) {
1352 if ( null === $schema_name ) {
1353 global $wpdb;
1354 $wpdadb = $wpdb;
1355 } else {
1356 $wpdadb = WPDADB::get_db_connection( $schema_name );
1357 }
1358
1359 if ( null === $wpdadb ) {
1360 return null;
1361 }
1362
1363 if ( null !== $var_name ) {
1364 $var_value = $wpdadb->get_results( "SHOW VARIABLES LIKE '$var_name'", 'ARRAY_N' );
1365 if ( is_array( $var_value ) && isset( $var_value[0][1] ) ) {
1366 return $var_value[0][1];
1367 } else {
1368 return null;
1369 }
1370 } else {
1371 return $wpdadb->get_results( 'SHOW VARIABLES', 'ARRAY_N' );
1372 }
1373 }
1374
1375 public static function get_dbms_global( $global_name = null, $schema_name = null ) {
1376 if ( null === $schema_name ) {
1377 global $wpdb;
1378 $wpdadb = $wpdb;
1379 } else {
1380 $wpdadb = WPDADB::get_db_connection( $schema_name );
1381 }
1382
1383 if ( null === $wpdadb ) {
1384 return null;
1385 }
1386
1387 if ( null !== $global_name ) {
1388 $global_value = $wpdadb->get_results( "SHOW GLOBAL STATUS LIKE '$global_name'", 'ARRAY_N' );
1389 if ( is_array( $global_value ) && isset( $global_value[0][1] ) ) {
1390 return $global_value[0][1];
1391 } else {
1392 return null;
1393 }
1394 } else {
1395 return $wpdadb->get_results( 'SHOW GLOBAL STATUS', 'ARRAY_N' );
1396 }
1397 }
1398
1399 public static function secondsToTime( $seconds ) {
1400 $dtF = new \DateTime('@0');
1401 $dtT = new \DateTime("@$seconds");
1402 return $dtF->diff( $dtT )->format('%a days, %h hours, %i minutes and %s seconds');
1403 }
1404
1405 public static function get_sonce_token() {
1406 $encrypt_method = 'AES-256-CBC';
1407 $key = hash( 'sha256', WPDA::get_option( WPDA::OPTION_PLUGIN_SECRET_KEY ) );
1408 $iv = substr( hash( 'sha256', WPDA::get_option( WPDA::OPTION_PLUGIN_SECRET_IV ) ), 0, 16 );
1409
1410 return base64_encode( openssl_encrypt( WPDA::get_option( WPDA::OPTION_PLUGIN_SONCE_SEED ) . $_SERVER['REMOTE_ADDR'], $encrypt_method, $key, 0, $iv ) );
1411 }
1412
1413 public static function wpda_create_sonce( $action = 'undefined' ) {
1414 $token = self::get_sonce_token();
1415 $i = wp_nonce_tick();
1416
1417 return substr( wp_hash( $i . '|' . $action . '|' . $token, 'nonce' ), -12, 10 );
1418 }
1419
1420 public static function wpda_verify_sonce( $sonce, $action = 'undefined' ) {
1421 $expected = WPDA::wpda_create_sonce($action);
1422
1423 return hash_equals( $expected , $sonce );
1424 }
1425
1426 public static function get_plugin_upload_dir() {
1427 $uploads = wp_upload_dir();
1428
1429 return $uploads['basedir'] . DIRECTORY_SEPARATOR . 'wp-data-access' . DIRECTORY_SEPARATOR;
1430 }
1431
1432 public static function wpda_create_content_folder() {
1433 $upload_dir = WPDA::get_plugin_upload_dir();
1434 if ( ! file_exists( $upload_dir ) ) {
1435 mkdir( $upload_dir, 0755, true );
1436
1437 $fw = fopen( $upload_dir . ".htaccess", 'w' );
1438 if ( false !== $fw ) {
1439 fwrite( $fw, "IndexIgnore *" );
1440 }
1441 fclose( $fw );
1442 }
1443 }
1444
1445 public static function wpda_delete_content_folder() {
1446 $upload_dir = WPDA::get_plugin_upload_dir();
1447 if ( file_exists( $upload_dir ) ) {
1448 $files = glob( $upload_dir . '*', GLOB_MARK );
1449 foreach ( $files as $file ) {
1450 unlink( $file );
1451 }
1452 unlink( $upload_dir . '.htaccess' );
1453
1454 rmdir( $upload_dir );
1455 }
1456 }
1457
1458 public static function sent_header( $content_type, $cors = null, $attachment = null ) {
1459 if ( null !== $cors ) {
1460 header( "Access-Control-Allow-Origin: {$cors}" );
1461 }
1462
1463 if ( null !== $attachment ) {
1464 header("Content-Disposition: attachment; filename={$attachment}");
1465 }
1466
1467 header( "Content-type: {$content_type}" );
1468 header( 'Cache-Control: no-store, no-cache, must-revalidate, max-age=0' );
1469 header( 'Cache-Control: post-check=0, pre-check=0', false );
1470 header( 'Pragma: no-cache' );
1471 header( 'Expires: 0' );
1472 }
1473
1474 public static function sent_msg( $status, $msg ) {
1475 echo json_encode(
1476 array(
1477 'status' => $status,
1478 'msg' => $msg,
1479 )
1480 ); // phpcs:ignore
1481 }
1482
1483 public static function is_post() {
1484 global $post;
1485 return 'post' === get_post_type( $post );
1486 }
1487
1488 public static function is_page() {
1489 global $post;
1490 return 'page' === get_post_type( $post );
1491 }
1492
1493 public static function can_manage() {
1494 $user_id = get_current_user_id();
1495
1496 $wpda_hide_manage_link = get_option( 'wpda_hide_manage_link' );
1497 if ( is_array( $wpda_hide_manage_link ) ) {
1498 $wpda_hide_manage_list = array_flip( $wpda_hide_manage_link );
1499 } else {
1500 $wpda_hide_manage_list = [];
1501 }
1502
1503 return ! isset( $wpda_hide_manage_list[ $user_id ] );
1504 }
1505
1506 /**
1507 * Remove backticks from string
1508 *
1509 * @param string $s Subject.
1510 * @return array|string|string[]
1511 */
1512 public static function remove_backticks( $s ) {
1513 return str_replace( '`', '', $s );
1514 }
1515
1516 /**
1517 * Sanitize array:
1518 * uses sanitize_text_field on all array elements
1519 * supports multi dimensional arrays
1520 *
1521 * @param mixed $input Any value (initial value is supposed to be an array).
1522 * @return array|mixed
1523 */
1524 public static function sanitize_text_field_array( $input ) {
1525 return
1526 is_array( $input ) ?
1527 array_map( array( WPDA::class, 'sanitize_text_field_array' ), $input ) :
1528 ( is_scalar( $input ) ? sanitize_text_field( wp_unslash( $input ) ) : $input );
1529 }
1530
1531 }
1532
1533 }
1534