123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363 |
- <?php
- /**
- * WPSEO plugin file.
- *
- * @package WPSEO\Inc
- */
- /**
- * Handles requests to MyYoast.
- */
- class WPSEO_MyYoast_Api_Request {
- /**
- * The Request URL.
- *
- * @var string
- */
- protected $url;
- /**
- * The request parameters.
- *
- * @var array
- */
- protected $args = [
- 'method' => 'GET',
- 'timeout' => 5,
- 'headers' => [
- 'Accept-Encoding' => '*',
- ],
- ];
- /**
- * Contains the fetched response.
- *
- * @var stdClass
- */
- protected $response;
- /**
- * Contains the error message when request went wrong.
- *
- * @var string
- */
- protected $error_message = '';
- /**
- * The MyYoast client object.
- *
- * @var WPSEO_MyYoast_Client
- */
- protected $client;
- /**
- * Constructor.
- *
- * @codeCoverageIgnore
- *
- * @param string $url The request url.
- * @param array $args The request arguments.
- */
- public function __construct( $url, array $args = [] ) {
- $this->url = 'https://my.yoast.com/api/' . $url;
- $this->args = wp_parse_args( $args, $this->args );
- }
- /**
- * Fires the request.
- *
- * @return bool True when request is successful.
- */
- public function fire() {
- try {
- $response = $this->do_request( $this->url, $this->args );
- $this->response = $this->decode_response( $response );
- return true;
- }
- /**
- * The Authentication exception only occurs when using Access Tokens (>= PHP 5.6).
- * In other case this exception won't be thrown.
- *
- * When authentication failed just try to get a new access token based
- * on the refresh token. If that request also has an authentication issue
- * we just invalidate the access token by removing it.
- */
- catch ( WPSEO_MyYoast_Authentication_Exception $authentication_exception ) {
- try {
- $access_token = $this->get_access_token();
- if ( $access_token !== false ) {
- $response = $this->do_request( $this->url, $this->args );
- $this->response = $this->decode_response( $response );
- }
- return true;
- }
- catch ( WPSEO_MyYoast_Authentication_Exception $authentication_exception ) {
- $this->error_message = $authentication_exception->getMessage();
- $this->remove_access_token( $this->get_current_user_id() );
- return false;
- }
- catch ( WPSEO_MyYoast_Bad_Request_Exception $bad_request_exception ) {
- $this->error_message = $bad_request_exception->getMessage();
- return false;
- }
- }
- catch ( WPSEO_MyYoast_Bad_Request_Exception $bad_request_exception ) {
- $this->error_message = $bad_request_exception->getMessage();
- return false;
- }
- }
- /**
- * Retrieves the error message.
- *
- * @return string The set error message.
- */
- public function get_error_message() {
- return $this->error_message;
- }
- /**
- * Retrieves the response.
- *
- * @return stdClass The response object.
- */
- public function get_response() {
- return $this->response;
- }
- /**
- * Performs the request using WordPress internals.
- *
- * @codeCoverageIgnore
- *
- * @param string $url The request URL.
- * @param array $request_arguments The request arguments.
- *
- * @return string The retrieved body.
- * @throws WPSEO_MyYoast_Authentication_Exception When authentication has failed.
- * @throws WPSEO_MyYoast_Bad_Request_Exception When request is invalid.
- */
- protected function do_request( $url, $request_arguments ) {
- $request_arguments = $this->enrich_request_arguments( $request_arguments );
- $response = wp_remote_request( $url, $request_arguments );
- if ( is_wp_error( $response ) ) {
- throw new WPSEO_MyYoast_Bad_Request_Exception( $response->get_error_message() );
- }
- $response_code = wp_remote_retrieve_response_code( $response );
- $response_message = wp_remote_retrieve_response_message( $response );
- // Do nothing, response code is okay.
- if ( $response_code === 200 || strpos( $response_code, '200' ) !== false ) {
- return wp_remote_retrieve_body( $response );
- }
- // Authentication failed, throw an exception.
- if ( strpos( $response_code, '401' ) && $this->has_oauth_support() ) {
- throw new WPSEO_MyYoast_Authentication_Exception( esc_html( $response_message ), 401 );
- }
- throw new WPSEO_MyYoast_Bad_Request_Exception( esc_html( $response_message ), (int) $response_code );
- }
- /**
- * Decodes the JSON encoded response.
- *
- * @param string $response The response to decode.
- *
- * @return stdClass The json decoded response.
- * @throws WPSEO_MyYoast_Invalid_JSON_Exception When decoded string is not a JSON object.
- */
- protected function decode_response( $response ) {
- $response = json_decode( $response );
- if ( ! is_object( $response ) ) {
- throw new WPSEO_MyYoast_Invalid_JSON_Exception(
- esc_html__( 'No JSON object was returned.', 'wordpress-seo' )
- );
- }
- return $response;
- }
- /**
- * Checks if MyYoast tokens are allowed and adds the token to the request body.
- *
- * When tokens are disallowed it will add the url to the request body.
- *
- * @param array $request_arguments The arguments to enrich.
- *
- * @return array The enriched arguments.
- */
- protected function enrich_request_arguments( array $request_arguments ) {
- $request_arguments = wp_parse_args( $request_arguments, [ 'headers' => [] ] );
- $addon_version_headers = $this->get_installed_addon_versions();
- foreach ( $addon_version_headers as $addon => $version ) {
- $request_arguments['headers'][ $addon . '-version' ] = $version;
- }
- $request_body = $this->get_request_body();
- if ( $request_body !== [] ) {
- $request_arguments['body'] = $request_body;
- }
- return $request_arguments;
- }
- /**
- * Retrieves the request body based on URL or access token support.
- *
- * @codeCoverageIgnore
- *
- * @return array The request body.
- */
- public function get_request_body() {
- if ( ! $this->has_oauth_support() ) {
- return [ 'url' => WPSEO_Utils::get_home_url() ];
- }
- try {
- $access_token = $this->get_access_token();
- if ( $access_token ) {
- return [ 'token' => $access_token->getToken() ];
- }
- }
- // @codingStandardsIgnoreLine Generic.CodeAnalysis.EmptyStatement.DetectedCATCH -- There is nothing to do.
- catch ( WPSEO_MyYoast_Bad_Request_Exception $bad_request ) {
- // Do nothing.
- }
- return [];
- }
- /**
- * Retrieves the access token.
- *
- * @codeCoverageIgnore
- *
- * @return bool|WPSEO_MyYoast_AccessToken_Interface The AccessToken when valid.
- * @throws WPSEO_MyYoast_Bad_Request_Exception When something went wrong in getting the access token.
- */
- protected function get_access_token() {
- $client = $this->get_client();
- if ( ! $client ) {
- return false;
- }
- $access_token = $client->get_access_token();
- if ( ! $access_token ) {
- return false;
- }
- if ( ! $access_token->hasExpired() ) {
- return $access_token;
- }
- try {
- $access_token = $client
- ->get_provider()
- ->getAccessToken(
- 'refresh_token',
- [
- 'refresh_token' => $access_token->getRefreshToken(),
- ]
- );
- $client->save_access_token( $this->get_current_user_id(), $access_token );
- return $access_token;
- }
- catch ( Exception $e ) {
- $error_code = $e->getCode();
- if ( $error_code >= 400 && $error_code < 500 ) {
- $this->remove_access_token( $this->get_current_user_id() );
- }
- throw new WPSEO_MyYoast_Bad_Request_Exception( $e->getMessage() );
- }
- }
- /**
- * Retrieves an instance of the MyYoast client.
- *
- * @codeCoverageIgnore
- *
- * @return WPSEO_MyYoast_Client Instance of the client.
- */
- protected function get_client() {
- if ( $this->client === null ) {
- $this->client = new WPSEO_MyYoast_Client();
- }
- return $this->client;
- }
- /**
- * Wraps the get current user id function.
- *
- * @codeCoverageIgnore
- *
- * @return int The user id.
- */
- protected function get_current_user_id() {
- return get_current_user_id();
- }
- /**
- * Removes the access token for given user id.
- *
- * @codeCoverageIgnore
- *
- * @param int $user_id The user id.
- *
- * @return void
- */
- protected function remove_access_token( $user_id ) {
- if ( ! $this->has_oauth_support() ) {
- return;
- }
- // Remove the access token entirely.
- $this->get_client()->remove_access_token( $user_id );
- }
- /**
- * Retrieves the installed addons as http headers.
- *
- * @codeCoverageIgnore
- *
- * @return array The installed addon versions.
- */
- protected function get_installed_addon_versions() {
- $addon_manager = new WPSEO_Addon_Manager();
- return $addon_manager->get_installed_addons_versions();
- }
- /**
- * Wraps the has_access_token support method.
- *
- * @codeCoverageIgnore
- *
- * @return bool False to disable the support.
- */
- protected function has_oauth_support() {
- return false;
- // @todo: Uncomment the following statement when we are implementing the oAuth flow.
- // return WPSEO_Utils::has_access_token_support();
- }
- }
|