PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 2.05.09
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v2.05.09
6.35 6.34 6.33.1 6.33 6.32.1 6.32 6.31 6.25 6.25.1 6.26 6.26.1 6.27 6.28 6.29 6.3 6.3.1 6.3.2 6.30 6.4 6.4.1 6.4.2 6.5 6.5.1 6.5.2 6.5.3 All 141 releases
formidable / classes / models / FrmDb.php

FrmDb.php in Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More 2.05.09, at classes/models/FrmDb.php

722 lines 19.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 class FrmDb {
4 public $fields;
5 public $forms;
6 public $entries;
7 public $entry_metas;
8
9 public function __construct() {
10 if ( ! defined('ABSPATH') ) {
11 die('You are not allowed to call this page directly.');
12 }
13
14 _deprecated_function( __METHOD__, '2.05.06', 'FrmMigrate' );
15 global $wpdb;
16 $this->fields = $wpdb->prefix . 'frm_fields';
17 $this->forms = $wpdb->prefix . 'frm_forms';
18 $this->entries = $wpdb->prefix . 'frm_items';
19 $this->entry_metas = $wpdb->prefix . 'frm_item_metas';
20 }
21
22 /**
23 * Change array into format $wpdb->prepare can use
24 *
25 * @param array $args
26 * @param string $starts_with
27 */
28 public static function get_where_clause_and_values( &$args, $starts_with = ' WHERE ' ) {
29 if ( empty($args) ) {
30 // add an arg to prevent prepare from failing
31 $args = array(
32 'where' => $starts_with . '1=%d',
33 'values' => array( 1 ),
34 );
35 return;
36 }
37
38 $where = '';
39 $values = array();
40
41 if ( is_array( $args ) ) {
42 $base_where = $starts_with;
43 self::parse_where_from_array( $args, $base_where, $where, $values );
44 }
45
46 $args = compact( 'where', 'values' );
47 }
48
49 /**
50 * @param array $args
51 * @param string $base_where
52 * @param string $where
53 * @param array $values
54 */
55 public static function parse_where_from_array( $args, $base_where, &$where, &$values ) {
56 $condition = ' AND';
57 if ( isset( $args['or'] ) ) {
58 $condition = ' OR';
59 unset( $args['or'] );
60 }
61
62 foreach ( $args as $key => $value ) {
63 $where .= empty( $where ) ? $base_where : $condition;
64 $array_inc_null = ( ! is_numeric( $key ) && is_array( $value ) && in_array( null, $value ) );
65 if ( is_numeric( $key ) || $array_inc_null ) {
66 $where .= ' ( ';
67 $nested_where = '';
68 if ( $array_inc_null ) {
69 foreach ( $value as $val ) {
70 $parse_where = array(
71 $key => $val,
72 'or' => 1,
73 );
74 self::parse_where_from_array( $parse_where, '', $nested_where, $values );
75 }
76 } else {
77 self::parse_where_from_array( $value, '', $nested_where, $values );
78 }
79 $where .= $nested_where;
80 $where .= ' ) ';
81 } else {
82 self::interpret_array_to_sql( $key, $value, $where, $values );
83 }
84 }
85 }
86
87 /**
88 * @param string $key
89 * @param string|array $value
90 * @param string $where
91 * @param array $values
92 */
93 private static function interpret_array_to_sql( $key, $value, &$where, &$values ) {
94 $key = trim( $key );
95
96 if ( strpos( $key, 'created_at' ) !== false || strpos( $key, 'updated_at' ) !== false ) {
97 $k = explode(' ', $key);
98 $where .= ' DATE_FORMAT(' . reset( $k ) . ', %s) ' . str_replace( reset( $k ), '', $key );
99 $values[] = '%Y-%m-%d %H:%i:%s';
100 } else {
101 $where .= ' ' . $key;
102 }
103
104 $lowercase_key = explode( ' ', strtolower( $key ) );
105 $lowercase_key = end( $lowercase_key );
106
107 if ( is_array( $value ) ) {
108 // translate array of values to "in"
109 if ( strpos( $lowercase_key, 'like' ) !== false ) {
110 $where = preg_replace('/' . $key . '$/', '', $where);
111 $where .= '(';
112 $start = true;
113 foreach ( $value as $v ) {
114 if ( ! $start ) {
115 $where .= ' OR ';
116 }
117 $start = false;
118 $where .= $key . ' %s';
119 $values[] = '%' . self::esc_like( $v ) . '%';
120 }
121 $where .= ')';
122 } else if ( ! empty( $value ) ) {
123 $where .= ' in (' . self::prepare_array_values( $value, '%s' ) . ')';
124 $values = array_merge( $values, $value );
125 }
126 } else if ( strpos( $lowercase_key, 'like' ) !== false ) {
127 /**
128 * Allow string to start or end with the value
129 * If the key is like% then skip the first % for starts with
130 * If the key is %like then skip the last % for ends with
131 */
132 $start = '%';
133 $end = '%';
134 if ( $lowercase_key == 'like%' ) {
135 $start = '';
136 $where = rtrim( $where, '%' );
137 } else if ( $lowercase_key == '%like' ) {
138 $end = '';
139 $where = rtrim( rtrim( $where, '%like' ), '%LIKE' );
140 $where .= 'like';
141 }
142
143 $where .= ' %s';
144 $values[] = $start . self::esc_like( $value ) . $end;
145
146 } else if ( $value === null ) {
147 $where .= ' IS NULL';
148 } else {
149 // allow a - to prevent = from being added
150 if ( substr( $key, -1 ) == '-' ) {
151 $where = rtrim( $where, '-' );
152 } else {
153 $where .= '=';
154 }
155
156 self::add_query_placeholder( $key, $value, $where );
157
158 $values[] = $value;
159 }
160 }
161
162 /**
163 * Add %d, or %s to query
164 *
165 * @since 2.02.05
166 * @param string $key
167 * @param int|string $value
168 * @param string $where
169 */
170 private static function add_query_placeholder( $key, $value, &$where ) {
171 if ( is_numeric( $value ) && ( strpos( $key, 'meta_value' ) === false || strpos( $key, '+0' ) !== false ) ) {
172 $where .= '%d';
173 } else {
174 $where .= '%s';
175 }
176 }
177
178 /**
179 * @param string $table
180 * @param array $where
181 * @param array $args
182 * @return int
183 */
184 public static function get_count( $table, $where = array(), $args = array() ) {
185 $count = self::get_var( $table, $where, 'COUNT(*)', $args );
186 return $count;
187 }
188
189 /**
190 * @param string $table
191 * @param array $where
192 * @param string $field
193 * @param array $args
194 * @param string $limit
195 * @param string $type
196 * @return array|null|string|object
197 */
198 public static function get_var( $table, $where = array(), $field = 'id', $args = array(), $limit = '', $type = 'var' ) {
199 $group = '';
200 self::get_group_and_table_name( $table, $group );
201 self::convert_options_to_array( $args, '', $limit );
202
203 $query = self::generate_query_string_from_pieces( $field, $table, $where, $args );
204
205 $cache_key = self::generate_cache_key( $where, $args, $field, $type );
206 $results = self::check_cache( $cache_key, $group, $query, 'get_' . $type );
207 return $results;
208 }
209
210 /**
211 * Generate a cache key from the where query, field, type, and other arguments
212 *
213 * @since 2.03.07
214 *
215 * @param array $where
216 * @param array $args
217 * @param string $field
218 * @param string $type
219 *
220 * @return string
221 */
222 private static function generate_cache_key( $where, $args, $field, $type ) {
223 $cache_key = '';
224 $where = FrmAppHelper::array_flatten( $where );
225 foreach ( $where as $key => $value ) {
226 $cache_key .= $key . '_' . $value;
227 }
228 $cache_key .= implode( '_', $args ) . $field . '_' . $type;
229 $cache_key = str_replace( array( ' ', ',' ), '_', $cache_key );
230
231 return $cache_key;
232 }
233
234 /**
235 * @param string $table
236 * @param array $where
237 * @param string $field
238 * @param array $args
239 * @param string $limit
240 * @return mixed
241 */
242 public static function get_col( $table, $where = array(), $field = 'id', $args = array(), $limit = '' ) {
243 return self::get_var( $table, $where, $field, $args, $limit, 'col' );
244 }
245
246 /**
247 * @since 2.0
248 * @param string $table
249 * @param array $where
250 * @param string $fields
251 * @param array $args
252 * @return mixed
253 */
254 public static function get_row( $table, $where = array(), $fields = '*', $args = array() ) {
255 $args['limit'] = 1;
256 return self::get_var( $table, $where, $fields, $args, '', 'row' );
257 }
258
259 /**
260 * Prepare a key/value array before DB call
261 *
262 * @since 2.0
263 * @param string $table
264 * @param array $where
265 * @param string $fields
266 * @param array $args
267 * @return mixed
268 */
269 public static function get_results( $table, $where = array(), $fields = '*', $args = array() ) {
270 return self::get_var( $table, $where, $fields, $args, '', 'results' );
271 }
272
273 /**
274 * Check for like, not like, in, not in, =, !=, >, <, <=, >=
275 * Return a value to append to the where array key
276 *
277 * @param string $where_is
278 * @return string
279 */
280 public static function append_where_is( $where_is ) {
281 $switch_to = array(
282 '=' => '',
283 '!=' => '!',
284 '<=' => '<',
285 '>=' => '>',
286 'like' => 'like',
287 'not like' => 'not like',
288 'in' => '',
289 'not in' => 'not',
290 'like%' => 'like%',
291 '%like' => '%like',
292 );
293
294 $where_is = strtolower( $where_is );
295 if ( isset( $switch_to[ $where_is ] ) ) {
296 return ' ' . $switch_to[ $where_is ];
297 }
298
299 // > and < need a little more work since we don't want them switched to >= and <=
300 if ( $where_is == '>' || $where_is == '<' ) {
301 return ' ' . $where_is . '-'; // the - indicates that the = should not be added later
302 }
303
304 // fallback to = if the query is none of these
305 return '';
306 }
307
308 /**
309 * Get 'frm_forms' from wp_frm_forms or a longer table param that includes a join
310 * Also add the wpdb->prefix to the table if it's missing
311 *
312 * @param string $table
313 * @param string $group
314 */
315 private static function get_group_and_table_name( &$table, &$group ) {
316 global $wpdb, $wpmuBaseTablePrefix;
317
318 $table_parts = explode(' ', $table);
319 $group = reset($table_parts);
320 $group = str_replace( $wpdb->prefix, '', $group );
321
322 $prefix = $wpmuBaseTablePrefix ? $wpmuBaseTablePrefix : $wpdb->base_prefix;
323 $group = str_replace( $prefix, '', $group );
324
325 if ( $group == $table ) {
326 $table = $wpdb->prefix . $table;
327 }
328
329 // switch to singular group name
330 $group = rtrim( $group, 's' );
331 }
332
333 private static function convert_options_to_array( &$args, $order_by = '', $limit = '' ) {
334 if ( ! is_array($args) ) {
335 $args = array( 'order_by' => $args );
336 }
337
338 if ( ! empty( $order_by ) ) {
339 $args['order_by'] = $order_by;
340 }
341
342 if ( ! empty( $limit ) ) {
343 $args['limit'] = $limit;
344 }
345
346 $temp_args = $args;
347 foreach ( $temp_args as $k => $v ) {
348 if ( $v == '' ) {
349 unset( $args[ $k ] );
350 continue;
351 }
352
353 $db_name = strtoupper( str_replace( '_', ' ', $k ) );
354 if ( strpos( $v, $db_name ) === false ) {
355 $args[ $k ] = $db_name . ' ' . $v;
356 }
357 }
358
359 // Make sure LIMIT is the last argument
360 if ( isset( $args['order_by'] ) && isset( $args['limit'] ) ) {
361 $temp_limit = $args['limit'];
362 unset( $args['limit'] );
363 $args['limit'] = $temp_limit;
364 }
365 }
366
367 /**
368 * Get the associative array results for the given columns, table, and where query
369 *
370 * @since 2.02.05
371 * @param string $columns
372 * @param string $table
373 * @param array $where
374 * @return mixed
375 */
376 public static function get_associative_array_results( $columns, $table, $where ) {
377 $group = '';
378 self::get_group_and_table_name( $table, $group );
379
380 $query = self::generate_query_string_from_pieces( $columns, $table, $where );
381
382 $cache_key = str_replace( array( ' ', ',' ), '_', trim( implode( '_', FrmAppHelper::array_flatten( $where ) ) . $columns . '_results_ARRAY_A', ' WHERE' ) );
383 $results = self::check_cache( $cache_key, $group, $query, 'get_associative_results' );
384
385 return $results;
386 }
387
388 /**
389 * Combine the pieces of a query to form a full, prepared query
390 *
391 * @since 2.02.05
392 *
393 * @param string $columns
394 * @param string $table
395 * @param mixed $where
396 * @param array $args
397 * @return string
398 */
399 private static function generate_query_string_from_pieces( $columns, $table, $where, $args = array() ) {
400 $query = 'SELECT ' . $columns . ' FROM ' . $table;
401
402 self::esc_query_args( $args );
403
404 if ( is_array( $where ) || empty( $where ) ) {
405 self::get_where_clause_and_values( $where );
406 global $wpdb;
407 $query = $wpdb->prepare( $query . $where['where'] . ' ' . implode( ' ', $args ), $where['values'] );
408 } else {
409 /**
410 * Allow the $where to be prepared before we recieve it here.
411 * This is a fallback for reverse compatability, but is not recommended
412 */
413 _deprecated_argument( 'where', '2.0', __( 'Use the query in an array format so it can be properly prepared.', 'formidable' ) );
414 $query .= $where . ' ' . implode( ' ', $args );
415 }
416
417 return $query;
418 }
419
420 /**
421 * @since 2.05.07
422 */
423 private static function esc_query_args( &$args ) {
424 foreach ( $args as $param => $value ) {
425 if ( $param == 'order_by' ) {
426 $args[ $param ] = self::esc_order( $value );
427 } elseif ( $param == 'limit' ) {
428 $args[ $param ] = self::esc_limit( $value );
429 }
430
431 if ( $args[ $param ] == '' ) {
432 unset( $args[ $param ] );
433 }
434 }
435 }
436
437 /**
438 * Added for < WP 4.0 compatability
439 *
440 * @since 2.05.06
441 *
442 * @param string $term The value to escape
443 * @return string The escaped value
444 */
445 public static function esc_like( $term ) {
446 global $wpdb;
447 if ( method_exists( $wpdb, 'esc_like' ) ) {
448 // WP 4.0
449 $term = $wpdb->esc_like( $term );
450 } else {
451 $term = like_escape( $term );
452 }
453
454 return $term;
455 }
456
457 /**
458 * @since 2.05.06
459 * @param string $order_query
460 */
461 public static function esc_order( $order_query ) {
462 if ( empty( $order_query ) ) {
463 return '';
464 }
465
466 // remove ORDER BY before santizing
467 $order_query = strtolower( $order_query );
468 if ( strpos( $order_query, 'order by' ) !== false ) {
469 $order_query = str_replace( 'order by', '', $order_query );
470 }
471
472 $order_query = explode( ' ', trim( $order_query ) );
473
474 $order = trim( reset( $order_query ) );
475 $safe_order = array( 'count(*)' );
476 if ( ! in_array( strtolower( $order ), $safe_order ) ) {
477 $order = preg_replace( '/[^a-zA-Z0-9\-\_\.]/', '', $order );
478 }
479
480 $order_by = '';
481 if ( count( $order_query ) > 1 ) {
482 $order_by = end( $order_query );
483 self::esc_order_by( $order_by );
484 }
485
486 return ' ORDER BY ' . $order . ' ' . $order_by;
487 }
488
489 /**
490 * Make sure this is ordering by either ASC or DESC
491 * @since 2.05.06
492 */
493 public static function esc_order_by( &$order_by ) {
494 $sort_options = array( 'asc', 'desc' );
495 if ( ! in_array( strtolower( $order_by ), $sort_options ) ) {
496 $order_by = 'asc';
497 }
498 }
499
500 /**
501 * @param string $limit
502 * @since 2.05.06
503 */
504 public static function esc_limit( $limit ) {
505 if ( empty( $limit ) ) {
506 return '';
507 }
508
509 $limit = trim( str_replace( 'limit ', '', strtolower( $limit ) ) );
510 if ( is_numeric( $limit ) ) {
511 return ' LIMIT ' . $limit;
512 }
513
514 $limit = explode( ',', trim( $limit ) );
515 foreach ( $limit as $k => $l ) {
516 if ( is_numeric( $l ) ) {
517 $limit[ $k ] = $l;
518 }
519 }
520
521 $limit = implode( ',', $limit );
522 return ' LIMIT ' . $limit;
523 }
524
525 /**
526 * Get an array of values ready to go through $wpdb->prepare
527 * @since 2.05.06
528 */
529 public static function prepare_array_values( $array, $type = '%s' ) {
530 $placeholders = array_fill( 0, count( $array ), $type );
531 return implode( ', ', $placeholders );
532 }
533
534 /**
535 * @since 2.05.06
536 */
537 public static function prepend_and_or_where( $starts_with = ' WHERE ', $where = '' ) {
538 if ( empty( $where ) ) {
539 return '';
540 }
541
542 if ( is_array( $where ) ) {
543 global $wpdb;
544 self::get_where_clause_and_values( $where, $starts_with );
545 $where = $wpdb->prepare( $where['where'], $where['values'] );
546 } else {
547 $where = $starts_with . $where;
548 }
549
550 return $where;
551 }
552
553 /**
554 * Prepare and save settings in styles and actions
555 *
556 * @param array $settings
557 * @param string $group
558 *
559 * @since 2.05.06
560 */
561 public static function save_settings( $settings, $group ) {
562 $settings = (array) $settings;
563 $settings['post_content'] = FrmAppHelper::prepare_and_encode( $settings['post_content'] );
564
565 if ( empty( $settings['ID'] ) ) {
566 unset( $settings['ID'] );
567 }
568
569 // delete all caches for this group
570 self::cache_delete_group( $group );
571
572 return self::save_json_post( $settings );
573 }
574
575 /**
576 * Since actions are JSON encoded, we don't want any filters messing with it.
577 * Remove the filters and then add them back in case any posts or views are
578 * also being imported.
579 *
580 * Used when saving form actions and styles
581 *
582 * @since 2.05.06
583 */
584 public static function save_json_post( $settings ) {
585 global $wp_filter;
586 $filters = $wp_filter['content_save_pre'];
587
588 // Remove the balanceTags filter in case WordPress is trying to validate the XHTML
589 remove_all_filters( 'content_save_pre' );
590
591 $post = wp_insert_post( $settings );
592
593 // add the content filters back for views or posts
594 $wp_filter['content_save_pre'] = $filters;
595
596 return $post;
597 }
598
599 /**
600 * Check cache before fetching values and saving to cache
601 *
602 * @since 2.05.06
603 *
604 * @param string $cache_key The unique name for this cache
605 * @param string $group The name of the cache group
606 * @param string $query If blank, don't run a db call
607 * @param string $type The wpdb function to use with this query
608 * @return mixed $results The cache or query results
609 */
610 public static function check_cache( $cache_key, $group = '', $query = '', $type = 'get_var', $time = 300 ) {
611 $results = wp_cache_get( $cache_key, $group );
612 if ( ! FrmAppHelper::is_empty_value( $results, false ) || empty( $query ) ) {
613 return $results;
614 }
615
616 if ( 'get_posts' == $type ) {
617 $results = get_posts( $query );
618 } elseif ( 'get_associative_results' == $type ) {
619 global $wpdb;
620 $results = $wpdb->get_results( $query, OBJECT_K );
621 } else {
622 global $wpdb;
623 $results = $wpdb->{$type}( $query );
624 }
625
626 self::set_cache( $cache_key, $results, $group, $time );
627
628 return $results;
629 }
630
631 /**
632 * @since 2.05.06
633 */
634 public static function set_cache( $cache_key, $results, $group = '', $time = 300 ) {
635 if ( ! FrmAppHelper::prevent_caching() ) {
636 self::add_key_to_group_cache( $cache_key, $group );
637 wp_cache_set( $cache_key, $results, $group, $time );
638 }
639 }
640
641 /**
642 * Keep track of the keys cached in each group so they can be deleted
643 * in Redis and Memcache
644 * @since 2.05.06
645 */
646 public static function add_key_to_group_cache( $key, $group ) {
647 $cached = self::get_group_cached_keys( $group );
648 $cached[ $key ] = $key;
649 wp_cache_set( 'cached_keys', $cached, $group, 300 );
650 }
651
652 /**
653 * @since 2.05.06
654 */
655 public static function get_group_cached_keys( $group ) {
656 $cached = wp_cache_get( 'cached_keys', $group );
657 if ( ! $cached || ! is_array( $cached ) ) {
658 $cached = array();
659 }
660
661 return $cached;
662 }
663
664 /**
665 * @since 2.05.06
666 * @param string $cache_key
667 */
668 public static function delete_cache_and_transient( $cache_key, $group = 'default' ) {
669 delete_transient( $cache_key );
670 wp_cache_delete( $cache_key, $group );
671 }
672
673 /**
674 * Delete all caching in a single group
675 *
676 * @since 2.05.06
677 *
678 * @param string $group The name of the cache group
679 */
680 public static function cache_delete_group( $group ) {
681 $cached_keys = self::get_group_cached_keys( $group );
682
683 if ( ! empty( $cached_keys ) ) {
684 foreach ( $cached_keys as $key ) {
685 wp_cache_delete( $key, $group );
686 }
687
688 wp_cache_delete( 'cached_keys', $group );
689 }
690 }
691
692 /**
693 * @deprecated 2.05.06
694 */
695 public function upgrade( $old_db_version = false ) {
696 _deprecated_function( __METHOD__, '2.05.06', 'FrmMigrate::upgrade' );
697
698 $db = new FrmMigrate();
699 $db->upgrade( $old_db_version );
700 }
701
702 /**
703 * @deprecated 2.05.06
704 */
705 public function collation() {
706 _deprecated_function( __METHOD__, '2.05.06', 'FrmMigrate::collation' );
707
708 $db = new FrmMigrate();
709 return $db->collation();
710 }
711
712 /**
713 * @deprecated 2.05.06
714 */
715 public function uninstall() {
716 _deprecated_function( __METHOD__, '2.05.06', 'FrmMigrate::uninstall' );
717
718 $db = new FrmMigrate();
719 $db->uninstall();
720 }
721 }
722