PluginProbe
WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards / 5.5.79
WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards v5.5.79
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 / Connection / WPDADB.php

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

535 lines 17.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Suppress "error - 0 - No summary was found for this file" on phpdoc generation
4 *
5 * @package WPDataAccess\Connection
6 */
7
8 namespace WPDataAccess\Connection {
9
10 use WPDataAccess\Data_Dictionary\WPDA_Dictionary_Exist;
11 use WPDataAccess\WPDA;
12
13 /**
14 * Class WPDADB
15 *
16 * Manage local and remote database connections.
17 *
18 * @author Peter Schulz
19 * @since 3.0.0
20 */
21 class WPDADB {
22
23 /**
24 * Database connections cached per database name (schema_name)
25 *
26 * Remote database are prefixed with "rdb:"
27 *
28 * @var array
29 */
30 protected static $db_connections = array();
31
32 /**
33 * Remote database access definitions
34 *
35 * @var array|bool
36 */
37 protected static $remote_databases = false;
38
39 /**
40 * Stores te lower_case_table_names db value
41 *
42 * @var null|int
43 */
44 protected static $lower_case_table_names = null;
45
46 /**
47 * Encrypt a string with the WPDA secret key and iv
48 *
49 * @param string $string String to be encrypted.
50 *
51 * @return string
52 */
53 public static function string_encrypt( $string ) {
54 $secret_key = WPDA::get_option( WPDA::OPTION_PLUGIN_SECRET_KEY );
55 $secret_iv = WPDA::get_option( WPDA::OPTION_PLUGIN_SECRET_IV );
56
57 $encrypt_method = 'AES-256-CBC';
58 $key = hash( 'sha256', $secret_key );
59 $iv = substr( hash( 'sha256', $secret_iv ), 0, 16 );
60
61 return base64_encode( openssl_encrypt( $string, $encrypt_method, $key, 0, $iv ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
62 }
63
64 /**
65 * Decrypt a string with the WPDA secret key and iv
66 *
67 * @param string $string String to be decrypted.
68 *
69 * @return string
70 */
71 public static function string_decrypt( $string ) {
72 $secret_key = WPDA::get_option( WPDA::OPTION_PLUGIN_SECRET_KEY );
73 $secret_iv = WPDA::get_option( WPDA::OPTION_PLUGIN_SECRET_IV );
74
75 $encrypt_method = 'AES-256-CBC';
76 $key = hash( 'sha256', $secret_key );
77 $iv = substr( hash( 'sha256', $secret_iv ), 0, 16 );
78
79 return openssl_decrypt( base64_decode( $string ), $encrypt_method, $key, 0, $iv ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
80 }
81
82 /**
83 * Load remote database connections into memory
84 *
85 * @return void
86 */
87 public static function load_remote_databases() {
88 if ( false === self::$remote_databases ) {
89 $decrypted_databases = array();
90 $encrypted_databases = get_option( 'wpda_remote_databases' );
91 if ( false !== $encrypted_databases ) {
92 foreach ( $encrypted_databases as $key => $val ) {
93 $no_pds = !wpda_freemius()->can_use_premium_code() &&
94 self::string_decrypt( $val[0] ) === 'wpdafree.youniquedata.com';
95
96 if ( ! $no_pds ) {
97 $decrypted_databases[ self::string_decrypt( $key ) ] = array(
98 'host' => self::string_decrypt( $val[0] ),
99 'username' => self::string_decrypt( $val[1] ),
100 'password' => self::string_decrypt( $val[2] ),
101 'port' => self::string_decrypt( $val[3] ),
102 'database' => self::string_decrypt( $val[4] ),
103 'disabled' => $val[5],
104 'ssl' => isset( $val[6] ) ? self::string_decrypt( $val[6] ) : 'off',
105 'ssl_key' => isset( $val[7] ) ? self::string_decrypt( $val[7] ) : '',
106 'ssl_cert' => isset( $val[8] ) ? self::string_decrypt( $val[8] ) : '',
107 'ssl_ca' => isset( $val[9] ) ? self::string_decrypt( $val[9] ) : '',
108 'ssl_path' => isset( $val[10] ) ? self::string_decrypt( $val[10] ) : '',
109 'ssl_cipher' => isset( $val[11] ) ? self::string_decrypt( $val[11] ) : '',
110 );
111 }
112 }
113 }
114 self::$remote_databases = $decrypted_databases;
115 }
116 }
117
118 /**
119 * Save remote database connections
120 *
121 * @return void
122 */
123 public static function save_remote_databases() {
124 self::load_remote_databases();
125
126 $encrypted_databases = array();
127 foreach ( self::$remote_databases as $key => $val ) {
128 $encrypted_databases[ self::string_encrypt( $key ) ] = array(
129 0 => self::string_encrypt( $val['host'] ),
130 1 => self::string_encrypt( $val['username'] ),
131 2 => self::string_encrypt( $val['password'] ),
132 3 => self::string_encrypt( $val['port'] ),
133 4 => self::string_encrypt( $val['database'] ),
134 5 => $val['disabled'],
135 6 => isset( $val['ssl'] ) ? self::string_encrypt( $val['ssl'] ) : 'off',
136 7 => isset( $val['ssl_key'] ) ? self::string_encrypt( $val['ssl_key'] ) : '',
137 8 => isset( $val['ssl_cert'] ) ? self::string_encrypt( $val['ssl_cert'] ) : '',
138 9 => isset( $val['ssl_ca'] ) ? self::string_encrypt( $val['ssl_ca'] ) : '',
139 10 => isset( $val['ssl_path'] ) ? self::string_encrypt( $val['ssl_path'] ) : '',
140 11 => isset( $val['ssl_cipher'] ) ? self::string_encrypt( $val['ssl_cipher'] ) : '',
141 );
142 }
143 update_option( 'wpda_remote_databases', $encrypted_databases );
144 }
145
146 /**
147 * Get all available remote databas econnections
148 *
149 * @param boolean $include_disabled Include disabled remote connections.
150 * @return array|bool
151 */
152 public static function get_remote_databases( $include_disabled = false ) {
153 self::load_remote_databases();
154
155 if ( $include_disabled ) {
156 return self::$remote_databases;
157 } else {
158 $exclude_disabled = self::$remote_databases;
159 foreach ( self::$remote_databases as $key => $remote_database ) {
160 if ( $remote_database['disabled'] ) {
161 unset( $exclude_disabled[ $key ] );
162 }
163 }
164 return $exclude_disabled;
165 }
166 }
167
168 /**
169 * Get one specific remote database connection
170 *
171 * @param string $database Remote database connection name.
172 * @param boolean $include_disabled Include disabled remote connections.
173 * @return false|mixed
174 */
175 public static function get_remote_database( $database, $include_disabled = false ) {
176 self::load_remote_databases();
177
178 if ( isset( self::$remote_databases[ $database ] ) ) {
179 if ( $include_disabled ) {
180 return self::$remote_databases[ $database ];
181 } else {
182 if ( ! self::$remote_databases[ $database ]['disabled'] ) {
183 return self::$remote_databases[ $database ];
184 } else {
185 return false;
186 }
187 }
188 } else {
189 return false;
190 }
191 }
192
193 /**
194 * Add remote database connection
195 *
196 * @param string $database Database name.
197 * @param string $host Host name.
198 * @param string $user User name.
199 * @param string $passwd Password.
200 * @param string $port Remote port.
201 * @param string $schema Database schema name.
202 * @param string $ssl SSL.
203 * @param string $ssl_key SSL key.
204 * @param string $ssl_cert SSL certificate.
205 * @param string $ssl_ca SSL CA.
206 * @param string $ssl_path SSL path.
207 * @param string $ssl_cipher SSL cipher.
208 * @return bool
209 */
210 public static function add_remote_database(
211 $database, $host, $user, $passwd, $port, $schema,
212 $ssl, $ssl_key, $ssl_cert, $ssl_ca, $ssl_path, $ssl_cipher
213 ) {
214 self::load_remote_databases();
215
216 if ( false === self::get_remote_database( $database ) ) {
217 self::$remote_databases[ $database ] = array(
218 'host' => $host,
219 'username' => $user,
220 'password' => $passwd,
221 'port' => $port,
222 'database' => $schema,
223 'disabled' => false,
224 'ssl' => $ssl,
225 'ssl_key' => $ssl_key,
226 'ssl_cert' => $ssl_cert,
227 'ssl_ca' => $ssl_ca,
228 'ssl_path' => $ssl_path,
229 'ssl_cipher' => $ssl_cipher,
230 );
231 self::save_remote_databases();
232
233 return true;
234 } else {
235 return false;
236 }
237 }
238
239 /**
240 * Delete remote database connection
241 *
242 * @param string $database Remote database connection name.
243 * @return bool
244 */
245 public static function del_remote_database( $database ) {
246 self::load_remote_databases();
247
248 if ( false === self::get_remote_database( $database, true ) ) {
249 return false;
250 } else {
251 unset( self::$remote_databases[ $database ] );
252 self::save_remote_databases();
253
254 return true;
255 }
256 }
257
258 /**
259 * Disable remote database connection
260 *
261 * @param string $database Remote database connection name.
262 * @return bool
263 */
264 public static function dis_remote_database( $database, $disabled ) {
265 self::load_remote_databases();
266
267 if ( false === self::get_remote_database( $database, true ) ) {
268 return false;
269 } else {
270 self::$remote_databases[ $database ]['disabled'] = $disabled;
271 self::save_remote_databases();
272
273 return true;
274 }
275 }
276
277 /**
278 * Update remote connection
279 *
280 * @param string $database Database name.
281 * @param string $host Host name.
282 * @param string $user User name.
283 * @param string $passwd Password.
284 * @param string $port Remote port.
285 * @param string $schema Database schema name.
286 * @param string $disabled Disabled.
287 * @param string $database_old Old remote database connection name.
288 * @param string $ssl SSL.
289 * @param string $ssl_key SSL key.
290 * @param string $ssl_cert SSL certificate.
291 * @param string $ssl_ca SSL CA.
292 * @param string $ssl_path SSL path.
293 * @param string $ssl_cipher SSL cipher.
294 * @return bool
295 */
296 public static function upd_remote_database(
297 $database, $host, $user, $passwd, $port, $schema, $disabled, $database_old,
298 $ssl, $ssl_key, $ssl_cert, $ssl_ca, $ssl_path, $ssl_cipher
299 ) {
300 self::load_remote_databases();
301
302 if ( false !== $database_old && $database !== $database_old ) {
303 self::add_remote_database(
304 $database,
305 $host,
306 $user,
307 $passwd,
308 $port,
309 $schema,
310 $ssl,
311 $ssl_key,
312 $ssl_cert,
313 $ssl_ca,
314 $ssl_path,
315 $ssl_cipher
316 );
317 self::del_remote_database( $database_old );
318
319 return true;
320 } else {
321 if ( false === self::get_remote_database( $database, true ) ) {
322 return false;
323 } else {
324 self::$remote_databases[ $database ] = array(
325 'host' => $host,
326 'username' => $user,
327 'password' => $passwd,
328 'port' => $port,
329 'database' => $schema,
330 'disabled' => $disabled,
331 'ssl' => $ssl,
332 'ssl_key' => $ssl_key,
333 'ssl_cert' => $ssl_cert,
334 'ssl_ca' => $ssl_ca,
335 'ssl_path' => $ssl_path,
336 'ssl_cipher' => $ssl_cipher,
337 );
338 self::save_remote_databases();
339
340 return true;
341 }
342 }
343 }
344
345 public static function change_password( $database, $passwd ) {
346 self::load_remote_databases();
347
348 if ( false === self::get_remote_database( $database, true ) ) {
349 return false;
350 } else {
351 self::$remote_databases[ $database ]['password'] = $passwd;
352 self::save_remote_databases();
353
354 return true;
355 }
356 }
357
358 /**
359 * Get database connection
360 *
361 * Remote schema name starts with prefix "rdb:"
362 *
363 * @param string $schema_name Database (schema) name.
364 *
365 * @return mixed|\wpdb
366 */
367 public static function get_db_connection( $schema_name ) {
368 global $wpdb;
369 if ( 'rdb:' === substr( (string) $schema_name, 0, 4 ) ) {
370 // Remote database (other ip|port).
371 self::load_remote_databases();
372 if ( ! isset( self::$db_connections[ $schema_name ] ) ) {
373 if (
374 isset( self::$remote_databases[ $schema_name ] ) &&
375 ! self::$remote_databases[ $schema_name ]['disabled']
376 ) {
377 $host = self::$remote_databases[ $schema_name ]['host'];
378 if (
379 '' !== self::$remote_databases[ $schema_name ]['port'] &&
380 '3306' !== self::$remote_databases[ $schema_name ]['port']
381 ) {
382 $host .= ':' . self::$remote_databases[ $schema_name ]['port'];
383 }
384 $wpda_remote_database = new WPDADB_WPDB(
385 self::$remote_databases[ $schema_name ]['username'],
386 self::$remote_databases[ $schema_name ]['password'],
387 self::$remote_databases[ $schema_name ]['database'],
388 $host,
389 self::$remote_databases[ $schema_name ]['ssl'],
390 self::$remote_databases[ $schema_name ]['ssl_key'],
391 self::$remote_databases[ $schema_name ]['ssl_cert'],
392 self::$remote_databases[ $schema_name ]['ssl_ca'],
393 self::$remote_databases[ $schema_name ]['ssl_path'],
394 self::$remote_databases[ $schema_name ]['ssl_cipher']
395 );
396 if ( $wpda_remote_database->get_connect_errno() === 0 ) {
397 self::$db_connections[ $schema_name ] = $wpda_remote_database;
398 } else {
399 // Connection failed.
400 self::$db_connections[ $schema_name ] = null;
401 }
402 } else {
403 // Remote schema name not found.
404 self::$db_connections[ $schema_name ] = null;
405 }
406 }
407
408 do_action( 'wpda_dbinit', self::$db_connections[ $schema_name ] );
409 return self::$db_connections[ $schema_name ];
410 } else {
411 // Database runs in local WordPress instance.
412 if ( '' === $schema_name || null === $schema_name || self::iswpdb( $schema_name ) ) {
413 do_action( 'wpda_dbinit', $wpdb );
414 return $wpdb;
415 } else {
416 if ( ! WPDA_Dictionary_Exist::schema_exists( $schema_name ) ) {
417 do_action( 'wpda_dbinit', $wpdb );
418 return $wpdb;
419 }
420
421 if ( ! isset( self::$db_connections[ $schema_name ] ) ) {
422 self::$db_connections[ $schema_name ] = new \wpdb( DB_USER, DB_PASSWORD, $schema_name, DB_HOST );
423 do_action( 'wpda_dbinit', self::$db_connections[ $schema_name ] );
424 }
425
426 return self::$db_connections[ $schema_name ];
427 }
428 }
429 }
430
431 /**
432 * Check if WordPress is installed in the given database schema name
433 *
434 * @param string $schema_name Schema name.
435 * @return bool
436 */
437 public static function iswpdb( $schema_name ) {
438 global $wpdb;
439 if ( null === self::$lower_case_table_names ) {
440 $lower_case_table_names = $wpdb->get_results( "SHOW VARIABLES LIKE 'lower_case_table_names'", 'ARRAY_N' ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
441 if ( is_array( $lower_case_table_names ) && isset( $lower_case_table_names[0][1] ) ) {
442 self::$lower_case_table_names = $lower_case_table_names[0][1];
443 } else {
444 self::$lower_case_table_names = 0;
445 }
446 }
447 switch ( self::$lower_case_table_names ) {
448 case 1:
449 case 2:
450 return strtolower( $wpdb->dbname ) === $schema_name;
451 default:
452 return $wpdb->dbname === $schema_name;
453 }
454 }
455
456 /**
457 * Check if a connection with a remote database can be established
458 *
459 * @return \wpdb
460 */
461 public function check_remote_database_connection() {
462 echo 'Preparing connection...<br/>';
463
464 $host = isset( $_REQUEST['host'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['host'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification
465 $user = isset( $_REQUEST['user'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['user'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification
466 // Cannot use sanitize_text_field on password field!
467 $passwd = isset( $_REQUEST['passwd'] ) ? // phpcs:ignore WordPress.Security.NonceVerification
468 wp_unslash( $_REQUEST['passwd'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification
469 $port = isset( $_REQUEST['port'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['port'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification
470 $schema = isset( $_REQUEST['schema'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['schema'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification
471
472 // Add ssl.
473 $ssl = isset( $_REQUEST['ssl'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['ssl'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification
474 $ssl_key = isset( $_REQUEST['ssl_key'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['ssl_key'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification
475 $ssl_cert = isset( $_REQUEST['ssl_cert'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['ssl_cert'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification
476 $ssl_ca = isset( $_REQUEST['ssl_ca'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['ssl_ca'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification
477 $ssl_path = isset( $_REQUEST['ssl_path'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['ssl_path'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification
478 $ssl_cipher = isset( $_REQUEST['ssl_cipher'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['ssl_cipher'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification
479
480 if ( '' === $host || '' === $user || '' === $passwd || '' === $schema ) {
481 return false;
482 }
483
484 if ( '' !== $port && '3306' !== $port ) {
485 $host .= ':' . $port;
486 }
487
488 echo 'Establishing connection...<br/>';
489
490 $wpdadb = new WPDADB_WPDB(
491 $user,
492 $passwd,
493 $schema,
494 $host,
495 $ssl,
496 $ssl_key,
497 $ssl_cert,
498 $ssl_ca,
499 $ssl_path,
500 $ssl_cipher
501 );
502
503 if ( $wpdadb->get_connect_errno() !== 0 ) {
504 echo '
505 <br/>
506 ERROR ' . esc_attr( $wpdadb->get_connect_errno() ) . ' - ' . esc_attr( $wpdadb->get_connect_error() ) . '
507 <br/><br/>
508 <strong>Connection failed!</strong>
509 ';
510 } else {
511 $query = $wpdadb->prepare(
512 'select 1 from information_schema.tables where table_schema = %s',
513 array(
514 $schema,
515 )
516 );
517 $wpdadb->get_results( $query, 'ARRAY_A' );
518
519 echo '
520 <br/>
521 Connection established...
522 <br/>
523 Counting tables...
524 <br/>
525 Found ' . esc_attr( $wpdadb->num_rows ) . ' tables on remote host...
526 <br/><br/>
527 <strong>Remote database connection valid!</strong>
528 ';
529 }
530 }
531
532 }
533
534 }
535