Completed
Push — master ( 93a9d6...9e736e )
by Stephanie
02:51
created

FrmDb::get_row()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 4
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
class FrmDb {
4
    var $fields;
5
    var $forms;
6
    var $entries;
7
    var $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
        global $wpdb;
15
        $this->fields         = $wpdb->prefix . 'frm_fields';
16
        $this->forms          = $wpdb->prefix . 'frm_forms';
17
        $this->entries        = $wpdb->prefix . 'frm_items';
18
        $this->entry_metas    = $wpdb->prefix . 'frm_item_metas';
19
    }
20
21
    public function upgrade( $old_db_version = false ) {
22
	    do_action( 'frm_before_install' );
23
24
        global $wpdb;
25
        //$frm_db_version is the version of the database we're moving to
26
        $frm_db_version = FrmAppHelper::$db_version;
27
        $old_db_version = (float) $old_db_version;
28
        if ( ! $old_db_version ) {
29
            $old_db_version = get_option('frm_db_version');
30
        }
31
32
        if ( $frm_db_version != $old_db_version ) {
33
			// update rewrite rules for views and other custom post types
34
			flush_rewrite_rules();
35
36
			require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
37
38
            $this->create_tables();
39
            $this->migrate_data($frm_db_version, $old_db_version);
40
41
            /***** SAVE DB VERSION *****/
42
            update_option('frm_db_version', $frm_db_version);
43
44
            /**** ADD/UPDATE DEFAULT TEMPLATES ****/
45
            FrmXMLController::add_default_templates();
46
47
			if ( ! $old_db_version ) {
48
				$this->maybe_create_contact_form();
49
			}
50
        }
51
52
        do_action('frm_after_install');
53
54
        /**** update the styling settings ****/
55
		if ( is_admin() && function_exists( 'get_filesystem_method' ) ) {
56
			$frm_style = new FrmStyle();
57
			$frm_style->update( 'default' );
58
		}
59
    }
60
61
    public function collation() {
62
        global $wpdb;
63
        if ( ! $wpdb->has_cap( 'collation' ) ) {
64
            return '';
65
        }
66
67
        $charset_collate = '';
68
		if ( ! empty( $wpdb->charset ) ) {
69
			$charset_collate .= ' DEFAULT CHARACTER SET ' . $wpdb->charset;
70
		}
71
72
		if ( ! empty( $wpdb->collate ) ) {
73
			$charset_collate .= ' COLLATE ' . $wpdb->collate;
74
		}
75
76
        return $charset_collate;
77
    }
78
79
    private function create_tables() {
80
        $charset_collate = $this->collation();
81
        $sql = array();
82
83
        /* Create/Upgrade Fields Table */
84
		$sql[] = 'CREATE TABLE ' . $this->fields . ' (
85
				id BIGINT(20) NOT NULL auto_increment,
86
				field_key varchar(100) default NULL,
87
                name text default NULL,
88
                description longtext default NULL,
89
                type text default NULL,
90
                default_value longtext default NULL,
91
                options longtext default NULL,
92
                field_order int(11) default 0,
93
                required int(1) default NULL,
94
                field_options longtext default NULL,
95
                form_id int(11) default NULL,
96
                created_at datetime NOT NULL,
97
                PRIMARY KEY  (id),
98
                KEY form_id (form_id),
99
                UNIQUE KEY field_key (field_key)
100
        )';
101
102
        /* Create/Upgrade Forms Table */
103
		$sql[] = 'CREATE TABLE ' . $this->forms . ' (
104
                id int(11) NOT NULL auto_increment,
105
				form_key varchar(100) default NULL,
106
                name varchar(255) default NULL,
107
                description text default NULL,
108
                parent_form_id int(11) default 0,
109
                logged_in tinyint(1) default NULL,
110
                editable tinyint(1) default NULL,
111
                is_template tinyint(1) default 0,
112
                default_template tinyint(1) default 0,
113
                status varchar(255) default NULL,
114
                options longtext default NULL,
115
                created_at datetime NOT NULL,
116
                PRIMARY KEY  (id),
117
                UNIQUE KEY form_key (form_key)
118
        )';
119
120
        /* Create/Upgrade Items Table */
