Server-to-Server App using Google Drive not responses to APIs calls - php

I'm working on a project where I have to make a server to server app with PHP.
The concept is : the company uploads bills to Google drive and the users use the website to retrieve their bills. First of all I didn't use a composer to the server because I have no permission to install. So I downloaded the libs and uploaded to server with ftp. Then I created a G Suite Google account and followed the instructions from their guide https://developers.google.com/api-client-library/php/auth/service-accounts.
The weird thing is if var_dump(service) after $results = $service->files , I see that the verification for the client has be done. When I try to use the api with $results = $service->files->listFiles($optParams); the page doesn't respond. Im really confused with this.
<?php
session_start();
require_once "vendor/autoload.php";
require 'init.php';
putenv('GOOGLE_APPLICATION_CREDENTIALS=service.json');
$client = getClient();
$service = new Google_Service_Drive($client);
function getClient() {
$client = new Google_Client();
$client->useApplicationDefaultCredentials();
return $client;
}
$optParams = array(
'pageSize' => 5,
'fields' => 'files(webViewLink, name , parents, id)'
);
$results = $service->files->listFiles($optParams);

Solved it. The problem was PHP version. I switched to 7.2 and seems to work perfect!

Related

Connect to Google AdSense API via PHP

I'm trying to connect to AdSense API using a PHP script.
I started using this tutorial by google: https://developers.google.com/api-client-library/php/start/get_started#build-the-client-object
However, I didn't manage to connect. This is what I've tried:
$client = new Google_Client();
$client->setApplicationName("AppName");
$client->setDeveloperKey(API_Key);
$client->setAuthConfigFile('../AdSense/google-api-php-client/client_secret.json');
$service = new Google_Service_AdSenseTest($client);
$results = $service->testReportsGenerate();
foreach($results as $item)
{
echo $item;
}
And I came across a few problems, the main one is that the code doesn't recognize the "Google_Service_AdSenseTest" class - even though the code suggested it.
So my real question is this: What service should I use if I want to pull data from AdSense? And how do I set the needed parameters (meaning - which dimensions and metrics to get)?
Thank you.
You need to implement OAuth requests as you do for every single google api, (use Phil Sturgeon's OAuth2.0 protocol if you use codeigniter, well implemented.) or any oauth2 client scripts will do.
The google api library is here : https://github.com/googleapis/google-api-php-client-services. Use composer to install these libraries.
The adsense class is here : https://github.com/googleapis/google-api-php-client-services/blob/master/src/Google/Service/AdSense.php
The class/function which makes the request to google must setup an oauth client and specify a redirect url (which in turn must be registered on google api console )
The scopes are
../auth/adsense
../auth/adsense.readonly
Once everything is done, you can make a request.
I implemented it with Codeigniter for searchconsole, adsense and other useful libraries they all works awesome. Besides i connected google sheets as well, so every report is available to me in google sheet as it is needed.
With oAuth Access token, The code :
$client = new Google_Client();
$adsenseService = new Google_Service_AdSense(...);
$client->setApplicationName("Adsense Console");
$client->setDeveloperKey($apiKey);
$client->setAccessToken( $token->access_token );
$params = array('maxResults' => 1000, 'pageToken' => null, 'alt' => 'json', 'fields' => array(), 'prettyPrint' => true, 'quotaUser' => '', 'userIp' => '' );
$accounts = $adsenseService->accounts->listAccounts($params);
//this will print a json array
echo '<pre>' ; print_r($accounts); echo '<pre>'; die();
for adclients,
$adsense->adclients->listAccountsAdclients($params);
The params ref is here,
https://developers.google.com/adsense/management/v1.4/reference/accounts/adclients/list#try-it
you could try the example from https://github.com/googleads/googleads-adsense-examples/tree/master/php-clientlib-1.x/v1.x
More info at https://developers.google.com/adsense/management/getting_started

Accessing GDrive from Google App Engine with domain-wide delegation service account

This is my first time using Google App Engine, so some of my terminology might be a bit off, bear with me.
I had some php code running in a web app outside of GAE that was using the google-api-php-client library to access gdrive folders and create files. It was working wonderfully.
I'm trying to migrate to GAE with a project that has domain-wide delegation so that my app can access/create files in my gdrive account. For example, let's say my domain is kennywyland.com and my Google account that I'm using is kenny#kennywyland.com.
I create my Google Client like this, which I got from https://developers.google.com/api-client-library/php/auth/service-accounts:
$client = new Google_Client();
$client->setAuth(new Google_Auth_AppIdentity($client));
$client->getAuth()->authenticateForScope('https://www.googleapis.com/auth/drive');
Then I create the gdrive service like this:
$service = new Google_Service_Drive($client);
I didn't get any errors from this and I am able to perform queries without error messages being thrown, however, I'm getting back completely empty result sets. I've got plenty of files in my gdrive account, so I would assume that I should see them when I publish the following code to GAE and run it (the retreiveAllFiles() function is from Google's code example found here: https://developers.google.com/drive/v2/reference/files/list#try-it):
$allfiles = retrieveAllFiles($service);
print_r($allfiles);
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;
}
However, I get an empty result set. The print_r() prints an empty array:
Array ( )
What am I missing? I feel like my project/app is able to successfully access the gdrive server, but it's just not able to see any files in my account associated with this work domain.
The solution involved one primary change which required one further change. The primary change was that I was using the google-api-php-client v1 but I needed to be using the v2 release candidate (which is oddly located in the https://github.com/google/google-api-php-client/tree/v1-master branch).
They have a list of code changes needed to upgrade from 1.0 to 2.0 (thank you, very handy githubers!)
https://github.com/google/google-api-php-client/blob/master/UPGRADING.md
I ended up configuring my client with the following code and then it was immediately able to access gdrive as if it were the currently logged in person (assuming 'kenny#kennywyland.com' in my example, who is part of my special domain with domain-wide delegation).
require_once('vendor/autoload.php');
$client = new Google_Client();
$client->setAuthConfig('myapp-xxxxxxxx.json');
$user_to_impersonate = "kenny#kennywyland.com";
$client->setSubject($user_to_impersonate);
$client->addScope('https://www.googleapis.com/auth/drive');
$service = new Google_Service_Drive($client);
The myapp-xxxxxxx.json file was generated in my Developer Console for my App's Service Account.

How to browse files from projects google drive

i have created project in google console with service type credentials. I have downloaded p12 key file, and then wrote sample code for inserting file to test it:
<?php
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";
$scopes = array('https://www.googleapis.com/auth/drive');
$accountEmail = 'SECRET';
$accountP12FilePath = './key.p12';
$key = file_get_contents($accountP12FilePath);
$auth = new Google_AssertionCredentials($accountEmail, $scopes, $key);
$client = new Google_Client();
$client->setUseObjects(true);
$client->setAssertionCredentials($auth);
$service = new Google_DriveService($client);
$file = new Google_DriveFile();
$file->setTitle('Test Title');
$file->setDescription('test description');
$parent = new Google_ParentReference();
$file->setParents(array($parent));
$createdFile = $service->files->insert($file, array(
'data' => 'test data',
'mimeType' => 'text/plain'
));
var_dump($createdFile);
?>
It dumps Google_DriveFile object with many urls. Some of them, like 'downloadUrl', returns 401 Unauthorized error. When I tried 'alternateLink' it showed google drive page with information that i need access, and buttons to request access and to switch account.
It also said that Im currently logged on my account, that was beeing used to create project, and that is visible on Permissions page of the project on the google console page.
How can I access drive that belongs to the project I used in the script ?
Finally found solution, it was missing permissions on file. Its worth to note that passing permission object to the $file object (before insertion) didn't work. I had to insert permission by passing already created file ID and permission object to the $service->permissions->insert method, just like that:
$permission = new Google_Permission();
$permission->setValue('PERSONAL.ACCOUNT#gmail.com');
$permission->setType('user');
$permission->setRole('writer');
$service->permissions->insert($createdFile->getId(), $permission);
Still I wasn't able to actually edit this file. When I opened file with URL
$createdFile->getAlternateLink();
Then I had to reopen that file with google docs. That copied file to my personal account and then I could only edit only that copy of a file, not a base file itself.
I dont know if there is a way to make that files truly editable, but I moved to the dropbox, as google drive API and its documentation SUX.

Upload File from App Engine to Google Drive

Eventually, I would like to upload a file to my Google Drive via App Engine php script.
However, following tutorials such as https://developers.google.com/drive/web/quickstart/quickstart-php
force the individual to be signed in. I'm assuming that in this case, I would have to use Service Account credentials.
From here, I uploaded the following code along with the needed API Client Library files
<?php
require_once 'autoload.php';
//require_once 'Auth/AssertionCredentials.php';
require_once 'Client.php';
require_once 'Service/Drive.php';
//
$client = new Google_Client();
$client->setApplicationName("blah-blah-00000");
$client->setClientID("000000000000-00000000000000000000000000000000.apps.googleusercontent.com");
$service = new Google_Service_Drive($client);
// This file location should point to the private key file.
$key = file_get_contents("BlahBlah-000000000000.p12");
$cred = new Google_Auth_AssertionCredentials(
"000000000000-00000000000000000000000000000000#developer.gserviceaccount.com",
// Replace this with the scopes you are requesting.
array('https://www.googleapis.com/auth/drive',
'https://www.googleapis.com/auth/drive.file'),
$key
);
$client->setAssertionCredentials($cred);
//Insert a file
$file = new Google_Service_Drive_DriveFile();
$file->setTitle('HelloWorld');
$file->setDescription('A test document');
$file->setMimeType('text/plain');
$data = "Hello World!";
$createdFile = $service->files->insert($file, array(
'data' => $data,
'mimeType' => 'text/plain',
'uploadType' => 'media'
));
//print_r($createdFile);
?>
After visiting the associated appspot.com, the page is blank. At this point, I check the Google Drive associated with the account; however no new files are found.
Am I correct in using a Service account? Provided that this is correct, my next question is am I correctly setting up the credentials? Do I have to impersonate my user account/the account that the App Engine application is setup with?
Am I correct in using a Service account?
Probably not. I see a lot of people using a Service Account when what they should be using is offline access to a standard account.
"At this point, I check the Google Drive associated with the account; however no new files are found". Specifically, people don't realise that a Service Account is NOT associated with their standard account, so naturally when viewing Drive for their standard account, the files from the Service Account aren't there. They're in the Service Account which has no UI.
Provided that this is correct, my next question is am I correctly setting up the credentials?
It isn't. You say " following tutorials such as ... force the individual to be signed in." There aren't any tutorials that show your use case, but that doesn't mean it can't be done. Just that nobody wrote a tutorial on how to do it.
Do I have to impersonate my user account/the account that the App Engine application is setup with?
You need to:-
do a one-time authorize for your account which requests offline access. This will give you a refresh Token which you need to save.
Then use the Refresh Token to request an Access Token when you want to access Drive.
The good news is step 1 doesn't require you to write any code. See How do I authorise an app (web or installed) without user intervention? (canonical ?)
After following pinoyyid's LINK and using an offline OAuth2 refresh token, I updated my code to the following
<?php
require_once 'autoload.php';
require_once 'Client.php';
require_once 'Service/Drive.php';
//
$client = new Google_Client();
// Replace this with your application name.
$client->setApplicationName("00000-00000-00000");
$client->setClientID("000000000000-00000000000000000000000000000000.apps.googleusercontent.com");
$client->setClientSecret("XXXXXXXXXXXXXXXXXXXX");
$client->refreshToken("1/KXXXXXXXXXXXXXXXXXXXXXXXXX");
// Replace this with the service you are using.
$service = new Google_Service_Drive($client);
$_SESSION['service_token'] = $client->getAccessToken();
//Insert a file
$file = new Google_Service_Drive_DriveFile();
$file->setTitle('HelloWorld');
$file->setDescription('A test document');
$file->setMimeType('text/plain');
$data = "Hello World!";
$createdFile = $service->files->insert($file, array(
'data' => $data,
'mimeType' => 'text/plain',
'uploadType' => 'media'
));
?>

How to resolve oAuth 2.0 Google Spreadsheets authentication issue?

I'm building a server-side application that would need to authenticate with Google Spreadsheets API and read data from it. Using this PHP client with Google APIs client.
What I need to do is to authenticate with Google without user interaction.
Installed everything with composer and loaded with autoloader.php.
The problem I'm having is, in this section of the documentation, an $accessToken variable is used which I can't generate. I created a project in Google Developers Console and oAuth 2.0 credentials with service account client ID. As a result, I got two files - JSON and p12, alongside with the CLIENT ID, EMAIL ADDRESS and PUBLIC KEY FINGERPRINTS credentials, which I don't know how to use to obtain the authorization token.
Also, I'm facing a redirect_uri_mismatch error and I can't set it up in Google Developers Console.
The authenticate method in OAuth2.php is requiring a $code variable which I don't have and don't know how to obtain.
If I could obtain that $accessToken variable, I could try to debug further.
Any help is highly appreciated.
This is what worked for me:
$client = new Google_Client();
$client->setApplicationName(GOOGLE_APPLICATION_NAME);
$client->setClientId(GOOGLE_CLIENT_ID);
$key = file_get_contents(GOOGLE_KEY_FILE);
$cred = new Google_Auth_AssertionCredentials(
GOOGLE_CLIENT_EMAIL,
array(GOOGLE_SPREADSHEETS_URL),
$key
);
$client->setAssertionCredentials($cred);
if($client->getAuth()->isAccessTokenExpired()) {
$client->getAuth()->refreshTokenWithAssertion($cred);
}
$service_token = json_decode($client->getAccessToken());
$accessToken = $service_token->access_token;
use Google\Spreadsheet\DefaultServiceRequest;
use Google\Spreadsheet\ServiceRequestFactory;
$serviceRequest = new DefaultServiceRequest($accessToken);
ServiceRequestFactory::setInstance($serviceRequest);
$spreadsheetService = new Google\Spreadsheet\SpreadsheetService();
$spreadsheetFeed = $spreadsheetService->getSpreadsheets();
GOOGLE_SPREADSHEETS_URL is https://spreadsheets.google.com/feeds and GOOGLE_KEY_FILE is the location of your XXX.p12 file.
I do hope this will help somebody in a similar situation.

Categories