I'm trying to get access bigquery api using PHP library, but I always have this error:
Fatal error: Uncaught exception 'Google_Service_Exception' with message 'Error calling GET https://www.googleapis.com/bigquery/v2/projects/primeval-shadow-571/datasets/Test/tables: (401) Login Required' in ...
I have a web application, that needs to get some data from table in bigquery. The Remote account is not mine, but it was created by some guy (and I don't have login and pass to log in), who gave me the .json file which included thoose parameters:
auth_uri,
client_secret,
token_uri,
client_email,
client_x509_cert_url,
client_id and
auth_provider_x509_cert_url.
Here is my php code:
<?php
require_once 'Google/Client.php';
require_once 'Google/Service/Bigquery.php';
$client = new Google_Client();
$client->setAuthConfigFile('google-config.json');
$service = new Google_Service_Bigquery($client);
$service->tables->listTables('primeval-shadow-571', 'Test');
But finally I got error that's above.
Can anybody tell me where am I wrong?
P.S. I just started work with google api two days ago, so I'm just beginning learn it.
Thanks a lot.
Here is a sample code that works for us:
session_start();
define('PROJECT_ID', 'edited');
define('DATASET_ID', 'edited');
define('API_KEY', 'edited');
$client_id = 'edited';
$service_account_name = 'edited';
$key_file_location = '.ssh/privatekey-bigquery.p12';
$service_token_file_location = 'bigquery_current_service_token.json';
set_include_path("google-api-php/src/" . PATH_SEPARATOR . get_include_path());
require_once 'google-api-php/src/Google/Client.php';
require_once 'google-api-php/src/Google/Service/Bigquery.php';
$client = new Google_Client();
$client->setApplicationName("Client_Library_Examples");
//$client->setDeveloperKey(API_KEY);
if (!is_file($service_token_file_location)) {
if (!is_writable($service_token_file_location)) {
#chmod($service_token_file_location, 0777);
if (!is_writable($service_token_file_location)) {
die('Service token file is not writable: ' . $service_token_file_location);
}
}
file_put_contents($service_token_file_location, '');
} else {
if (!is_writable($service_token_file_location)) {
#chmod($service_token_file_location, 0777);
if (!is_writable($service_token_file_location)) {
die('Service token file is not writable: ' . $service_token_file_location);
}
}
}
$service_token = #file_get_contents($service_token_file_location);
if (!empty($service_token)) {
$client->setAccessToken($service_token);
}
if (!file_exists($key_file_location)) {
die('Key file is missing: ' . $key_file_location);
}
$key = file_get_contents($key_file_location);
$cred = new Google_Auth_AssertionCredentials(
$service_account_name, array(
'https://www.googleapis.com/auth/bigquery',
), $key
);
$client->setAssertionCredentials($cred);
if ($client->getAuth()->isAccessTokenExpired()) {
$client->getAuth()->refreshTokenWithAssertion($cred);
}
$service_token = $client->getAccessToken();
file_put_contents($service_token_file_location, $service_token);
// start using $client
Related
I need form PHP level, in background without user interaction login on google drive and get files list. I found similar topic and code for question working, but is required handly login, where I need login from php in background.
In second post with code for possibly login witout user interaction, but I don't know where is bug.
My code PHP:
<?php
require_once 'vendor/autoload.php';
require_once 'src/Google_Client.php';
require_once 'src/contrib/Google_DriveService.php';
require_once 'src/auth/Google_AssertionCredentials.php';
$client_email = 'xxxxxx#xxxxxxxxxxxxx.xxx.gserviceaccount.com';
$private_key = file_get_contents('key.p12');
$user_to_impersonate = 'xxxxxxxxxxxxxxx#gmail.com';
$scopes = array('https://www.googleapis.com/auth/drive');
$credentials = new Google_AssertionCredentials(
$client_email,
$scopes,
$private_key,
'notasecret', // Default P12 password
'http://oauth.net/grant_type/jwt/1.0/bearer', // Default grant type
$user_to_impersonate
);
$client = new Google_Client();
$client->setAssertionCredentials($credentials);
if ($client->getAuth()->isAccessTokenExpired()) {
$client->getAuth()->refreshTokenWithAssertion();
}
$service = new Google_Service_Drive($client);
$files = $service->files->listFiles();
echo "count files=".count($files)."<br>";
foreach( $files as $item ) {
echo "title=".$item['title']."<br>";
}
?>
Vendor directory I get from this instruction, and other files I get from this GitHub
I had problem with function Google_Auth_AssertionCredentials, PHP hasn't file with this function. I found that file src/auth/Google_AssertionCredentials.php has similar function Google_AssertionCredentials. I included Google_AssertionCredentials.php file and changed function name.
In finally I have new error:
PHP Fatal error: Cannot call constructor in
\google_drive\vendor\google\apiclient-services\src\Google\Service\Drive.php
on line 75
I don't know what doing again. I tried many other metod for login on google drive, eg. load file list GET method with API_KEY, or via json file.
As result I want get file list, download them. edit and upload.
Any sugestions?
EDIT:
I have part sucess. I found liblary this, and them work with this code:
<?php
function retrieveAllFiles($service) {
$result = array();
$pageToken = NULL;
do {
try {
$parameters = array();
if ($pageToken) {
$parameters['pageToken'] = $pageToken;
}
$files = $service->files->listFiles($parameters);
$result = array_merge($result, $files->getItems());
$pageToken = $files->getNextPageToken();
} catch (Exception $e) {
print "An error occurred: " . $e->getMessage();
$pageToken = NULL;
}
} while ($pageToken);
return $result;
}
session_start();
require_once '/google-api-php-client/autoload.php';
$client_email = 'xxxx#xxxxx.iam.gserviceaccount.com';
$user_to_impersonate = 'xxxxxx#gmail.com';
$private_key = file_get_contents('key.p12');
$scopes = array('https://www.googleapis.com/auth/drive');
$credentials = new Google_Auth_AssertionCredentials(
$client_email,
$scopes,
$private_key,
'notasecret', // Default P12 password
'http://oauth.net/grant_type/jwt/1.0/bearer',
$user_to_impersonate
);
$client = new Google_Client();
if(isset($_SESSION['service_token'])==false && $_SESSION['service_token']=='') {
$client->setAssertionCredentials($credentials);
if ($client->getAuth()->isAccessTokenExpired()) {
$client->getAuth()->refreshTokenWithAssertion($credentials);
}
$_SESSION['service_token'] = $client->getAccessToken();
}
if(isset($_SESSION['service_token']) && $_SESSION['service_token']) {
$client->setAccessToken($_SESSION['service_token']);
if ($client->isAccessTokenExpired()) {
$client->refreshToken($client->getRefreshToken());
$_SESSION['service_token'] = $client->getAccessToken();
}
$service = new Google_Service_Drive($client);
print_r(retrieveAllFiles($service));
}
?>
And in result I have only one file [originalFilename] => Getting started, this is PDF, but I don't see this file on Gogle dirve. On google drive I uploaded file: README.md.
I'm not sure, but maybe this file is on ` 'xxxx#xxxxx.iam.gserviceaccount.com' and script not logged to 'xxxxxx#gmail.com'?
I'm trying to connect to Gmail but server says:
Uncaught exception 'Google_Service_Exception' with message 'Error calling
GET https://www.googleapis.com/gmail/v1/users/{test}%40gmail.com/messages:
(400) Bad Request' in C:\...\google-api-php-client\src\Google\Http\REST.php on line 110
I can't seem to find the problem. Here's the code:
$google_accounts = $this->getGoogleAccounts();
if (count($google_accounts) > 0) {
require_once $_SERVER['DOCUMENT_ROOT'] . '/include/google-api-php-client/src/Google/autoload.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/include/google-api-php-client/src/Google/Client.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/include/google-api-php-client/src/Google/Service/Gmail.php';
$scopes = array(
'https://mail.google.com',
'https://www.googleapis.com/auth/gmail.readonly',
'https://www.googleapis.com/auth/gmail.modify',
);
$key_file_location = $_SERVER['DOCUMENT_ROOT'] . '/include/google-api-php-client/src/keys/';
foreach ($google_accounts as $one_account) {
if (!empty($one_account->client_id) && !empty($one_account->service_mail) && !empty($one_account->key_file)) {var_dump($one_account);
$key = file_get_contents($key_file_location . $one_account->key_file);
$client = new Google_Client();
$cred = new Google_Auth_AssertionCredentials($one_account->service_mail, $scopes, $key);
$client->setAssertionCredentials($cred);
$client->setClientId($one_account->client_id);
$client->setAccessType('offline_access');
$service = new Google_Service_Gmail($client);
$opt_param = array();
$messagesResponse = $service->users_messages->listUsersMessages($one_account->login, $opt_param);
var_dump($messagesResponse);
}
}
return $list;
}
else {
return false;
}
You need to add:
$cred->sub = $userEmail;
right after creating $cred where $userEmail is the email address of the user you are trying to impersonate. For reference, see the Google Drive Service Account documentation which uses a different scope and API call but is otherwise similar to what you'd want to do with Gmail API.
This question already has answers here:
Bigquery + PHP examples
(4 answers)
Closed 8 years ago.
I am currently trying to develop some sort of a web app and I need it to be able to execute queries on a table that has over ~50,000,000 Rows.
I thought about using Google BigQuery for this matter but I am having problems using their API.
I've searched the whole internet for the past 3 hours and I couldn't find a way to get an authentication and execute a query with PHP only. For authentication I found a way using javascript but that will not be good for me. I need it to be server sided only.
The whole php google api documention seems outdated for me.
Thanks in advanced, Sagi.
Here is a sample code that works for us:
session_start();
define('PROJECT_ID', 'edited');
define('DATASET_ID', 'edited');
define('API_KEY', 'edited');
$client_id = 'edited';
$service_account_name = 'edited';
$key_file_location = '.ssh/privatekey-bigquery.p12';
$service_token_file_location = 'bigquery_current_service_token.json';
set_include_path("google-api-php/src/" . PATH_SEPARATOR . get_include_path());
require_once 'google-api-php/src/Google/Client.php';
require_once 'google-api-php/src/Google/Service/Bigquery.php';
$client = new Google_Client();
$client->setApplicationName("Client_Library_Examples");
//$client->setDeveloperKey(API_KEY);
if (!is_file($service_token_file_location)) {
if (!is_writable($service_token_file_location)) {
#chmod($service_token_file_location, 0777);
if (!is_writable($service_token_file_location)) {
die('Service token file is not writable: ' . $service_token_file_location);
}
}
file_put_contents($service_token_file_location, '');
} else {
if (!is_writable($service_token_file_location)) {
#chmod($service_token_file_location, 0777);
if (!is_writable($service_token_file_location)) {
die('Service token file is not writable: ' . $service_token_file_location);
}
}
}
$service_token = #file_get_contents($service_token_file_location);
if (!empty($service_token)) {
$client->setAccessToken($service_token);
}
if (!file_exists($key_file_location)) {
die('Key file is missing: ' . $key_file_location);
}
$key = file_get_contents($key_file_location);
$cred = new Google_Auth_AssertionCredentials(
$service_account_name, array(
'https://www.googleapis.com/auth/bigquery',
), $key
);
$client->setAssertionCredentials($cred);
if ($client->getAuth()->isAccessTokenExpired()) {
$client->getAuth()->refreshTokenWithAssertion($cred);
}
$service_token = $client->getAccessToken();
file_put_contents($service_token_file_location, $service_token);
// start using $client
I'm getting the following error:
The OAuth 2.0 access token has expired, and a refresh token is not available. Refresh tokens are not returned for responses that were auto-approved
I have a web application which only my server will be accessing, the initial auth works fine, but after an hour, the aforementioned error message pops up. My script looks like this:
require_once 'Google/Client.php';
require_once 'Google/Service/Analytics.php';
session_start();
$client = new Google_Client();
$client->setApplicationName("Client_Library_Examples");
$client->setDeveloperKey("{MY_API_KEY}");
$client->setClientId('{MY_CLIENT_ID}.apps.googleusercontent.com');
$client->setClientSecret('{MY_KEY}');
$client->setRedirectUri('{MY_REDIRECT_URI}');
$client->setScopes(array('https://www.googleapis.com/auth/gmail.readonly'));
if (isset($_GET['code'])) {
$client->authenticate($_GET['code']);
$_SESSION['token'] = $client->getAccessToken();
$redirect = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
header('Location: ' . filter_var($redirect, FILTER_SANITIZE_URL));
}
if (!$client->getAccessToken() && !isset($_SESSION['token'])) {
$authUrl = $client->createAuthUrl();
print "<a class='login' href='$authUrl'>Connect Me!</a>";
}
How can I set up a refresh token for this?
Edit 1: I've tried doing this with a Service account as well. I followed the documentation available on GitHub:
https://github.com/google/google-api-php-client/blob/master/examples/service-account.php
My script looks like this:
session_start();
include_once "templates/base.php";
require_once 'Google/Client.php';
require_once 'Google/Service/Gmail.php';
$client_id = '{MY_CLIENT_ID}.apps.googleusercontent.com';
$service_account_name = '{MY_EMAIL_ADDRESS}#developer.gserviceaccount.com ';
$key_file_location = 'Google/{MY_KEY_FILE}.p12';
echo pageHeader("Service Account Access");
if ($client_id == ''
|| !strlen($service_account_name)
|| !strlen($key_file_location)) {
echo missingServiceAccountDetailsWarning();
}
$client = new Google_Client();
$client->setApplicationName("Client_Library_Examples");
$service = new Google_Service_Gmail($client);
if (isset($_SESSION['service_token'])) {
$client->setAccessToken($_SESSION['service_token']);
}
$key = file_get_contents($key_file_location);
$cred = new Google_Auth_AssertionCredentials(
$service_account_name,
array('https://www.googleapis.com/auth/gmail.readonly'),
$key
);
$client->setAssertionCredentials($cred);
if($client->getAuth()->isAccessTokenExpired()) {
$client->getAuth()->refreshTokenWithAssertion($cred);
}
This returns the following message:
Error refreshing the OAuth2 token, message: '{ "error" : "invalid_grant" }''
After tracking this code to it's source, which can be found in Google/Auth/OAuth2.php
The method in question, refreshTokenRequest:
private function refreshTokenRequest($params)
{
$http = new Google_Http_Request(
self::OAUTH2_TOKEN_URI,
'POST',
array(),
$params
);
$http->disableGzip();
$request = $this->client->getIo()->makeRequest($http);
$code = $request->getResponseHttpCode();
$body = $request->getResponseBody();
if (200 == $code) {
$token = json_decode($body, true);
if ($token == null) {
throw new Google_Auth_Exception("Could not json decode the access token");
}
if (! isset($token['access_token']) || ! isset($token['expires_in'])) {
throw new Google_Auth_Exception("Invalid token format");
}
if (isset($token['id_token'])) {
$this->token['id_token'] = $token['id_token'];
}
$this->token['access_token'] = $token['access_token'];
$this->token['expires_in'] = $token['expires_in'];
$this->token['created'] = time();
} else {
throw new Google_Auth_Exception("Error refreshing the OAuth2 token, message: '$body'", $code);
}
}
Which means that the $code variable is NULL.
I found this post on SO:
Error refreshing the OAuth2 token { “error” : “invalid_grant” }
And can see that there is still no prefered solution. This is driving me nuts. There is very little to no documentation available on this and if anybody has a solution, I'm sure I'm not the only one looking for it.
Each access_token expires after a few seconds and need to be refreshed by refresh_token, "Offline access" is what you are looking for. Here you can follow the documentation:
https://developers.google.com/accounts/docs/OAuth2WebServer#offline
To obtain a refresh_token you have to run this code only one time:
require_once 'Google/Client.php';
$client = new Google_Client();
$client->setClientId('{MY_CLIENT_ID}.apps.googleusercontent.com');
$client->setClientSecret('{MY_KEY}');
$client->setRedirectUri('{MY_REDIRECT_URI}');
//next two line added to obtain refresh_token
$client->setAccessType('offline');
$client->setApprovalPrompt('force');
$client->setScopes(array('https://www.googleapis.com/auth/gmail.readonly'));
if (isset($_GET['code'])) {
$credentials = $client->authenticate($_GET['code']);
/*TODO: Store $credentials somewhere secure */
} else {
$authUrl = $client->createAuthUrl();
print "<a class='login' href='$authUrl'>Connect Me!</a>";
}
$credentials includes an access token and a refresh token. You have to store this to obtain new access tokens at any time. So when you wanted to make a call to api:
require_once 'Google/Client.php';
require_once 'Google/Service/Gmail.php';
/*TODO: get stored $credentials */
$client = new Google_Client();
$client->setClientId('{MY_CLIENT_ID}.apps.googleusercontent.com');
$client->setRedirectUri('{MY_REDIRECT_URI}');
$client->setClientSecret('{MY_KEY}');
$client->setScopes(array('https://www.googleapis.com/auth/gmail.readonly'));
$client->setAccessToken($credentials);
$service = new Google_Service_Gmail($client);
how to retrieve a all users from a Google apps doamin . I have tried with the following coed but google return error like "Error calling GET https://www.googleapis.com/admin/directory/v1/users?domain=domainname.com: (401) Login Required "
set_include_path(get_include_path() . PATH_SEPARATOR . 'E:\wamp\www\Google APIs\google-api-php-client\src');
ini_set("memory_limit", -1);
require_once 'google-api-php-client/src/Google/Client.php';
require_once 'google-api-php-client/src/Google/Service/Drive.php';
require_once 'google-api-php-client/src/Google/Service/Oauth2.php';
require_once 'google-api-php-client/src/Google/Service/Directory.php';
$client = new Google_Client();
$client->setApplicationName("Google+ PHP Starter Application");
$client->setClientId('42X74XXXXXercontent.com');
$client->setClientSecret('OxzVALdXwd');
$client->setRedirectUri('http://localhost/Google%20APIs/index.php');
$client->setAccessType("offline");
$client->setApprovalPrompt("force");
$client->setDeveloperKey("AIXXXXXJDUdX48");
$SCOPES = array(
'https://www.googleapis.com/auth/admin.directory.user',
'https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/userinfo.profile');
$client->setScopes($SCOPES);
$token = '{"access_token":"ya29.1.AAXXXaeTg","token_type":"Bearer","expires_in":3600,"id_token":"eyJhbXXXXXXX9cEjDMUMe6PVrgo","refresh_token":"1\/sN-XXXXX5qdIGMeEW95tJv-0a1ujWk","created":1397878356}';
$decoded = json_decode($token);
$client->setAccessToken($token);
if ($client->isAccessTokenExpired()) {
$client->refreshToken($decoded->refresh_token);
}
$adminsdk = new Google_Service_Directory($client);
$users_list = $adminsdk->users->listUsers(array('domain'='domainon.info'));
Note : I have Perform a authorization with
$SCOPES = array(
'https://www.googleapis.com/auth/admin.directory.user',
'https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/userinfo.profile');
Please help me
You say you're performing the authorization for those scopes, but those scopes aren't included in the client. Make sure you include this code before you run $client->refreshToken():
$client->setScopes($SCOPES);