PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 3.06.06
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v3.06.06
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 / FrmAddon.php

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

624 lines 18.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if ( ! defined( 'ABSPATH' ) ) {
4 die( 'You are not allowed to call this page directly.' );
5 }
6
7 class FrmAddon {
8 public $store_url = 'https://formidableforms.com';
9 public $download_id;
10 public $plugin_file;
11 public $plugin_folder;
12 public $plugin_name;
13 public $plugin_slug;
14 public $option_name;
15 public $version;
16 public $author = 'Strategy11';
17 public $is_parent_licence = false;
18 private $is_expired_addon = false;
19 public $license;
20 protected $get_beta = false;
21
22 public function __construct() {
23
24 if ( empty( $this->plugin_slug ) ) {
25 $this->plugin_slug = preg_replace( '/[^a-zA-Z0-9_\s]/', '', str_replace( ' ', '_', strtolower( $this->plugin_name ) ) );
26 }
27 if ( empty( $this->option_name ) ) {
28 $this->option_name = 'edd_' . $this->plugin_slug . '_license_';
29 }
30
31 $this->plugin_folder = plugin_basename( $this->plugin_file );
32 $this->license = $this->get_license();
33
34 add_filter( 'frm_installed_addons', array( &$this, 'insert_installed_addon' ) );
35 $this->edd_plugin_updater();
36 }
37
38 public static function load_hooks() {
39 add_filter( 'frm_include_addon_page', '__return_true' );
40 //new static();
41 }
42
43 public function insert_installed_addon( $plugins ) {
44 $plugins[ $this->plugin_slug ] = $this;
45 return $plugins;
46 }
47
48 public static function get_addon( $plugin_slug ) {
49 $plugins = apply_filters( 'frm_installed_addons', array() );
50 $plugin = false;
51 if ( isset( $plugins[ $plugin_slug ] ) ) {
52 $plugin = $plugins[ $plugin_slug ];
53 }
54 return $plugin;
55 }
56
57 public function edd_plugin_updater() {
58
59 $this->is_license_revoked();
60 $license = $this->license;
61
62 add_action( 'after_plugin_row_' . plugin_basename( $this->plugin_file ), array( $this, 'maybe_show_license_message' ), 10, 2 );
63
64 if ( ! empty( $license ) ) {
65
66 if ( 'formidable/formidable.php' !== $this->plugin_folder ) {
67 add_filter( 'plugins_api', array( &$this, 'plugins_api_filter' ), 10, 3 );
68 }
69
70 add_filter( 'site_transient_update_plugins', array( &$this, 'clear_expired_download' ) );
71 }
72 }
73
74 /**
75 * Updates information on the "View version x.x details" page with custom data.
76 *
77 * @uses api_request()
78 *
79 * @param mixed $_data
80 * @param string $_action
81 * @param object $_args
82 * @return object $_data
83 */
84 public function plugins_api_filter( $_data, $_action = '', $_args = null ) {
85
86 if ( $_action != 'plugin_information' ) {
87 return $_data;
88 }
89
90 $slug = basename( $this->plugin_file, '.php' );
91 if ( ! isset( $_args->slug ) || $_args->slug != $slug ) {
92 return $_data;
93 }
94
95 $item_id = $this->download_id;
96 if ( empty( $item_id ) ) {
97 $_data = array(
98 'name' => $this->plugin_name,
99 'excerpt' => '',
100 'changelog' => 'See the full changelog at <a href="' . esc_url( $this->store_url . '/changelog/' ) . '"></a>',
101 'banners' => array(
102 'high' => '',
103 'low' => 'https://ps.w.org/formidable/assets/banner-1544x500.png',
104 ),
105 );
106 } else {
107 $api = new FrmFormApi( $this->license );
108 $plugins = $api->get_api_info();
109 $_data = $plugins[ $item_id ];
110 }
111
112 $_data['sections'] = array(
113 'description' => $_data['excerpt'],
114 'changelog' => $_data['changelog'],
115 );
116 $_data['author'] = '<a href="' . esc_url( $this->store_url ) . '">' . esc_html( $this->author ) . '</a>';
117 $_data['homepage'] = $this->store_url;
118
119 return (object) $_data;
120 }
121
122 public function get_license() {
123 $license = $this->maybe_get_pro_license();
124 if ( ! empty( $license ) ) {
125 return $license;
126 }
127
128 $license = trim( get_option( $this->option_name . 'key' ) );
129 if ( empty( $license ) ) {
130 $license = $this->activate_defined_license();
131 }
132
133 return $license;
134 }
135
136 /**
137 * @since 3.04.03
138 */
139 protected function maybe_get_pro_license() {
140 // prevent a loop if $this is the pro plugin
141 $get_license = FrmAppHelper::pro_is_installed() && is_callable( 'FrmProAppHelper::get_updater' ) && $this->plugin_name != 'Formidable Pro';
142
143 if ( ! $get_license ) {
144 return false;
145 }
146
147 $api = new FrmFormApi();
148 $api->get_pro_updater();
149 $license = $api->get_license();
150 if ( empty( $license ) ) {
151 return false;
152 }
153
154 $this->get_api_info( $license );
155 if ( ! $this->is_parent_licence ) {
156 $license = false;
157 }
158
159 return $license;
160 }
161
162 /**
163 * Activate the license in wp-config.php
164 *
165 * @since 2.04
166 */
167 public function activate_defined_license() {
168 $license = $this->get_defined_license();
169 if ( ! empty( $license ) && ! $this->is_active() && $this->is_time_to_auto_activate() ) {
170 $response = $this->activate_license( $license );
171 $this->set_auto_activate_time();
172 if ( ! $response['success'] ) {
173 $license = '';
174 }
175 }
176 return $license;
177 }
178
179 /**
180 * Check the wp-config.php for the license key
181 *
182 * @since 2.04
183 */
184 public function get_defined_license() {
185 $consant_name = 'FRM_' . strtoupper( $this->plugin_slug ) . '_LICENSE';
186 return defined( $consant_name ) ? constant( $consant_name ) : false;
187 }
188
189 public function set_license( $license ) {
190 update_option( $this->option_name . 'key', $license );
191 }
192
193 /**
194 * If the license is in the config, limit the frequency of checks.
195 * The license may be entered incorrectly, so we don't want to check on every page load.
196 *
197 * @since 2.04
198 */
199 private function is_time_to_auto_activate() {
200 $last_try = get_option( $this->option_name . 'last_activate' );
201 return ( ! $last_try || $last_try < strtotime( '-1 day' ) );
202 }
203
204 private function set_auto_activate_time() {
205 update_option( $this->option_name . 'last_activate', time() );
206 }
207
208 public function is_active() {
209 return get_option( $this->option_name . 'active' );
210 }
211
212 /**
213 * @since 3.04.03
214 * @param array error
215 */
216 public function maybe_clear_license( $error ) {
217 if ( $error['code'] === 'disabled' && $error['license'] === $this->license ) {
218 $this->clear_license();
219 }
220 }
221
222 public function clear_license() {
223 delete_option( $this->option_name . 'active' );
224 delete_option( $this->option_name . 'key' );
225 delete_site_option( $this->transient_key() );
226 delete_option( $this->transient_key() );
227 $this->delete_cache();
228 }
229
230 public function set_active( $is_active ) {
231 update_option( $this->option_name . 'active', $is_active );
232 $this->delete_cache();
233 FrmAppHelper::save_combined_js();
234 }
235
236 /**
237 * @since 3.04.03
238 */
239 protected function delete_cache() {
240 delete_transient( 'frm_api_licence' );
241
242 $api = new FrmFormApi( $this->license );
243 $api->reset_cached();
244
245 $api = new FrmFormTemplateApi( $this->license );
246 $api->reset_cached();
247 }
248
249 /**
250 * The Pro version includes the show_license_message function.
251 * We need an extra check before we allow it to show a message.
252 *
253 * @since 3.04.03
254 */
255 public function maybe_show_license_message( $file, $plugin ) {
256 if ( $this->is_expired_addon || isset( $plugin['package'] ) ) {
257 // let's not show a ton of duplicate messages
258 return;
259 }
260
261 $this->show_license_message( $file, $plugin );
262 }
263
264 public function show_license_message( $file, $plugin ) {
265 $message = '';
266 if ( empty( $this->license ) ) {
267 /* translators: %1$s: Plugin name, %2$s: Start link HTML, %3$s: end link HTML */
268 $message = sprintf( esc_html__( 'Your %1$s license key is missing. Please add it on the %2$slicenses page%3$s.', 'formidable' ), esc_html( $this->plugin_name ), '<a href="' . esc_url( admin_url( 'admin.php?page=formidable-settings&t=licenses_settings' ) ) . '">', '</a>' );
269 } else {
270 $api = new FrmFormApi( $this->license );
271 $errors = $api->error_for_license();
272 if ( ! empty( $errors ) ) {
273 $message = reset( $errors );
274 }
275 }
276
277 if ( empty( $message ) ) {
278 return;
279 }
280
281 $wp_list_table = _get_list_table( 'WP_Plugins_List_Table' );
282 $id = sanitize_title( $plugin['Name'] ) . '-next';
283 echo '<tr class="plugin-update-tr active" id="' . esc_attr( $id ) . '"><td colspan="' . esc_attr( $wp_list_table->get_column_count() ) . '" class="plugin-update colspanchange"><div class="update-message notice error inline notice-error notice-alt"><p>';
284 echo FrmAppHelper::kses( $message, 'a' ); // WPCS: XSS ok.
285 echo '<script type="text/javascript">var d = document.getElementById("' . esc_attr( $id ) . '").previousSibling;if ( d !== null ){ d.className = d.className + " update"; }</script>';
286 echo '</p></div></td></tr>';
287 }
288
289 public function clear_expired_download( $transient ) {
290 if ( ! is_object( $transient ) ) {
291 return $transient;
292 }
293
294 if ( $this->is_current_version( $transient ) ) {
295 //make sure it doesn't show there is an update if plugin is up-to-date
296 if ( isset( $transient->response[ $this->plugin_folder ] ) ) {
297 unset( $transient->response[ $this->plugin_folder ] );
298 }
299 } elseif ( isset( $transient->response ) && isset( $transient->response[ $this->plugin_folder ] ) ) {
300 $this->prepare_update_details( $transient->response[ $this->plugin_folder ] );
301
302 // if the transient has expired, clear the update and trigger it again
303 if ( $transient->response[ $this->plugin_folder ] === false ) {
304 if ( ! $this->has_been_cleared() ) {
305 $this->cleared_plugins();
306 $this->manually_queue_update();
307 }
308 unset( $transient->response[ $this->plugin_folder ] );
309 }
310 }
311
312 return $transient;
313 }
314
315 /**
316 * Check if the plugin information is correct to allow an update
317 *
318 * @since 3.04.03
319 * @param object $transient - the current plugin info saved for update
320 */
321 private function prepare_update_details( &$transient ) {
322 $version_info = $transient;
323 $has_beta_url = isset( $version_info->beta ) && ! empty( $version_info->beta );
324 if ( $this->get_beta && ! $has_beta_url ) {
325 $version_info = (object) $this->get_api_info( $this->license );
326 }
327
328 if ( isset( $version_info->new_version ) && ! empty( $version_info->new_version ) ) {
329 $this->clear_old_plugin_version( $version_info );
330 if ( $version_info === false ) { // was cleared with timeout
331 $transient = false;
332 } else {
333 $this->maybe_use_beta_url( $version_info );
334
335 if ( version_compare( $version_info->new_version, $this->version, '>' ) ) {
336 $transient = $version_info;
337 }
338 }
339 }
340 }
341
342 /**
343 * Get the API info for this plugin
344 *
345 * @since 3.04.03
346 */
347 protected function get_api_info( $license ) {
348 $api = new FrmFormApi( $license );
349 $addon = $api->get_addon_for_license( $this );
350
351 // if there is no download url, this license does not apply to the addon
352 if ( isset( $addon['package'] ) ) {
353 $this->is_parent_licence = true;
354 } elseif ( isset( $addons['error'] ) ) {
355 // if the license is expired, we must assume all add-ons were packaged
356 $this->is_parent_licence = true;
357 $this->is_expired_addon = true;
358 }
359
360 return $addon;
361 }
362
363 /**
364 * Make sure transients don't stick around on sites that
365 * don't save the transient expiration
366 *
367 * @since 2.05.05
368 */
369 private function clear_old_plugin_version( &$version_info ) {
370 $timeout = ( isset( $version_info->timeout ) && ! empty( $version_info->timeout ) ) ? $version_info->timeout : 0;
371 if ( ! empty( $timeout ) && time() > $timeout ) {
372 $version_info = false; // Cache is expired
373 $api = new FrmFormApi( $this->license );
374 $api->reset_cached();
375 }
376 }
377
378 /**
379 * The beta url is always included if the download has a beta.
380 * Check if the beta should be downloaded.
381 *
382 * @since 3.04.03
383 */
384 private function maybe_use_beta_url( &$version_info ) {
385 if ( $this->get_beta && isset( $version_info->beta ) && ! empty( $version_info->beta ) ) {
386 $version_info->new_version = $version_info->beta['version'];
387 $version_info->package = $version_info->beta['package'];
388 if ( isset( $version_info->plugin ) && ! empty( $version_info->plugin ) ) {
389 $version_info->plugin = $version_info->beta['plugin'];
390 }
391 }
392 }
393
394 private function is_current_version( $transient ) {
395 if ( empty( $transient->checked ) || ! isset( $transient->checked[ $this->plugin_folder ] ) ) {
396 return false;
397 }
398
399 $response = ! isset( $transient->response ) || empty( $transient->response );
400 if ( $response ) {
401 return true;
402 }
403
404 return isset( $transient->response ) && isset( $transient->response[ $this->plugin_folder ] ) && $transient->checked[ $this->plugin_folder ] === $transient->response[ $this->plugin_folder ]->new_version;
405 }
406
407 private function has_been_cleared() {
408 $last_cleared = get_option( 'frm_last_cleared' );
409 return ( $last_cleared && $last_cleared > date( 'Y-m-d H:i:s', strtotime( '-5 minutes' ) ) );
410 }
411
412 private function cleared_plugins() {
413 update_option( 'frm_last_cleared', date( 'Y-m-d H:i:s' ) );
414 }
415
416 private function is_license_revoked() {
417 if ( empty( $this->license ) || empty( $this->plugin_slug ) || isset( $_POST['license'] ) ) { // WPCS: CSRF ok.
418 return;
419 }
420
421 if ( is_multisite() ) {
422 $last_checked = get_site_option( $this->transient_key() );
423 } else {
424 $last_checked = get_option( $this->transient_key() );
425 }
426
427 $seven_days_ago = date( 'Y-m-d H:i:s', strtotime( '-7 days' ) );
428
429 if ( ! $last_checked || $last_checked < $seven_days_ago ) {
430 // check weekly
431 if ( is_multisite() ) {
432 update_site_option( $this->transient_key(), date( 'Y-m-d H:i:s' ) );
433 } else {
434 update_option( $this->transient_key(), date( 'Y-m-d H:i:s' ) );
435 }
436
437 $response = $this->get_license_status();
438 if ( 'revoked' === $response['status'] || 'blocked' === $response['status'] || 'disabled' === $response['status'] ) {
439 $this->clear_license();
440 }
441 }
442 }
443
444 private function transient_key() {
445 return 'frm_' . md5( sanitize_key( $this->license . '_' . $this->plugin_slug ) );
446 }
447
448 public static function activate() {
449 FrmAppHelper::permission_check( 'frm_change_settings' );
450 check_ajax_referer( 'frm_ajax', 'nonce' );
451
452 if ( ! isset( $_POST['license'] ) || empty( $_POST['license'] ) ) {
453 wp_die(
454 json_encode(
455 array(
456 'message' => __( 'Oops! You forgot to enter your license number.', 'formidable' ),
457 'success' => false,
458 )
459 )
460 );
461 }
462
463 $license = stripslashes( sanitize_text_field( $_POST['license'] ) );
464 $plugin_slug = sanitize_text_field( $_POST['plugin'] );
465 $this_plugin = self::get_addon( $plugin_slug );
466 $response = $this_plugin->activate_license( $license );
467
468 echo json_encode( $response );
469 wp_die();
470 }
471
472 private function activate_license( $license ) {
473 $this->set_license( $license );
474 $this->license = $license;
475
476 $response = $this->get_license_status();
477 $response['message'] = '';
478 $response['success'] = false;
479
480 if ( $response['error'] ) {
481 $response['message'] = $response['status'];
482 } else {
483 $messages = $this->get_messages();
484 if ( is_string( $response['status'] ) && isset( $messages[ $response['status'] ] ) ) {
485 $response['message'] = $messages[ $response['status'] ];
486 } else {
487 $response['message'] = FrmAppHelper::kses( $response['status'], array( 'a' ) );
488 }
489
490 $is_valid = false;
491 if ( 'valid' === $response['status'] ) {
492 $is_valid = 'valid';
493 $response['success'] = true;
494 }
495 $this->set_active( $is_valid );
496 }
497
498 return $response;
499 }
500
501 private function get_license_status() {
502 $response = array(
503 'status' => 'missing',
504 'error' => true,
505 );
506 if ( empty( $this->license ) ) {
507 $response['error'] = false;
508 return $response;
509 }
510
511 try {
512 $response['error'] = false;
513 $license_data = $this->send_mothership_request( 'activate_license' );
514
515 // $license_data->license will be either "valid" or "invalid"
516 if ( is_array( $license_data ) ) {
517 if ( in_array( $license_data['license'], array( 'valid', 'invalid' ), true ) ) {
518 $response['status'] = $license_data['license'];
519 }
520 } else {
521 $response['status'] = $license_data;
522 }
523 } catch ( Exception $e ) {
524 $response['status'] = $e->getMessage();
525 }
526
527 return $response;
528 }
529
530 private function get_messages() {
531 return array(
532 'valid' => __( 'Your license has been activated. Enjoy!', 'formidable' ),
533 'invalid' => __( 'That license key is invalid', 'formidable' ),
534 'expired' => __( 'That license is expired', 'formidable' ),
535 'revoked' => __( 'That license has been refunded', 'formidable' ),
536 'no_activations_left' => __( 'That license has been used on too many sites', 'formidable' ),
537 'invalid_item_id' => __( 'Oops! That is the wrong license key for this plugin.', 'formidable' ),
538 'missing' => __( 'That license key is invalid', 'formidable' ),
539 );
540 }
541
542 public static function deactivate() {
543 FrmAppHelper::permission_check( 'frm_change_settings' );
544 check_ajax_referer( 'frm_ajax', 'nonce' );
545
546 $plugin_slug = sanitize_text_field( $_POST['plugin'] );
547 $this_plugin = self::get_addon( $plugin_slug );
548 $license = $this_plugin->get_license();
549 $this_plugin->license = $license;
550
551 $response = array(
552 'success' => false,
553 'message' => '',
554 );
555 try {
556 // $license_data->license will be either "deactivated" or "failed"
557 $license_data = $this_plugin->send_mothership_request( 'deactivate_license' );
558 if ( is_array( $license_data ) && 'deactivated' === $license_data['license'] ) {
559 $response['success'] = true;
560 $response['message'] = __( 'That license was removed successfully', 'formidable' );
561 } else {
562 $response['message'] = __( 'There was an error deactivating your license.', 'formidable' );
563 }
564 } catch ( Exception $e ) {
565 $response['message'] = $e->getMessage();
566 }
567
568 $this_plugin->clear_license();
569
570 echo json_encode( $response );
571 wp_die();
572 }
573
574 public function send_mothership_request( $action ) {
575 $api_params = array(
576 'edd_action' => $action,
577 'license' => $this->license,
578 'url' => home_url(),
579 );
580 if ( is_numeric( $this->download_id ) ) {
581 $api_params['item_id'] = absint( $this->download_id );
582 } else {
583 $api_params['item_name'] = rawurlencode( $this->plugin_name );
584 }
585
586 $arg_array = array(
587 'body' => $api_params,
588 'timeout' => 25,
589 'user-agent' => $this->plugin_slug . '/' . $this->version . '; ' . get_bloginfo( 'url' ),
590 );
591
592 $resp = wp_remote_post( $this->store_url, $arg_array );
593 $body = wp_remote_retrieve_body( $resp );
594
595 $message = __( 'Your License Key was invalid', 'formidable' );
596 if ( is_wp_error( $resp ) ) {
597 $link = FrmAppHelper::admin_upgrade_link( 'api', 'knowledgebase/why-cant-i-activate-formidable-pro/' );
598 /* translators: %1$s: Start link HTML, %2$s: End link HTML */
599 $message = sprintf( __( 'You had an error communicating with the Formidable API. %1$sClick here%2$s for more information.', 'formidable' ), '<a href="' . esc_url( $link ) . '" target="_blank">', '</a>' );
600 $message .= ' ' . $resp->get_error_message();
601 } elseif ( 'error' === $body || is_wp_error( $body ) ) {
602 $message = __( 'You had an HTTP error connecting to the Formidable API', 'formidable' );
603 } else {
604 $json_res = json_decode( $body, true );
605 if ( null !== $json_res ) {
606 if ( is_array( $json_res ) && isset( $json_res['error'] ) ) {
607 $message = $json_res['error'];
608 } else {
609 $message = $json_res;
610 }
611 } elseif ( isset( $resp['response'] ) && isset( $resp['response']['code'] ) ) {
612 /* translators: %1$s: Error code, %2$s: Error message */
613 $message = sprintf( __( 'There was a %1$s error: %2$s', 'formidable' ), $resp['response']['code'], $resp['response']['message'] . ' ' . $resp['body'] );
614 }
615 }
616
617 return $message;
618 }
619
620 public function manually_queue_update() {
621 set_site_transient( 'update_plugins', null );
622 }
623 }
624