I am doing a very basic test of Gmail API using PHP. I am using the code supplied by Google (after a successful authorization via OAuth followed by a successful -- code 200 -- test run on the API workbench. My error is:
PHP Fatal error: Call to a member function listUsersMessages() on null
The line that fails:
$messagesResponse = $service->users_messages->listUsersMessages($userId, $opt_param);
The full Code:
$userId = 'my gmail id';
$service = 'my api client id, for example,12356686375';
$messages = listMessages($service,$userId);
/**
* Get list of Messages in user's mailbox.
*
* #param Google_Service_Gmail $service Authorized Gmail API instance.
* #param string $userId User's email address. The special value 'me'
* can be used to indicate the authenticated user.
* #return array Array of Messages.
*/
function listMessages($service, $userId) {
$pageToken = NULL;
$messages = array();
$opt_param = array();
do {
try {
if ($pageToken) {
$opt_param['pageToken'] = $pageToken;
}
$messagesResponse = $service->users_messages->listUsersMessages($userId, $opt_param);
if ($messagesResponse->getMessages()) {
$messages = array_merge($messages, $messagesResponse->getMessages());
$pageToken = $messagesResponse->getNextPageToken();
}
} catch (Exception $e) {
print 'An error occurred: ' . $e->getMessage();
}
} while ($pageToken);
foreach ($messages as $message) {
print 'Message with ID: ' . $message->getId() . '<br/>';
}
return $messages;
}
As mentioned by #Morfinismo, $service variable should have the Gmail service initialized and not the client id.
It should be:
// Get the API client and construct the service object.
$client = getClient();
$service = new Google_Service_Gmail($client);
You may follow this quickstart.
Related
I would want to have one script in order to forward one selected message. When I execute my script, I have the next error:
An error occurred: {
"error": {
"errors": [
{
"domain": "global",
"reason": "invalidArgument",
"message": "'raw' RFC822 payload message string or uploading message via /upload/* URL required"
}
],
"code": 400,
"message": "'raw' RFC822 payload message string or uploading message via /upload/* URL required"
}
}
I use this script:
<pre>
require __DIR__ . '/vendor/autoload.php';
if (php_sapi_name() != 'cli') {
throw new Exception('This application must be run on the command line.');
}
/**
* Send Message.
*
* #param Google_Service_Gmail $service Authorized Gmail API instance.
* #param string $userId User's email address. The special value 'me'
* can be used to indicate the authenticated user.
* #param Google_Service_Gmail_Message $message Message to send.
* #return Google_Service_Gmail_Message sent Message.
*/
function sendMessage($service, $userId, $message) {
try {
$message = $service->users_messages->send($userId, $message);
print 'Message with ID: ' . $message->getId() . ' sent.';
return $message;
} catch (Exception $e) {
print 'An error occurred: ' . $e->getMessage();
}
}
//MAIN
// Get the API client and construct the service object.
$client = getClient();
$service = new Google_Service_Gmail($client);
$user = 'me';
// Get the messages in the user's account.
$messages = listMessages($service, $user, [
'maxResults' => 20, // Return 20 messages.
'labelIds' => 'INBOX', // Return messages in inbox.
'q' => 'From:xxx#yyy.zzz'
]);
$email_forward = 'email_to_forward#gmail.com';
foreach ($messages as $message) {
print 'Message with ID: ' . $message->getId() . "|";
sendMessage($service, 'me', $message);
}
</pre>
It's one message with only text, without any attachment. Anyone can help me, please?
Thanks.
I have followed https://developers.google.com/drive/api/v2/reference/files/list, successful! I got it all. But not my 'drive'. I received a warning 'You need to be granted access here. So what should I do to fix the above error?
I created a new project, Service account keys and OAuth 2.0 client IDs. but it's bad it doesn't properly link to my 'google drive' account
This is my whole code
<?php
session_start ();
require_once 'google-api-php-client/src/Google_Client.php';
require_once 'google-api-php-client/src/contrib/Google_DriveService.php';
require_once 'google-api-php-client/src/contrib/Google_Oauth2Service.php';
require_once 'vendor/autoload.php';
$DRIVE_SCOPE = 'https://www.googleapis.com/auth/drive';
$SERVICE_ACCOUNT_EMAIL = 'xxx#phim-240702.iam.gserviceaccount.com';
$SERVICE_ACCOUNT_PKCS12_FILE_PATH = 'phim-240702-a98343eb742a.p12';
function buildService(){
global $DRIVE_SCOPE, $SERVICE_ACCOUNT_EMAIL, $SERVICE_ACCOUNT_PKCS12_FILE_PATH;
$key = file_get_contents($SERVICE_ACCOUNT_PKCS12_FILE_PATH);
$auth = new Google_AssertionCredentials(
$SERVICE_ACCOUNT_EMAIL,
array($DRIVE_SCOPE),
$key);
$client = new Google_Client();
$client->setApplicationName("googletest5");
$client->setDeveloperKey("b2016fa55e916faf35337ccb1db830ecdb590cc3");
$client->setUseObjects(true);
$client->setAssertionCredentials($auth);
return new Google_DriveService($client);
}
/**
* Insert new file.
*
* #param Google_Service_Drive $service Drive API service instance.
* #param string $title Title of the file to insert, including the extension.
* #param string $description Description of the file to insert.
* #param string $parentId Parent folder's ID.
* #param string $mimeType MIME type of the file to insert.
* #param string $filename Filename of the file to insert.
* #return Google_Service_Drive_DriveFile The file that was inserted. NULL is
* returned if an API error occurred.
*/
function insertFile($service, $title, $description, $parentId, $mimeType, $filename) {
$file = new Google_DriveFile();
$file->setTitle($title);
$file->setDescription($description);
$file->setMimeType($mimeType);
// Set the parent folder.
if ($parentId != null) {
$parent = new Google_Service_Drive_ParentReference();
$parent->setId($parentId);
$file->setParents(array($parent));
}
try {
$data = file_get_contents($filename);
$createdFile = $service->files->insert($file, array(
'data' => $data,
'mimeType' => '$mimeType',
));
return $createdFile;
} catch (Exception $e) {
print "An error occurred: " . $e->getMessage();
}
}
/**
* Retrieve a list of File resources.
*
* #param Google_Service_Drive $service Drive API service instance.
* #return Array List of Google_Service_Drive_DriveFile resources.
*/
function retrieveAllFiles($service) {
$result = array();
$pageToken = NULL;
do {
try {
$parameters = array(
'maxResults' => '100'
);
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;
try {
$root_id = null;
$service = buildService();
print_r(retrieveAllFiles($service));
}catch (Exception $e) {
print "An error occurred: " . $e->getMessage();
}
?>
What you need to remember is that a Service account is not you. A service account is a dummy user. It has its own google drive account. when you upload the files to the service accounts drive account they are only accessible by that account as it is the owner of it.
Share a drive
If you want it to be able to access files on your personal drive account you will need to grant it access to them by sharing them with the service accounts email address. This is how service accounts are pre approved.
getting path
As for getting the path of a file there is no easy way to do that you will need to step your way though it by getting the file, then getting its parent, followed by getting any more parents until you hit the top and build it up that way.
I have an API built with Slim v2 and I secure certain routes passing a middleware function "authenticate":
/**
* List marca novos
* method GET
* url /novos/marca/:idmarca
*/
$app->get('/novos/marca/:idmarca', 'authenticate', function($idmarca) {
$response = array();
$db = new DbHandler('dbnovos');
// fetching marca
$marca = $db->getMarcaNovos($idmarca);
$response["error"] = false;
$response["marca"] = array();
array_walk_recursive($marca, function(&$val) {
$val = utf8_encode((string)$val);
});
array_push($response["marca"], $marca);
echoRespnse(200, $response, "marcaoutput");
})->via('GET', 'POST');
The authenticate function checks if a headers Authorization value was sent (user_api_key) and checks it against the database.
I'm trying to get the same functionality in a Slim v3 API with the folowwing route:
/**
* List marca novos
* method GET
* url /novos/marca/:idmarca
*/
$app->get('/novos/marca/{idmarca}', function ($request, $response, $args) {
$output = array();
$db = new DbHandler('mysql-localhost');
$marca = $db->getMarcaNovos($args['idmarca']);
if ($marca != NULL) {
$i = 0;
foreach($marca as $m) {
$output[$i]["id"] = $m['id'];
$output[$i]["nome"] = utf8_encode($m['nome']);
$i++;
}
} else {
// unknown error occurred
$output['error'] = true;
$output['message'] = "An error occurred. Please try again";
}
// Render marca view
echoRespnse(200, $response, $output, "marca");
})->add($auth);
This is my middleware
/**
* Adding Middle Layer to authenticate every request
* Checking if the request has valid api key in the 'Authorization' header
*/
$auth = function ($request, $response, $next) {
$headers = $request->getHeaders();
$outcome = array();
// Verifying Authorization Header
if (isset($headers['Authorization'])) {
$db = new DbHandler('mysql-localhost');
// get the api key
$api_key = $headers['Authorization'];
// validating api key
if (!$db->isValidApiKey($api_key)) {
// api key is not present in users table
$outcome["error"] = true;
$outcome["message"] = "Access Denied. Invalid Api key";
echoRespnse(401, $outcome, $output);
} else {
global $user_id;
// get user primary key id
$user_id = $db->getUserId($api_key);
$response = $next($request, $response);
return $response;
}
} else {
// api key is missing in header
$outcome["error"] = true;
$outcome["message"] = "Api key is missing";
//echoRespnse(400, $response, $outcome);
return $response->withStatus(401)->write("Not allowed here - ".$outcome["message"]);
}
};
But I always get the error: "Not allowed here - Api key is missing"
Basically, the test if $headers['Authorization'] is set is failing. What is the $headers array structure or how do I get the Authorization value passed through the header?
If you are sending something else than valid HTTP Basic Authorization header, PHP will not have access to it. You can work around this by adding the following rewrite rule to your .htaccess file.
RewriteRule .* - [env=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
I got a problem with Gmail API service account, I would like to get my personal email from Gmail API without ask for verifying Gmail account and password. Exactly it could be interested to get them from my back-end code.
I have tried to implement this function but it was not worked.
public function list_email()
{
$this->load->library('google');
$client = new Google_Client();
$service = new Google_Service_Gmail($client);
$client->setApplicationName('airxpress-message-api');
$client_email = '867003685660-dk6896nclmfdql86cudt65q2c06f8ooa#developer.gserviceaccount.com';
$private_key = file_get_contents(base_url().G_API.'p12/airxpress-message-api-45eb6393e620.p12');
$scopes = array('https://mail.google.com/');
$credentials = new Google_Auth_AssertionCredentials(
$client_email,
$scopes,
$private_key
);
$credentials->sub = 'notifications-vd#gmail.com';
$client->setAssertionCredentials($credentials);
if ($client->getAuth()->isAccessTokenExpired())
{
$client->getAuth()->refreshTokenWithAssertion();
}
$messages = array();
try
{
$opt_param['labelIds'] = 'INBOX';
$opt_param['q'] = 'subject:"reservation request"';
$messagesResponse = $service->users_messages->listUsersMessages('me', $opt_param);
if ($messagesResponse->getMessages())
{
$messages = array_merge($messages, $messagesResponse->getMessages());
}
}
catch (Exception $e)
{
print 'An error occurred: ' . $e->getMessage();
}
print_r($messages);
}
I met this message error :
Fatal error: Uncaught exception 'Google_Auth_Exception' with message 'Error refreshing the OAuth2 token, message: '{ "error" : "unauthorized_client", "error_description" : "Unauthorized client or scope in request." }''
So, I have gotten the reference from :
https://developers.google.com/api-client-library/php/auth/service-accounts
Could anyone tell me how to solve it?
I try to use Google API PHP client to make my application use its Google Drive account in offline way, because I dont want my application to redirect every time to google for getting authorisation.
So when I connect for the first time and recieve credentials with access_token and refresh_token I backup it and try to use it every time.
Problem is that it works till expiration and than , when API client tries to refresh acces token I'm keep getting this error:
Error refreshing the OAuth2 token, message: '{ "error" : "invalid_request", "error_description" : "Client must specify either client_id or client_assertion, not both" }
My stored credentials are in json form:
{"access_token":"XXX","token_type":"Bearer","expires_in":3600,"refresh_token":"XXX,"created":1406537500}
My code (taken from Google tutorials with some changes):
function exchangeCode($authorizationCode) {
try {
$client = new Google_Client();
$client->setClientId(self::$clientId);
$client->setClientSecret(self::$clientSacred);
$client->setRedirectUri(self::getRedirectURI());
$_GET['code'] = $authorizationCode;
return $client->authenticate();
} catch (Google_AuthException $e) {
echo 'An Google_AuthException occurred: ' . $e->getMessage();
throw new CodeExchangeException(null);
}
}
function getCredentials($authorizationCode, $state='') {
$emailAddress = '';
try {
$credentials = self::exchangeCode($authorizationCode);
$credentialsArray = json_decode($credentials, true);
if (isset($credentialsArray['refresh_token'])) {
self::storeCredentials($credentials);
return $credentials;
} else {
$credentials = self::getStoredCredentials();
$credentialsArray = json_decode($credentials, true);
if ($credentials != null &&
isset($credentialsArray['refresh_token'])) {
return $credentials;
}
}
} catch (CodeExchangeException $e) {
print 'An CodeExchangeException occurred during code exchange.';
$e->setAuthorizationUrl(self::getAuthorizationUrl($emailAddress, $state));
throw $e;
} catch (NoUserIdException $e) {
print 'No e-mail address could be retrieved.';
}
$authorizationUrl = self::getAuthorizationUrl($emailAddress, $state);
throw new NoRefreshTokenException($authorizationUrl);
}
function buildService($credentials) {
$apiClient = new Google_Client();
$apiClient->setUseObjects(true);
$apiClient->setAccessToken($credentials);
return new Google_DriveService($apiClient);
}
function test()
{
$credentials = self::getStoredCredentials();
if ( empty($credentials) )
{
if (!isset($_GET["code"]))
{
header("location:".self::getAuthorizationUrl("xxx#gmail.com", ''));
die();
}
$credentials = self::getCredentials($_GET["code"]);
echo "NEW: ".$credentials;
}
else
{
echo "STORED: ".$credentials;
}
$service = self::buildService($credentials);
}
The error happends in buildService method when its client object tries to refresh based on credentials passed.