121
		$sql[] = 'CREATE TABLE ' . $this->entries . ' (
122
				id BIGINT(20) NOT NULL auto_increment,
123
				item_key varchar(100) default NULL,
124
                name varchar(255) default NULL,
125
                description text default NULL,
126
                ip text default NULL,
127
				form_id BIGINT(20) default NULL,
128
				post_id BIGINT(20) default NULL,
129
				user_id BIGINT(20) default NULL,
130
				parent_item_id BIGINT(20) default 0,
131
				is_draft tinyint(1) default 0,
132
				updated_by BIGINT(20) default NULL,
133
                created_at datetime NOT NULL,
134
                updated_at datetime NOT NULL,
135
                PRIMARY KEY  (id),
136
                KEY form_id (form_id),
137
                KEY post_id (post_id),
138
                KEY user_id (user_id),
139
                KEY parent_item_id (parent_item_id),
140
                UNIQUE KEY item_key (item_key)
141
        )';
142
143
        /* Create/Upgrade Meta Table */
144
		$sql[] = 'CREATE TABLE ' . $this->entry_metas . ' (
145
				id BIGINT(20) NOT NULL auto_increment,
146
				meta_value longtext default NULL,
147
				field_id BIGINT(20) NOT NULL,
148
				item_id BIGINT(20) NOT NULL,
149
                created_at datetime NOT NULL,
150
                PRIMARY KEY  (id),
151
                KEY field_id (field_id),
152
                KEY item_id (item_id)
153
        )';
154
155
        foreach ( $sql as $q ) {
156
			if ( function_exists( 'dbDelta' ) ) {
157
				dbDelta( $q . $charset_collate . ';' );
158
			} else {
159
				global $wpdb;
160
				$wpdb->query( $q . $charset_collate );
161
			}
162
            unset($q);
163
        }
164
    }
165
166
	private function maybe_create_contact_form() {
167
		$template_id = FrmForm::getIdByKey( 'contact' );
168
		if ( $template_id ) {
169
			$form_id = FrmForm::duplicate( $template_id, false, true );
170
			if ( $form_id ) {
171
				$values = array(
172
					'status'   => 'published',
173
					'form_key' => 'contact-form',
174
				);
175
				FrmForm::update( $form_id, $values );
176
			}
177
		}
178
	}
179
180
    /**
181
     * @param integer $frm_db_version
182
	 * @param int $old_db_version
183
     */
184
	private function migrate_data( $frm_db_version, $old_db_version ) {
185
		$migrations = array( 4, 6, 11, 16, 17, 23, 25 );
186
        foreach ( $migrations as $migration ) {
187
            if ( $frm_db_version >= $migration && $old_db_version < $migration ) {
188
				$function_name = 'migrate_to_' . $migration;
189
                $this->$function_name();
190
            }
191
        }
192
    }
193
194
    /**
195
     * Change array into format $wpdb->prepare can use
196
	 *
197
	 * @param array $args
198
	 * @param string $starts_with
199
     */
200
    public static function get_where_clause_and_values( &$args, $starts_with = ' WHERE ' ) {
201
        if ( empty($args) ) {
202
			// add an arg to prevent prepare from failing
203
			$args = array( 'where' => $starts_with . '1=%d', 'values' => array( 1 ) );
204
			return;
205
        }
206
207
		$where = '';
208
		$values = array();
209
210
		if ( is_array( $args ) ) {
211
			$base_where = $starts_with;
212
			self::parse_where_from_array( $args, $base_where, $where, $values );
213
		}
214
215
		$args = compact( 'where', 'values' );
216
    }
217
218
    /**
219
	 * @param array $args
220
     * @param string $base_where
221
     * @param string $where
222
	 * @param array $values
223
     */
