PluginProbe
Automatic YouTube Gallery – Embed Auto-Updating YouTube Video Galleries, Feeds, Playlists & Channels / 2.3.8
Automatic YouTube Gallery – Embed Auto-Updating YouTube Video Galleries, Feeds, Playlists & Channels v2.3.8
2.9.1 2.9.0 trunk 1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 2.0.0 2.1.0 2.2.0 2.3.2 2.3.3 2.3.5 2.3.6 2.3.8 2.3.9 2.4.3 All 37 releases
← All changes | freemius/includes/class-fs-api.php +177 -122 1.6.12.3.8 View file →
@@ -64,8 +64,16 @@
64 64 */
65 65 private $_sdk_version;
66 66
67 67 /**
68 + * @author Leo Fajardo (@leorw)
69 + * @since 2.5.0
70 + *
71 + * @var string
72 + */
73 + private $_url;
74 +
75 + /**
68 76 * @param string $slug
69 77 * @param string $scope 'app', 'developer', 'user' or 'install'.
70 78 * @param number $id Element's id.
71 79 * @param string $public_key Public key.
@@ -71,8 +79,9 @@
71 79 * @param string $public_key Public key.
72 80 * @param bool $is_sandbox
73 81 * @param bool|string $secret_key Element's secret key.
74 82 * @param null|string $sdk_version
83 + * @param null|string $url
75 84 *
76 85 * @return FS_Api
77 86 */
78 87 static function instance(
@@ -81,9 +90,10 @@
81 90 $id,
82 91 $public_key,
83 92 $is_sandbox,
84 93 $secret_key = false,
85 - $sdk_version = null
94 + $sdk_version = null,
95 + $url = null
86 96 ) {
87 97 $identifier = md5( $slug . $scope . $id . $public_key . ( is_string( $secret_key ) ? $secret_key : '' ) . json_encode( $is_sandbox ) );
88 98
89 99 if ( ! isset( self::$_instances[ $identifier ] ) ) {
@@ -88,9 +98,9 @@
88 98
89 99 if ( ! isset( self::$_instances[ $identifier ] ) ) {
90 100 self::_init();
91 101
92 - self::$_instances[ $identifier ] = new FS_Api( $slug, $scope, $id, $public_key, $secret_key, $is_sandbox, $sdk_version );
102 + self::$_instances[ $identifier ] = new FS_Api( $slug, $scope, $id, $public_key, $secret_key, $is_sandbox, $sdk_version, $url );
93 103 }
94 104
95 105 return self::$_instances[ $identifier ];
96 106 }
@@ -122,8 +132,9 @@
122 132 * @param string $public_key Public key.
123 133 * @param bool|string $secret_key Element's secret key.
124 134 * @param bool $is_sandbox
125 135 * @param null|string $sdk_version
136 + * @param null|string $url
126 137 */
127 138 private function __construct(
128 139 $slug,
129 140 $scope,
@@ -130,14 +141,16 @@
130 141 $id,
131 142 $public_key,
132 143 $secret_key,
133 144 $is_sandbox,
134 - $sdk_version
145 + $sdk_version,
146 + $url
135 147 ) {
136 148 $this->_api = new Freemius_Api_WordPress( $scope, $id, $public_key, $secret_key, $is_sandbox );
137 149
138 150 $this->_slug = $slug;
139 151 $this->_sdk_version = $sdk_version;
152 + $this->_url = $url;
140 153 $this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_' . $slug . '_api', WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
141 154 }
142 155
143 156 /**
@@ -175,15 +188,17 @@
175 188 *
176 189 * @param string $path
177 190 * @param string $method
178 191 * @param array $params
179 - * @param bool $retry Is in retry or first call attempt.
192 + * @param bool $in_retry Is in retry or first call attempt.
180 193 *
181 194 * @return array|mixed|string|void
182 195 */
183 - private function _call( $path, $method = 'GET', $params = array(), $retry = false ) {
196 + private function _call( $path, $method = 'GET', $params = array(), $in_retry = false ) {
184 197 $this->_logger->entrance( $method . ':' . $path );
185 198
199 + $force_http = ( ! $in_retry && self::$_options->get_option( 'api_force_http', false ) );
200 +
186 201 if ( self::is_temporary_down() ) {
187 202 $result = $this->get_temporary_unavailable_error();
188 203 } else {
189 204 /**
@@ -197,16 +212,30 @@
197 212 $path = add_query_arg( 'sdk_version', $this->_sdk_version, $path );
198 213 }
199 214 }
200 215
216 + /**
217 + * @since 2.5.0 Include the site's URL, if available, in all API requests that are going through the API manager.
218 + */
219 + if ( ! empty( $this->_url ) ) {
220 + if ( false === strpos( $path, 'url=' ) &&
221 + ! isset( $params['url'] )
222 + ) {
223 + $path = add_query_arg( 'url', $this->_url, $path );
224 + }
225 + }
226 +
201 227 $result = $this->_api->Api( $path, $method, $params );
202 228
203 - if ( null !== $result &&
204 - isset( $result->error ) &&
205 - isset( $result->error->code ) &&
206 - 'request_expired' === $result->error->code
229 + if (
230 + ! $in_retry &&
231 + null !== $result &&
232 + isset( $result->error ) &&
233 + isset( $result->error->code )
207 234 ) {
208 - if ( ! $retry ) {
235 + $retry = false;
236 +
237 + if ( 'request_expired' === $result->error->code ) {
209 238 $diff = isset( $result->error->timestamp ) ?
210 239 ( time() - strtotime( $result->error->timestamp ) ) :
211 240 false;
212 241
@@ -212,17 +241,37 @@
212 241
213 242 // Try to sync clock diff.
214 243 if ( false !== $this->_sync_clock_diff( $diff ) ) {
215 244 // Retry call with new synced clock.
216 - return $this->_call( $path, $method, $params, true );
245 + $retry = true;
217 246 }
247 + } else if (
248 + Freemius_Api_WordPress::IsHttps() &&
249 + FS_Api::is_ssl_error_response( $result )
250 + ) {
251 + $force_http = true;
252 + $retry = true;
218 253 }
254 +
255 + if ( $retry ) {
256 + if ( $force_http ) {
257 + $this->toggle_force_http( true );
258 + }
259 +
260 + $result = $this->_call( $path, $method, $params, true );
261 + }
219 262 }
220 263 }
221 264
222 - if ( $this->_logger->is_on() && self::is_api_error( $result ) ) {
223 - // Log API errors.
224 - $this->_logger->api_error( $result );
265 + if ( self::is_api_error( $result ) ) {
266 + if ( $this->_logger->is_on() ) {
267 + // Log API errors.
268 + $this->_logger->api_error( $result );
269 + }
270 +
271 + if ( $force_http ) {
272 + $this->toggle_force_http( false );
273 + }
225 274 }
226 275
227 276 return $result;
228 277 }
@@ -312,8 +361,45 @@
312 361
313 362 return $cached_result;
314 363 }
315 364
365 + /**
366 + * @todo Remove this method after migrating Freemius::safe_remote_post() to FS_Api::call().
367 + *
368 + * @author Leo Fajardo (@leorw)
369 + * @since 2.5.4
370 + *
371 + * @param string $url
372 + * @param array $remote_args
373 + *
374 + * @return array|WP_Error The response array or a WP_Error on failure.
375 + */
376 + static function remote_request( $url, $remote_args ) {
377 + if ( ! class_exists( 'Freemius_Api_WordPress' ) ) {
378 + require_once WP_FS__DIR_SDK . '/FreemiusWordPress.php';
379 + }
380 +
381 + if ( method_exists( 'Freemius_Api_WordPress', 'RemoteRequest' ) ) {
382 + return Freemius_Api_WordPress::RemoteRequest( $url, $remote_args );
383 + }
384 +
385 + // The following is for backward compatibility when a modified PHP SDK version is in use and the `Freemius_Api_WordPress:RemoteRequest()` method doesn't exist.
386 + $response = wp_remote_request( $url, $remote_args );
387 +
388 + if (
389 + is_array( $response ) &&
390 + (
391 + empty( $response['headers'] ) ||
392 + empty( $response['headers']['x-api-server'] )
393 + )
394 + ) {
395 + // API is considered blocked if the response doesn't include the `x-api-server` header. When there's no error but this header doesn't exist, the response is usually not in the expected form (e.g., cannot be JSON-decoded).
396 + $response = new WP_Error( 'api_blocked', htmlentities( $response['body'] ) );
397 + }
398 +
399 + return $response;
400 + }
401 +
316 402 /**
317 403 * Check if there's a cached version of the API request.
318 404 *
319 405 * @author Vova Feldman (@svovaf)
@@ -382,53 +468,40 @@
382 468 // return $method . '_' . array_pop($exploded) . '_' . md5($canonized . json_encode($params));
383 469 return strtolower( $method . ':' . $canonized ) . ( ! empty( $params ) ? '#' . md5( json_encode( $params ) ) : '' );
384 470 }
385 471
386 - /**
387 - * Test API connectivity.
388 - *
389 - * @author Vova Feldman (@svovaf)
390 - * @since 1.0.9 If fails, try to fallback to HTTP.
391 - * @since 1.1.6 Added a 5-min caching mechanism, to prevent from overloading the server if the API if
392 - * temporary down.
393 - *
394 - * @return bool True if successful connectivity to the API.
395 - */
396 - static function test() {
397 - self::_init();
472 + /**
473 + * @author Leo Fajardo (@leorw)
474 + * @since 2.5.4
475 + *
476 + * @param bool $is_http
477 + */
478 + private function toggle_force_http( $is_http ) {
479 + self::$_options->set_option( 'api_force_http', $is_http, true );
398 480
399 - $cache_key = 'ping_test';
481 + if ( $is_http ) {
482 + Freemius_Api_WordPress::SetHttp();
483 + } else if ( method_exists( 'Freemius_Api_WordPress', 'SetHttps' ) ) {
484 + Freemius_Api_WordPress::SetHttps();
485 + }
486 + }
400 487
401 - $test = self::$_cache->get_valid( $cache_key, null );
488 + /**
489 + * @author Leo Fajardo (@leorw)
490 + * @since 2.5.4
491 + *
492 + * @param mixed $response
493 + *
494 + * @return bool
495 + */
496 + static function is_blocked( $response ) {
497 + return (
498 + self::is_api_error_object( $response, true ) &&
499 + isset( $response->error->code ) &&
500 + 'api_blocked' === $response->error->code
501 + );
502 + }
402 503
403 - if ( is_null( $test ) ) {
404 - $test = Freemius_Api_WordPress::Test();
405 -
406 - if ( false === $test && Freemius_Api_WordPress::IsHttps() ) {
407 - // Fallback to HTTP, since HTTPS fails.
408 - Freemius_Api_WordPress::SetHttp();
409 -
410 - self::$_options->set_option( 'api_force_http', true, true );
411 -
412 - $test = Freemius_Api_WordPress::Test();
413 -
414 - if ( false === $test ) {
415 - /**
416 - * API connectivity test fail also in HTTP request, therefore,
417 - * fallback to HTTPS to keep connection secure.
418 - *
419 - * @since 1.1.6
420 - */
421 - self::$_options->set_option( 'api_force_http', false, true );
422 - }
423 - }
424 -
425 - self::$_cache->set( $cache_key, $test, WP_FS__TIME_5_MIN_IN_SEC );
426 - }
427 -
428 - return $test;
429 - }
430 -
431 504 /**
432 505 * Check if API is temporary down.
433 506 *
434 507 * @author Vova Feldman (@svovaf)
@@ -461,58 +534,8 @@
461 534 );
462 535 }
463 536
464 537 /**
465 - * Ping API for connectivity test, and return result object.
466 - *
467 - * @author Vova Feldman (@svovaf)
468 - * @since 1.0.9
469 - *
470 - * @param null|string $unique_anonymous_id
471 - * @param array $params
472 - *
473 - * @return object
474 - */
475 - function ping( $unique_anonymous_id = null, $params = array() ) {
476 - $this->_logger->entrance();
477 -
478 - if ( self::is_temporary_down() ) {
479 - return $this->get_temporary_unavailable_error();
480 - }
481 -
482 - $pong = is_null( $unique_anonymous_id ) ?
483 - Freemius_Api_WordPress::Ping() :
484 - $this->_call( 'ping.json?' . http_build_query( array_merge(
485 - array( 'uid' => $unique_anonymous_id ),
486 - $params
487 - ) ) );
488 -
489 - if ( $this->is_valid_ping( $pong ) ) {
490 - return $pong;
491 - }
492 -
493 - if ( self::should_try_with_http( $pong ) ) {
494 - // Fallback to HTTP, since HTTPS fails.
495 - Freemius_Api_WordPress::SetHttp();
496 -
497 - self::$_options->set_option( 'api_force_http', true, true );
498 -
499 - $pong = is_null( $unique_anonymous_id ) ?
500 - Freemius_Api_WordPress::Ping() :
501 - $this->_call( 'ping.json?' . http_build_query( array_merge(
502 - array( 'uid' => $unique_anonymous_id ),
503 - $params
504 - ) ) );
505 -
506 - if ( ! $this->is_valid_ping( $pong ) ) {
507 - self::$_options->set_option( 'api_force_http', false, true );
508 - }
509 - }
510 -
511 - return $pong;
512 - }
513 -
514 - /**
515 538 * Check if based on the API result we should try
516 539 * to re-run the same request with HTTP instead of HTTPS.
517 540 *
518 541 * @author Vova Feldman (@svovaf)
@@ -539,22 +562,8 @@
539 562 ) ) );
540 563
541 564 }
542 565
543 - /**
544 - * Check if valid ping request result.
545 - *
546 - * @author Vova Feldman (@svovaf)
547 - * @since 1.1.1
548 - *
549 - * @param mixed $pong
550 - *
551 - * @return bool
552 - */
553 - function is_valid_ping( $pong ) {
554 - return Freemius_Api_WordPress::Test( $pong );
555 - }
556 -
557 566 function get_url( $path = '' ) {
558 567 return Freemius_Api_WordPress::GetUrl( $path, $this->_api->IsSandbox() );
559 568 }
560 569
@@ -570,8 +579,16 @@
570 579 self::$_cache = FS_Cache_Manager::get_manager( WP_FS__API_CACHE_OPTION_NAME );
571 580 self::$_cache->clear();
572 581 }
573 582
583 + /**
584 + * @author Leo Fajardo (@leorw)
585 + * @since 2.5.4
586 + */
587 + static function clear_force_http_flag() {
588 + self::$_options->unset_option( 'api_force_http' );
589 + }
590 +
574 591 #----------------------------------------------------------------------------------
575 592 #region Error Handling
576 593 #----------------------------------------------------------------------------------
577 594
@@ -592,16 +609,54 @@
592 609 * @author Vova Feldman (@svovaf)
593 610 * @since 2.0.0
594 611 *
595 612 * @param mixed $result
613 + * @param bool $ignore_message
596 614 *
597 615 * @return bool Is API result contains an error.
598 616 */
599 - static function is_api_error_object( $result ) {
617 + static function is_api_error_object( $result, $ignore_message = false ) {
600 618 return (
601 619 is_object( $result ) &&
602 620 isset( $result->error ) &&
603 - isset( $result->error->message )
621 + ( $ignore_message || isset( $result->error->message ) )
622 + );
623 + }
624 +
625 + /**
626 + * @author Leo Fajardo (@leorw)
627 + * @since 2.5.4
628 + *
629 + * @param WP_Error|object|string $response
630 + *
631 + * @return bool
632 + */
633 + static function is_ssl_error_response( $response ) {
634 + $http_error = null;
635 +
636 + if ( $response instanceof WP_Error ) {
637 + if (
638 + isset( $response->errors ) &&
639 + isset( $response->errors['http_request_failed'] )
640 + ) {
641 + $http_error = strtolower( $response->errors['http_request_failed'][0] );
642 + }
643 + } else if (
644 + self::is_api_error_object( $response ) &&
645 + ! empty( $response->error->message )
646 + ) {
647 + $http_error = $response->error->message;
648 + }
649 +
650 + return (
651 + ! empty( $http_error ) &&
652 + (
653 + false !== strpos( $http_error, 'curl error 35' ) ||
654 + (
655 + false === strpos( $http_error, '</html>' ) &&
656 + false !== strpos( $http_error, 'ssl' )
657 + )
658 + )
604 659 );
605 660 }
606 661
607 662 /**