[php]google-api-php-clientでCould not json decode the access tokenというエラーが出た
phpで google-api-php-client を用いて、 GoogleAnalytics からアクセス数の多いページを取得する処理を書いていたのですが、proxy環境下だと
Could not json decode the access token
とエラーになってしまう現象が発生しました。
調べてみたところ
GoogleAnalyticsAPIを使ってみる(PHP編)
こちらの記事に、
Jsonフォーマットの戻り値の頭に、レスポンスヘッダが付いてしまう場合があるみたい。(これがエラーになったり、ならなかったりで発生条件が掴めない。。)
とあり、同じ現象が発生している模様。
proxy設定自体は 以下のようにライブラリを利用するアプリケーション側でcurlのproxy設定オプションを渡すことができます。
$client = new Google_Client();
# proxy setting
$client::$io->setOptions(array(
CURLOPT_PROXY => 'proxy',
CURLOPT_PROXYPORT => 8080
));
しかし、今回のエラー修正にはライブラリに修正を加える必要がありました。
参考記事にあったように HTTP通信結果を取得した際に、不要な情報が付与されている場合は省くようにしました。
# google-api-php-client/src/auth/Google_OAuth2.php
public function setAccessToken($token) {
$position = strpos($token, '{'); # 追加
$body = substr($token, $position); # 追加
$token = json_decode($token, true);
if ($token == null) {
throw new Google_AuthException('Could not json decode the token');
}
if (! isset($token['access_token'])) {
throw new Google_AuthException("Invalid token format");
}
$this->token = $token;
}
・・・・
private function refreshTokenRequest($params) {
$http = new Google_HttpRequest(self::OAUTH2_TOKEN_URI, 'POST', array(), $params);
$request = Google_Client::$io->makeRequest($http);
$code = $request->getResponseHttpCode();
$body = $request->getResponseBody();
if (200 == $code) {
$position = strpos($body, '{'); # 追加
$body = substr($body, $position); # 追加
$token = json_decode($body, true);
if ($token == null) {
throw new Google_AuthException("Could not json decode the access token");
}
・・・・・
# google-api-php-client/src/io/Google_REST.php
public static function decodeHttpResponse($response) {
$code = $response->getResponseHttpCode();
$body = $response->getResponseBody();
$decoded = null;
if ((intVal($code)) >= 300) {
$decoded = json_decode($body, true);
$err = 'Error calling ' . $response->getRequestMethod() . ' ' . $response->getUrl();
if ($decoded != null && isset($decoded['error']['message']) && isset($decoded['error']['code'])) {
// if we're getting a json encoded error definition, use that instead of the raw response
// body for improved readability
$err .= ": ({$decoded['error']['code']}) {$decoded['error']['message']}";
} else {
$err .= ": ($code) $body";
}
throw new Google_ServiceException($err, $code, null, $decoded['error']['errors']);
}
// Only attempt to decode the response, if the response code wasn't (204) 'no content'
if ($code != '204') {
$position = strpos($body, '{'); # 追加
$body = substr($body, $position); # 追加
$decoded = json_decode($body, true);
if ($decoded === null || $decoded === "") {
throw new Google_ServiceException("Invalid json in service response: $body");
}
}
return $decoded;
}
これにだいぶはまりました。。。