224
    public static function parse_where_from_array( $args, $base_where, &$where, &$values ) {
225
        $condition = ' AND';
226
        if ( isset( $args['or'] ) ) {
227
            $condition = ' OR';
228
            unset( $args['or'] );
229
        }
230
231
        foreach ( $args as $key => $value ) {
232
            $where .= empty( $where ) ? $base_where : $condition;
233
            $array_inc_null = ( ! is_numeric( $key ) && is_array( $value ) && in_array( null, $value ) );
234
            if ( is_numeric( $key ) || $array_inc_null ) {
235
                $where .= ' ( ';
236
                $nested_where = '';
237
                if ( $array_inc_null ) {
238
                    foreach ( $value as $val ) {
239
                        self::parse_where_from_array( array( $key => $val, 'or' => 1 ), '', $nested_where, $values );
240
                    }
241
                } else {
242
                    self::parse_where_from_array( $value, '', $nested_where, $values );
243
                }
244
                $where .= $nested_where;
245
                $where .= ' ) ';
246
            } else {
247
                self::interpret_array_to_sql( $key, $value, $where, $values );
248
            }
249
        }
250
    }
251
252
    /**
253
     * @param string $key
254
	 * @param string|array $value
255
     * @param string $where
256
	 * @param array $values
257
     */
258
    private static function interpret_array_to_sql( $key, $value, &$where, &$values ) {
259
		$key = trim( $key );
260
261
		if ( strpos( $key, 'created_at' ) !== false || strpos( $key, 'updated_at' ) !== false ) {
262
            $k = explode(' ', $key);
263
            $where .= ' DATE_FORMAT(' . reset( $k ) . ', %s) ' . str_replace( reset( $k ), '', $key );
264
            $values[] = '%Y-%m-%d %H:%i:%s';
265
        } else {
266
			$where .= ' ' . $key;
267
        }
268
269
		$lowercase_key = explode( ' ', strtolower( $key ) );
270
		$lowercase_key = end( $lowercase_key );
271
272
        if ( is_array( $value ) ) {
273
            // translate array of values to "in"
274
			if ( strpos( $lowercase_key, 'like' ) !== false ) {
275
				$where = preg_replace('/' . $key . '$/', '', $where);
276
				$where .= '(';
277
				$start = true;
278
				foreach ( $value as $v ) {
279
					if ( ! $start ) {
280
						$where .= ' OR ';
281
					}
282
					$start = false;
283
					$where .= $key . ' %s';
284
					$values[] = '%' . FrmAppHelper::esc_like( $v ) . '%';
285
				}
286
				$where .= ')';
287
			} else if ( ! empty( $value ) ) {
288
				$where .= ' in (' . FrmAppHelper::prepare_array_values( $value, '%s' ) . ')';
289
				$values = array_merge( $values, $value );
290
			}
291
        } else if ( strpos( $lowercase_key, 'like' ) !== false ) {
292
			/**
293
			 * Allow string to start or end with the value
294
			 * If the key is like% then skip the first % for starts with
295
			 * If the key is %like then skip the last % for ends with
296
			 */
297
			$start = '%';
298
			$end = '%';
299
			if ( $lowercase_key == 'like%' ) {
300
				$start = '';
301
				$where = rtrim( $where, '%' );
302
			} else if ( $lowercase_key == '%like' ) {
303
				$end = '';
304
				$where = rtrim( rtrim( $where, '%like' ), '%LIKE' );
305
				$where .= 'like';
306
			}
307
308
			$where .= ' %s';
309
			$values[] = $start . FrmAppHelper::esc_like( $value ) . $end;
310
311
        } else if ( $value === null ) {
312
            $where .= ' IS NULL';
313
        } else {
314
			// allow a - to prevent = from being added
315
			if ( substr( $key, -1 ) == '-' ) {
316
				$where = rtrim( $where, '-' );
317
			} else {
318
				$where .= '=';
319
			}
320
321
			self::add_query_placeholder( $key, $value, $where );
322
323
            $values[] = $value;
324
        }
325
    }
326
327
	/**
328
	 * Add %d, or %s to query
329
	 *
330
	 * @since 2.02.05
331
	 * @param string $key
332
	 * @param int|string $value
333
	 * @param string $where
334
	 */
335
    private static function add_query_placeholder( $key, $value, &$where ) {
336
		if ( is_numeric( $value ) && ( strpos( $key, 'meta_value' ) === false || strpos( $key, '+0' ) !== false ) ) {
337
			$where .= '%d';
338
		} else {
339
			$where .= '%s';
340
		}
341
	}
342
343
    /**
344
     * @param string $table
345
	 * @param array $where
346
	 * @param array $args
347
	 * @return int
348
     */
