PluginProbe ʕ •ᴥ•ʔ
WPForms – Easy Form Builder for WordPress – Contact Forms, Payment Forms, Surveys, & More / 1.9.1.2
WPForms – Easy Form Builder for WordPress – Contact Forms, Payment Forms, Surveys, & More v1.9.1.2
1.10.1 1.10.0.5 trunk 1.1.4 1.1.4.2 1.1.5 1.1.5.1 1.1.6 1.1.6.1 1.1.7 1.1.7.1 1.1.7.2 1.1.8 1.1.8.1 1.1.8.2 1.1.8.3 1.1.8.4 1.10.0.1 1.10.0.2 1.10.0.3 1.10.0.4 1.2.0 1.2.0.1 1.2.1 1.2.2 1.2.2.1 1.2.2.2 1.2.3 1.2.3.1 1.2.3.2 1.2.4 1.2.4.1 1.2.5 1.2.5.1 1.2.6 1.2.7 1.2.8 1.2.8.1 1.2.9 1.3.0 1.3.1 1.3.1.1 1.3.1.2 1.3.2 1.3.3 1.3.5 1.3.6 1.3.6.1 1.3.6.2 1.3.7.2 1.3.7.3 1.3.7.4 1.3.8 1.3.9.1 1.4.0.1 1.4.1.1 1.4.2 1.4.2.1 1.4.2.2 1.4.3 1.4.4 1.4.4.1 1.4.5 1.4.5.1 1.4.5.2 1.4.5.3 1.4.6 1.4.7.1 1.4.7.2 1.4.8.1 1.4.9 1.5.0.1 1.5.0.3 1.5.0.4 1.5.1 1.5.1.1 1.5.1.3 1.5.2.1 1.5.2.2 1.5.2.3 1.5.3 1.5.3.1 1.5.4.1 1.5.4.2 1.5.5 1.5.5.1 1.5.6 1.5.6.2 1.5.7 1.5.8.2 1.5.9.1 1.5.9.4 1.5.9.5 1.6.0.1 1.6.0.2 1.6.1 1.6.2.2 1.6.2.3 1.6.3.1 1.6.4 1.6.4.1 1.6.5 1.6.6 1.6.7 1.6.7.1 1.6.7.2 1.6.7.3 1.6.8 1.6.8.1 1.6.9 1.7.0 1.7.1.1 1.7.1.2 1.7.2 1.7.2.1 1.7.3 1.7.4 1.7.4.1 1.7.4.2 1.7.5.1 1.7.5.2 1.7.5.3 1.7.5.5 1.7.6 1.7.7 1.7.7.1 1.7.7.2 1.7.8 1.7.9 1.7.9.1 1.8.0.1 1.8.0.2 1.8.1.1 1.8.1.2 1.8.1.3 1.8.2.1 1.8.2.2 1.8.2.3 1.8.3 1.8.3.1 1.8.4 1.8.4.1 1.8.5.2 1.8.5.3 1.8.5.4 1.8.6.2 1.8.6.3 1.8.6.4 1.8.7.2 1.8.8.2 1.8.8.3 1.8.9.1 1.8.9.2 1.8.9.4 1.8.9.5 1.8.9.6 1.9.0.1 1.9.0.2 1.9.0.3 1.9.0.4 1.9.1.1 1.9.1.2 1.9.1.3 1.9.1.4 1.9.1.5 1.9.1.6 1.9.2.1 1.9.2.2 1.9.2.3 1.9.3.1 1.9.3.2 1.9.4.1 1.9.4.2 1.9.5 1.9.5.1 1.9.5.2 1.9.6 1.9.6.1 1.9.6.2 1.9.7.1 1.9.7.2 1.9.7.3 1.9.8.1 1.9.8.2 1.9.8.4 1.9.8.7 1.9.9.2 1.9.9.3 1.9.9.4
wpforms-lite / includes / class-db.php
wpforms-lite / includes Last commit date
admin 1 year ago emails 1 year ago fields 1 year ago functions 1 year ago providers 1 year ago templates 1 year ago class-db.php 1 year ago class-fields.php 1 year ago class-form.php 1 year ago class-install.php 1 year ago class-process.php 1 year ago class-providers.php 1 year ago class-templates.php 1 year ago class-widget.php 1 year ago deprecated.php 1 year ago functions-list.php 1 year ago functions.php 1 year ago integrations.php 1 year ago
class-db.php
897 lines
1 <?php
2
3 // phpcs:disable WPForms.Comments.PHPDocHooks.RequiredHookDocumentation, WPForms.PHP.ValidateHooks.InvalidHookName
4 // phpcs:disable Generic.Commenting.DocComment.MissingShort
5 /** @noinspection AutoloadingIssuesInspection */
6 /** @noinspection PhpIllegalPsrClassPathInspection */
7 // phpcs:disable Generic.Commenting.DocComment.MissingShort
8
9 use WPForms\Helpers\DB;
10
11 /**
12 * DB class.
13 *
14 * This handy class originated from Pippin's Easy Digital Downloads.
15 * See https://github.com/easydigitaldownloads/easy-digital-downloads/blob/master/includes/class-edd-db.php
16 *
17 * Subclasses should define $table_name, $version, and $primary_key in __construct() method.
18 *
19 * @since 1.1.6
20 */
21 abstract class WPForms_DB {
22
23 /**
24 * Maximum length of index key.
25 *
26 * Indexes have a maximum size of 767 bytes. Historically, we haven't needed to be concerned about that.
27 * As of WP 4.2, however, WP moved to utf8mb4, which uses 4 bytes per character. This means that an index, which
28 * used to have room for floor(767/3) = 255 characters, now only has room for floor(767/4) = 191 characters.
29 *
30 * @since 1.8.2
31 */
32 const MAX_INDEX_LENGTH = 191;
33
34 /**
35 * The dedicated cache key to store the All Keys array.
36 *
37 * @since 1.9.0
38 */
39 const ALL_KEYS = '_all_keys';
40
41 /**
42 * Database table name.
43 *
44 * @since 1.1.6
45 *
46 * @var string
47 */
48 public $table_name;
49
50 /**
51 * Database version.
52 *
53 * @since 1.1.6
54 *
55 * @var string
56 */
57 public $version;
58
59 /**
60 * Primary key (unique field) for the database table.
61 *
62 * @since 1.1.6
63 *
64 * @var string
65 */
66 public $primary_key;
67
68 /**
69 * Database type identifier.
70 *
71 * @since 1.5.1
72 *
73 * @var string
74 */
75 public $type;
76
77 /**
78 * Cache group.
79 *
80 * @since 1.9.0
81 *
82 * @var string
83 */
84 private $cache_group;
85
86 /**
87 * Cache disabled.
88 *
89 * @since 1.9.0
90 *
91 * @var bool
92 */
93 private $cache_disabled;
94
95 /**
96 * WPForms_DB constructor.
97 *
98 * @since 1.9.0
99 */
100 public function __construct() {
101
102 $this->cache_group = static::class . '_cache';
103 $this->cache_disabled = defined( 'WPFORMS_DISABLE_DB_CACHE' ) && WPFORMS_DISABLE_DB_CACHE;
104
105 $this->hooks();
106 }
107
108 /**
109 * Query filter.
110 *
111 * @since 1.9.0
112 *
113 * @return void
114 */
115 private function hooks() {
116
117 add_filter( 'query', [ $this, 'query_filter' ] );
118 }
119
120 /**
121 * Retrieve the list of columns for the database table.
122 * Subclasses should define an array of columns here.
123 *
124 * @since 1.1.6
125 *
126 * @return array List of columns.
127 */
128 public function get_columns() {
129
130 return [];
131 }
132
133 /**
134 * Retrieve column defaults.
135 * Subclasses can define default for any/all columns defined in the get_columns() method.
136 *
137 * @since 1.1.6
138 *
139 * @return array All defined column defaults.
140 */
141 public function get_column_defaults() {
142
143 return [];
144 }
145
146 /**
147 * Filter the query.
148 *
149 * @since 1.9.0
150 *
151 * @param string|mixed $query Query.
152 *
153 * @return string
154 */
155 public function query_filter( $query ): string {
156
157 $query = (string) $query;
158
159 if ( strpos( $query, $this->table_name ) === false ) {
160 // Not a query for our table, bail out.
161 return $query;
162 }
163
164 if ( ! $this->is_select( $query ) ) {
165 // Flush cache on non-SELECT queries.
166 $this->cache_flush_group();
167 }
168
169 return $query;
170 }
171
172 /**
173 * Retrieve a row from the database based on a given row ID.
174 *
175 * @since 1.1.6
176 *
177 * @param int $row_id Row ID.
178 *
179 * @return null|object
180 */
181 public function get( $row_id ) {
182
183 global $wpdb;
184
185 $key = md5( __METHOD__ . $row_id );
186 $row = $this->cache_get( $key, $found );
187
188 if ( $found ) {
189 return $row;
190 }
191
192 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
193 $row = $wpdb->get_row(
194 $wpdb->prepare(
195 "SELECT * FROM $this->table_name WHERE $this->primary_key = %d LIMIT 1;", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
196 (int) $row_id
197 )
198 );
199
200 $this->cache_set( $key, $row );
201
202 return $row;
203 }
204
205 /**
206 * Retrieve a row based on column and row ID.
207 *
208 * @since 1.1.6
209 *
210 * @param string $column Column name.
211 * @param int|string $value Column value.
212 *
213 * @return object|null Database query result, object or null on failure.
214 */
215 public function get_by( $column, $value ) {
216
217 global $wpdb;
218
219 if (
220 empty( $value ) ||
221 ! array_key_exists( $column, $this->get_columns() )
222 ) {
223 return null;
224 }
225
226 $key = md5( __METHOD__ . $column . $value );
227 $row = $this->cache_get( $key, $found );
228
229 if ( $found ) {
230 return $row;
231 }
232
233 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
234 $row = $wpdb->get_row(
235 $wpdb->prepare(
236 "SELECT * FROM $this->table_name WHERE $column = %s LIMIT 1;", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
237 $value
238 )
239 );
240
241 $this->cache_set( $key, $row );
242
243 return $row;
244 }
245
246 /**
247 * Retrieve a value based on column name and row ID.
248 *
249 * @since 1.1.6
250 *
251 * @param string $column Column name.
252 * @param int|string $row_id Row ID.
253 *
254 * @return string|null Database query result (as string), or null on failure.
255 * @noinspection PhpUnused
256 */
257 public function get_column( $column, $row_id ) {
258
259 global $wpdb;
260
261 if ( empty( $row_id ) || ! array_key_exists( $column, $this->get_columns() ) ) {
262 return null;
263 }
264
265 $key = md5( __METHOD__ . $column . $row_id );
266 $var = $this->cache_get( $key, $found );
267
268 if ( $found ) {
269 return $var;
270 }
271
272 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
273 $var = $wpdb->get_var(
274 $wpdb->prepare(
275 "SELECT $column FROM $this->table_name WHERE $this->primary_key = %d LIMIT 1;", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
276 (int) $row_id
277 )
278 );
279
280 $this->cache_set( $key, $var );
281
282 return $var;
283 }
284
285 /**
286 * Retrieve one column value based on another given column and matching value.
287 *
288 * @since 1.1.6
289 *
290 * @param string $column Column name.
291 * @param string $column_where Column to match against in the WHERE clause.
292 * @param string $column_value Value to match to the column in the WHERE clause.
293 *
294 * @return string|null Database query result (as string), or null on failure.
295 * @noinspection PhpUnused
296 */
297 public function get_column_by( $column, $column_where, $column_value ) {
298
299 global $wpdb;
300
301 if (
302 empty( $column ) ||
303 empty( $column_where ) ||
304 empty( $column_value ) ||
305 ! array_key_exists( $column_where, $this->get_columns() ) ||
306 ! array_key_exists( $column, $this->get_columns() )
307 ) {
308 return null;
309 }
310
311 $key = md5( __METHOD__ . $column . $column_where . $column_value );
312 $var = $this->cache_get( $key, $found );
313
314 if ( $found ) {
315 return $var;
316 }
317
318 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
319 $var = $wpdb->get_var(
320 $wpdb->prepare(
321 "SELECT $column FROM $this->table_name WHERE $column_where = %s LIMIT 1;", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
322 $column_value
323 )
324 );
325
326 $this->cache_set( $key, $var );
327
328 return $var;
329 }
330
331 /**
332 * Clone of $wpdb->query() with caching.
333 *
334 * @since 1.9.0
335 *
336 * @param string $query Database query.
337 *
338 * @return int|bool Boolean true for CREATE, ALTER, TRUNCATE and DROP queries. Number of rows
339 * affected/selected for all other queries. Boolean false on error.
340 *
341 * @noinspection PhpMissingParamTypeInspection
342 */
343 public function query( $query ) {
344
345 global $wpdb;
346
347 if ( ! $this->is_select( $query ) ) {
348 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
349 return $wpdb->query( $query );
350 }
351
352 $key = md5( __METHOD__ . $query );
353 $results = $this->cache_get( $key, $found );
354
355 if ( $found ) {
356 return $results;
357 }
358
359 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
360 $results = $wpdb->query( $query );
361
362 $this->cache_set( $key, $results );
363
364 return $results;
365 }
366
367 /**
368 * Clone of $wpdb->get_results() with caching.
369 *
370 * @since 1.9.0
371 *
372 * @param string|null $query SQL query.
373 * @param string $output Any of ARRAY_A | ARRAY_N | OBJECT | OBJECT_K constants.
374 *
375 * @return array|object|null Database query results.
376 * @noinspection PhpMissingParamTypeInspection
377 */
378 public function get_results( $query = null, $output = OBJECT ) {
379
380 global $wpdb;
381
382 if ( ! $this->is_select( $query ) ) {
383 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
384 return $wpdb->get_results( $query, $output );
385 }
386
387 $key = md5( __METHOD__ . $query . $output );
388 $results = $this->cache_get( $key, $found );
389
390 if ( $found ) {
391 return $results;
392 }
393
394 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
395 $results = $wpdb->get_results( $query, $output );
396
397 $this->cache_set( $key, $results );
398
399 return $results;
400 }
401
402 /**
403 * Clone of $wpdb->get_row() with caching.
404 *
405 * @since 1.9.0
406 *
407 * @param string|null $query SQL query.
408 * @param string $output Optional. The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which
409 * correspond to an stdClass object, an associative array, or a numeric array,
410 * respectively. Default OBJECT.
411 * @param int $y Optional. Row to return. Indexed from 0. Default 0.
412 *
413 * @return array|int|object|stdClass|null Database query result in format specified by $output or null on failure.
414 * @noinspection PhpMissingParamTypeInspection
415 */
416 public function get_row( $query = null, $output = OBJECT, $y = 0 ) {
417
418 global $wpdb;
419
420 if ( ! $query ) {
421 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
422 return $wpdb->get_row( $query, $output, $y );
423 }
424
425 $key = md5( __METHOD__ . $query . $output . $y );
426 $row = $this->cache_get( $key, $found );
427
428 if ( $found ) {
429 return $row;
430 }
431
432 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
433 $row = $wpdb->get_row( $query, $output, $y );
434
435 $this->cache_set( $key, $row );
436
437 return $row;
438 }
439
440 /**
441 * Clone of $wpdb->get_var() with caching.
442 *
443 * @since 1.9.0
444 *
445 * @param string|null $query Optional. SQL query. Defaults to null, use the result from the previous query.
446 * @param int $x Optional. Column of value to return. Indexed from 0. Default 0.
447 * @param int $y Optional. Row of value to return. Indexed from 0. Default 0.
448 *
449 * @return string|null Database query result (as string), or null on failure.
450 *
451 * @noinspection PhpMissingParamTypeInspection
452 */
453 public function get_var( $query = null, $x = 0, $y = 0 ) {
454
455 global $wpdb;
456
457 if ( ! $query ) {
458 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
459 return $wpdb->get_var( $query, $x, $y );
460 }
461
462 $key = md5( __METHOD__ . $query . $x . $y );
463 $var = $this->cache_get( $key, $found );
464
465 if ( $found ) {
466 return $var;
467 }
468
469 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
470 $var = $wpdb->get_var( $query, $x, $y );
471
472 $this->cache_set( $key, $var );
473
474 return $var;
475 }
476
477 /**
478 * Insert a new record into the database.
479 *
480 * @since 1.1.6
481 *
482 * @param array $data Column data.
483 * @param string $type Optional. Data type context.
484 *
485 * @return int ID for the newly inserted record. Zero otherwise.
486 */
487 public function add( $data, $type = '' ) {
488
489 global $wpdb;
490
491 // Set default values.
492 $data = wp_parse_args( $data, $this->get_column_defaults() );
493
494 do_action( 'wpforms_pre_insert_' . $type, $data );
495
496 // Initialise column format array.
497 $column_formats = $this->get_columns();
498
499 // Force fields to lower a case.
500 $data = array_change_key_case( $data );
501
502 // Whitelist columns.
503 $data = array_intersect_key( $data, $column_formats );
504
505 // Reorder $column_formats to match the order of columns given in $data.
506 $data_keys = array_keys( $data );
507 $column_formats = array_merge( array_flip( $data_keys ), $column_formats );
508
509 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
510 $wpdb->insert( $this->table_name, $data, $column_formats );
511
512 do_action( 'wpforms_post_insert_' . $type, $wpdb->insert_id, $data );
513
514 return $wpdb->insert_id;
515 }
516
517 /**
518 * Insert a new record into the database. This runs the add() method.
519 *
520 * @see add()
521 *
522 * @since 1.1.6
523 *
524 * @param array $data Column data.
525 *
526 * @return int ID for the newly inserted record.
527 */
528 public function insert( $data ) {
529
530 return $this->add( $data );
531 }
532
533 /**
534 * Update an existing record in the database.
535 *
536 * @since 1.1.6
537 *
538 * @param int|string $row_id Row ID for the record being updated.
539 * @param array $data Optional. Array of columns and associated data to update. Default empty array.
540 * @param string $where Optional. Column to match against in the WHERE clause. If empty, $primary_key
541 * will be used. Default empty.
542 * @param string $type Optional. Data type context, e.g. 'affiliate', 'creative', etc. Default empty.
543 *
544 * @return bool False if the record could not be updated, true otherwise.
545 */
546 public function update( $row_id, $data = [], $where = '', $type = '' ) {
547
548 global $wpdb;
549
550 // Row ID must be a positive integer.
551 $row_id = absint( $row_id );
552
553 if ( empty( $row_id ) ) {
554 return false;
555 }
556
557 if ( empty( $where ) ) {
558 $where = $this->primary_key;
559 }
560
561 do_action( 'wpforms_pre_update_' . $type, $data );
562
563 // Initialise column format array.
564 $column_formats = $this->get_columns();
565
566 // Force fields to the lower case.
567 $data = array_change_key_case( $data );
568
569 // Whitelist columns.
570 $data = array_intersect_key( $data, $column_formats );
571
572 // Reorder $column_formats to match the order of columns given in $data.
573 $data_keys = array_keys( $data );
574 $column_formats = array_merge( array_flip( $data_keys ), $column_formats );
575
576 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
577 if ( $wpdb->update( $this->table_name, $data, [ $where => $row_id ], $column_formats ) === false ) {
578 return false;
579 }
580
581 do_action( 'wpforms_post_update_' . $type, $data );
582
583 return true;
584 }
585
586 /**
587 * Delete a record from the database.
588 *
589 * @since 1.1.6
590 *
591 * @param int|string $row_id Row ID.
592 *
593 * @return bool False if the record could not be deleted, true otherwise.
594 */
595 public function delete( $row_id = 0 ): bool {
596
597 global $wpdb;
598
599 // Row ID must be a positive integer.
600 $row_id = absint( $row_id );
601
602 if ( empty( $row_id ) ) {
603 return false;
604 }
605
606 /**
607 * Fires before a record is deleted from the database.
608 *
609 * @since 1.5.9
610 *
611 * @param int $row_id Row ID.
612 */
613 do_action( 'wpforms_pre_delete', $row_id );
614
615 /**
616 * Fires before a record is deleted from the database by type.
617 *
618 * @since 1.5.9
619 * @since 1.8.6 Added `$primary_key` parameter.
620 *
621 * @param int $row_id Column value.
622 * @param string $primary_key Column name.
623 */
624 do_action( 'wpforms_pre_delete_' . $this->type, $row_id, $this->primary_key );
625
626 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
627 $result = $wpdb->query(
628 $wpdb->prepare(
629 "DELETE FROM $this->table_name WHERE $this->primary_key = %d", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
630 $row_id
631 )
632 );
633
634 if ( $result === false ) {
635 return false;
636 }
637
638 do_action( 'wpforms_post_delete', $row_id );
639 do_action( 'wpforms_post_delete_' . $this->type, $row_id );
640
641 return true;
642 }
643
644 /**
645 * Delete a record from the database by column.
646 *
647 * @since 1.1.6
648 *
649 * @param string $column Column name.
650 * @param int|string $column_value Column value.
651 *
652 * @return bool False if the record could not be deleted, true otherwise.
653 */
654 public function delete_by( $column, $column_value ) {
655
656 global $wpdb;
657
658 if (
659 empty( $column ) ||
660 empty( $column_value ) ||
661 ! array_key_exists( $column, $this->get_columns() )
662 ) {
663 return false;
664 }
665
666 // This action is documented in includes/class-db.php method delete().
667 do_action( 'wpforms_pre_delete', $column_value );
668
669 // This action is documented in includes/class-db.php method delete().
670 do_action( 'wpforms_pre_delete_' . $this->type, $column_value, $column );
671
672 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
673 $result = $wpdb->query(
674 $wpdb->prepare(
675 "DELETE FROM $this->table_name WHERE $column = %s", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
676 $column_value
677 )
678 );
679
680 if ( $result === false ) {
681 return false;
682 }
683
684 do_action( 'wpforms_post_delete', $column_value );
685 do_action( 'wpforms_post_delete_' . $this->type, $column_value );
686
687 return true;
688 }
689
690 /**
691 * Delete record(s) from the database using WHERE IN syntax.
692 *
693 * @since 1.6.4
694 *
695 * @param string $column Column name.
696 * @param mixed $column_values Column values.
697 *
698 * @return int|bool Number of deleted records, false otherwise.
699 */
700 public function delete_where_in( $column, $column_values ) {
701
702 global $wpdb;
703
704 if ( empty( $column ) || empty( $column_values ) ) {
705 return false;
706 }
707
708 if ( ! array_key_exists( $column, $this->get_columns() ) ) {
709 return false;
710 }
711
712 $values = (array) $column_values;
713
714 foreach ( $values as $key => $value ) {
715 // Check if a string contains an integer and sanitize accordingly.
716 if ( (string) (int) $value === $value ) {
717 $values[ $key ] = (int) $value;
718 $placeholders[ $key ] = '%d';
719 } else {
720 $values[ $key ] = sanitize_text_field( $value );
721 $placeholders[ $key ] = '%s';
722 }
723 }
724
725 $placeholders = isset( $placeholders ) ? implode( ',', $placeholders ) : '';
726 $sql = "DELETE FROM $this->table_name WHERE $column IN ( $placeholders )";
727
728 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
729 return $wpdb->query( $wpdb->prepare( $sql, $values ) );
730 }
731
732 /**
733 * Check if the given table exists.
734 *
735 * @since 1.1.6
736 * @since 1.5.9 Default value is now the current child class table name.
737 *
738 * @param string $table The table name. Defaults to the child class table name.
739 *
740 * @return bool If the table name exists.
741 */
742 public function table_exists( string $table = '' ): bool {
743
744 $table = ! empty( $table ) ? sanitize_text_field( $table ) : $this->table_name;
745
746 return DB::table_exists( $table );
747 }
748
749 /**
750 * Build WHERE for a query.
751 *
752 * @since 1.7.2.2
753 *
754 * @param array $args Optional args.
755 * @param array $keys Allowed arg items.
756 * @param string|string[] $formats Formats of arg items.
757 *
758 * @return string
759 */
760 protected function build_where( $args, $keys = [], $formats = [] ) {
761
762 $formats = array_pad( $formats, count( $keys ), '%d' );
763 $where = '';
764
765 foreach ( $keys as $index => $key ) {
766 // Value `$args[ $key ]` can be a natural number and a numeric string.
767 // We should skip empty string values, but continue working with '0'.
768 if ( empty( $args[ $key ] ) && $args[ $key ] !== '0' ) {
769 continue;
770 }
771
772 $ids = wpforms_wpdb_prepare_in( $args[ $key ], $formats[ $index ] );
773
774 $where .= empty( $where ) ? 'WHERE' : 'AND';
775 $where .= " `{$key}` IN ( {$ids} ) ";
776 }
777
778 return $where;
779 }
780
781 /**
782 * WP Cache Get wrapper.
783 *
784 * @since 1.9.0
785 *
786 * @param int|string $key Cache key.
787 * @param bool|null $found Whether the key was found in the cache.
788 *
789 * @return false|mixed
790 * @noinspection PhpMissingParamTypeInspection
791 */
792 private function cache_get( $key, &$found ) {
793
794 if ( $this->cache_disabled ) {
795 $found = false;
796
797 return false;
798 }
799
800 $all_keys = wp_cache_get( self::ALL_KEYS, $this->cache_group, false, $found );
801 $all_keys = $found ? (array) $all_keys : [];
802
803 if ( ! in_array( $key, $all_keys, true ) ) {
804 $found = false;
805
806 return false;
807 }
808
809 $data = wp_cache_get( $key, $this->cache_group, false, $found );
810
811 return $found ? $data : false;
812 }
813
814 /**
815 * WP Cache Set wrapper.
816 *
817 * @since 1.9.0
818 *
819 * @param string $key Cache key.
820 * @param mixed $data Cache data.
821 *
822 * @return bool
823 * @noinspection PhpReturnValueOfMethodIsNeverUsedInspection
824 */
825 private function cache_set( string $key, $data ): bool {
826
827 if ( $this->cache_disabled ) {
828 return false;
829 }
830
831 $all_keys = wp_cache_get( self::ALL_KEYS, $this->cache_group, false, $found );
832 $all_keys = $found ? array_unique( array_merge( (array) $all_keys, [ $key ] ) ) : [ $key ];
833
834 return (
835 wp_cache_set( $key, $data, $this->cache_group ) &&
836 wp_cache_set( self::ALL_KEYS, $all_keys, $this->cache_group )
837 );
838 }
839
840 /**
841 * Flush the cache group.
842 *
843 * @since 1.9.0
844 *
845 * @return bool
846 * @noinspection PhpReturnValueOfMethodIsNeverUsedInspection
847 */
848 private function cache_flush_group(): bool {
849
850 if ( $this->cache_disabled ) {
851 return false;
852 }
853
854 $all_keys = wp_cache_get( self::ALL_KEYS, $this->cache_group, false, $found );
855
856 if ( ! $found ) {
857 return true;
858 }
859
860 $result = wp_cache_delete( self::ALL_KEYS, $this->cache_group );
861
862 foreach ( (array) $all_keys as $key ) {
863 $result = wp_cache_delete( $key, $this->cache_group ) && $result;
864 }
865
866 return $result;
867 }
868
869 /**
870 * Check if the query is a SELECT query.
871 *
872 * @since 1.9.0
873 *
874 * @param string|null $query SQL query.
875 *
876 * @return bool
877 * @noinspection PhpMissingParamTypeInspection
878 */
879 private function is_select( $query ): bool {
880
881 return stripos( trim( (string) $query ), 'SELECT' ) === 0;
882 }
883
884 /**
885 * Get an instance of the current class.
886 * Used to reload the class while going through the blogs of multisite.
887 *
888 * @see WPForms_Install::maybe_create_tables()
889 *
890 * @since 1.8.9
891 */
892 public static function get_instance(): WPForms_DB {
893
894 return new static();
895 }
896 }
897