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

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

451 lines 8.9 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 class FrmFormApi {
7
8 /**
9 * @var string
10 */
11 protected $license = '';
12
13 /**
14 * @var string
15 */
16 protected $cache_key = '';
17
18 /**
19 * @var string
20 */
21 protected $cache_timeout = '+6 hours';
22
23 /**
24 * The number of days an add-on is new.
25 *
26 * @var int
27 */
28 protected $new_days = 90;
29
30 /**
31 * @since 3.06
32 *
33 * @param string|null $license The license key.
34 *
35 * @return void
36 */
37 public function __construct( $license = null ) {
38 $this->set_license( $license );
39 $this->set_cache_key();
40 }
41
42 /**
43 * @since 3.06
44 *
45 * @param string|null $license The license key.
46 *
47 * @return void
48 */
49 private function set_license( $license ) {
50 if ( $license === null ) {
51 $edd_update = $this->get_pro_updater();
52
53 if ( ! empty( $edd_update ) ) {
54 $license = $edd_update->license;
55 }
56 }
57 $this->license = $license;
58 }
59
60 /**
61 * @since 3.06
62 *
63 * @return string
64 */
65 public function get_license() {
66 return $this->license;
67 }
68
69 /**
70 * @since 3.06
71 *
72 * @return void
73 */
74 protected function set_cache_key() {
75 $this->cache_key = 'frm_addons_l' . ( empty( $this->license ) ? '' : md5( $this->license ) );
76 }
77
78 /**
79 * @since 3.06
80 *
81 * @return string
82 */
83 public function get_cache_key() {
84 return $this->cache_key;
85 }
86
87 /**
88 * @since 3.06
89 *
90 * @return array
91 */
92 public function get_api_info() {
93 $url = $this->api_url();
94
95 if ( ! empty( $this->license ) ) {
96 $url .= '?l=' . urlencode( base64_encode( $this->license ) );
97 }
98
99 $addons = $this->get_cached();
100
101 if ( is_array( $addons ) ) {
102 return $addons;
103 }
104
105 if ( $this->is_running() ) {
106 // If there's no saved cache, we'll need to wait for the current request to finish.
107 return array();
108 }
109
110 $this->set_running();
111
112 // We need to know the version number to allow different downloads.
113 $agent = 'formidable/' . FrmAppHelper::plugin_version();
114
115 if ( class_exists( 'FrmProDb' ) ) {
116 $agent = 'formidable-pro/' . FrmProDb::$plug_version;
117 }
118
119 $response = wp_remote_get(
120 $url,
121 array(
122 'timeout' => 25,
123 'user-agent' => $agent . '; ' . get_bloginfo( 'url' ),
124 )
125 );
126
127 if ( is_array( $response ) && ! is_wp_error( $response ) ) {
128 $addons = $response['body'] ? json_decode( $response['body'], true ) : array();
129 }
130
131 if ( ! is_array( $addons ) ) {
132 $addons = array();
133 }
134
135 $addons['response_code'] = wp_remote_retrieve_response_code( $response );
136
137 foreach ( $addons as $k => $addon ) {
138 if ( ! is_array( $addon ) ) {
139 continue;
140 }
141
142 if ( isset( $addon['categories'] ) ) {
143 $cats = array_intersect( $this->skip_categories(), $addon['categories'] );
144
145 if ( ! empty( $cats ) ) {
146 unset( $addons[ $k ] );
147 continue;
148 }
149 }
150
151 if ( ! array_key_exists( 'is_new', $addon ) && array_key_exists( 'released', $addon ) ) {
152 $addons[ $k ]['is_new'] = $this->is_new( $addon );
153 }
154 }
155
156 $this->set_cached( $addons );
157 $this->done_running();
158
159 return $addons;
160 }
161
162 /**
163 * Prevent multiple requests from running at the same time.
164 *
165 * @since 6.8.3
166 *
167 * @return bool
168 */
169 protected function is_running() {
170 if ( $this->run_as_multisite() ) {
171 return get_site_transient( $this->transient_key() );
172 }
173 return get_transient( $this->transient_key() );
174 }
175
176 /**
177 * @since 6.8.3
178 *
179 * @return void
180 */
181 protected function set_running() {
182 $expires = 2 * MINUTE_IN_SECONDS;
183
184 if ( $this->run_as_multisite() ) {
185 set_site_transient( $this->transient_key(), true, $expires );
186 return;
187 }
188
189 set_transient( $this->transient_key(), true, $expires );
190 }
191
192 /**
193 * @since 6.8.3
194 *
195 * @return void
196 */
197 protected function done_running() {
198 if ( $this->run_as_multisite() ) {
199 delete_site_transient( $this->transient_key() );
200 }
201 delete_transient( $this->transient_key() );
202 }
203
204 /**
205 * Only allow one site in the network to make the api request at a time.
206 * If there is a license for the request, run individually.
207 *
208 * @since 6.8.3
209 *
210 * @return bool
211 */
212 protected function run_as_multisite() {
213 return is_multisite() && empty( $this->license );
214 }
215
216 /**
217 * @since 6.8.3
218 *
219 * @return string
220 */
221 protected function transient_key() {
222 return strtolower( self::class ) . '_request_lock';
223 }
224
225 /**
226 * @since 3.06
227 *
228 * @return string
229 */
230 protected function api_url() {
231 if ( empty( $this->license ) ) {
232 // Direct traffic to Cloudflare worker when there is no license.
233 return 'https://plapi.formidableforms.com/list/';
234 }
235 return 'https://formidableforms.com/wp-json/s11edd/v1/updates/';
236 }
237
238 /**
239 * @since 3.06
240 *
241 * @return string[]
242 */
243 protected function skip_categories() {
244 return array( 'WordPress Form Templates', 'WordPress Form Style Templates' );
245 }
246
247 /**
248 * @since 3.06
249 *
250 * @param object $license_plugin The FrmAddon object.
251 * @param array $addons
252 *
253 * @return array
254 */
255 public function get_addon_for_license( $license_plugin, $addons = array() ) {
256 if ( empty( $addons ) ) {
257 $addons = $this->get_api_info();
258 }
259
260 $download_id = $license_plugin->download_id;
261 $plugin = array();
262
263 if ( empty( $download_id ) && ! empty( $addons ) ) {
264 foreach ( $addons as $addon ) {
265 if ( is_array( $addon ) && ! empty( $addon['title'] ) && strtolower( $license_plugin->plugin_name ) === strtolower( $addon['title'] ) ) {
266 return $addon;
267 }
268 }
269 } elseif ( isset( $addons[ $download_id ] ) ) {
270 $plugin = $addons[ $download_id ];
271 }
272
273 return $plugin;
274 }
275
276 /**
277 * @since 3.06
278 *
279 * @return false|object
280 */
281 public function get_pro_updater() {
282 if ( FrmAppHelper::pro_is_installed() && is_callable( 'FrmProAppHelper::get_updater' ) ) {
283 $updater = FrmProAppHelper::get_updater();
284 $this->set_license( $updater->license );
285
286 return $updater;
287 }
288
289 return false;
290 }
291
292 /**
293 * @since 3.06
294 *
295 * @return array|bool
296 */
297 protected function get_cached() {
298 $cache = $this->get_cached_option();
299
300 if ( empty( $cache ) ) {
301 return false;
302 }
303
304 $is_expired = empty( $cache['timeout'] ) || time() > $cache['timeout'];
305
306 if ( ! $is_expired && isset( $cache['version'] ) && $cache['version'] !== FrmAppHelper::plugin_version() ) {
307 $is_expired = true;
308 }
309
310 // Avoid old cached data, unless we're currently trying to query for new data.
311 // The call to $this->is_running likely triggers a database query, so only call if if we're expired.
312 // (Rather than the other way around, which is less efficient).
313 if ( $is_expired && ! $this->is_running() ) {
314 return false;
315 }
316
317 $values = json_decode( $cache['value'], true );
318
319 return $values;
320 }
321
322 /**
323 * Get the cache for the network if multisite.
324 *
325 * @since 6.8.3
326 *
327 * @return mixed
328 */
329 protected function get_cached_option() {
330 if ( is_multisite() ) {
331 $cached = get_site_option( $this->cache_key );
332
333 if ( $cached ) {
334 return $cached;
335 }
336 }
337
338 return get_option( $this->cache_key );
339 }
340
341 /**
342 * @since 3.06
343 *
344 * @param array $addons
345 *
346 * @return void
347 */
348 protected function set_cached( $addons ) {
349 $data = array(
350 'timeout' => strtotime( $this->get_cache_timeout( $addons ), time() ),
351 'value' => wp_json_encode( $addons ),
352 'version' => FrmAppHelper::plugin_version(),
353 );
354
355 if ( is_multisite() ) {
356 update_site_option( $this->cache_key, $data );
357 } else {
358 // Autoload the license cache because it gets called everywhere.
359 $autoload = 0 === strpos( $this->cache_key, 'frm_addons_l' );
360 update_option( $this->cache_key, $data, $autoload );
361 }
362 }
363
364 /**
365 * If the last check was a a rate limit, we'll need to check again sooner.
366 *
367 * @since 6.8.3
368 *
369 * @param array $addons
370 *
371 * @return string
372 */
373 protected function get_cache_timeout( $addons ) {
374 $timeout = $this->cache_timeout;
375
376 if ( isset( $addons['response_code'] ) && 429 === $addons['response_code'] ) {
377 $timeout = '+5 minutes';
378 }
379 return $timeout;
380 }
381
382 /**
383 * @since 3.06
384 *
385 * @return void
386 */
387 public function reset_cached() {
388 if ( is_multisite() ) {
389 delete_site_option( $this->cache_key );
390 } else {
391 delete_option( $this->cache_key );
392 }
393 $this->done_running();
394 }
395
396 /**
397 * @since 3.06
398 *
399 * @return array
400 */
401 public function error_for_license() {
402 $errors = array();
403
404 if ( ! empty( $this->license ) ) {
405 $errors = $this->get_error_from_response();
406 }
407
408 return $errors;
409 }
410
411 /**
412 * @since 3.06
413 *
414 * @param array $addons
415 *
416 * @return array
417 */
418 public function get_error_from_response( $addons = array() ) {
419 if ( empty( $addons ) ) {
420 $addons = $this->get_api_info();
421 }
422
423 $errors = array();
424
425 if ( isset( $addons['error'] ) ) {
426 if ( is_string( $addons['error'] ) ) {
427 $errors[] = $addons['error'];
428 } elseif ( ! empty( $addons['error']['message'] ) ) {
429 $errors[] = $addons['error']['message'];
430 }
431
432 do_action( 'frm_license_error', $addons['error'] );
433 }
434
435 return $errors;
436 }
437
438 /**
439 * Check if a template is new.
440 *
441 * @since 6.0
442 *
443 * @param array $addon
444 *
445 * @return bool
446 */
447 protected function is_new( $addon ) {
448 return strtotime( $addon['released'] ) > strtotime( '-' . $this->new_days . ' days' );
449 }
450 }
451