349
    public static function get_count( $table, $where = array(), $args = array() ) {
350
        $count = self::get_var( $table, $where, 'COUNT(*)', $args );
351
        return $count;
352
    }
353
354
	/**
355
	 * @param string $table
356
	 * @param array $where
357
	 * @param string $field
358
	 * @param array $args
359
	 * @param string $limit
360
	 * @param string $type
361
	 * @return array|null|string|object
362
	 */
363
    public static function get_var( $table, $where = array(), $field = 'id', $args = array(), $limit = '', $type = 'var' ) {
364
        $group = '';
365
        self::get_group_and_table_name( $table, $group );
366
		self::convert_options_to_array( $args, '', $limit );
367
368
		$query = self::generate_query_string_from_pieces( $field, $table, $where, $args );
369
370
		$cache_key = self::generate_cache_key( $where, $args, $field, $type );
371
		$results = FrmAppHelper::check_cache( $cache_key, $group, $query, 'get_' . $type );
372
        return $results;
373
    }
374
375
	/**
376
	 * Generate a cache key from the where query, field, type, and other arguments
377
	 *
378
	 * @since 2.03.07
379
	 *
380
	 * @param array $where
381
	 * @param array $args
382
	 * @param string $field
383
	 * @param string $type
384
	 *
385
	 * @return string
386
	 */
387
	private static function generate_cache_key( $where, $args, $field, $type ) {
388
		$cache_key = '';
389
		$where = FrmAppHelper::array_flatten( $where );
390
		foreach ( $where as $key => $value ) {
391
			$cache_key .= $key . '_' . $value;
392
		}
393
		$cache_key .= implode( '_', $args ) . $field . '_' . $type;
394
		$cache_key = str_replace( array( ' ', ',' ), '_', $cache_key );
395
396
		return $cache_key;
397
	}
398
399
    /**
400
     * @param string $table
401
     * @param array $where
402
	 * @param string $field
403
	 * @param array $args
404
	 * @param string $limit
405
	 * @return mixed
406
     */
407
    public static function get_col( $table, $where = array(), $field = 'id', $args = array(), $limit = '' ) {
408
        return self::get_var( $table, $where, $field, $args, $limit, 'col' );
409
    }
410
411
    /**
412
     * @since 2.0
413
     * @param string $table
414
	 * @param array $where
415
	 * @param string $fields
416
	 * @param array $args
417
	 * @return mixed
418
     */
419
    public static function get_row( $table, $where = array(), $fields = '*', $args = array() ) {
420
        $args['limit'] = 1;
421
        return self::get_var( $table, $where, $fields, $args, '', 'row' );
422
    }
423
424
    /**
425
     * Prepare a key/value array before DB call
426
	 *
427
     * @since 2.0
428
     * @param string $table
429
	 * @param array $where
430
	 * @param string $fields
431
	 * @param array $args
432
	 * @return mixed
433
     */
434
    public static function get_results( $table, $where = array(), $fields = '*', $args = array() ) {
435
        return self::get_var( $table, $where, $fields, $args, '', 'results' );
436
    }
437
438
	/**
439
	 * Check for like, not like, in, not in, =, !=, >, <, <=, >=
440
	 * Return a value to append to the where array key
441
	 *
442
	 * @param string $where_is
443
	 * @return string
444
	 */
445
	public static function append_where_is( $where_is ) {
446
		$switch_to = array(
447
			'='		=> '',
448
			'!=' 	=> '!',
449
			'<='	=> '<',
450
			'>='	=> '>',
451
			'like'	=> 'like',
452
			'not like' => 'not like',
453
			'in'	=> '',
454
			'not in' => 'not',
455
			'like%'	=> 'like%',
456
			'%like'	=> '%like',
457
		);
458
459
		$where_is = strtolower( $where_is );
460
		if ( isset( $switch_to[ $where_is ] ) ) {
461
			return ' ' . $switch_to[ $where_is ];
462
		}
463
464
		// > and < need a little more work since we don't want them switched to >= and <=
465
		if ( $where_is == '>' || $where_is == '<' ) {
466
			return ' ' . $where_is . '-'; // the - indicates that the = should not be added later
467
		}
468
469
		// fallback to = if the query is none of these
470
		return '';
471
	}
