PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.31
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.31
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 / FrmUsage.php

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

646 lines 14.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if ( ! defined( 'ABSPATH' ) ) {
3 die( 'You are not allowed to call this page directly.' );
4 }
5
6 /**
7 * @since 3.06.04
8 */
9 class FrmUsage {
10
11 /**
12 * @since 3.06.04
13 *
14 * @return void
15 */
16 public function send_snapshot() {
17 if ( ! $this->tracking_allowed() ) {
18 return;
19 }
20
21 $snapshot = $this->snapshot();
22 $this->clean_before_send( $snapshot );
23
24 $ep = 'aHR0cHM6Ly91c2FnZTIuZm9ybWlkYWJsZWZvcm1zLmNvbS9zbmFwc2hvdA==';
25 // $ep = base64_encode( 'http://localhost:4567/snapshot' ); // Uncomment for testing
26 $body = json_encode( $snapshot );
27
28 // Setup variable for wp_remote_request.
29 $post = array(
30 'method' => 'POST',
31 'headers' => array(
32 'Accept' => 'application/json',
33 'Content-Type' => 'application/json',
34 'Content-Length' => strlen( $body ),
35 ),
36 'body' => $body,
37 // Without this, Debug Log catches the `http_request_failed` error.
38 'timeout' => 45,
39 );
40
41 // Remove time limit to execute this function.
42 if ( function_exists( 'set_time_limit' ) ) {
43 set_time_limit( 0 );
44 }
45
46 wp_remote_request( base64_decode( $ep ), $post );
47 }
48
49 /**
50 * @since 3.06.04
51 *
52 * @param bool $regenerate
53 *
54 * @return string
55 */
56 public function uuid( $regenerate = false ) {
57 $uuid_key = 'frm-usage-uuid';
58 $uuid = get_option( $uuid_key );
59
60 if ( $regenerate || ! $uuid ) {
61 // Definitely not cryptographically secure but
62 // close enough to provide a unique id
63 $uuid = md5( uniqid() . site_url() );
64 update_option( $uuid_key, $uuid, false );
65 }
66
67 return $uuid;
68 }
69
70 /**
71 * @since 3.06.04
72 *
73 * @return array
74 */
75 public function snapshot() {
76 global $wpdb, $wp_version;
77
78 $theme_data = wp_get_theme();
79 $form_counts = FrmForm::get_count();
80
81 $snap = array(
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(),
88
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(),
94
95 'theme_name' => is_object( $theme_data ) ? $theme_data->Name : '', // phpcs:ignore WordPress.NamingConventions
96 'plugins' => $this->plugins(),
97 'settings' => array(
98 $this->settings(),
99 ),
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' ),
109 );
110
111 if ( method_exists( 'FrmProAddonsController', 'get_readable_license_type' ) ) {
112 $snap['active_license'] = FrmProAddonsController::get_readable_license_type();
113 }
114
115 return apply_filters( 'frm_usage_snapshot', $snap );
116 }
117
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 /**
319 * @since 3.06.04
320 *
321 * @return array
322 */
323 private function plugins() {
324 $plugin_list = FrmAppHelper::get_plugins();
325 $plugins = array();
326
327 foreach ( $plugin_list as $slug => $info ) {
328 $plugins[] = array(
329 'name' => $info['Name'],
330 'slug' => $slug,
331 'version' => $info['Version'],
332 'active' => is_plugin_active( $slug ),
333 );
334 }
335
336 return $plugins;
337 }
338
339 /**
340 * Add global settings to tracking data.
341 *
342 * @since 3.06.04
343 *
344 * @return array
345 */
346 private function settings() {
347 $settings_list = FrmAppHelper::get_settings();
348 $settings = array(
349 'messages' => $this->messages( $settings_list ),
350 'permissions' => $this->permissions( $settings_list ),
351 );
352 $pass_settings = array(
353 'load_style',
354 'fade_form',
355 're_type',
356 're_lang',
357 're_multi',
358 'menu',
359 'mu_menu',
360 'no_ips',
361 'custom_header_ip',
362 'enable_gdpr',
363 'no_gdpr_cookies',
364 'btsp_css',
365 'btsp_version',
366 'admin_bar',
367 'summary_emails',
368 'active_captcha',
369 'honeypot',
370 'wp_spam_check',
371 'denylist_check',
372 'email_style',
373 );
374
375 foreach ( $pass_settings as $setting ) {
376 if ( isset( $settings_list->$setting ) ) {
377 $settings[ $setting ] = $this->maybe_json( $settings_list->$setting );
378 }
379 }
380
381 $settings = apply_filters( 'frm_usage_settings', $settings );
382
383 $settings['messages'] = $this->maybe_json( $settings['messages'] );
384 $settings['permissions'] = $this->maybe_json( $settings['permissions'] );
385
386 return $settings;
387 }
388
389 /**
390 * Include the permissions settings for each capability.
391 *
392 * @since 3.06.04
393 *
394 * @param FrmSettings $settings_list
395 *
396 * @return array
397 */
398 private function messages( $settings_list ) {
399 $messages = array(
400 'success_msg',
401 'blank_msg',
402 'unique_msg',
403 'invalid_msg',
404 'failed_msg',
405 'submit_value',
406 'login_msg',
407 'admin_permission',
408 );
409
410 $default = $settings_list->default_options();
411 $message_settings = array();
412
413 foreach ( $messages as $message ) {
414 $message_settings[ 'changed-' . $message ] = $settings_list->$message === $default[ $message ] ? 0 : 1;
415 }
416
417 return $message_settings;
418 }
419
420 /**
421 * Include the permissions settings for each capability.
422 *
423 * @since 3.06.04
424 *
425 * @param FrmSettings $settings_list
426 *
427 * @return array
428 */
429 private function permissions( $settings_list ) {
430 $permissions = array();
431 $frm_roles = FrmAppHelper::frm_capabilities();
432
433 foreach ( $frm_roles as $frm_role => $frm_role_description ) {
434 if ( isset( $settings_list->$frm_role ) ) {
435 $permissions[ $frm_role ] = $settings_list->$frm_role;
436 }
437 }
438
439 return $permissions;
440 }
441
442 /**
443 * @since 3.06.04
444 *
445 * @return array
446 */
447 private function forms() {
448 $s_query = array(
449 array(
450 'or' => 1,
451 'parent_form_id' => null,
452 'parent_form_id <' => 1,
453 ),
454 );
455
456 $saved_forms = FrmForm::getAll( $s_query );
457 $forms = array();
458 $settings = array(
459 'form_class',
460 'akismet',
461 'antispam',
462 'stopforumspam',
463 'custom_style',
464 'success_action',
465 'show_form',
466 'no_save',
467 'ajax_load',
468 'ajax_submit',
469 'js_validate',
470 'logged_in_role',
471 'single_entry',
472 'single_entry_type',
473 'editable_role',
474 'open_editable_role',
475 'edit_action',
476 'edit_value',
477 'edit_msg',
478 'save_draft',
479 'draft_msg',
480 'submit_align',
481 'protect_files',
482 'protect_files_role',
483 'max_entries',
484 'open_status',
485 'closed_msg',
486 'open_date',
487 'close_date',
488 'copy',
489 'prev_value',
490 'submit_conditions',
491 );
492
493 $style = new FrmStyle();
494
495 foreach ( $saved_forms as $form ) {
496 $new_form = array(
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 ),
504 'form_action_count' => $this->form_action_count( $form->id ),
505 );
506
507 foreach ( $settings as $setting ) {
508 if ( ! isset( $form->options[ $setting ] ) ) {
509 continue;
510 }
511
512 if ( 'custom_style' !== $setting ) {
513 $new_form[ $setting ] = $this->maybe_json( $form->options[ $setting ] );
514 continue;
515 }
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
531 $forms[] = apply_filters( 'frm_usage_form', $new_form, compact( 'form' ) );
532 }//end foreach
533
534 // If the array uses numeric keys, reset them.
535 return $forms;
536 }
537
538 /**
539 * @since 3.06.04
540 *
541 * @param int|string $form_id Form ID.
542 *
543 * @return int
544 */
545 private function form_field_count( $form_id ) {
546 global $wpdb;
547
548 $join = $wpdb->prefix . 'frm_fields fi JOIN ' . $wpdb->prefix . 'frm_forms fo ON (fi.form_id=fo.id)';
549
550 $field_query = array(
551 'or' => 1,
552 'fi.form_id' => $form_id,
553 'parent_form_id' => $form_id,
554 );
555
556 return FrmDb::get_count( $join, $field_query );
557 }
558
559 /**
560 * @since 3.06.04
561 *
562 * @param int|string $form_id Form ID.
563 *
564 * @return int
565 */
566 private function form_action_count( $form_id ) {
567 $args = array(
568 'post_type' => FrmFormActionsController::$action_post_type,
569 'menu_order' => $form_id,
570 'fields' => 'ids',
571 );
572
573 $actions = FrmDb::check_cache( json_encode( $args ), 'frm_actions', $args, 'get_posts' );
574 return count( $actions );
575 }
576
577 /**
578 * Get the last 100 fields created.
579 *
580 * @since 3.06.04
581 *
582 * @return array
583 */
584 private function fields() {
585 $args = array(
586 'limit' => 50,
587 'order_by' => 'id DESC',
588 );
589
590 $fields = FrmDb::get_results( 'frm_fields', array(), 'id, form_id, name, type, field_options', $args );
591
592 foreach ( $fields as $k => $field ) {
593 FrmAppHelper::unserialize_or_decode( $field->field_options );
594 $fields[ $k ]->field_options = $field->field_options;
595 }
596
597 return $fields;
598 }
599
600 /**
601 * @since 3.06.04
602 *
603 * @return array
604 */
605 private function actions() {
606 $args = array(
607 'post_type' => FrmFormActionsController::$action_post_type,
608 'numberposts' => 100,
609 );
610
611 $actions = array();
612 $saved_actions = FrmDb::check_cache( json_encode( $args ), 'frm_actions', $args, 'get_posts' );
613
614 foreach ( $saved_actions as $action ) {
615 $actions[] = array(
616 'form_id' => $action->menu_order,
617 'type' => $action->post_excerpt,
618 'status' => $action->post_status,
619 'settings' => FrmAppHelper::maybe_json_decode( $action->post_content ),
620 );
621 }
622
623 return $actions;
624 }
625
626 /**
627 * @since 3.06.04
628 *
629 * @return bool
630 */
631 private function tracking_allowed() {
632 return FrmUsageController::tracking_allowed();
633 }
634
635 /**
636 * @since 3.06.04
637 *
638 * @param mixed $value Value.
639 *
640 * @return string
641 */
642 private function maybe_json( $value ) {
643 return is_array( $value ) ? json_encode( $value ) : $value;
644 }
645 }
646