I was wondering is there any method to upload the files directly to our own Google drive by using php , Currently i am using a method like this.
$drive = new Google_Client();
$drive->setClientId($client_id);
$drive->setClientSecret($client_secret);
$drive->setRedirectUri($redirect_uri);
$drive->setScopes(array('https://www.googleapis.com/auth/drive'));
$gdrive = new Google_DriveService($drive);
$_GET['code'] = 'ya2-------------------------OZXiA';
//file_put_contents('token.json', $drive->authenticate());
$drive->setAccessToken(file_get_contents('token.json'));
$doc = new Google_DriveFile();
$doc->setTitle('Test Document');
$doc->setDescription('Test description');
$doc->setMimeType('text/plain');
$content = file_get_contents('/assets/new--detils.txt');
$output = $gdrive->files->insert($doc, array(
'data' => $content,
'mimeType' => 'text/plain',
));
print_r($output);
But this shows an error as
Fatal error: Uncaught exception Google_AuthException with message 'Error fetching OAuth2 access token, message: 'invalid_grant'' in /var/www/path/src/auth/Google_OAuth2.php:115
Here i am using $_GET['code'] = 'ya2-------------------------OZXiA' generated for that app,
Can anyone please suggest a method to do this, thanks in advance.
Not sure if it helps but I found this looking through Google Code...
"You'll get the invalid_grant error when you try to use the same authorization code."
I found it here: https://code.google.com/p/google-api-php-client/issues/detail?id=94
Not sure if that will help you or not...
Also found this tutorial: http://25labs.com/tutorial-implementing-google-api-using-oauth-2-0-in-php/
$drive = new Google_Client();
$drive->setClientId($client_id);
$drive->setClientSecret($client_secret);
$drive->setRedirectUri($redirect_uri);
**$drive->setAccessType('offline');**
$authUrl = $client->createAuthUrl();
echo $authUrl;
Now go the auth url and get the refresh token and other things.
Make sure this is the first time you are asking for permission, if you aren't then you wont get the refreshtoken which is necessary to make authtokens in the future.
If you have already give permissions just go to your google account and revoke the permissions of the app.
This is what you should have in the file which you are redirecting too.
$tokeninfo = $drive->getAccessToken();
print_r($tokeninfo);
Now save the tokeninfo in a file like "token.json".
Now go back to the original file which will contain the code for upload.
$drive = new Google_Client();
$drive->setClientId($client_id);
$drive->setClientSecret($client_secret);
$drive->setRedirectUri($redirect_uri);
$drive->setScopes(array('https://www.googleapis.com/auth/drive'));
$drive->setAccessType('offline');
$service = new Google_Service_Drive($drive);
$refreshToken = "Your refresh token";
/* get it from token.json and it will look some like this 1**\/**asasfasfsfsd
remove the \ since this is actually json encoded.*/
$tokens = file_get_contents(TOKEN); /*TOKEN = the token.json file*/
$drive->setAccessToken($tokens);
if ($drive->isAccessTokenExpired()) {
$drive->refreshToken($refreshToken);
file_put_contents(TOKEN,$drive->getAccessToken());
}
Now you have done the authentication and just need to upload the file.
if ($drive->getAccessToken()) {
$file = new Google_Service_Drive_DriveFile();
$file->title ="the file name";
/*the upload code can be found in the examples*/
}
Note
The file you upload cannot be downloaded by other ppl, you need to set googlepermissions to make the file shared.
Just drop a comment if you need to code to add permissions.
Related
I am trying to create folder using google drive api. I am able to get file id at the end. but i am not able to my folder in google drive. it seems some permission issue?
$scopes = array(
'https://www.googleapis.com/auth/drive',
'https://www.googleapis.com/auth/drive.appdata','https://www.googleapis.com/auth/drive.apps.readonly',
'https://www.googleapis.com/auth/drive.metadata','https://www.googleapis.com/auth/drive.file',
'https://www.googleapis.com/auth/drive.readonly','https://www.googleapis.com/auth/drive.photos.readonly'
);
$creds = new Google_Auth_AssertionCredentials(
$serviceAccountName,
$scopes,
file_get_contents($keyFile)
);
$client = new Google_Client();
$client->setApplicationName($appName);
$client->setClientId($clientId);
$client->setAssertionCredentials($creds);
$service = new Google_Service_Drive($client);
$fileMetadata = new Google_Service_Drive_DriveFile(array(
'name' => 'Invoices',
'permissions' => array('type'=>'anyone','role'=>'reader','allowFileDiscovery'=>1),
'mimeType' => 'application/vnd.google-apps.folder'));
$file = $service->files->create($fileMetadata, array());
printf("File ID: %s\n", $file->id);
The files that are being created belong to the API account email (something like api-service-account#yourproject.iam.gserviceaccount.com. If you go to the drive URL:
https://docs.google.com/document/d/{ID}, you will get a "Permission Denied, request access" page.
The service account email is not related to your user email.
In order to create files with your user, you need to create an OAauth token authorization.
Create the OAuth credentials following the steps "Step 1: Turn on the Drive API" on this page
Modify your script, by following the example on this page, you can have:
use Google_Client;
use Google_Service_Drive;
use Google_Service_Drive_DriveFile;
...
$file = 'root/to/your/credentials.json';
$client = new Google_Client();
$client->setScopes([
'https://www.googleapis.com/auth/drive',
'https://www.googleapis.com/auth/drive.appdata',
'https://www.googleapis.com/auth/drive.apps.readonly',
'https://www.googleapis.com/auth/drive.metadata',
'https://www.googleapis.com/auth/drive.file',
'https://www.googleapis.com/auth/drive.readonly',
'https://www.googleapis.com/auth/drive.photos.readonly'
]);
$client->setAuthConfig($file);
$authUrl = $client->createAuthUrl();
printf("Open the following link in your browser:\n%s\n", $authUrl);
// You will need to open this url
print 'Enter verification code: ';
$authCode = trim(fgets(STDIN));
$accessToken = $client->authenticate($authCode);
file_put_contents($credentialsPath, $accessToken);
printf("Credentials saved to %s\n", $credentialsPath);
$client->setAccessToken(json_decode($accessToken, true));
$service = new Google_Service_Drive($client);
$metadata = new Google_Service_Drive_DriveFile([
'name' => 'testing drive',
'mimeType' => "application/vnd.google-apps.document"
]);
$file = $service->files->create($metadata, []);
print_r($file);
The file should be in your Drive home directory.
By the way, I suggest you try the new version google/apiclient:2.0.2 (which is still on Beta, but works okay).
Mayrop answer is partially right.
The files that are being created belong to the API account email (something like api-service-account#yourproject.iam.gserviceaccount.com.
You need to give permission to owner of that account like
$newPermission = new Google_Service_Drive_Permission();
$value="email id";
$type="user";
$role="writer";
$newPermission->setValue($value);
$newPermission->setType($type);
$newPermission->setRole($role);
try {
$res= $service->permissions->insert($fileId, $newPermission);
print_r($res);
} catch (Exception $e) {
print "An error occurred: " . $e->getMessage();
}
You will see that folder in Shared with me. You can also add in your drive manually.
You can also disable sending notification via email using
$service->permissions->insert($fileId, $newPermission,array('sendNotificationEmails'=>false));
Hope this will work for you.
Yes, It seems permissions issue. Try removing
'permissions' => array('type'=>'anyone','role'=>'reader','allowFileDiscovery'=>1),
from
$fileMetadata = new Google_Service_Drive_DriveFile(array(
'name' => 'Invoices',
'permissions' => array('type'=>'anyone','role'=>'reader','allowFileDiscovery'=>1),
'mimeType' => 'application/vnd.google-apps.folder'));
so I have worked over it, and finally got the full working solution for Google Drive V3 in Php. As follows:
You can go through this gist for full code and better understanding:
https://gist.github.com/KartikWatts/22dc9eb20980b5b4e041ddcaf04caf9e
First of all adding to the answer from #Hitu Bansal:
This code works fine:
$this->newPermission = new Google_Service_Drive_Permission();
$value=<YOUR EMAIL ADDRESS>;
$type="user";
$role="reader";
$this->newPermission->setEmailAddress($value);
$this->newPermission->setType($type);
$this->newPermission->setRole($role);
$this->newPermission->allowFileDiscovery;
try {
$res= $this->service->permissions->create($folder_id, $this->newPermission);
print_r($res);
catch (Exception $e) {
print "An error occurred: " . $e->getMessage();
}
If, instead you want to share the link with anyone: You may use
$type="anyone";
$this->newPermission->setType($type);
$this->newPermission->setRole($role);
$this->newPermission->allowFileDiscovery;
$this->newPermission->view;
NOTE:
In this case, setEmailAddress() shall be removed.
IMPORTANT: In case of 'anyone', the folder will not be visible in your personal drive for sure, but you can still visit and interact with the folder as per given roles by visiting the link making use of the folder_id that you know already. So, you can visit the link as: https://drive.google.com/drive/u/5/folders/**{folder_id}** It will be publically accessible now.
For more clear reference to the parameters along with a description, this is really helpful: https://developers.google.com/drive/api/v3/reference/permissions#methods
NOTE: In my personal opinion, a better way to work with Google Drive API is to create the folder first manually (if workflow allows it), then upload the files using the folder_id of that created folder. Remember, In case folder is created manually, permission shall be provided to the Service Account email-id before.
While permission issue is the main cause of this problem. What I did to make the folders or files appear after I uploaded it with service account was to specify the parent folder. If you upload / create folder / files without parent folder ID, that object's owner will be the service account that you are using.
By specifying parent ID, it will use the inherited permissions.
Here's the code I use in php (google/apiclient)
$driveFile = new Google\Service\Drive\DriveFile();
$driveFile->name = 'New Folder';
$driveFile->mimeType = 'application/vnd.google-apps.folder';
$driveFile->parents = ['123456789qwertyuiop'];
$result = $service->files->create($driveFile);
struggling to understand the oauth2 token and refresh token processes
ive got this code
$url = 'https://www.googleapis.com/oauth2/v3/token';
$data = array('client_id' => 'clientid', 'client_secret' => 'secret','refresh_token' => 'token','grant_type' => 'refresh_token');
$options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded",
'method' => 'POST',
'approval_prompt'=>'force',
'access_type'=>'offline',
'content' => http_build_query($data),
),
);
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
that code above gives me an access token , and i followed this link suggested by one fellow stackoverflower, pinoyyid, BUT , im confunsed on how to correctly use the resulting access token to access drive and copy a file...
all the process ive seen usually involves $client = new Google_Client() and im not sure on how to use the whole POST http://..... thing, so basically i need to figure out if i use the access token i got with the code above in a new instance of google client, or i simply do a post to a url with necesary info ( which im not clear on also ) any help/clarification is appreciated guys really
EDIT #1
what i want to achieve is to allow the end user to access my drive via my webpage, to let them copy a spreadsheet in my drive , and access it via my website, to store data on the spreadsheet,the spreadsheet will always be on my drive, never on the end user
EDIT #2
code as per your posts is as follows, using the service account,,,,the files are inside that gmail account which i created on the api console a service account
<?php
require 'Google/autoload.php';
$client = new Google_Client();
// Replace this with your application name.
$client->setApplicationName("TEST");
// Replace this with the service you are using.
$service = new Google_Service_Drive($client);
// This file location should point to the private key file.
$key = file_get_contents($_SERVER['DOCUMENT_ROOT'] . '/number-privatekey.p12');
$user_to_impersonate = 'admin#testpr.com';
$cred = new Google_Auth_AssertionCredentials(
'number#developer.gserviceaccount.com',
array('https://www.googleapis.com/auth/drive'), ****//this here has to be drive not drive.file
$key,
'notasecret',
'http://oauth.net/grant_type/jwt/1.0/bearer',
$user_to_impersonate
);
$client->setAssertionCredentials($cred);
if ($client->getAuth()->isAccessTokenExpired()) {
$client->getAuth()->refreshTokenWithAssertion();
}
$originFileId = "longnumber";
$copyTitle = 'copied';
$newfile = copyFile($service, $originFileId, $copyTitle);
print_r($newfile);
function copyFile($service, $originFileId, $copyTitle)
{
$copiedFile = new Google_Service_Drive_DriveFile();
$copiedFile->setTitle($copyTitle);
try {
return $service->files->copy($originFileId, $copiedFile);
} catch (Exception $e) {
print "An error occurred: " . $e->getMessage();
}
return NULL;
}
?>
so got it working just now, ty all for your time guys really and edited my post to reflect the dang thing
If you want to give the end user access to your drive, you have to give your application authority to make API calls on behalf of a user (in this case you) in your domain. For this you have to set up a service account and generate a p12 key in the Google Developers Console. You have to enter the https://www.googleapis.com/auth/drive API scope in your Admin Console as well.
Full explanation and examples can be found here: https://developers.google.com/api-client-library/php/auth/service-accounts.
To achieve this you also need the Google API's client library: https://github.com/google/google-api-php-client (also mentioned in the Google manual).
Code example to let users make API calls on behalf of one of your accounts: https://developers.google.com/api-client-library/php/guide/aaa_oauth2_service
I am new to Google Drive and have uploaded many files. I have changed the status of all files to be shared if the download link is known.
I would like to use PHP to generate a list of all of the direct download links for the files. The PHP script is run on my localhost and I just need the array to be saved to a text file to be used later.
I have had a very hard time trying to get Oauth working but came across this script that looks like what I need. I set up my service account and have my service account email and .p12 file.
I downloaded the Google PHP client code base and set up a test script on my localhost. This is what I have
require_once "Google/Client.php";
require_once "Google/Service/Drive.php";
require_once "Google/Service/Oauth2.php";
require_once "Google/Auth/AssertionCredentials.php";
session_start();
function buildService($userEmail) {
$SERVICE_ACCOUNT_EMAIL = '12345#developer.gserviceaccount.com';
$SERVICE_ACCOUNT_PKCS12_FILE_PATH = '12345-privatekey.p12';
$key = file_get_contents($SERVICE_ACCOUNT_PKCS12_FILE_PATH);
$auth = new Google_AssertionCredentials(
$SERVICE_ACCOUNT_EMAIL,
array('https://www.googleapis.com/auth/drive'),
$key);
$auth->sub = $userEmail;
$client = new Google_Client();
$client->setUseObjects(true);
$client->setAssertionCredentials($auth);
return new Google_DriveService($client);
}
//... function retrieveAllFiles($service)
$service = buildService("myemail#gmail.com");
$allFiles = retrieveAllFiles($service);
print_r($allFiles);
I am working off of this example
http://stackoverflow.com/questions/21046631/google-drive-api-php-cant-list-files
and this
https://developers.google.com/drive/web/delegation#instantiate_a_drive_service_object
I am unsure what to do, I have added the required libraries but the following functions are coming up as being unknown in the PHP script
Google_AssertionCredentials
setUseObjects
Google_DriveService
retrieveAllFiles
Am I missing an obvious library? They are named different in the example but I'm guessing the base names have changed since there were updates... I have spent a lot of time reading up on Google Drive and Oauth without any luck. My only goal with this script is to get a list of the direct download links. I can do it manually but there are too many files.
Any help would be great.
Thanks.
* EDIT: *
So I this is what I have tried to obtain my token:
I am following this quick start guide:
https://developers.google.com/drive/web/quickstart/quickstart-php
Here is my code
<?php
require_once 'Google/client.php';
require_once 'Google/Service/drive.php';
defined('STDIN') or define('STDIN', fopen('php://stdin', 'r')); //I had to add this part as I was getting an undefined error for STDIN
$client = new Google_Client();
// Get your credentials from the console
$client->setClientId('xxx.apps.googleusercontent.com');
$client->setClientSecret('xxx');
$client->setRedirectUri('http://localhost/test/fetch.php'); //same as registered one
$client->setScopes(array('https://www.googleapis.com/auth/drive'));
$service = new Google_Service_Drive($client);
$authUrl = $client->createAuthUrl();
//Request authorization
print "Please visit:\n$authUrl\n\n";
print "Please enter the auth code:\n";
$authCode = trim(fgets(STDIN));
// Exchange authorization code for access token
$accessToken = $client->authenticate($authCode);
$client->setAccessToken($accessToken);
This results in error
Fatal error: Uncaught exception 'Google_Auth_Exception' with message 'Invalid code' in C:\Apache24\htdocs\test\Google\Auth\OAuth2.php:95 Stack trace: #0 C:\Apache24\htdocs\test\Google\Client.php(135): Google_Auth_OAuth2->authenticate('') #1 C:\Apache24\htdocs\test\new.php(26): Google_Client->authenticate('') #2 {main} thrown in C:\Apache24\htdocs\test\Google\Auth\OAuth2.php on line 95
Any thoughts ?
Thanks.
ANOTHER EDIT
So I have reverted to the old Drive PHP library as the new Drive PHP library has no documentation or examples.
This is my attempt to obtain a token and fetch the direct download file links
require_once 'google-old/google-api-php-client/src/Google_Client.php';
require_once 'google-old/google-api-php-client/src/contrib/Google_DriveService.php';
$client = new Google_Client();
// Get your credentials from the console
$client->setClientId('xx.apps.googleusercontent.com');
$client->setClientSecret('xx');
$client->setRedirectUri('urn:ietf:wg:oauth:2.0:oob');
$client->setScopes(array('https://www.googleapis.com/auth/drive'));
$service = new Google_DriveService($client);
$authUrl = $client->createAuthUrl();
//Request authorization
print "Please visit:\n$authUrl\n\n";
print "Please enter the auth code:\n";
$authCode = trim(fgets(STDIN));
// Exchange authorization code for access token
$accessToken = $client->authenticate($authCode);
$client->setAccessToken($accessToken);
$getAll = retrieveAllFiles($service);
print "<pre>";
print_r($getAll);
print "</pre>";
/**
* Retrieve a list of File resources.
*
* #param Google_DriveService $service Drive API service instance.
* #return Array List of Google_DriveFile resources.
*/
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;
}
The problem I now face is that I am stuck at the "Paste the code into your app" part.
The
$authCode = trim(fgets(STDIN));
doesn't seem to want to execute.
Also I believe the file fetching code will just fetch the file names, and not the direct download links. I could not find an example for this.
Any suggestions would be much appreciated.
Thanks.
I am testing this on my localhost.
Firstly, separate your learning about OAuth from your learning about Drive. As a combined problem, it's hard, but as two separate problems, it's pretty simple.
For OAuth, everything you need to know is on this one web page https://developers.google.com/accounts/docs/OAuth2WebServer
Having read that page and understood it, if you want to use a library to make the calls, go ahead. IMHO the OAuth libraries don't do a great job, but ymmv. With or without a library, it is essential that you understand what is happening.
Having cracked OAuth, you end up with a shiny access_token which you drop into the Drive API, either as an http header if you are calling the rar API, or wrapped in a credential object if you are using one of the libraries.
Replace the STDIN stuff.
put this in instead:
if (!isset($_GET['code'])) {
print "Please visit:\n$authUrl\n\n";
print "Please enter the auth code:\n";
} else { $authCode = ''; }
//$authCode = trim(fgets(STDIN));
$authCode = $_GET['code'];
Google's code is buggy in terms of their thing. Having done so I'm getting file creation (it's still pumping out an error but it's producing the files).
replace their file_get_contents line with:
$data = 'blahblah blah';//file_get_contents('document.txt');
and there you go.
Everyone
I need to upload file to Google Drive via the API, I did exactly what it is mention https://developers.google.com/drive/quickstart-php.
I had generated the access token and saved it in the file, the problem is that it only works for the first time and next time it gives error
OAuth2 token, message: '{ "error" : "invalid_grant" }
We only need to upload files to Google drive (our own account) after getting from the users by form.
I had tried scripts from many tutorial but it didn't seem to work.
I had also tried with offline access permission but still no luck.
Update:
Here it the code that I use to generate access token
require_once APP_PATH.'_includes/google_drive/Google_Client.php';
require_once APP_PATH.'_includes/google_drive/contrib/Google_DriveService.php';
$drive = new Google_Client();
$drive->setClientId('xxxxxxxxxxxxxxxx');
$drive->setClientSecret('xxxxxxxxxxxxxxx');
$drive->setRedirectUri('urn:ietf:wg:oauth:2.0:oob');
$drive->setScopes(array('https://www.googleapis.com/auth/drive'));
$gdrive = new Google_DriveService($drive);
$url = $drive->createAuthUrl();
$authorizationCode = trim(fgets(STDIN));
$token = $drive->authenticate($authorizationCode);
And then I used this code
$drive = new Google_Client();
$drive->setClientId('xxxxxxxxxxx');
$drive->setClientSecret('xxxxxxxxxxxxxxx');
$drive->setRedirectUri('urn:ietf:wg:oauth:2.0:oob');
$drive->setScopes(array('https://www.googleapis.com/auth/drive'));
$gdrive = new Google_DriveService($drive);
$_GET['code']= '4/axxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
file_put_contents('token.json', $drive->authenticate());
$drive->setAccessToken(file_get_contents('token.json'));
$doc = new Google_DriveFile();
$doc->setTitle('Test Document');
$doc->setDescription('Test description');
$doc->setMimeType('text/plain');
$content = file_get_contents('document.txt');
$output = $gdrive->files->insert($doc, array(
'data' => $content,
'mimeType' => 'text/plain',
));
print_r($output);
it works good and but when I run the page again it says
Fatal error: Uncaught exception 'Google_AuthException' with message 'Error fetching OAuth2 access token, message: 'invalid_grant'' in ...Google_OAuth2.php on line 115
any help is appreciated.
Based on #BurcuDogan's comment, commenting out authenticate method resolved the issue.
//file_put_contents('token.json', $drive->authenticate());
I'm starting some development based in Google Drive. Some type of 'Edit in Excel, put it in database'. The problem is: I'm trying to download the file from drive, but I can't get the downloadUrl attribute.
I'm following this page, from Google itself: https://developers.google.com/drive/manage-downloads
It says that I have to get the file metadata and then extract the downloadUrl attribute.
There's something to do with permission? Or some sort of things like that?
EDIT
Here is the code (part of) that I'm using.
First, a function that is showed on Google's page
function downloadFile($service, $file) {
$downloadUrl = $file->getDownloadUrl();
if ($downloadUrl) {
$request = new Google_HttpRequest($downloadUrl, 'GET', null, null);
$httpRequest = Google_Client::$io->authenticatedRequest($request);
if ($httpRequest->getResponseHttpCode() == 200) {
return $httpRequest->getResponseBody();
}
}
}
The rest of the code still as the example:
$client = new Google_Client();
// Get your credentials from the APIs Console
$client->setClientId('xxxxxxxxxxxxxxxxxxx');
$client->setClientSecret('xxxxxxxxxxxxxxxxxxxxxx');
$client->setRedirectUri('urn:ietf:wg:oauth:2.0:oob');
$client->setScopes(array('https://www.googleapis.com/auth/drive'));
$service = new Google_DriveService($client);
$authUrl = $client->createAuthUrl();
//Request authorization
print "Please visit:\n$authUrl\n\n";
print "Please enter the auth code:\n";
$authCode = trim(fgets(STDIN));
// Exchange authorization code for access token
$accessToken = $client->authenticate($authCode);
$client->setAccessToken($accessToken);
//Retrive a file
$file = new Google_DriveFile();
$file->setDownloadUrl("https://www.googleapis.com/drive/v2/files/{fileID}");
$requestedFile = json_decode(downloadFile($service, $file));
print_r($requestedFile);
When printed, I can't see the downloadUrl attribute. Of course, I can't access it too!
Try this code
$service = new Google_Service_Drive($client);
/** #var GuzzleHttp\Psr7\Response $content */
$content = $service->files->get($googleDriveId, ['alt' => 'media']);
I also recommend you use sdk v2, that has integration with guzzle. And this code will return GuzzleHttp\Psr7\Response instead of string.
In my blog I go into detail about how to get the authorization code and then get a directory listing. Each file in the listing has metadata, including the downloadUrl attribute. This is covered in the blog as well here.
I am also trying to download a file but am having a different problem, but you might find it of use here.