472
473
    /**
474
     * Get 'frm_forms' from wp_frm_forms or a longer table param that includes a join
475
     * Also add the wpdb->prefix to the table if it's missing
476
     *
477
     * @param string $table
478
     * @param string $group
479
     */
480
    private static function get_group_and_table_name( &$table, &$group ) {
481
		global $wpdb, $wpmuBaseTablePrefix;
482
483
        $table_parts = explode(' ', $table);
484
        $group = reset($table_parts);
485
        $group = str_replace( $wpdb->prefix, '', $group );
486
487
		$prefix = $wpmuBaseTablePrefix ? $wpmuBaseTablePrefix : $wpdb->base_prefix;
488
		$group = str_replace( $prefix, '', $group );
489
490
        if ( $group == $table ) {
491
            $table = $wpdb->prefix . $table;
492
        }
493
494
		// switch to singular group name
495
		$group = rtrim( $group, 's' );
496
    }
497
498
    private static function convert_options_to_array( &$args, $order_by = '', $limit = '' ) {
499
        if ( ! is_array($args) ) {
500
			$args = array( 'order_by' => $args );
501
        }
502
503
        if ( ! empty( $order_by ) ) {
504
            $args['order_by'] = $order_by;
505
        }
506
507
        if ( ! empty( $limit ) ) {
508
            $args['limit'] = $limit;
509
        }
510
511
        $temp_args = $args;
512
        foreach ( $temp_args as $k => $v ) {
513
            if ( $v == '' ) {
514
				unset( $args[ $k ] );
515
                continue;
516
            }
517
518
            if ( $k == 'limit' ) {
519
				$args[ $k ] = FrmAppHelper::esc_limit( $v );
520
            }
521
            $db_name = strtoupper( str_replace( '_', ' ', $k ) );
522
            if ( strpos( $v, $db_name ) === false ) {
523
				$args[ $k ] = $db_name . ' ' . $v;
524
            }
525
        }
526
527
		// Make sure LIMIT is the last argument
528
		if ( isset( $args['order_by'] ) && isset( $args['limit'] ) ) {
529
			$temp_limit = $args['limit'];
530
			unset( $args['limit'] );
531
			$args['limit'] = $temp_limit;
532
		}
533
    }
534
535
	/**
536
	 * Get the associative array results for the given columns, table, and where query
537
	 *
538
	 * @since 2.02.05
539
	 * @param string $columns
540
	 * @param string $table
541
	 * @param array $where
542
	 * @return mixed
543
	 */
544
	public static function get_associative_array_results( $columns, $table, $where ) {
545
		$group = '';
546
		self::get_group_and_table_name( $table, $group );
547
548
		$query = self::generate_query_string_from_pieces( $columns, $table, $where );
549
550
		$cache_key = str_replace( array( ' ', ',' ), '_', trim( implode( '_', FrmAppHelper::array_flatten( $where ) ) . $columns . '_results_ARRAY_A' , ' WHERE' ) );
551
		$results = FrmAppHelper::check_cache( $cache_key, $group, $query, 'get_associative_results' );
552
553
		return $results;
554
	}
555
556
	/**
557
	 * Combine the pieces of a query to form a full, prepared query
558
	 *
559
	 * @since 2.02.05
560
	 *
561
	 * @param string $columns
562
	 * @param string $table
563
	 * @param mixed $where
564
	 * @param array $args
565
	 * @return string
566
	 */
567
	private static function generate_query_string_from_pieces( $columns, $table, $where, $args = array() ) {
568
		$query = 'SELECT ' . $columns . ' FROM ' . $table;
569
570
		if ( is_array( $where ) || empty( $where ) ) {
571
			self::get_where_clause_and_values( $where );
572
			global $wpdb;
573
			$query = $wpdb->prepare( $query . $where['where'] . ' ' . implode( ' ', $args ), $where['values'] );
574
		} else {
575
			/**
576
			 * Allow the $where to be prepared before we recieve it here.
577
			 * This is a fallback for reverse compatability, but is not recommended
578
			 */
579
			_deprecated_argument( 'where', '2.0', __( 'Use the query in an array format so it can be properly prepared.', 'formidable' ) );
580
			$query .= $where . ' ' . implode( ' ', $args );
581
		}
582
583
		return $query;
584
	}
585
586
	/**
587
	 * Only allow specific Order options
588
	 * @since 2.05.06
589
	 */
590
	public static function sanitize_order( $order ) {
591
		$allowed = array( 'rand()', 'asc', 'desc' );
592
		$order = trim( strtolower( $order ) );
593
		if ( ! in_array( $order, $allowed ) ) {
594
			$order = '';
595
		}
596
		return $order;
597
	}
598
599
    public function uninstall() {
600
		if ( ! current_user_can( 'administrator' ) ) {
601
            $frm_settings = FrmAppHelper::get_settings();
602
            wp_die($frm_settings->admin_permission);
603
        }
604
605
        global $wpdb, $wp_roles;
606
607
		$wpdb->query( 'DROP TABLE IF EXISTS ' . $this->fields );
608
		$wpdb->query( 'DROP TABLE IF EXISTS ' . $this->forms );
609
		$wpdb->query( 'DROP TABLE IF EXISTS ' . $this->entries );
610
		$wpdb->query( 'DROP TABLE IF EXISTS ' . $this->entry_metas );
611
612
        delete_option('frm_options');
613
        delete_option('frm_db_version');
614
615
        //delete roles
616
        $frm_roles = FrmAppHelper::frm_capabilities();
617
        $roles = get_editable_roles();
618
        foreach ( $frm_roles as $frm_role => $frm_role_description ) {
619
            foreach ( $roles as $role => $details ) {
620
                $wp_roles->remove_cap( $role, $frm_role );
621
                unset($role, $details);
622
    		}
623
    		unset($frm_role, $frm_role_description);
624
		}
625
		unset($roles, $frm_roles);
626
627
		// delete actions, views, and styles
628
629
		// prevent the post deletion from triggering entries to be deleted
630
		remove_action( 'before_delete_post', 'FrmProDisplaysController::before_delete_post' );
631
		remove_action( 'deleted_post', 'FrmProEntriesController::delete_entry' );
632
633
		$post_ids = $wpdb->get_col( $wpdb->prepare( 'SELECT ID FROM ' . $wpdb->posts . ' WHERE post_type in (%s, %s, %s)', FrmFormActionsController::$action_post_type, FrmStylesController::$post_type, 'frm_display' ) );
634
		foreach ( $post_ids as $post_id ) {
635
			// Delete's each post.
636
			wp_delete_post( $post_id, true );
637
		}
638
		unset( $post_ids );
639
640
		// delete transients
641
		delete_transient( 'frmpro_css' );
642
		delete_transient( 'frm_options' );
643
		delete_transient( 'frmpro_options' );
644
645
		$wpdb->query( $wpdb->prepare( 'DELETE FROM ' . $wpdb->options . ' WHERE option_name LIKE %s OR option_name LIKE %s', '_transient_timeout_frm_form_fields_%', '_transient_frm_form_fields_%' ) );
646
647
        do_action('frm_after_uninstall');
648
        return true;
649
    }
650
651
	/**
652
	 * Migrate old styling settings. If sites are using the old
653
	 * default 400px field width, switch it to 100%
654
	 *
655
	 * @since 2.0.4
656
	 */
657
	private function migrate_to_25() {
658
		// get the style that was created with the style migration
659
		$frm_style = new FrmStyle();
660
		$styles = $frm_style->get_all( 'post_date', 'ASC', 1 );
661
		if ( empty( $styles ) ) {
662
			return;
663
		}
664
665
		foreach ( $styles as $style ) {
666
			if ( $style->post_content['field_width'] == '400px' ) {
667
				$style->post_content['field_width'] = '100%';
668
				$frm_style->save( (array) $style );
669
				return;
670
			}
671
		}
672
	}
673
674
	/**
675
	 * Check if the parent_form_id columns exists.
676
	 * If not, try and add it again
677
	 *
678
	 * @since 2.0.2
679
	 */
680
	private function migrate_to_23() {
681
		global $wpdb;
682
		$exists = $wpdb->get_row( 'SHOW COLUMNS FROM ' . $this->forms . ' LIKE "parent_form_id"' );
683
		if ( empty( $exists ) ) {
684
			$wpdb->query( 'ALTER TABLE ' . $this->forms . ' ADD parent_form_id int(11) default 0' );
685
		}
686
	}
