PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.32
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.32
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
← All changes | classes/models/FrmUsage.php +329 -61 6.36.32 View file →
@@ -17,28 +17,41 @@
17 17 if ( ! $this->tracking_allowed() ) {
18 18 return;
19 19 }
20 20
21 - $ep = 'aHR0cHM6Ly9mcm0tdXNlci10cmFja2luZy5oZXJva3VhcHAuY29tL3NuYXBzaG90';
21 + $snapshot = $this->snapshot();
22 + $this->clean_before_send( $snapshot );
23 +
24 + $ep = 'aHR0cHM6Ly91c2FnZTIuZm9ybWlkYWJsZWZvcm1zLmNvbS9zbmFwc2hvdA==';
22 25 // $ep = base64_encode( 'http://localhost:4567/snapshot' ); // Uncomment for testing
23 - $body = json_encode( $this->snapshot() );
26 + $body = json_encode( $snapshot );
24 27
25 28 // Setup variable for wp_remote_request.
26 29 $post = array(
27 - 'method' => 'POST',
28 - 'headers' => array(
30 + 'method' => 'POST',
31 + 'headers' => array(
29 32 'Accept' => 'application/json',
30 33 'Content-Type' => 'application/json',
31 34 'Content-Length' => strlen( $body ),
32 35 ),
33 - 'body' => $body,
36 + 'body' => $body,
37 + // Without this, Debug Log catches the `http_request_failed` error.
38 + 'timeout' => 45,
34 39 );
35 40
41 + // Remove time limit to execute this function.
42 + if ( function_exists( 'set_time_limit' ) ) {
43 + set_time_limit( 0 );
44 + }
45 +
36 46 wp_remote_request( base64_decode( $ep ), $post );
37 47 }
38 48
39 49 /**
40 50 * @since 3.06.04
51 + *
52 + * @param bool $regenerate
53 + *
41 54 * @return string
42 55 */
43 56 public function uuid( $regenerate = false ) {
44 57 $uuid_key = 'frm-usage-uuid';
@@ -43,13 +56,13 @@
43 56 public function uuid( $regenerate = false ) {
44 57 $uuid_key = 'frm-usage-uuid';
45 58 $uuid = get_option( $uuid_key );
46 59
47 - if ( $regenerate || empty( $uuid ) ) {
60 + if ( $regenerate || ! $uuid ) {
48 61 // Definitely not cryptographically secure but
49 - // close enough to provide an unique id
62 + // close enough to provide a unique id
50 63 $uuid = md5( uniqid() . site_url() );
51 - update_option( $uuid_key, $uuid, 'no' );
64 + update_option( $uuid_key, $uuid, false );
52 65 }
53 66
54 67 return $uuid;
55 68 }
@@ -55,8 +68,9 @@
55 68 }
56 69
57 70 /**
58 71 * @since 3.06.04
72 + *
59 73 * @return array
60 74 */
61 75 public function snapshot() {
62 76 global $wpdb, $wp_version;
@@ -64,48 +78,259 @@
64 78 $theme_data = wp_get_theme();
65 79 $form_counts = FrmForm::get_count();
66 80
67 81 $snap = array(
68 - 'uuid' => $this->uuid(),
69 - 'admin_email' => '', // Let's keep it anonymous.
70 - 'wp_version' => $wp_version,
71 - 'php_version' => phpversion(),
72 - 'mysql_version' => $wpdb->db_version(),
73 - 'os' => php_uname( 's' ),
74 - 'locale' => get_locale(),
82 + 'uuid' => $this->uuid(),
83 + 'wp_version' => $wp_version,
84 + 'php_version' => phpversion(),
85 + 'mysql_version' => $wpdb->db_version(),
86 + 'os' => FrmAppHelper::get_server_os(),
87 + 'locale' => get_locale(),
75 88
76 - 'active_license' => FrmAppHelper::pro_is_installed(),
77 - 'form_count' => $form_counts->published,
78 - 'entry_count' => FrmEntry::getRecordCount(),
79 - 'timestamp' => gmdate( 'c' ),
89 + 'active_license' => FrmAppHelper::pro_is_installed(),
90 + 'form_count' => $form_counts->published,
91 + 'entry_count' => FrmEntry::getRecordCount(),
92 + 'timestamp' => gmdate( 'c' ),
93 + 'misc' => array(),
80 94
81 - 'theme_name' => is_object( $theme_data ) ? $theme_data->Name : '', // phpcs:ignore WordPress.NamingConventions
82 - 'plugins' => $this->plugins(),
83 - 'settings' => array(
95 + 'theme_name' => is_object( $theme_data ) ? $theme_data->Name : '', // phpcs:ignore WordPress.NamingConventions
96 + 'plugins' => $this->plugins(),
97 + 'settings' => array(
84 98 $this->settings(),
85 99 ),
86 - 'forms' => $this->forms(),
87 - 'fields' => $this->fields(),
88 - 'actions' => $this->actions(),
100 + 'forms' => $this->forms(),
101 + 'fields' => $this->fields(),
102 + 'actions' => $this->actions(),
103 +
104 + 'onboarding-wizard' => $this->onboarding_wizard(),
105 + 'welcome-tour' => FrmWelcomeTourController::get_usage_data(),
106 + 'flows' => FrmUsageController::get_flows_data(),
107 + 'payments' => $this->payments(),
108 + 'subscriptions' => $this->payments( 'frm_subscriptions' ),
89 109 );
90 110
111 + if ( method_exists( 'FrmProAddonsController', 'get_readable_license_type' ) ) {
112 + $snap['active_license'] = FrmProAddonsController::get_readable_license_type();
113 + }
114 +
91 115 return apply_filters( 'frm_usage_snapshot', $snap );
92 116 }
93 117
94 118 /**
119 + * Cleans the snapshot data before sending.
120 + *
121 + * @param array $data Snapshot data.
122 + *
123 + * @return void
124 + */
125 + private function clean_before_send( &$data ) {
126 + $skip_keys = array(
127 + 'plan_id',
128 + 'paypal_item_name',
129 + 'account_num',
130 + 'routing_num',
131 + 'bank_name',
132 + 'business_email',
133 +
134 + // Form action settings.
135 + 'quiz',
136 + 'email_to',
137 + 'cc',
138 + 'bcc',
139 + 'from',
140 + 'email_subject',
141 + 'email_msg',
142 + 'email_message',
143 + 'success_msg',
144 + 'success_url',
145 + 'success_page_id',
146 + 'redirect_msg',
147 + 'conditions',
148 + 'list_id',
149 + 'api_key',
150 + 'url',
151 + 'data_fields',
152 + 'reg_email_msg',
153 +
154 + // Form settings.
155 + 'form_id',
156 + 'description',
157 + 'submit_conditions-hide_field',
158 + 'submit_conditions-hide_field_cond',
159 + 'submit_conditions-hide_opt',
160 + 'submit_conditions-show_hide',
161 + 'submit_conditions-any_all',
162 +
163 + // Field settings.
164 + 'show_hide',
165 + 'any_all',
166 + 'hide_field',
167 + 'hide_field_cond',
168 + 'hide_opt',
169 + 'custom_html',
170 + 'blank',
171 + 'required_indicator',
172 + 'invalid',
173 + 'unique_msg',
174 + 'edit_text',
175 + 'start_over_label',
176 + 'add_label',
177 + 'remove_label',
178 + 'draft',
179 + );
180 +
181 + /**
182 + * Filter the keys to skip when cleaning the snapshot data before sending.
183 + *
184 + * @since 6.28
185 + *
186 + * @param array $skip_keys Data keys.
187 + */
188 + $skip_keys = apply_filters( 'frm_usage_skip_keys', $skip_keys );
189 +
190 + $long_text_keys = array( 'description' );
191 +
192 + /**
193 + * Filter the keys to replace with a long text placeholder before sending.
194 + *
195 + * @since 6.28
196 + *
197 + * @paramm array $long_text_keys Data keys.
198 + */
199 + $long_text_keys = apply_filters( 'frm_usage_long_text_keys', $long_text_keys );
200 +
201 + foreach ( $data as $key => &$value ) {
202 + if ( ! $value ) {
203 + continue;
204 + }
205 +
206 + if ( in_array( $key, $skip_keys, true ) || str_ends_with( $key, '_url' ) ) {
207 + unset( $data[ $key ] );
208 + continue;
209 + }
210 +
211 + if ( is_object( $value ) ) {
212 + $value = '{{object}}';
213 + continue;
214 + }
215 +
216 + if ( is_array( $value ) ) {
217 + $this->clean_before_send( $value );
218 + continue;
219 + }
220 +
221 + if ( in_array( $key, $long_text_keys, true ) || str_ends_with( $key, '_msg' ) ) {
222 + // Replace it with a placeholder.
223 + $value = '{{long_text}}';
224 + continue;
225 + }
226 +
227 + // If key ends with `_email`, or value contains `@`, this might contain an email address.
228 + if ( str_ends_with( $key, '_email' ) || str_contains( $value, '@' ) ) {
229 + // Replace it with a placeholder.
230 + $value = '{{contain_email}}';
231 + }
232 + }//end foreach
233 + }
234 +
235 + /**
236 + * Gets onboarding wizard data.
237 + *
238 + * @since 6.16.1
239 + *
240 + * @return array
241 + */
242 + private function onboarding_wizard() {
243 + $data = FrmOnboardingWizardController::get_usage_data();
244 + $skipped_keys = array(
245 + 'default_email',
246 + 'is_subscribed',
247 + 'allows_tracking',
248 + 'summary_emails',
249 + 'installed_addons',
250 + );
251 +
252 + foreach ( $skipped_keys as $skipped_key ) {
253 + unset( $data[ $skipped_key ] );
254 + }
255 +
256 + return $data;
257 + }
258 +
259 + /**
260 + * Gets payments data.
261 + *
262 + * @since 6.16.1
263 + *
264 + * @param string $table Database table name.
265 + *
266 + * @return array
267 + */
268 + private function payments( $table = 'frm_payments' ) {
269 + $allowed_tables = array( 'frm_payments', 'frm_subscriptions' );
270 +
271 + if ( ! in_array( $table, $allowed_tables, true ) || ! FrmTransLiteAppHelper::payments_table_exists() ) {
272 + return array();
273 + }
274 +
275 + $rows = $this->get_payment_db_rows( $table );
276 + $payments = array();
277 +
278 + foreach ( $rows as $row ) {
279 + $payments[] = array(
280 + 'amount' => (float) $row->amount,
281 + 'status' => $row->status,
282 + 'gateway' => $row->paysys,
283 + 'created_at' => $row->created_at,
284 + );
285 + }
286 +
287 + return $payments;
288 + }
289 +
290 + /**
291 + * @since 6.30
292 + *
293 + * @param string $table
294 + *
295 + * @return array
296 + */
297 + private function get_payment_db_rows( $table ) {
298 + global $wpdb;
299 +
300 + if ( FrmDb::db_column_exists( $table, 'test' ) ) {
301 + return $wpdb->get_results(
302 + $wpdb->prepare(
303 + 'SELECT amount, status, paysys, created_at FROM %i WHERE test IS NULL OR test != 1',
304 + $wpdb->prefix . $table
305 + )
306 + );
307 + }
308 +
309 + // Fallback for PayPal add-on where this column does not exist.
310 + return $wpdb->get_results(
311 + $wpdb->prepare(
312 + 'SELECT amount, status, paysys, created_at FROM %i',
313 + $wpdb->prefix . $table
314 + )
315 + );
316 + }
317 +
318 + /**
95 319 * @since 3.06.04
320 + *
96 321 * @return array
97 322 */
98 323 private function plugins() {
99 324 $plugin_list = FrmAppHelper::get_plugins();
325 + $plugins = array();
100 326
101 - $plugins = array();
102 327 foreach ( $plugin_list as $slug => $info ) {
103 328 $plugins[] = array(
104 - 'name' => $info['Name'],
105 - 'slug' => $slug,
106 - 'version' => $info['Version'],
107 - 'active' => is_plugin_active( $slug ),
329 + 'name' => $info['Name'],
330 + 'slug' => $slug,
331 + 'version' => $info['Version'],
332 + 'active' => is_plugin_active( $slug ),
108 333 );
109 334 }
110 335
111 336 return $plugins;
@@ -114,21 +339,20 @@
114 339 /**
115 340 * Add global settings to tracking data.
116 341 *
117 342 * @since 3.06.04
343 + *
118 344 * @return array
119 345 */
120 346 private function settings() {
121 - $settings_list = FrmAppHelper::get_settings();
122 - $settings = array(
347 + $settings_list = FrmAppHelper::get_settings();
348 + $settings = array(
123 349 'messages' => $this->messages( $settings_list ),
124 350 'permissions' => $this->permissions( $settings_list ),
125 351 );
126 352 $pass_settings = array(
127 353 'load_style',
128 - 'use_html',
129 354 'fade_form',
130 - 'jquery_css',
131 355 're_type',
132 356 're_lang',
133 357 're_multi',
134 358 'menu',
@@ -133,11 +357,20 @@
133 357 're_multi',
134 358 'menu',
135 359 'mu_menu',
136 360 'no_ips',
361 + 'custom_header_ip',
362 + 'enable_gdpr',
363 + 'no_gdpr_cookies',
137 364 'btsp_css',
138 - 'btsp_errors',
365 + 'btsp_version',
139 366 'admin_bar',
367 + 'summary_emails',
368 + 'active_captcha',
369 + 'honeypot',
370 + 'wp_spam_check',
371 + 'denylist_check',
372 + 'email_style',
140 373 );
141 374
142 375 foreach ( $pass_settings as $setting ) {
143 376 if ( isset( $settings_list->$setting ) ) {
@@ -157,11 +390,10 @@
157 390 * Include the permissions settings for each capability.
158 391 *
159 392 * @since 3.06.04
160 393 *
161 - * @return array
394 + * @param FrmSettings $settings_list
162 395 *
163 - * @param FrmSettings $settings_list
164 396 * @return array
165 397 */
166 398 private function messages( $settings_list ) {
167 399 $messages = array(
@@ -174,11 +406,13 @@
174 406 'login_msg',
175 407 'admin_permission',
176 408 );
177 409
410 + $default = $settings_list->default_options();
178 411 $message_settings = array();
412 +
179 413 foreach ( $messages as $message ) {
180 - $message_settings[ $message ] = $settings_list->$message;
414 + $message_settings[ 'changed-' . $message ] = $settings_list->$message === $default[ $message ] ? 0 : 1;
181 415 }
182 416
183 417 return $message_settings;
184 418 }
@@ -188,8 +422,9 @@
188 422 *
189 423 * @since 3.06.04
190 424 *
191 425 * @param FrmSettings $settings_list
426 + *
192 427 * @return array
193 428 */
194 429 private function permissions( $settings_list ) {
195 430 $permissions = array();
@@ -205,15 +440,16 @@
205 440 }
206 441
207 442 /**
208 443 * @since 3.06.04
444 + *
209 445 * @return array
210 446 */
211 447 private function forms() {
212 448 $s_query = array(
213 449 array(
214 - 'or' => 1,
215 - 'parent_form_id' => null,
450 + 'or' => 1,
451 + 'parent_form_id' => null,
216 452 'parent_form_id <' => 1,
217 453 ),
218 454 );
219 455
@@ -221,10 +457,10 @@
221 457 $forms = array();
222 458 $settings = array(
223 459 'form_class',
224 460 'akismet',
225 - 'honeypot',
226 461 'antispam',
462 + 'stopforumspam',
227 463 'custom_style',
228 464 'success_action',
229 465 'show_form',
230 466 'no_save',
@@ -253,28 +489,48 @@
253 489 'prev_value',
254 490 'submit_conditions',
255 491 );
256 492
493 + $style = new FrmStyle();
494 +
257 495 foreach ( $saved_forms as $form ) {
258 496 $new_form = array(
259 - 'form_id' => $form->id,
260 - 'description' => $form->description,
261 - 'logged_in' => $form->logged_in,
262 - 'editable' => $form->editable,
263 - 'is_template' => $form->is_template,
264 - 'entry_count' => FrmEntry::getRecordCount( $form->id ),
265 - 'field_count' => $this->form_field_count( $form->id ),
497 + 'form_id' => $form->id,
498 + 'description' => $form->description,
499 + 'logged_in' => $form->logged_in,
500 + 'editable' => $form->editable,
501 + 'is_template' => $form->is_template,
502 + 'entry_count' => FrmEntry::getRecordCount( $form->id ),
503 + 'field_count' => $this->form_field_count( $form->id ),
266 504 'form_action_count' => $this->form_action_count( $form->id ),
267 505 );
268 506
269 507 foreach ( $settings as $setting ) {
270 - if ( isset( $form->options[ $setting ] ) ) {
508 + if ( ! isset( $form->options[ $setting ] ) ) {
509 + continue;
510 + }
511 +
512 + if ( 'custom_style' !== $setting ) {
271 513 $new_form[ $setting ] = $this->maybe_json( $form->options[ $setting ] );
514 + continue;
272 515 }
273 - }
274 516
517 + $style->id = $form->options[ $setting ];
518 +
519 + if ( ! $style->id ) {
520 + $style_name = 0;
521 + } elseif ( 1 === intval( $style->id ) ) {
522 + $style_name = 'formidable-style';
523 + } else {
524 + $style_post = $style->get_one();
525 + $style_name = $style_post ? $style_post->post_name : 'formidable-style';
526 + }
527 +
528 + $new_form[ $setting ] = $style_name;
529 + }//end foreach
530 +
275 531 $forms[] = apply_filters( 'frm_usage_form', $new_form, compact( 'form' ) );
276 - }
532 + }//end foreach
277 533
278 534 // If the array uses numeric keys, reset them.
279 535 return $forms;
280 536 }
@@ -280,14 +536,17 @@
280 536 }
281 537
282 538 /**
283 539 * @since 3.06.04
540 + *
541 + * @param int|string $form_id Form ID.
542 + *
284 543 * @return int
285 544 */
286 545 private function form_field_count( $form_id ) {
287 546 global $wpdb;
288 547
289 - $join = $wpdb->prefix . 'frm_fields fi LEFT OUTER JOIN ' . $wpdb->prefix . 'frm_forms fo ON (fi.form_id=fo.id)';
548 + $join = $wpdb->prefix . 'frm_fields fi JOIN ' . $wpdb->prefix . 'frm_forms fo ON (fi.form_id=fo.id)';
290 549
291 550 $field_query = array(
292 551 'or' => 1,
293 552 'fi.form_id' => $form_id,
@@ -298,8 +557,11 @@
298 557 }
299 558
300 559 /**
301 560 * @since 3.06.04
561 + *
562 + * @param int|string $form_id Form ID.
563 + *
302 564 * @return int
303 565 */
304 566 private function form_action_count( $form_id ) {
305 567 $args = array(
@@ -315,26 +577,30 @@
315 577 /**
316 578 * Get the last 100 fields created.
317 579 *
318 580 * @since 3.06.04
581 + *
319 582 * @return array
320 583 */
321 584 private function fields() {
322 - $args = array(
585 + $args = array(
323 586 'limit' => 50,
324 587 'order_by' => 'id DESC',
325 588 );
326 589
327 - $fields = FrmDb::get_results( 'frm_fields', array(), 'form_id, name, type, field_options', $args );
590 + $fields = FrmDb::get_results( 'frm_fields', array(), 'id, form_id, name, type, field_options', $args );
591 +
328 592 foreach ( $fields as $k => $field ) {
329 593 FrmAppHelper::unserialize_or_decode( $field->field_options );
330 - $fields[ $k ]->field_options = json_encode( $field->field_options );
594 + $fields[ $k ]->field_options = $field->field_options;
331 595 }
596 +
332 597 return $fields;
333 598 }
334 599
335 600 /**
336 601 * @since 3.06.04
602 + *
337 603 * @return array
338 604 */
339 605 private function actions() {
340 606 $args = array(
@@ -341,17 +607,17 @@
341 607 'post_type' => FrmFormActionsController::$action_post_type,
342 608 'numberposts' => 100,
343 609 );
344 610
345 - $actions = array();
611 + $actions = array();
612 + $saved_actions = FrmDb::check_cache( json_encode( $args ), 'frm_actions', $args, 'get_posts' );
346 613
347 - $saved_actions = FrmDb::check_cache( json_encode( $args ), 'frm_actions', $args, 'get_posts' );
348 614 foreach ( $saved_actions as $action ) {
349 615 $actions[] = array(
350 616 'form_id' => $action->menu_order,
351 617 'type' => $action->post_excerpt,
352 618 'status' => $action->post_status,
353 - 'settings' => $action->post_content,
619 + 'settings' => FrmAppHelper::maybe_json_decode( $action->post_content ),
354 620 );
355 621 }
356 622
357 623 return $actions;
@@ -358,17 +624,20 @@
358 624 }
359 625
360 626 /**
361 627 * @since 3.06.04
628 + *
362 629 * @return bool
363 630 */
364 631 private function tracking_allowed() {
365 - $settings = FrmAppHelper::get_settings();
366 - return $settings->tracking;
632 + return FrmUsageController::tracking_allowed();
367 633 }
368 634
369 635 /**
370 636 * @since 3.06.04
637 + *
638 + * @param mixed $value Value.
639 + *
371 640 * @return string
372 641 */
373 642 private function maybe_json( $value ) {
374 643 return is_array( $value ) ? json_encode( $value ) : $value;
@@ -373,5 +642,4 @@
373 642 private function maybe_json( $value ) {
374 643 return is_array( $value ) ? json_encode( $value ) : $value;
375 644 }
376 645 }
377 -