我有谷歌api-php-client,但我无法登录,因为我总是收到错误:
[02-Nov-2017 15:30:52 Europe/Helsinki] ***START***
scripto\CustomException: [0: E_CUSTOM: Suppressed or Custom error] cURL error 6: Could not resolve host: www.googleapis.com (see http://curl.haxx.se/libcurl/c/libcurl-errors.html).
in /home/suexec-test/server/GuzzleHttp/Handler/CurlFactory.php on line 186
[Trace]:
#0 /home/suexec-test/server/ExceptionFactory.php(117): scripto\CustomException::buildFromException(Object(GuzzleHttp\Exception\ConnectException))
#1 [internal function]: scripto\ExceptionFactory::exception_handler(Object(GuzzleHttp\Exception\ConnectException))
#2 {main}
[Previous]:
scripto\CustomException: [0: E_CUSTOM: Suppressed or Custom error] cURL error 6: Could not resolve host: www.googleapis.com (see http://curl.haxx.se/libcurl/c/libcurl-errors.html).
in /home/suexec-test/server/GuzzleHttp/Handler/CurlFactory.php on line 186
[Trace]:
#0 /home/suexec-test/server/GuzzleHttp/Handler/CurlFactory.php(150): GuzzleHttp\Handler\CurlFactory::createRejection(Object(GuzzleHttp\Handler\EasyHandle), Array)
#1 /home/suexec-test/server/GuzzleHttp/Handler/CurlFactory.php(103): GuzzleHttp\Handler\CurlFactory::finishError(Object(GuzzleHttp\Handler\CurlHandler), Object(GuzzleHttp\Handler\EasyHandle), Object(GuzzleHttp\Handler\CurlFactory))
#2 /home/suexec-test/server/GuzzleHttp/Handler/CurlHandler.php(43): GuzzleHttp\Handler\CurlFactory::finish(Object(GuzzleHttp\Handler\CurlHandler), Object(GuzzleHttp\Handler\EasyHandle), Object(GuzzleHttp\Handler\CurlFactory))
#3 /home/suexec-test/server/GuzzleHttp/Handler/Proxy.php(28): GuzzleHttp\Handler\CurlHandler->__invoke(Object(GuzzleHttp\Psr7\Request), Array)
#4 /home/suexec-test/server/GuzzleHttp/Handler/Proxy.php(51): GuzzleHttp\Handler\Proxy::GuzzleHttp\Handler\{closure}(Object(GuzzleHttp\Psr7\Request), Array)
#5 /home/suexec-test/server/GuzzleHttp/PrepareBodyMiddleware.php(66): GuzzleHttp\Handler\Proxy::GuzzleHttp\Handler\{closure}(Object(GuzzleHttp\Psr7\Request), Array)
#6 /home/suexec-test/server/GuzzleHttp/Middleware.php(30): GuzzleHttp\PrepareBodyMiddleware->__invoke(Object(GuzzleHttp\Psr7\Request), Array)
#7 /home/suexec-test/server/GuzzleHttp/RedirectMiddleware.php(70): GuzzleHttp\Middleware::GuzzleHttp\{closure}(Object(GuzzleHttp\Psr7\Request), Array)
#8 /home/suexec-test/server/GuzzleHttp/Middleware.php(57): GuzzleHttp\RedirectMiddleware->__invoke(Object(GuzzleHttp\Psr7\Request), Array)
#9 /home/suexec-test/server/GuzzleHttp/HandlerStack.php(67): GuzzleHttp\Middleware::GuzzleHttp\{closure}(Object(GuzzleHttp\Psr7\Request), Array)
#10 /home/suexec-test/server/GuzzleHttp/Client.php(281): GuzzleHttp\HandlerStack->__invoke(Object(GuzzleHttp\Psr7\Request), Array)
#11 /home/suexec-test/server/GuzzleHttp/Client.php(103): GuzzleHttp\Client->transfer(Object(GuzzleHttp\Psr7\Request), Array)
#12 /home/suexec-test/server/GuzzleHttp/Client.php(110): GuzzleHttp\Client->sendAsync(Object(GuzzleHttp\Psr7\Request), Array)
#13 /home/suexec-test/server/Google/Auth/HttpHandler/Guzzle6HttpHandler.php(34): GuzzleHttp\Client->send(Object(GuzzleHttp\Psr7\Request), Array)
#14 /home/suexec-test/server/Google/Auth/OAuth2.php(501): Google\Auth\HttpHandler\Guzzle6HttpHandler->__invoke(Object(GuzzleHttp\Psr7\Request))
#15 /home/suexec-test/server/Google/Google_Client.php(195): Google\Auth\OAuth2->fetchAuthToken(Object(Google\Auth\HttpHandler\Guzzle6HttpHandler))
#16 /home/suexec-test/server/Google/Google_Client.php(174): Google_Client->fetchAccessTokenWithAuthCode('4/4BhYCtvi43DGf...')
#17 /home/suexec-test/tests/testGoogle-4.php(56): Google_Client->authenticate('4/4BhYCtvi43DGf...')
#18 /home/suexec-test/server/Dispatcher.php(96): require_once('/home/suexec-te...')
#19 /home/suexec-test/server/Controller.php(68): scripto\Dispatcher->run()
#20 /home/suexec-test/public_html/index.php(7): scripto\Controller->run()
#21 {main}
***END***
我创建了一个网络应用程序,
问题是,即使加载了所有类,我的代码也无法通过
$client->authenticate($_GET['code']);
。
我为您准备了一个测试文件:在
http://localhost/auth/google/login
和 http://localhost/auth/google/logout
您应该调用同一个文件来观察抛出的错误。
测试文件是对this帖子的修改:
<?php
if (\session_status() != PHP_SESSION_ACTIVE) {
Session_start();
}
$whoami = $_SERVER['REQUEST_URI'];
$login = $logout = false;
if (\strpos($whoami, '/login') !== false)
$login = true;
if (\strpos($whoami, '/logout') !== false)
$logout = true;
/*
* Configuration and setup Google SDK
*/
$appId = '519650546062-XXXXXX.apps.googleusercontent.com';
$appSecret = 'XXXXXXX';
// CALLED BY US & GOOGLE!
$loginUri = 'http://localhost/auth/google/login';
// CALLED BY US!
$logoutUri = 'http://localhost/auth/google/logout';
$access = 'online';
$scopes = "openid profile email";
$incremental_scopes = false; // what if for true?
//$state = 123;
//Create Google Client
$client = new Google_Client();
$client->setApplicationName("PHP Google OAuth Login Example");
$client->setClientId($appId);
$client->setClientSecret($appSecret);
$client->setRedirectUri($loginUri);
$client->setAccessType($access);
$client->setIncludeGrantedScopes($incremental_scopes);
$client->addScope($scopes);
//$client->setState($state);
//Send Client Request?
$objOAuthService = new Google_Service_Oauth2($client);
//CALLED BY US
if ($logout) {
unset($_SESSION['access_token']);
$client->revokeToken();
// Back to login!
header('Location: ' . filter_var($loginUri, FILTER_SANITIZE_URL));
}
//CALLED BY GOOGLE
if (isset($_GET['code'])) {
error_log('1....I\'M GOING TO BREAK...');
$client->authenticate($_GET['code']);
$_SESSION['access_token'] = $client->getAccessToken();
// Back to this file!
header('Location: ' . filter_var($loginUri, FILTER_SANITIZE_URL));
}
//CALLED BY US 2ND TIME (after previous header)
if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
error_log('2....session access token='.$_SESSION['access_token']);
$client->setAccessToken($_SESSION['access_token']);
}
//ONLY DURING 2ND CALL (from previous if...)
if ($client->getAccessToken()) {
$userData = $objOAuthService->userinfo->get();
if(!empty($userData)) {
// do sth with data!
}
$_SESSION['access_token'] = $client->getAccessToken();
error_log('3.....user data:'.print_r($userData, true));
} else {
$authUrl = $client->createAuthUrl();
}
$out = <<<EOT
<html>
<head>
<title>Google OAuth v.2.0 Login test</title>
</head>
<body>
EOT;
if (isset($authUrl)) {
$d = \urldecode($authUrl);
$out .= <<<EOT
<p>decoded authUrl = '{$d}'</p>
EOT;
}
$out .= <<<EOT
<h2>PHP Google OAuth 2.0 Login</h2>
EOT;
if (isset($authUrl)) {
$out .= <<<EOT
<p><a href='{$authUrl}'>Login with Google API</a></p>
EOT;
} else {
$out .= <<<EOT
<p>Welcome <a href="{$userData['link']}">{$userData['name']}</a>.</p>
<p>Your email: {$userData['email']}</p>
<p><a href={$logoutUri}>Logout</a></p>
EOT;
}
$e = \nl2br(\htmlspecialchars(\print_r($_SESSION, true)));
$out .= <<<EOT
<p><h3>SESSION:</h3></p>
<p>{$e}</p>
</body>
</html>
EOT;
echo $out;
代码在
error_log('1....I\'M GOING TO BREAK...');
之后就中断了。
有趣的是,我设法用 curl 绕过了 whole 库并获得了以下形式的访问令牌:
[02-Nov-2017 14:06:38 Europe/Helsinki] Array
(
[access_token] => ya29.Glv3B...xlSKIL_N67PE4...PYGDjZo-jD8v...ITFTnU
[expires_in] => 2017-11-02 15:06:37
[id_token] => eyJhbGciOiJImt...tlf_-Y1hXoCVSp...Ve_bK8F-jTCt...zg
[token_type] => Bearer
)
但是我找不到端点来获取用户的数据:像这样的东西[偶尔]会中断[我统计了多达90%的失败]
public function userinfo() {
$access_token = $this->access['access_token'];
$url = 'https://www.googleapis.com/plus/v1/people/me';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Authorization: Bearer '. $access_token));
$data = json_decode(curl_exec($ch), true);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($http_code != 200)
throw new \ErrorException(__CLASS__ . "::userinfo() is called but failed to get user information!", 0, 1);
$this->data = $data;
}
感谢这个优秀的帖子。
知道官方 php 库有什么问题吗? 我在控制台中缺少什么吗?
谢谢你。
经过一番查找,
如谷歌文档所说:
也可在OpenId:
本文档描述了我们的 OAuth 2.0 实现 身份验证,符合 OpenID Connect 规范, 并获得 OpenID 认证。使用 OAuth 2.0 中找到的文档 访问 Google API 也适用于此服务。
因此,我将所有库发送到我的回收站,并使用 REST 和 cURL 来发出服务器请求。 让我们定义一个类
GoogleToken
,其中包含与我们对 Google 服务器的请求相关的属性,例如 url、客户端 ID、客户端密钥等:
<?php
namespace test;
/**
* Google authentication Config class
*/
class GoogleToken {
/** See the list: https://developers.google.com/identity/protocols/OAuth2WebServer#creatingclient */
/** the application/client id */
const appId = '';
/** the application/client secret */
const appSecret = '';
/** the application/client redirect uri after login */
const loginUri = 'http://localhost/auth/google/login';
/** the application/client redirect uri after logout */
const logoutUri = 'http://localhost/auth/google/logout';
/** use 'online' to get the access token!
* use 'offline' to get a refresh token along with the access token,
* see also 'prompt'!
*/
const access = 'offline';
/** the application/client approval prompt [auto|force]
* use 'force' to get a refresh token!
*/
const prompt = 'force';
/** the application/client access permissions
* [openid profile email|see https://developers.google.com/identity/protocols/googlescopes]
*/
const scopes = 'openid profile email';
public function __construct() {}
}
上面的类应该被视为一个编程令牌,帮助其他类实现他们的目标(也许这是一个新的范例,你可以评估它)。实际上,它是一个更复杂的类,可以通过数据 IO 方法来满足我们的目的,方便用户管理而无需接触 php 文件等。
让我们构建一个类,向 Google 服务器发出请求并存储(临时)响应,即 Google 发送的实际令牌:
该类的骨架:
public function authenticate($code)
public function verify($access_token)
public function validate($verify_token, $user)
public function refresh($refresh_token)
public function revokeToken($access_token)
public function userInfo($access_token)
public function createAuthUrl()
所有方法都接受参数,因为重定向时内部存储的内容会丢失,这就是我们需要存储机制来提供这些参数的原因。 文件
test.php
提供了存储类属性并在需要时调用它们的顶层。
有趣的是方法authenticate()
应该按顺序进行:
验证请求
用户信息请求
而不是相反,否则您将遇到来自 Google 的延迟/错误。 班级
GoogleHttpClient
:
<?php
namespace test;
/**
* The GoogleHttpClient is a helper class.
*
* As this class is called between different calls, it needs access to a state
* storage mechanism like sessions.
* Even though the methods try to abstract away the complexity of the calls by
* a logical organisation of the actions involved, you are responsible for the
* order or context under which they are called.
*/
class GoogleHttpClient {
/** @var GoogleToken $token The GoogleToken class object */
protected $token;
/**
* @var string[] $auth The authorization data returned by Google in the form:
* Array(
* [access_token] => xxx
* [expires_in] => [unix timestamp]
* [id_token] => xxx.xxx.xxx
* [refresh_token] => xxx
* [token_type] => Bearer
* )
*
* This property should be stored in session (per user) in case we need a
* verification or refresh.
*/
protected $auth;
/**
* @var string[] $verify The response data returned by Google in the form:
* Array(
* [issued_to] => xxx.apps.googleusercontent.com (@see GoogleToken['values']['appId'])
* [audience] => xxx.apps.googleusercontent.com (@see GoogleToken['values']['appId'])
* [user_id] => xxx
* [scope] => xxx (@see createAuthUrl())
* [expires_in] => xxx (<= 3600)
* [email] => xxx
* [verified_email] => 1
* [access_type] => xxx (@see createAuthUrl())
* )
*
* You shouldn't store this property in session.
*/
protected $verify;
/**
* @var string[] $user The user data returned by Google.
*
* You should verify this property with your native authorization system and
* integrate with it finally.
*/
protected $user;
/** @var string[] $error The error returned by Google */
protected $error;
/**
* @var boolean $log If you should log errors and assigned properties for debuging
*/
protected $log;
const INVALID_TOKEN = 1;
/**
* Constructor.
*
* preconditions: a GoogleToken should be passed.
*
* postconditions:
*
* @param GoogleToken $token The GoogleToken that contains initialization values
* @param boolean $log True, if we want to log errors and assigned properties
*
* @return GoogleHttpClient A GoogleHttpClient object
*/
public function __construct(GoogleToken $token, $log = false) {
$this->token = $token;
$this->log = $log;
}
/**
* It makes a authentication request to Google.
*
* preconditions: after the call to Google at this link, @see createAuthUrl(),
* Google responds by making a call back with a unique id that should be
* passed as argument.
*
* postconditions: it sets properties $auth, $user, $verify and $error.
* On error, $auth, $verify and $error contain the responses returned by
* Google depending at the method where error appeared, @see verify(), @see validate().
* If the authentication succeeds then, $error is null.
*
* @param string $code A unique request id issued by Google
*
* @return boolean True on success
*/
public function authenticate($code) {
$client_id = $this->token::appId;
$client_secret = $this->token::appSecret;
$redirect_uri = $this->token::loginUri;
$url = 'https://accounts.google.com/o/oauth2/token';
$curlPost = 'client_id=' . $client_id . '&client_secret=' . $client_secret . '&redirect_uri=' . $redirect_uri . '&code='. $code . '&grant_type=authorization_code';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $curlPost);
$data = json_decode(curl_exec($ch), true);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($http_code != 200) {
if ($this->log)
error_log(__CLASS__ . '::authenticate() error: http code not 200. Responded: '.print_r($data, true));
$this->error = $data;
} else {
if ($this->log)
error_log(__CLASS__ . '::auth='.print_r($data, true));
$this->verify($data['access_token']);
$this->user = $this->userInfo($data['access_token']);
$this->validate($this->verify, $this->user);
}
$this->auth = $data;
if ($this->error)
return false;
else
return true;
}
/**
* It requests for a verification token from Google.
*
* preconditions: it is called from @see authenticate().
* Calling this method from redirects means all properties are null and we
* pass session data.
*
* postconditions: it sets property $verify.
* On error, $verify and $error contain the responses returned by Google.
* If the request succeeds then, $error is null.
*
* @param string $access_token Google's authorization response under key 'access_token'
*
* @return boolean True on success
*/
public function verify($access_token) {
$client_id = $this->token::appId;
$client_secret = $this->token::appSecret;
$url = 'https://www.googleapis.com/oauth2/v2/tokeninfo';
$curlPost = 'access_token='. $access_token;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $curlPost);
$data = json_decode(curl_exec($ch), true);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($http_code != 200) {
if ($this->log)
error_log(__CLASS__ . '::verify() error: http code not 200. Responded: '.print_r($data, true));
$this->error = $data;
} else {
if ($this->log)
error_log(__CLASS__ . '::verify='.print_r($data, true));
}
$this->verify = $data;
if ($this->error)
return false;
else
return true;
}
/**
* It compares properties $verify with $user and GoogleToken.
*
* preconditions: it is called from @see authenticate().
* Calling this method from redirects means all properties are null and we
* pass session data.
*
* postconditions: on failed validation, $error contains a custom error with fields:
* -error_id: a number
* -error_description: a message.
* If the verification succeeds then, $error is null.
*
* @param string[] $verify_token Google's verification response token
* @param string $user Google's user info response
*
* @return boolean True on success
*/
public function validate($verify_token, $user) {
if (($verify_token['user_id'] != $user['id']) || ($verify_token['email'] != $user['email']) || ($verify_token['issued_to'] != $this->token::appId)) {
$this->error = array('error_id' => self::INVALID_TOKEN, 'error_description' => 'Access token does not pass validation!');
if ($this->log)
error_log(__CLASS__ . '::error='.print_r($this->error, true));
}
if ($this->error)
return false;
else
return true;
}
/**
* It is called when property $auth has expired.
*
* preconditions: authentication has been run, @see authenticate().
* Calling this method from redirects means all properties are null and we
* pass session data.
*
* postconditions: it re-sets property $auth.
* On error, $auth and $error contain the responses returned by Google.
* If the refresh succeeds then, $error is null.
*
* @param string $refresh_token Google's authorization response under key 'refresh_token'
*
* @return boolean True on success
*/
public function refresh($refresh_token) {
$client_id = $this->token::appId;
$client_secret = $this->token::appSecret;
$url = 'https://accounts.google.com/o/oauth2/token';
$curlPost = 'client_id=' . $client_id . '&client_secret=' . $client_secret . '&refresh_token='. $refresh_token . '&grant_type=refresh_token';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $curlPost);
$data = json_decode(curl_exec($ch), true);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($http_code != 200) {
if ($this->log)
error_log(__CLASS__ . '::refresh() error: http code not 200. Responded: '.print_r($data, true));
$this->error = $data;
} else {
if ($this->log)
error_log(__CLASS__ . '::auth='.print_r($data, true));
}
$this->auth = $data;
if ($this->error)
return false;
else
return true;
}
/**
* It un-registers application from user's account but id does not (and cannot)
* logout user from Google.
*
* preconditions: authentication has been run, @see authenticate().
* Calling this method from redirects means all properties are null and we
* pass session data.
*
* postconditions: it un-registers application from user's account.
* On error, $error contains the response returned by Google.
* If the revoke succeeds then, all properties are nullified.
*
* @param string $access_token Google's authorization response under key 'access_token'
*
* @return boolean True on success
*/
public function revokeToken($access_token) {
$client_id = $this->token::appId;
$client_secret = $this->token::appSecret;
$url = 'https://accounts.google.com/o/oauth2/revoke';
$curlPost = 'token=' . $access_token;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $curlPost);
$data = json_decode(curl_exec($ch), true);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($http_code != 200) {
if ($this->log)
error_log(__CLASS__ . '::revokeToken() error: http code not 200. Responded: '.print_r($data, true));
$this->error = $data;
} else {
$this->auth = null;
$this->user = null;
$this->verify = null;
$this->error = null;
if ($this->log)
error_log(__CLASS__ . '::revokeToken() run and erased all properties!');
}
if ($this->error)
return false;
else
return true;
}
/**
* It is called from @see authenticate() or you can call it independently at
* a later time.
*
* preconditions: authentication has been run, @see authenticate().
* Calling this method from redirects means all properties are null and we
* pass session data.
*
* postconditions: it sets property $user.
* On error, $user and $error contain the responses returned by Google.
* If the request succeeds then, $error is null.
*
* @param string $access_token Google's authorization response under key 'access_token'
*
* @return string[] A hash array of user's data
*/
public function userInfo($access_token) {
/** format of data:
* Array(
* [id] => xxx
* [email] => [email protected]
* [verified_email] => 1
* [name] => xxx xxx
* [given_name] => xxx
* [family_name] => xxx
* [picture] => https://lh6.googleusercontent.com/.../photo.jpg?sz=50
* [locale] => en
* )
*/
$url = 'https://www.googleapis.com/userinfo/v2/me';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Authorization: Bearer '. $access_token));
$data = json_decode(curl_exec($ch), true);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($http_code != 200) {
if ($this->log)
error_log(__CLASS__ . '::userInfo() error: http code not 200. Responded: '.print_r($data, true));
$this->error = $data;
} else {
if ($this->log)
error_log(__CLASS__ . '::user='.print_r($data, true));
}
$this->user = $data;
return $this->user;
}
/**
* Creates a authentication link to Google servers.
*/
public function createAuthUrl() {
$scopes = \urlencode($this->token::scopes);
$redirect = \urlencode($this->token::loginUri);
$appId = $this->token::appId;
$access = $this->token::access;
$prompt = $this->token::prompt;
return "https://accounts.google.com/o/oauth2/auth?scope={$scopes}&redirect_uri={$redirect}&response_type=code&client_id={$appId}&access_type={$access}&approval_prompt={$prompt}";
}
/**
* Returns property $token
*/
public function getToken() {
return $this->token;
}
/**
* Returns property $auth
*/
public function getAuthToken() {
return $this->auth;
}
/**
* Returns property $verify
*/
public function getVerifyToken() {
return $this->verify;
}
/**
* Returns property $user
*/
public function getUser() {
return $this->user;
}
/**
* Returns property $error
*/
public function getError() {
return $this->error;
}
}
现在我们可以调用 Google 并制作一个登录应用程序:
<?php
namespace test;
require_once __DIR__ . '/GoogleToken.php';
require_once __DIR__ . '/GoogleHttpClient.php';
if (\session_status() != PHP_SESSION_ACTIVE) {
session_start();
}
$whoami = $_SERVER['REQUEST_URI'];
$login = $logout = false;
if (\strpos($whoami, '/login') !== false)
$login = true;
if (\strpos($whoami, '/logout') !== false)
$logout = true;
$token = new GoogleToken();
$client = new GoogleHttpClient($token, true); // enable log
$loginUri = GoogleToken::loginUri;
$logoutUri = GoogleToken::logoutUri;
/* emulates...
* LOGIN endpoint
* --------------
*/
if ($login) {
if (isset($_GET['code'])) {
if ($client->authenticate($_GET['code']) {
$_SESSION['google']['auth'] = $auth;
$_SESSION['google']['auth']['expires_in'] = \date("Y-m-d H:i:s", \time() + $_SESSION['google']['auth']['expires_in']);
$_SESSION['google']['user'] = $user;
}
}
header('Location: ' . filter_var('http://localhost', FILTER_SANITIZE_URL));
}
/* emulates...
* LOGOUT endpoint
* ---------------
*/
if ($logout) {
$client->revokeToken($_SESSION['google']['auth']['access_token']);
unset($_SESSION['google']);
header('Location: ' . filter_var('http://localhost', FILTER_SANITIZE_URL));
}
$userData = '';
/* emulates...
* Redirect from:
* --------------
* - LOGIN endpoint
*/
if (isset($_SESSION['google'])) {
if(\time() > \strtotime($_SESSION['google']['auth']['expires_in'])) {
if(!$client->refresh($_SESSION['google']['auth']['access_token'])) {
$client->revokeToken();
unset($_SESSION['google']);
header('Location: ' . filter_var('http://localhost', FILTER_SANITIZE_URL));
}
}
$userData = $_SESSION['google']['user'];
/* emulates...
* INITIAL endpoint
* ----------------
* or,
* Redirect from:
* --------------
* - LOGOUT endpoint or,
* - failed REFRESH
*/
} else {
$authUrl = $client->createAuthUrl();
}
$out0 = <<<EOT
<html>
<head>
<title>Google REST OAuth v.2.0 Login test</title>
</head>
<body>
EOT;
if (isset($authUrl)) {
$d = \urldecode($authUrl);
$out0 .= <<<EOT
<p>decoded authUrl = '{$d}'</p>
EOT;
}
$out0 .= <<<EOT
<h2>PHP Google OAuth 2.0 Login</h2>
EOT;
if (isset($authUrl)) {
$out0 .= <<<EOT
<p><a href="{$authUrl}">Login with Google API</a></p>
EOT;
} else {
$out0 .= <<<EOT
<p>Welcome <img src="{$userData['picture']}" style="width:50px;height:50px;"></img> {$userData['name']}.</p>
<p>Your email: {$userData['email']}</p>
<p><a href={$logoutUri}>Logout</a></p>
EOT;
}
$e = \nl2br(\htmlspecialchars(\print_r($_SESSION, true)));
$out0 .= <<<EOT
<p><h3>SESSION:</h3></p>
<p>{$e}</p>
</body>
</html>
EOT;
echo $out0;
正如我们所见,类
GoogleHttpClient
完成了所有工作,但文件 test.php
实际上应该被替换为在 GoogleHttpClient
之上处理端点/请求的另一层。
玩得开心!