687
688
    /**
689
     * Change field size from character to pixel -- Multiply by 9
690
     */
691
    private function migrate_to_17() {
692
        global $wpdb;
693
		$pixel_conversion = 9;
694
695
        // Get query arguments
696
		$field_types = array( 'textarea', 'text', 'number', 'email', 'url', 'rte', 'date', 'phone', 'password', 'image', 'tag', 'file' );
697
		$query = array( 'type' => $field_types, 'field_options like' => 's:4:"size";', 'field_options not like' => 's:4:"size";s:0:' );
698
699
        // Get results
700
		$fields = FrmDb::get_results( $this->fields, $query, 'id, field_options' );
701
702
        $updated = 0;
703
        foreach ( $fields as $f ) {
0 ignored issues
show
Bug introduced by
The expression $fields of type array|null|string|object is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
704
            $f->field_options = maybe_unserialize($f->field_options);
705
            if ( empty($f->field_options['size']) || ! is_numeric($f->field_options['size']) ) {
706
                continue;
707
            }
708
709
			$f->field_options['size'] = round( $pixel_conversion * (int) $f->field_options['size'] );
710
            $f->field_options['size'] .= 'px';
711
            $u = FrmField::update( $f->id, array( 'field_options' => $f->field_options ) );
712
            if ( $u ) {
713
                $updated++;
714
            }
715
            unset($f);
716
        }
717
718
        // Change the characters in widgets to pixels
719
        $widgets = get_option('widget_frm_show_form');
720
        if ( empty($widgets) ) {
721
            return;
722
        }
723
724
        $widgets = maybe_unserialize($widgets);
725
        foreach ( $widgets as $k => $widget ) {
726
            if ( ! is_array($widget) || ! isset($widget['size']) ) {
727
                continue;
728
            }
729
			$size = round( $pixel_conversion * (int) $widget['size'] );
730
            $size .= 'px';
731
			$widgets[ $k ]['size'] = $size;
732
        }
733
        update_option('widget_frm_show_form', $widgets);
734
    }
735
736
    /**
737
     * Migrate post and email notification settings into actions
738
     */
739
    private function migrate_to_16() {
740
        global $wpdb;
741
742
        $forms = FrmDb::get_results( $this->forms, array(), 'id, options, is_template, default_template' );
743
744
        /**
745
        * Old email settings format:
746
        * email_to: Email or field id
747
        * also_email_to: array of fields ids
748
        * reply_to: Email, field id, 'custom'
749
        * cust_reply_to: string
750
        * reply_to_name: field id, 'custom'
751
        * cust_reply_to_name: string
752
        * plain_text: 0|1
753
        * email_message: string or ''
754
        * email_subject: string or ''
755
        * inc_user_info: 0|1
756
        * update_email: 0, 1, 2
757
        *
758
        * Old autoresponder settings format:
759
        * auto_responder: 0|1
760
        * ar_email_message: string or ''
761
        * ar_email_to: field id
762
        * ar_plain_text: 0|1
763
        * ar_reply_to_name: string
764
        * ar_reply_to: string
765
        * ar_email_subject: string
766
        * ar_update_email: 0, 1, 2
767
        *
768
        * New email settings:
769
        * post_content: json settings
770
        * post_title: form id
771
        * post_excerpt: message
772
        *
773
        */
774
775
        foreach ( $forms as $form ) {
0 ignored issues
show
Bug introduced by
The expression $forms of type array|null|string|object is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
776
			if ( $form->is_template && $form->default_template ) {
777
				// don't migrate the default templates since the email will be added anyway
778
				continue;
779
			}
780
781
            // Format form options
782
            $form_options = maybe_unserialize($form->options);
783
784
            // Migrate settings to actions
785
            FrmXMLHelper::migrate_form_settings_to_actions( $form_options, $form->id );
786
        }
787
    }
