Need to upload files on my PC to my own Google Drive (NOT to an end user's Google Drive) using PHP.
Is this possible using this SDK? If so, how?
Yes you could use this library to accomplish this - just download Service Account Credentials and set the file path with $client->setAuthConfig.
However, Wouldn't you be better off using the Drive desktop client for that?
@bshaffer Thank you for your reply. Yes, I tried with Service account, however, its not giving me the same results as I have in my Google Drive. You can check the results here
And here is what I actually have in my Google Drive
Would you please explain why this happens?
@bshaffer Here is the source code I've written:
<?php
include_once __DIR__ . '/vendor/autoload.php';
$client = new Google_Client();
$credentialsFile = __DIR__ . '/credentials/service_account.json';
if (!file_exists($credentialsFile)) {
throw new RuntimeException('Service account credentials Not Found!');
}
$client->setAuthConfig($credentialsFile);
$client->setApplicationName("Service Account Example");
$client->setScopes(Google_Service_Drive::DRIVE);
$service = new Google_Service_Drive($client);
$files = $service->files->listFiles();
print '<pre>';
foreach ($files as $file) {
print_r($file);
print PHP_EOL . '--------------' . PHP_EOL;
}
print '</pre>';
What results are you getting? It's probably because you need to set the subject. Try doing the following:
$client->setSubject('[email protected]');
I am surprised the API isn't just throwing an error. Is the response coming back with an empty array for files?
Not an empty array... It contains only one file.
@bshaffer I got an exception when I do that.
Please help me correct the issue. https://googledrive-sunlean.c9users.io/
@bshaffer it looks like using the setSubject() method is treated as an impersonation and that's the cause of the error. Does this mean every service account has its own google drive instance that is independent of the owner (Me)?
@bshaffer After getting rid of the setSubject() line, I tried to insert some files and it worked just fine. it's just working on a mysterious drive :) I want it to work on MY OWN drive. Is this one of the issues that the latest SDK has? Maybe I might have to check out an older SDK.
@bshaffer As long as I am using a @gmail.com account, I don't need to create a Google App account in order to do this, do I?
I'm not sure why you're seeing different files - I was under the impression it was impossible to upload to drive without a user context.
We are doing something here that might be useful. We set accessType to offline, and once the user authorizes, it comes back with a refresh token that gets automatically refreshed each time.
// create an authorized client
$client = new Google_Client();
$client->setClientId($clientId);
$client->setClientSecret($clientSecret);
// create file cache for storing the access token and refresh token
$cache = new Google_Cache_File(sys_get_temp_dir().'/google-api-php-client-tests');
// make sure we have a token
if (!$token = $cache->get('access_token')) {
$client->setRedirectUri("urn:ietf:wg:oauth:2.0:oob");
$client->setConfig('access_type', 'offline');
$authUrl = $client->createAuthUrl();
echo "\nPlease enter the auth code:\n";
ob_flush();
`open '$authUrl'`;
$authCode = trim(fgets(STDIN));
$token = $client->fetchAccessTokenWithAuthCode($authCode);
if (!isset($token['access_token'])) {
exit('failed!');
}
$cache->set('access_token', $token);
}
$client->setAccessToken($token);
@bshaffer I actually referred to this example that exists in the SDK.
https://github.com/google/google-api-php-client/blob/master/examples/service-account.php
For oAuth server-to-server interaction, I referred to this:
https://developers.google.com/api-client-library/php/auth/service-accounts
Probably the example is not for the right case?
The second link there is referring to version 1 of this library, and has changed according to the Upgrading document in version 2. I suggest you stick with the first example.
We'll be moving the docs to version 2 very soon.
@bshaffer I know that, but the example should work for my case. Can you give me sample code that do the job for me? I need it done ASAP... I know this is out of your interest/service but I'd like to ask you to for me :) I was not able to get the API to work for my case or to find any examples on the Internet that works with Google Drive. I have to use the service account because it shouldn't be asking me to log in.
I have already provided several code samples that will accomplish this task. In addition, there is this example that exists as part of the repository which accomplishes what you are trying to do.
@bshaffer This is not using service accounts. I wrote the code that combines the 2 examples (service account and file uploading) as you can see. As this reference says, I thought service accounts should work against my own google drive. Instead, it works against another mysterious google drive space that's independent of my drive and owned by that service account, which makes it impossible to access the files with my own google account. Is that a problem with the PHP SDK? Should I try version 1 or other SDK in other languages?
You have two options:
This is what I outlined in my code sample above. This does not use a service account, but instead uses an Oauth "installed app" which fetches the access token with a refresh token indefinitely
this is trickier, as you will need to create an OAuth Client _just to authorize your user_
go to API Manager > Credentials > New Credentials > OAuth Client ID and then select other as the client type.

Now download those credentials (below, client_secret_xxx.json) and use them like this:
$client->setAuthConfig('/path/to/client_secret_xxx.json');
$client->addScope("https://www.googleapis.com/auth/drive");
$client->setRedirectUri("urn:ietf:wg:oauth:2.0:oob"); // this is so you can grab the code in the browser
header('Location: '. $client->createAuthUrl());exit;
now you can copy the code and _exchange it for an access token_ like this:
$client->fetchAccessTokenWithAuthCode($code);
It is not enough for you to authorize the client in the browser, you must also have the client request an access token to complete the authorization.
After all this, you will see the client show up under your authorized clients:

_NEXT_, you can switch back to your service account credentials and set the subject as the user who has authorized the app:
$client->setAuthConfig('/path/to/service-account-credentials.json');
$client->addScope("https://www.googleapis.com/auth/drive");
$client->setSubject('[email protected]');
// continue to upload with Drive forever and ever...
@bshaffer Thanks a lot for your detailed explanation! :+1:
It allowed me to refactor an old Adapter for laravel piece by piece.
@bshaffer Now it says 'Requested client not authorized', even though I just pushed accept and copied the code and put it in the fetch function!
@AndreyNazarchuk does the authorized application show up in your authorized applications? If not, I assume the access token was not fetched as expected.
@bshaffer It did once, then after that I cant get it to show up again.
@bshaffer How can I ensure token is fetched as expected?
If the line $client->fetchAccessTokenWithAuthCode($code); returned an access token.
@bshaffer Your post saved my day!! I've been trying all kinds of things, and couldnt make it work as I wanted to, and your step-by-step guide has just been wonderful!! Thank YOU! After almost 10 hours of work with this: THANK YOU !
hey, I am bigner in PHP and i want to upload csv/pdf file in drive programatically.
namespace GoogleApi;
require 'GoogleApi/Client.php';
require 'GoogleApi/Contrib/apiOauth2Service.php';
require 'GoogleApi/Contrib/apiDriveService.php';
$pdfFile = 'files/pdf.pdf';
//$pdfFile = 'files/report.csv';
// API Console: https://code.google.com/apis/console/
// Create an API project ("web applications") and put the client id and client secret in config.ini.
// Set up the Drive SDK in the API console.
// Create a Chrome extension, set the "container" and "api_console_project_id" parameters, and install it.
$config = parse_ini_file('php.ini'); // client_id, client_secret
// initialise the client
$client = new Client();
$client->setUseObjects(true);
$client->setAuthClass('apiOAuth2');
$client->setScopes(array('https://www.googleapis.com/auth/drive.file'));
$client->setClientId($config['932339130642-s0t08hcbtvbnp8e6e9f9q7c2gdkba7hn.apps.googleusercontent.com']);
$client->setClientSecret($config['u1cKtQ2b6iQ5zZJF7zYNQrUu']);
$client->setRedirectUri($config['http://localhost/test/driver_data']);
$client->setAccessToken(authenticate($client));
// initialise the Google Drive service
$service = new apiDriveService($client);
// create and upload a new Google Drive file, including the data
try {
$file = new DriveFile;
$file->setTitle(basename($pdfFile));
$file->setMimeType('application/pdf');
$result = $service->files->insert($file, array('data' => file_get_contents($pdfFile), 'mimeType' => 'application/pdf'));
}
catch (Exception $e) {
print $e->getMessage();
}
print_r($result);
function authenticate($client, $file = 'token.json'){
if (file_exists($file)) return file_get_contents($file);
$_GET['code'] = ''; // insert the verification code here
// print the authentication URL
if (!$_GET['code']) {
exit($client->createAuthUrl(array('https://www.googleapis.com/auth/drive.file')) . "\n");
}
file_put_contents($file, $client->authenticate());
exit('Authentication saved to token.json - now run this script again.');
}
I am using above code but not working...Please help me.
Thank You
@abhay1003 Please open a new issue with your question, as this issue has been closed.
@bshaffer
Hi Brent,
Thanks for your detailed explanation, however I tried all the steps and I could get the app to show up in my account's authorized clients page, But I still get "unauthorized_client" error when I switch to service account's credentials and try to impersonate the account for which I authorized the app.
$client->setSubject('<ACCOUNT_THAT_AUTHORIZED_APP>@gmail.com');
I tried deleting service account, shutting down the project, starting everything over again, changing service account permissions (owner, editor, ...)
Is there anything else I can try?
I am having the exact same issue.
1) I got the code
2) Successfully used it to fetch a token
3) Verified that my app is listed in the "Third-party apps" for my personal gmail account.
4) Use the service account json file and successfully call:
putenv("GOOGLE_APPLICATION_CREDENTIALS=/path/to/my/service/account/json/file.json");
$client = new Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(Google_Service_Drive::DRIVE);
$client->setSubject("my personal gmail address");
$service = new Google_Service_Drive($client);
5) But then when I try to call the below to list the files, I get an authentication error:
$optParams = array( 'pageSize' => 10, 'fields' => 'nextPageToken, files(id, name)' );
$results = $service->files->listFiles($optParams);
Fatal error: Uncaught exception 'Google_Service_Exception' with message '{
"error": "unauthorized_client",
"error_description": "Client is unauthorized to retrieve access tokens using this method."
}
Any idea what I might be doing wrong?
Does this only work for GSuite accounts and not regular personal Gmail accounts.
Thanks.
@ignacvucko; my best guess is;
Does this only work for GSuite accounts and not regular personal Gmail accounts.
Yes, this is probably so, but let me check tomorrow.
My problem is even more strange. I managed to use the service account authorization, but all the files and folders that I create are hidden from My Drive dashboard. When I use this code
$optParams = array( 'pageSize' => 10, 'fields' => 'nextPageToken, files(id, name)' );
$results = $service->files->listFiles($optParams);
if (count($results->getFiles()) == 0) { print "No files found.\n"; }
else { print "Files:\n"; foreach ($results->getFiles() as $file) {
printf("%s (%s)\n", $file->getName(), $file->getId()); }
}
all the files & folders get listed like this
Files:
Hello World 3! (1R9EV0wrBZ87NgW3DH5pwZd398yRtwSTt)
My Folder 3 (1S1xhdatA3Ai-GlnfMhwYysgsbsdzjQTy)
Hello World 23! (1LMKPBoG5YxG30VRzr6Sh3FtWjuvqbrfx)
My Folder 23 (12FRTA26RqBia0VccBla_O9THSNdMarop)
Hello World 23! (1fbWwApNlQNwSbkzzXJ9Bs5iWA0TvBMgq)
My Folder 23 (1jt2SGEz8bl9eAfO29CJnDYC9JWq-3SiJ)
Hello World 23! (1yB88O2f5H7zozvBgzLzUSLPkC3JAeE5X)
My Folder 23 (1YvVKnwNa9V68Hs01UrEQ_NXwzmXgS-FF)
Hello World 3! (1s7cB1iQisYV3At_7rkhEQLyzcHTYEFvW)
My Folder 3 (1CEbxkQNUYZZtBkCQy7P7F0AMeAgD8mns)
Most helpful comment
You have two options:
1. Create an "installed application" and use a refresh token
This is what I outlined in my code sample above. This does not use a service account, but instead uses an Oauth "installed app" which fetches the access token with a refresh token indefinitely
2. Create a "service account" and from your USER account, authorize the client so it shows up here
this is trickier, as you will need to create an OAuth Client _just to authorize your user_
go to API Manager > Credentials > New Credentials > OAuth Client ID and then select other as the client type.

Now download those credentials (below,
client_secret_xxx.json) and use them like this:now you can copy the code and _exchange it for an access token_ like this:
After all this, you will see the client show up under your authorized clients:
_NEXT_, you can switch back to your
service account credentialsand set the subject as the user who has authorized the app: