1
|
|
|
<?php
|
|
|
|
|
2
|
|
|
/**
|
3
|
|
|
* @package Freemius
|
4
|
|
|
* @copyright Copyright (c) 2015, Freemius, Inc.
|
5
|
|
|
* @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3
|
6
|
|
|
* @since 1.0.4
|
7
|
|
|
*/
|
8
|
|
|
|
9
|
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
10
|
|
|
exit;
|
11
|
|
|
}
|
12
|
|
|
|
13
|
|
|
/**
|
14
|
|
|
* Class FS_Api
|
15
|
|
|
*
|
16
|
|
|
* Wraps Freemius API SDK to handle:
|
17
|
|
|
* 1. Clock sync.
|
18
|
|
|
* 2. Fallback to HTTP when HTTPS fails.
|
19
|
|
|
* 3. Adds caching layer to GET requests.
|
20
|
|
|
* 4. Adds consistency for failed requests by using last cached version.
|
21
|
|
|
*/
|
22
|
|
|
class FS_Api {
|
|
|
|
|
23
|
|
|
/**
|
24
|
|
|
* @var FS_Api[]
|
25
|
|
|
*/
|
26
|
|
|
private static $_instances = array();
|
27
|
|
|
|
28
|
|
|
/**
|
29
|
|
|
* @var FS_Option_Manager Freemius options, options-manager.
|
30
|
|
|
*/
|
31
|
|
|
private static $_options;
|
32
|
|
|
|
33
|
|
|
/**
|
34
|
|
|
* @var FS_Cache_Manager API Caching layer
|
35
|
|
|
*/
|
36
|
|
|
private static $_cache;
|
37
|
|
|
|
38
|
|
|
/**
|
39
|
|
|
* @var int Clock diff in seconds between current server to API server.
|
40
|
|
|
*/
|
41
|
|
|
private static $_clock_diff;
|
42
|
|
|
|
43
|
|
|
/**
|
44
|
|
|
* @var Freemius_Api_WordPress
|
45
|
|
|
*/
|
46
|
|
|
private $_api;
|
47
|
|
|
|
48
|
|
|
/**
|
49
|
|
|
* @var string
|
50
|
|
|
*/
|
51
|
|
|
private $_slug;
|
52
|
|
|
|
53
|
|
|
/**
|
54
|
|
|
* @var FS_Logger
|
55
|
|
|
* @since 1.0.4
|
56
|
|
|
*/
|
57
|
|
|
private $_logger;
|
58
|
|
|
|
59
|
|
|
/**
|
60
|
|
|
* @param string $slug
|
61
|
|
|
* @param string $scope 'app', 'developer', 'user' or 'install'.
|
62
|
|
|
* @param number $id Element's id.
|
63
|
|
|
* @param string $public_key Public key.
|
64
|
|
|
* @param bool $is_sandbox
|
65
|
|
|
* @param bool|string $secret_key Element's secret key.
|
66
|
|
|
*
|
67
|
|
|
* @return FS_Api
|
68
|
|
|
*/
|
69
|
|
|
static function instance( $slug, $scope, $id, $public_key, $is_sandbox, $secret_key = false ) {
|
|
|
|
|
70
|
|
|
$identifier = md5( $slug . $scope . $id . $public_key . ( is_string( $secret_key ) ? $secret_key : '' ) . json_encode( $is_sandbox ) );
|
71
|
|
|
|
72
|
|
|
if ( ! isset( self::$_instances[ $identifier ] ) ) {
|
73
|
|
|
self::_init();
|
74
|
|
|
|
75
|
|
|
self::$_instances[ $identifier ] = new FS_Api( $slug, $scope, $id, $public_key, $secret_key, $is_sandbox );
|
76
|
|
|
}
|
77
|
|
|
|
78
|
|
|
return self::$_instances[ $identifier ];
|
79
|
|
|
}
|
80
|
|
|
|
81
|
|
|
private static function _init() {
|
82
|
|
|
if ( isset( self::$_options ) ) {
|
83
|
|
|
return;
|
84
|
|
|
}
|
85
|
|
|
|
86
|
|
|
if ( ! class_exists( 'Freemius_Api_WordPress' ) ) {
|
87
|
|
|
require_once WP_FS__DIR_SDK . '/FreemiusWordPress.php';
|
88
|
|
|
}
|
89
|
|
|
|
90
|
|
|
self::$_options = FS_Option_Manager::get_manager( WP_FS__OPTIONS_OPTION_NAME, true, true );
|
91
|
|
|
self::$_cache = FS_Cache_Manager::get_manager( WP_FS__API_CACHE_OPTION_NAME );
|
92
|
|
|
|
93
|
|
|
self::$_clock_diff = self::$_options->get_option( 'api_clock_diff', 0 );
|
94
|
|
|
Freemius_Api_WordPress::SetClockDiff( self::$_clock_diff );
|
95
|
|
|
|
96
|
|
|
if ( self::$_options->get_option( 'api_force_http', false ) ) {
|
97
|
|
|
Freemius_Api_WordPress::SetHttp();
|
98
|
|
|
}
|
99
|
|
|
}
|
100
|
|
|
|
101
|
|
|
/**
|
102
|
|
|
* @param string $slug
|
103
|
|
|
* @param string $scope 'app', 'developer', 'user' or 'install'.
|
104
|
|
|
* @param number $id Element's id.
|
105
|
|
|
* @param string $public_key Public key.
|
106
|
|
|
* @param bool|string $secret_key Element's secret key.
|
107
|
|
|
* @param bool $is_sandbox
|
108
|
|
|
*/
|
109
|
|
|
private function __construct( $slug, $scope, $id, $public_key, $secret_key, $is_sandbox ) {
|
110
|
|
|
$this->_api = new Freemius_Api_WordPress( $scope, $id, $public_key, $secret_key, $is_sandbox );
|
111
|
|
|
|
112
|
|
|
$this->_slug = $slug;
|
113
|
|
|
$this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_' . $slug . '_api', WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
|
114
|
|
|
}
|
115
|
|
|
|
116
|
|
|
/**
|
117
|
|
|
* Find clock diff between server and API server, and store the diff locally.
|
118
|
|
|
*
|
119
|
|
|
* @param bool|int $diff
|
120
|
|
|
*
|
121
|
|
|
* @return bool|int False if clock diff didn't change, otherwise returns the clock diff in seconds.
|
122
|
|
|
*/
|
123
|
|
|
private function _sync_clock_diff( $diff = false ) {
|
124
|
|
|
$this->_logger->entrance();
|
125
|
|
|
|
126
|
|
|
// Sync clock and store.
|
127
|
|
|
$new_clock_diff = ( false === $diff ) ?
|
128
|
|
|
Freemius_Api_WordPress::FindClockDiff() :
|
129
|
|
|
$diff;
|
130
|
|
|
|
131
|
|
|
if ( $new_clock_diff === self::$_clock_diff ) {
|
132
|
|
|
return false;
|
133
|
|
|
}
|
134
|
|
|
|
135
|
|
|
self::$_clock_diff = $new_clock_diff;
|
|
|
|
|
136
|
|
|
|
137
|
|
|
// Update API clock's diff.
|
138
|
|
|
Freemius_Api_WordPress::SetClockDiff( self::$_clock_diff );
|
139
|
|
|
|
140
|
|
|
// Store new clock diff in storage.
|
141
|
|
|
self::$_options->set_option( 'api_clock_diff', self::$_clock_diff, true );
|
142
|
|
|
|
143
|
|
|
return $new_clock_diff;
|
144
|
|
|
}
|
145
|
|
|
|
146
|
|
|
/**
|
147
|
|
|
* Override API call to enable retry with servers' clock auto sync method.
|
148
|
|
|
*
|
149
|
|
|
* @param string $path
|
150
|
|
|
* @param string $method
|
151
|
|
|
* @param array $params
|
152
|
|
|
* @param bool $retry Is in retry or first call attempt.
|
153
|
|
|
*
|
154
|
|
|
* @return array|mixed|string|void
|
155
|
|
|
*/
|
156
|
|
|
private function _call( $path, $method = 'GET', $params = array(), $retry = false ) {
|
157
|
|
|
$this->_logger->entrance( $method . ':' . $path );
|
158
|
|
|
|
159
|
|
|
if ( self::is_temporary_down() ) {
|
160
|
|
|
$result = $this->get_temporary_unavailable_error();
|
161
|
|
|
} else {
|
162
|
|
|
$result = $this->_api->Api( $path, $method, $params );
|
163
|
|
|
|
164
|
|
|
if ( null !== $result &&
|
165
|
|
|
isset( $result->error ) &&
|
166
|
|
|
isset( $result->error->code ) &&
|
167
|
|
|
'request_expired' === $result->error->code
|
168
|
|
|
) {
|
169
|
|
|
if ( ! $retry ) {
|
170
|
|
|
$diff = isset( $result->error->timestamp ) ?
|
171
|
|
|
( time() - strtotime( $result->error->timestamp ) ) :
|
172
|
|
|
false;
|
173
|
|
|
|
174
|
|
|
// Try to sync clock diff.
|
175
|
|
|
if ( false !== $this->_sync_clock_diff( $diff ) ) {
|
176
|
|
|
// Retry call with new synced clock.
|
177
|
|
|
return $this->_call( $path, $method, $params, true );
|
178
|
|
|
}
|
179
|
|
|
}
|
180
|
|
|
}
|
181
|
|
|
}
|
182
|
|
|
|
183
|
|
|
if ( $this->_logger->is_on() && self::is_api_error( $result ) ) {
|
184
|
|
|
// Log API errors.
|
185
|
|
|
$this->_logger->api_error( $result );
|
186
|
|
|
}
|
187
|
|
|
|
188
|
|
|
return $result;
|
189
|
|
|
}
|
190
|
|
|
|
191
|
|
|
/**
|
192
|
|
|
* Override API call to wrap it in servers' clock sync method.
|
193
|
|
|
*
|
194
|
|
|
* @param string $path
|
195
|
|
|
* @param string $method
|
196
|
|
|
* @param array $params
|
197
|
|
|
*
|
198
|
|
|
* @return array|mixed|string|void
|
199
|
|
|
* @throws Freemius_Exception
|
200
|
|
|
*/
|
201
|
|
|
function call( $path, $method = 'GET', $params = array() ) {
|
|
|
|
|
202
|
|
|
return $this->_call( $path, $method, $params );
|
203
|
|
|
}
|
204
|
|
|
|
205
|
|
|
/**
|
206
|
|
|
* Get API request URL signed via query string.
|
207
|
|
|
*
|
208
|
|
|
* @param string $path
|
209
|
|
|
*
|
210
|
|
|
* @return string
|
211
|
|
|
*/
|
212
|
|
|
function get_signed_url( $path ) {
|
|
|
|
|
213
|
|
|
return $this->_api->GetSignedUrl( $path );
|
214
|
|
|
}
|
215
|
|
|
|
216
|
|
|
/**
|
217
|
|
|
* @param string $path
|
218
|
|
|
* @param bool $flush
|
219
|
|
|
* @param int $expiration (optional) Time until expiration in seconds from now, defaults to 24 hours
|
220
|
|
|
*
|
221
|
|
|
* @return stdClass|mixed
|
222
|
|
|
*/
|
223
|
|
|
function get( $path = '/', $flush = false, $expiration = WP_FS__TIME_24_HOURS_IN_SEC ) {
|
|
|
|
|
224
|
|
|
$this->_logger->entrance( $path );
|
225
|
|
|
|
226
|
|
|
$cache_key = $this->get_cache_key( $path );
|
227
|
|
|
|
228
|
|
|
// Always flush during development.
|
229
|
|
|
if ( WP_FS__DEV_MODE || $this->_api->IsSandbox() ) {
|
230
|
|
|
$flush = true;
|
231
|
|
|
}
|
232
|
|
|
|
233
|
|
|
$cached_result = self::$_cache->get( $cache_key );
|
234
|
|
|
|
235
|
|
|
if ( $flush || ! self::$_cache->has_valid( $cache_key, $expiration ) ) {
|
236
|
|
|
$result = $this->call( $path );
|
237
|
|
|
|
238
|
|
|
if ( ! is_object( $result ) || isset( $result->error ) ) {
|
239
|
|
|
// Api returned an error.
|
240
|
|
|
if ( is_object( $cached_result ) &&
|
241
|
|
|
! isset( $cached_result->error )
|
242
|
|
|
) {
|
243
|
|
|
// If there was an error during a newer data fetch,
|
244
|
|
|
// fallback to older data version.
|
245
|
|
|
$result = $cached_result;
|
246
|
|
|
|
247
|
|
|
if ( $this->_logger->is_on() ) {
|
248
|
|
|
$this->_logger->warn( 'Fallback to cached API result: ' . var_export( $cached_result, true ) );
|
249
|
|
|
}
|
250
|
|
|
} else {
|
251
|
|
|
if ( is_object( $result ) && 404 == $result->error->http ) {
|
252
|
|
|
/**
|
253
|
|
|
* If the response code is 404, cache the result for half of the `$expiration`.
|
254
|
|
|
*
|
255
|
|
|
* @author Leo Fajardo (@leorw)
|
256
|
|
|
* @since 2.2.3.1
|
257
|
|
|
*/
|
258
|
|
|
$expiration /= 2;
|
259
|
|
|
} else {
|
260
|
|
|
// If no older data version and the response code is not 404, return result without
|
261
|
|
|
// caching the error.
|
262
|
|
|
return $result;
|
263
|
|
|
}
|
264
|
|
|
}
|
265
|
|
|
}
|
266
|
|
|
|
267
|
|
|
self::$_cache->set( $cache_key, $result, $expiration );
|
268
|
|
|
|
269
|
|
|
$cached_result = $result;
|
270
|
|
|
} else {
|
271
|
|
|
$this->_logger->log( 'Using cached API result.' );
|
272
|
|
|
}
|
273
|
|
|
|
274
|
|
|
return $cached_result;
|
275
|
|
|
}
|
276
|
|
|
|
277
|
|
|
/**
|
278
|
|
|
* Check if there's a cached version of the API request.
|
279
|
|
|
*
|
280
|
|
|
* @author Vova Feldman (@svovaf)
|
281
|
|
|
* @since 1.2.1
|
282
|
|
|
*
|
283
|
|
|
* @param string $path
|
284
|
|
|
* @param string $method
|
285
|
|
|
* @param array $params
|
286
|
|
|
*
|
287
|
|
|
* @return bool
|
288
|
|
|
*/
|
289
|
|
|
function is_cached( $path, $method = 'GET', $params = array() ) {
|
|
|
|
|
290
|
|
|
$cache_key = $this->get_cache_key( $path, $method, $params );
|
291
|
|
|
|
292
|
|
|
return self::$_cache->has_valid( $cache_key );
|
293
|
|
|
}
|
294
|
|
|
|
295
|
|
|
/**
|
296
|
|
|
* Invalidate a cached version of the API request.
|
297
|
|
|
*
|
298
|
|
|
* @author Vova Feldman (@svovaf)
|
299
|
|
|
* @since 1.2.1.5
|
300
|
|
|
*
|
301
|
|
|
* @param string $path
|
302
|
|
|
* @param string $method
|
303
|
|
|
* @param array $params
|
304
|
|
|
*/
|
305
|
|
|
function purge_cache( $path, $method = 'GET', $params = array() ) {
|
|
|
|
|
306
|
|
|
$this->_logger->entrance( "{$method}:{$path}" );
|
307
|
|
|
|
308
|
|
|
$cache_key = $this->get_cache_key( $path, $method, $params );
|
309
|
|
|
|
310
|
|
|
self::$_cache->purge( $cache_key );
|
311
|
|
|
}
|
312
|
|
|
|
313
|
|
|
/**
|
314
|
|
|
* Invalidate a cached version of the API request.
|
315
|
|
|
*
|
316
|
|
|
* @author Vova Feldman (@svovaf)
|
317
|
|
|
* @since 2.0.0
|
318
|
|
|
*
|
319
|
|
|
* @param string $path
|
320
|
|
|
* @param int $expiration
|
321
|
|
|
* @param string $method
|
322
|
|
|
* @param array $params
|
323
|
|
|
*/
|
324
|
|
|
function update_cache_expiration( $path, $expiration = WP_FS__TIME_24_HOURS_IN_SEC, $method = 'GET', $params = array() ) {
|
|
|
|
|
325
|
|
|
$this->_logger->entrance( "{$method}:{$path}:{$expiration}" );
|
326
|
|
|
|
327
|
|
|
$cache_key = $this->get_cache_key( $path, $method, $params );
|
328
|
|
|
|
329
|
|
|
self::$_cache->update_expiration( $cache_key, $expiration );
|
330
|
|
|
}
|
331
|
|
|
|
332
|
|
|
/**
|
333
|
|
|
* @param string $path
|
334
|
|
|
* @param string $method
|
335
|
|
|
* @param array $params
|
336
|
|
|
*
|
337
|
|
|
* @return string
|
338
|
|
|
* @throws \Freemius_Exception
|
339
|
|
|
*/
|
340
|
|
|
private function get_cache_key( $path, $method = 'GET', $params = array() ) {
|
341
|
|
|
$canonized = $this->_api->CanonizePath( $path );
|
342
|
|
|
// $exploded = explode('/', $canonized);
|
|
|
|
|
343
|
|
|
// return $method . '_' . array_pop($exploded) . '_' . md5($canonized . json_encode($params));
|
344
|
|
|
return strtolower( $method . ':' . $canonized ) . ( ! empty( $params ) ? '#' . md5( json_encode( $params ) ) : '' );
|
345
|
|
|
}
|
346
|
|
|
|
347
|
|
|
/**
|
348
|
|
|
* Test API connectivity.
|
349
|
|
|
*
|
350
|
|
|
* @author Vova Feldman (@svovaf)
|
351
|
|
|
* @since 1.0.9 If fails, try to fallback to HTTP.
|
352
|
|
|
* @since 1.1.6 Added a 5-min caching mechanism, to prevent from overloading the server if the API if
|
353
|
|
|
* temporary down.
|
354
|
|
|
*
|
355
|
|
|
* @return bool True if successful connectivity to the API.
|
356
|
|
|
*/
|
357
|
|
|
static function test() {
|
|
|
|
|
358
|
|
|
self::_init();
|
359
|
|
|
|
360
|
|
|
$cache_key = 'ping_test';
|
361
|
|
|
|
362
|
|
|
$test = self::$_cache->get_valid( $cache_key, null );
|
363
|
|
|
|
364
|
|
|
if ( is_null( $test ) ) {
|
365
|
|
|
$test = Freemius_Api_WordPress::Test();
|
366
|
|
|
|
367
|
|
|
if ( false === $test && Freemius_Api_WordPress::IsHttps() ) {
|
368
|
|
|
// Fallback to HTTP, since HTTPS fails.
|
369
|
|
|
Freemius_Api_WordPress::SetHttp();
|
370
|
|
|
|
371
|
|
|
self::$_options->set_option( 'api_force_http', true, true );
|
372
|
|
|
|
373
|
|
|
$test = Freemius_Api_WordPress::Test();
|
374
|
|
|
|
375
|
|
|
if ( false === $test ) {
|
376
|
|
|
/**
|
377
|
|
|
* API connectivity test fail also in HTTP request, therefore,
|
378
|
|
|
* fallback to HTTPS to keep connection secure.
|
379
|
|
|
*
|
380
|
|
|
* @since 1.1.6
|
381
|
|
|
*/
|
382
|
|
|
self::$_options->set_option( 'api_force_http', false, true );
|
383
|
|
|
}
|
384
|
|
|
}
|
385
|
|
|
|
386
|
|
|
self::$_cache->set( $cache_key, $test, WP_FS__TIME_5_MIN_IN_SEC );
|
387
|
|
|
}
|
388
|
|
|
|
389
|
|
|
return $test;
|
390
|
|
|
}
|
391
|
|
|
|
392
|
|
|
/**
|
393
|
|
|
* Check if API is temporary down.
|
394
|
|
|
*
|
395
|
|
|
* @author Vova Feldman (@svovaf)
|
396
|
|
|
* @since 1.1.6
|
397
|
|
|
*
|
398
|
|
|
* @return bool
|
399
|
|
|
*/
|
400
|
|
|
static function is_temporary_down() {
|
|
|
|
|
401
|
|
|
self::_init();
|
402
|
|
|
|
403
|
|
|
$test = self::$_cache->get_valid( 'ping_test', null );
|
404
|
|
|
|
405
|
|
|
return ( false === $test );
|
406
|
|
|
}
|
407
|
|
|
|
408
|
|
|
/**
|
409
|
|
|
* @author Vova Feldman (@svovaf)
|
410
|
|
|
* @since 1.1.6
|
411
|
|
|
*
|
412
|
|
|
* @return object
|
413
|
|
|
*/
|
414
|
|
|
private function get_temporary_unavailable_error() {
|
415
|
|
|
return (object) array(
|
416
|
|
|
'error' => (object) array(
|
417
|
|
|
'type' => 'TemporaryUnavailable',
|
418
|
|
|
'message' => 'API is temporary unavailable, please retry in ' . ( self::$_cache->get_record_expiration( 'ping_test' ) - WP_FS__SCRIPT_START_TIME ) . ' sec.',
|
419
|
|
|
'code' => 'temporary_unavailable',
|
420
|
|
|
'http' => 503
|
421
|
|
|
)
|
422
|
|
|
);
|
423
|
|
|
}
|
424
|
|
|
|
425
|
|
|
/**
|
426
|
|
|
* Ping API for connectivity test, and return result object.
|
427
|
|
|
*
|
428
|
|
|
* @author Vova Feldman (@svovaf)
|
429
|
|
|
* @since 1.0.9
|
430
|
|
|
*
|
431
|
|
|
* @param null|string $unique_anonymous_id
|
432
|
|
|
* @param array $params
|
433
|
|
|
*
|
434
|
|
|
* @return object
|
435
|
|
|
*/
|
436
|
|
|
function ping( $unique_anonymous_id = null, $params = array() ) {
|
|
|
|
|
437
|
|
|
$this->_logger->entrance();
|
438
|
|
|
|
439
|
|
|
if ( self::is_temporary_down() ) {
|
440
|
|
|
return $this->get_temporary_unavailable_error();
|
441
|
|
|
}
|
442
|
|
|
|
443
|
|
|
$pong = is_null( $unique_anonymous_id ) ?
|
444
|
|
|
Freemius_Api_WordPress::Ping() :
|
445
|
|
|
$this->_call( 'ping.json?' . http_build_query( array_merge(
|
446
|
|
|
array( 'uid' => $unique_anonymous_id ),
|
447
|
|
|
$params
|
448
|
|
|
) ) );
|
449
|
|
|
|
450
|
|
|
if ( $this->is_valid_ping( $pong ) ) {
|
451
|
|
|
return $pong;
|
452
|
|
|
}
|
453
|
|
|
|
454
|
|
|
if ( self::should_try_with_http( $pong ) ) {
|
455
|
|
|
// Fallback to HTTP, since HTTPS fails.
|
456
|
|
|
Freemius_Api_WordPress::SetHttp();
|
457
|
|
|
|
458
|
|
|
self::$_options->set_option( 'api_force_http', true, true );
|
459
|
|
|
|
460
|
|
|
$pong = is_null( $unique_anonymous_id ) ?
|
461
|
|
|
Freemius_Api_WordPress::Ping() :
|
462
|
|
|
$this->_call( 'ping.json?' . http_build_query( array_merge(
|
463
|
|
|
array( 'uid' => $unique_anonymous_id ),
|
464
|
|
|
$params
|
465
|
|
|
) ) );
|
466
|
|
|
|
467
|
|
|
if ( ! $this->is_valid_ping( $pong ) ) {
|
468
|
|
|
self::$_options->set_option( 'api_force_http', false, true );
|
469
|
|
|
}
|
470
|
|
|
}
|
471
|
|
|
|
472
|
|
|
return $pong;
|
473
|
|
|
}
|
474
|
|
|
|
475
|
|
|
/**
|
476
|
|
|
* Check if based on the API result we should try
|
477
|
|
|
* to re-run the same request with HTTP instead of HTTPS.
|
478
|
|
|
*
|
479
|
|
|
* @author Vova Feldman (@svovaf)
|
480
|
|
|
* @since 1.1.6
|
481
|
|
|
*
|
482
|
|
|
* @param $result
|
483
|
|
|
*
|
484
|
|
|
* @return bool
|
485
|
|
|
*/
|
486
|
|
|
private static function should_try_with_http( $result ) {
|
487
|
|
|
if ( ! Freemius_Api_WordPress::IsHttps() ) {
|
488
|
|
|
return false;
|
489
|
|
|
}
|
490
|
|
|
|
491
|
|
|
return ( ! is_object( $result ) ||
|
492
|
|
|
! isset( $result->error ) ||
|
493
|
|
|
! isset( $result->error->code ) ||
|
494
|
|
|
! in_array( $result->error->code, array(
|
495
|
|
|
'curl_missing',
|
496
|
|
|
'cloudflare_ddos_protection',
|
497
|
|
|
'maintenance_mode',
|
498
|
|
|
'squid_cache_block',
|
499
|
|
|
'too_many_requests',
|
500
|
|
|
) ) );
|
501
|
|
|
|
502
|
|
|
}
|
503
|
|
|
|
504
|
|
|
/**
|
505
|
|
|
* Check if valid ping request result.
|
506
|
|
|
*
|
507
|
|
|
* @author Vova Feldman (@svovaf)
|
508
|
|
|
* @since 1.1.1
|
509
|
|
|
*
|
510
|
|
|
* @param mixed $pong
|
511
|
|
|
*
|
512
|
|
|
* @return bool
|
513
|
|
|
*/
|
514
|
|
|
function is_valid_ping( $pong ) {
|
|
|
|
|
515
|
|
|
return Freemius_Api_WordPress::Test( $pong );
|
516
|
|
|
}
|
517
|
|
|
|
518
|
|
|
function get_url( $path = '' ) {
|
|
|
|
|
519
|
|
|
return Freemius_Api_WordPress::GetUrl( $path, $this->_api->IsSandbox() );
|
520
|
|
|
}
|
521
|
|
|
|
522
|
|
|
/**
|
523
|
|
|
* Clear API cache.
|
524
|
|
|
*
|
525
|
|
|
* @author Vova Feldman (@svovaf)
|
526
|
|
|
* @since 1.0.9
|
527
|
|
|
*/
|
528
|
|
|
static function clear_cache() {
|
|
|
|
|
529
|
|
|
self::_init();
|
530
|
|
|
|
531
|
|
|
self::$_cache = FS_Cache_Manager::get_manager( WP_FS__API_CACHE_OPTION_NAME );
|
532
|
|
|
self::$_cache->clear();
|
533
|
|
|
}
|
534
|
|
|
|
535
|
|
|
#----------------------------------------------------------------------------------
|
536
|
|
|
#region Error Handling
|
537
|
|
|
#----------------------------------------------------------------------------------
|
538
|
|
|
|
539
|
|
|
/**
|
540
|
|
|
* @author Vova Feldman (@svovaf)
|
541
|
|
|
* @since 1.2.1.5
|
542
|
|
|
*
|
543
|
|
|
* @param mixed $result
|
544
|
|
|
*
|
545
|
|
|
* @return bool Is API result contains an error.
|
546
|
|
|
*/
|
547
|
|
|
static function is_api_error( $result ) {
|
|
|
|
|
548
|
|
|
return ( is_object( $result ) && isset( $result->error ) ) ||
|
549
|
|
|
is_string( $result );
|
550
|
|
|
}
|
551
|
|
|
|
552
|
|
|
/**
|
553
|
|
|
* @author Vova Feldman (@svovaf)
|
554
|
|
|
* @since 2.0.0
|
555
|
|
|
*
|
556
|
|
|
* @param mixed $result
|
557
|
|
|
*
|
558
|
|
|
* @return bool Is API result contains an error.
|
559
|
|
|
*/
|
560
|
|
|
static function is_api_error_object( $result ) {
|
|
|
|
|
561
|
|
|
return (
|
562
|
|
|
is_object( $result ) &&
|
563
|
|
|
isset( $result->error ) &&
|
564
|
|
|
isset( $result->error->message )
|
565
|
|
|
);
|
566
|
|
|
}
|
567
|
|
|
|
568
|
|
|
/**
|
569
|
|
|
* Checks if given API result is a non-empty and not an error object.
|
570
|
|
|
*
|
571
|
|
|
* @author Vova Feldman (@svovaf)
|
572
|
|
|
* @since 1.2.1.5
|
573
|
|
|
*
|
574
|
|
|
* @param mixed $result
|
575
|
|
|
* @param string|null $required_property Optional property we want to verify that is set.
|
576
|
|
|
*
|
577
|
|
|
* @return bool
|
578
|
|
|
*/
|
579
|
|
|
static function is_api_result_object( $result, $required_property = null ) {
|
|
|
|
|
580
|
|
|
return (
|
581
|
|
|
is_object( $result ) &&
|
582
|
|
|
! isset( $result->error ) &&
|
583
|
|
|
( empty( $required_property ) || isset( $result->{$required_property} ) )
|
584
|
|
|
);
|
585
|
|
|
}
|
586
|
|
|
|
587
|
|
|
/**
|
588
|
|
|
* Checks if given API result is a non-empty entity object with non-empty ID.
|
589
|
|
|
*
|
590
|
|
|
* @author Vova Feldman (@svovaf)
|
591
|
|
|
* @since 1.2.1.5
|
592
|
|
|
*
|
593
|
|
|
* @param mixed $result
|
594
|
|
|
*
|
595
|
|
|
* @return bool
|
596
|
|
|
*/
|
597
|
|
|
static function is_api_result_entity( $result ) {
|
|
|
|
|
598
|
|
|
return self::is_api_result_object( $result, 'id' ) &&
|
599
|
|
|
FS_Entity::is_valid_id( $result->id );
|
600
|
|
|
}
|
601
|
|
|
|
602
|
|
|
/**
|
603
|
|
|
* Get API result error code. If failed to get code, returns an empty string.
|
604
|
|
|
*
|
605
|
|
|
* @author Vova Feldman (@svovaf)
|
606
|
|
|
* @since 2.0.0
|
607
|
|
|
*
|
608
|
|
|
* @param mixed $result
|
609
|
|
|
*
|
610
|
|
|
* @return string
|
611
|
|
|
*/
|
612
|
|
|
static function get_error_code( $result ) {
|
|
|
|
|
613
|
|
|
if ( is_object( $result ) &&
|
614
|
|
|
isset( $result->error ) &&
|
615
|
|
|
is_object( $result->error ) &&
|
616
|
|
|
! empty( $result->error->code )
|
617
|
|
|
) {
|
618
|
|
|
return $result->error->code;
|
619
|
|
|
}
|
620
|
|
|
|
621
|
|
|
return '';
|
622
|
|
|
}
|
623
|
|
|
|
624
|
|
|
#endregion
|
625
|
|
|
} |
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.