788
789
    private function migrate_to_11() {
790
        global $wpdb;
791
792
        $forms = FrmDb::get_results( $this->forms, array(), 'id, options');
793
794
        $sending = __( 'Sending', 'formidable' );
795
		$img = FrmAppHelper::plugin_url() . '/images/ajax_loader.gif';
796
        $old_default_html = <<<DEFAULT_HTML
797
<div class="frm_submit">
798
[if back_button]<input type="submit" value="[back_label]" name="frm_prev_page" formnovalidate="formnovalidate" [back_hook] />[/if back_button]
799
<input type="submit" value="[button_label]" [button_action] />
800
<img class="frm_ajax_loading" src="$img" alt="$sending" style="visibility:hidden;" />
801
</div>
802
DEFAULT_HTML;
803
        unset($sending, $img);
804
805
        $new_default_html = FrmFormsHelper::get_default_html('submit');
806
        $draft_link = FrmFormsHelper::get_draft_link();
807
		foreach ( $forms as $form ) {
0 ignored issues
show
Bug introduced by
The expression $forms of type array|null|string|object is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
808
            $form->options = maybe_unserialize($form->options);
809
            if ( ! isset($form->options['submit_html']) || empty($form->options['submit_html']) ) {
810
                continue;
811
            }
812
813
            if ( $form->options['submit_html'] != $new_default_html && $form->options['submit_html'] == $old_default_html ) {
814
                $form->options['submit_html'] = $new_default_html;
815
				$wpdb->update( $this->forms, array( 'options' => serialize( $form->options ) ), array( 'id' => $form->id ) );
816
			} else if ( ! strpos( $form->options['submit_html'], 'save_draft' ) ) {
817
				$form->options['submit_html'] = preg_replace( '~\<\/div\>(?!.*\<\/div\>)~', $draft_link . "\r\n</div>", $form->options['submit_html'] );
818
				$wpdb->update( $this->forms, array( 'options' => serialize( $form->options ) ), array( 'id' => $form->id ) );
819
            }
820
            unset($form);
821
        }
822
        unset($forms);
823
    }
824
825
    private function migrate_to_6() {
826
        global $wpdb;
827
828
		$no_save = array_merge( FrmField::no_save_fields(), array( 'form', 'hidden', 'user_id' ) );
829
		$fields = FrmDb::get_results( $this->fields, array( 'type NOT' => $no_save ), 'id, field_options' );
830
831
        $default_html = <<<DEFAULT_HTML
832
<div id="frm_field_[id]_container" class="form-field [required_class] [error_class]">
833
    <label class="frm_pos_[label_position]">[field_name]
834
        <span class="frm_required">[required_label]</span>
835
    </label>
836
    [input]
837
    [if description]<div class="frm_description">[description]</div>[/if description]
838
</div>
839
DEFAULT_HTML;
840
841
        $old_default_html = <<<DEFAULT_HTML
842
<div id="frm_field_[id]_container" class="form-field [required_class] [error_class]">
843
    <label class="frm_pos_[label_position]">[field_name]
844
        <span class="frm_required">[required_label]</span>
845
    </label>
846
    [input]
847
    [if description]<p class="frm_description">[description]</p>[/if description]
848
</div>
849
DEFAULT_HTML;
850
851
        $new_default_html = FrmFieldsHelper::get_default_html('text');
852
        foreach ( $fields as $field ) {
0 ignored issues
show
Bug introduced by
The expression $fields of type array|null|string|object is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
853
            $field->field_options = maybe_unserialize($field->field_options);
854
			$html = FrmField::get_option( $field, 'custom_html' );
855
			if ( $html == $default_html || $html == $old_default_html ) {
856
                $field->field_options['custom_html'] = $new_default_html;
857
				$wpdb->update( $this->fields, array( 'field_options' => maybe_serialize( $field->field_options ) ), array( 'id' => $field->id ) );
858
            }
859
            unset($field);
860
        }
861
        unset($default_html, $old_default_html, $fields);
862
    }
863
864
    private function migrate_to_4() {
865
        global $wpdb;
866
		$user_ids = FrmEntryMeta::getAll( array( 'fi.type' => 'user_id' ) );
867
        foreach ( $user_ids as $user_id ) {
868
			$wpdb->update( $this->entries, array( 'user_id' => $user_id->meta_value ), array( 'id' => $user_id->item_id ) );
869
        }
870
    }
871
}
872