class-api-google-client.php 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. <?php
  2. /**
  3. * Class Yoast_Api_Google_Client
  4. */
  5. class Yoast_Api_Google_Client extends Yoast_Google_Client {
  6. /**
  7. * @var string
  8. */
  9. protected $option_refresh_token;
  10. /**
  11. * @var string
  12. */
  13. protected $option_access_token;
  14. /**
  15. * @var string
  16. */
  17. protected $api_url;
  18. /**
  19. * @var string
  20. */
  21. protected $http_response_code;
  22. /**
  23. * Initialize the config and refresh the token
  24. *
  25. * @param array $config
  26. * @param string $option_prefix
  27. * @param string $api_url
  28. */
  29. public function __construct( $config, $option_prefix, $api_url = '' ) {
  30. parent::__construct();
  31. $this->option_refresh_token = $option_prefix . '-refresh_token';
  32. $this->option_access_token = $option_prefix . '-access_token';
  33. $this->api_url = $api_url;
  34. // Initialize the config to set all properties properly.
  35. $this->init_config( $config );
  36. // Let's get an access token if we've got a refresh token.
  37. $this->refresh_tokens();
  38. }
  39. /**
  40. * Authenticate the client. If $authorization_code is empty it will lead the user through the validation process of
  41. * Google. If set it will be get the access token for current session and save the refresh_token for future use
  42. *
  43. * @param mixed $authorization_code
  44. *
  45. * @return bool
  46. */
  47. public function authenticate_client( $authorization_code = null ) {
  48. static $has_retried;
  49. // Authenticate client.
  50. try {
  51. $this->authenticate( $authorization_code );
  52. // Get access response.
  53. $response = $this->getAccessToken();
  54. // Check if there is a response body.
  55. if ( ! empty( $response ) ) {
  56. $response = json_decode( $response );
  57. if ( is_object( $response ) ) {
  58. // Save the refresh token.
  59. $this->save_refresh_token( $response->refresh_token );
  60. return true;
  61. }
  62. }
  63. } catch ( Yoast_Google_AuthException $exception ) {
  64. // If there aren't any attempts before, try again and set attempts on true, to prevent further attempts.
  65. if ( empty( $has_retried ) ) {
  66. $has_retried = true;
  67. return $this->authenticate_client( $authorization_code );
  68. }
  69. }
  70. return false;
  71. }
  72. /**
  73. * Doing a request to the API
  74. *
  75. * @param string $target_request_url
  76. * @param bool $decode_response
  77. * @param string $request_method
  78. *
  79. * @return array
  80. */
  81. public function do_request( $target_request_url, $decode_response = false, $request_method = 'GET' ) {
  82. // Get response.
  83. $response = $this->getIo()->authenticatedRequest(
  84. new Yoast_Google_HttpRequest( $this->api_url . $target_request_url, $request_method )
  85. );
  86. // Storing the response code.
  87. $this->http_response_code = $response->getResponseHttpCode();
  88. if ( $decode_response ) {
  89. return $this->decode_response( $response );
  90. }
  91. return $response;
  92. }
  93. /**
  94. * Decode the JSON response
  95. *
  96. * @param object $response
  97. * @param int $accepted_response_code
  98. *
  99. * @return mixed
  100. */
  101. public function decode_response( $response, $accepted_response_code = 200 ) {
  102. if ( $accepted_response_code === $response->getResponseHttpCode() ) {
  103. return json_decode( $response->getResponseBody() );
  104. }
  105. }
  106. /**
  107. * Getting the response code, saved from latest request to Google
  108. *
  109. * @return mixed
  110. */
  111. public function get_http_response_code() {
  112. return $this->http_response_code;
  113. }
  114. /**
  115. * Clears the options and revokes the token
  116. */
  117. public function clear_data() {
  118. $this->revokeToken();
  119. delete_option( $this->option_access_token );
  120. delete_option( $this->option_refresh_token );
  121. }
  122. /**
  123. * Check if user is authenticated
  124. *
  125. * @return bool
  126. */
  127. public function is_authenticated() {
  128. $has_refresh_token = ( $this->get_refresh_token() !== '' );
  129. $access_token_expired = $this->access_token_expired();
  130. return $has_refresh_token && ! $access_token_expired;
  131. }
  132. /**
  133. * Initialize the config, will merge given config with default config to be sure all settings are available
  134. *
  135. * @param array $config
  136. */
  137. protected function init_config( array $config ) {
  138. if ( ! empty( $config['application_name'] ) ) {
  139. $this->setApplicationName( $config['application_name'] );
  140. }
  141. if ( ! empty( $config['client_id'] ) ) {
  142. $this->setClientId( $config['client_id'] );
  143. }
  144. if ( ! empty( $config['client_secret'] ) ) {
  145. $this->setClientSecret( $config['client_secret'] );
  146. }
  147. // Set our settings.
  148. $this->setRedirectUri( $config['redirect_uri'] );
  149. $this->setScopes( $config['scopes'] );
  150. $this->setAccessType( 'offline' );
  151. }
  152. /**
  153. * Refreshing the tokens
  154. */
  155. protected function refresh_tokens() {
  156. if ( ( $refresh_token = $this->get_refresh_token() ) !== '' && $this->access_token_expired() ) {
  157. try {
  158. // Refresh the token.
  159. $this->refreshToken( $refresh_token );
  160. $response = $this->getAuth()->token;
  161. // Check response and if there is an access_token.
  162. if ( ! empty( $response ) && ! empty ( $response['access_token'] ) ) {
  163. $this->save_access_token( $response );
  164. }
  165. }
  166. catch ( Exception $e ) {
  167. return false;
  168. }
  169. }
  170. }
  171. /**
  172. * Save the refresh token
  173. *
  174. * @param string $refresh_token
  175. */
  176. protected function save_refresh_token( $refresh_token ) {
  177. update_option( $this->option_refresh_token, trim( $refresh_token ) );
  178. }
  179. /**
  180. * Return refresh token
  181. *
  182. * @return string
  183. */
  184. protected function get_refresh_token() {
  185. return get_option( $this->option_refresh_token, '' );
  186. }
  187. /**
  188. * Saving the access token as an option for further use till it expires.
  189. *
  190. * @param array $response
  191. */
  192. protected function save_access_token( $response ) {
  193. update_option(
  194. $this->option_access_token,
  195. array(
  196. 'refresh_token' => $this->get_refresh_token(),
  197. 'access_token' => $response['access_token'],
  198. 'expires' => current_time( 'timestamp' ) + $response['expires_in'],
  199. 'expires_in' => $response['expires_in'],
  200. 'created' => $response['created'],
  201. )
  202. );
  203. $this->setAccessToken( json_encode( $response ) );
  204. }
  205. /**
  206. * Check if current access token is expired.
  207. *
  208. * @return bool
  209. */
  210. private function access_token_expired() {
  211. $access_token = $this->get_access_token();
  212. if ( current_time( 'timestamp' ) >= $access_token['expires'] ) {
  213. return true;
  214. }
  215. $this->setAccessToken( json_encode( $access_token ) );
  216. }
  217. /**
  218. * Getting the current access token from the options
  219. *
  220. * @return mixed
  221. */
  222. private function get_access_token() {
  223. return get_option( $this->option_access_token, array( 'access_token' => false, 'expires' => 0 ) );
  224. }
  225. }