How to connect to a Google Drive API and get the AccessToken - php

I'm here with a little problem to connect my script with a Google Drive API using a credentials json file.
This is my code:
$oauth_credentials = __DIR__.'\credentials.json';
$redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
$client = new Google\Client();
$client->setAccessType('offline');
$client->setAuthConfig($oauth_credentials);
$client->setRedirectUri($redirect_uri);
$client->addScope("https://www.googleapis.com/auth/drive");
if (isset($_GET['code'])) {
$token = $client->fetchAccessTokenWithAuthCode($_GET['code']);
var_dump($token);
}
Obviously I used composer to add google apiclient project to my script, and I used the cloud console of google to enable Drive API and create the credentials for this, and I used the credentials.json file downloaded of Google Console.
All is apparently good, I added a test account and used this account to accept permissions to use the Drive API.
Using the playground, in this URL https://developers.google.com/oauthplayground I test my credentials and I get the authorization code to create a refresh token and access token, but when i use this authorization code in my script the result is this: ""
'error' => string 'invalid_grant' (length=13)
'error_description' => string 'Bad Request' (length=11)
Any suggests? this code is exactly like the code appear in the Google examples.

My problem is that the focus is wrong way, I create a service account and generate the json credentials file and I use this code for upload a file:
putenv('GOOGLE_APPLICATION_CREDENTIALS=credentials.json');
$client = new Google_Client();
$client->useApplicationDefaultCredentials();
$client->setScopes(['https://www.googleapis.com/auth/drive.file']);
try {
$service = new Google_Service_Drive($client);
$file_path = 'example.txt';
$file = new Google_Service_Drive_DriveFile();
$file->setName('example.txt');
$file->setParents([$this->folder_id]);
$file->setDescription('Example description text');
$result = $service->files->create($file,[
'data' => file_get_contents($file_path),
'mimeType' => 'text/plain',
'uploadType' => 'text'
]);
echo 'Link to the uploaded file';
}
catch(Google_Service_Exception $gs)
{
$m = json_decode($gs->getMessage());
echo $m->error->message;
}
catch(Exception $e)
{
echo $e->getMessage();
}

Related

How to force Google Drive API to upload files to one specific Drive, instead of that of the user logging in with OAuth?

I've been following a series of tutorials, and my PHP page hosted on XAMPP is able to upload a file to Google Drive using OAuth for authentication. However, I've realised that the application uploads the file to the Drive of whichever user logs in at the OAuth screen. For my project I need the files to always go to the same Drive regardless of who has logged in.
Below is the code for the page.
<?php
require __DIR__ . '/../vendor/autoload.php';
$client = new Google_Client();
// Get your credentials from the console
$client->setClientId('<<CLIENT ID>>');
$client->setClientSecret('<<CLIENT SECRET>>');
$client->setRedirectUri('https://127.0.0.1/Transcode/controller/processInput.php');
$client->setScopes(array('https://www.googleapis.com/auth/drive.file'));
session_start();
if (isset($_GET['code']) || (isset($_SESSION['access_token']) && $_SESSION['access_token'])) {
if (isset($_GET['code'])) {
$client->authenticate($_GET['code']);
$_SESSION['access_token'] = $client->getAccessToken();
} else
$client->setAccessToken($_SESSION['access_token']);
$service = new Google_Service_Drive($client);
//Insert a file
$file = new Google_Service_Drive_DriveFile();
$file->setName(uniqid().'.mkv');
$file->setDescription('A test document');
$file->setMimeType('application/octet-stream');
$data = file_get_contents('../110mb.mkv');
$createdFile = $service->files->create($file, array(
'data' => $data,
'mimeType' => 'application/octet-stream',
'uploadType' => 'multipart'
));
print_r($createdFile);
} else {
$authUrl = $client->createAuthUrl();
header('Location: ' . $authUrl);
exit();
}
?>
I've previously attempted to set this up using a Service Account instead of via OAuth, although I was unable to find examples of how to set this up that I could follow, as I am a beginner as far as the Google APIs are involved.
Essentially, what I'm looking for is a way to force the page to always upload to the same Drive. If this would better be implemented using a Service Account, then examples and links to tutorials would be appreciated.

Connect to Google drive API without user interaction using PHP

I want to upload files to Google Drive using the API, but I need to do this using a cron job (autobackup of webfiles+sql to Google drive).
That means (I suppose) that I need to authenticate using something else than the user interaction method.
The example that I have been using: https://developers.google.com/api-client-library/php/auth/web-app to get me going, and its working with user authenticating.
I would appreciate some tips on how to do this without user interaction, so it can run on a cronjob.
Here are the PHP code for authenticate and upload file (working example with manual user auth and single file upload)
<?php
require_once 'google-api-php-client/vendor/autoload.php';
/* Config */
$servername = 'content here';
$redirect_uri = 'https://example.com/';
$client = new Google_Client();
$client->setAuthConfig('client_manual_authentiation.json');
$client->addScope(Google_Service_Drive::DRIVE);
if(isset($_SESSION['access_token']) && $_SESSION['access_token']) {
$client->setAccessToken($_SESSION['access_token']);
$drive = new Google_Service_Drive($client);
foreach($drive->files->listFiles(array("q" => "name = '{$servername}'"))->getFiles() as $key => $element){
if($element->name == $servername){
//create todays folder on Google Drive
$today_folder_meta = new Google_Service_Drive_DriveFile(array(
'name' => 'myfile.txt',
'mimeType' => 'application/vnd.google-apps.folder',
'parents' => array($element['id'])
));
$today_folder = $drive->files->create($today_folder_meta, array(
'fields' => 'id'
));
}
}
}else{
if (!isset($_GET['code'])) {
$auth_url = $client->createAuthUrl();
header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
} else {
$client->authenticate($_GET['code']);
$_SESSION['access_token'] = $client->getAccessToken();
header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}
}
?>
To do this, you want to create a Google OAuth2 Service Account. You can then download a set of JSON credentials that your app will use to authenticate without user interaction.
This is described in the following article:
Using OAuth 2.0 for Server to Server Applications
https://developers.google.com/identity/protocols/OAuth2ServiceAccount
You will then be able to download credentials like the following to use in your app:
{
"type":"service_account",
"project_id":"your-project-id",
"private_key_id":"deadbeefdeadbeefdeadbeefdeadbeefdeadbeef",
"private_key":"-----BEGIN PRIVATE KEY-----\nMIIEv...4XIk=\n-----END PRIVATE KEY-----\n",
"client_email":"foobar#bazqux.iam.gserviceaccount.com",
"client_id":"12345678901234567890",
"auth_uri":"https://accounts.google.com/o/oauth2/auth",
"token_uri":"https://accounts.google.com/o/oauth2/token",
"auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url":"https://www.googleapis.com/robot/v1/metadata/x509/foobar%40bazqux.iam.gserviceaccount.com"
}
Here is a Google PHP example of how to use this:
https://github.com/google/google-api-php-client/blob/master/examples/service-account.php
You can create the Service Account in the Google API Console as shown here:

Google Drive API - upload and export file

I need to upload a file through Google Drive, and then export it as different format. For example upload DOCX and export it to PDF. I've been following the REST quickstart and the upload files guides. After executing code, I get error:
Fatal error: Uncaught exception 'Google_Service_Exception, "message":
"Insufficient Permission"
It's problem with permissions, but I don't know how to fix it.
Here's the code I use:
date_default_timezone_set('Europe/Sofia');
require_once __DIR__ . '/vendor/autoload.php';
define('APPLICATION_NAME', 'Drive API PHP Quickstart');
define('CREDENTIALS_PATH', '~/.credentials/drive-php-quickstart.json');
define('CLIENT_SECRET_PATH', __DIR__ . '/client_secret.json');
// If modifying these scopes, delete your previously saved credentials
// at ~/.credentials/drive-php-quickstart.json
define('SCOPES', implode(' ', array(
Google_Service_Drive::DRIVE_METADATA_READONLY)
));
//i've tried to change the scope to ::DRIVE, but still get the same error
if (php_sapi_name() != 'cli') {
throw new Exception('This application must be run on the command line.');
}
/**
* Returns an authorized API client.
* #return Google_Client the authorized client object
*/
function getClient() {
$client = new Google_Client();
$client->setApplicationName(APPLICATION_NAME);
$client->setScopes(SCOPES);
$client->setAuthConfig(CLIENT_SECRET_PATH);
$client->setAccessType('offline');
// Load previously authorized credentials from a file.
$credentialsPath = expandHomeDirectory(CREDENTIALS_PATH);
if (file_exists($credentialsPath)) {
$accessToken = json_decode(file_get_contents($credentialsPath), true);
} else {
// Request authorization from the user.
$authUrl = $client->createAuthUrl();
printf("Open the following link in your browser:\n%s\n", $authUrl);
print 'Enter verification code: ';
$authCode = trim(fgets(STDIN));
// Exchange authorization code for an access token.
$accessToken = $client->fetchAccessTokenWithAuthCode($authCode);
// Store the credentials to disk.
if(!file_exists(dirname($credentialsPath))) {
mkdir(dirname($credentialsPath), 0700, true);
}
file_put_contents($credentialsPath, json_encode($accessToken));
printf("Credentials saved to %s\n", $credentialsPath);
}
$client->setAccessToken($accessToken);
// Refresh the token if it's expired.
if ($client->isAccessTokenExpired()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
file_put_contents($credentialsPath, json_encode($client->getAccessToken()));
}
return $client;
}
/**
* Expands the home directory alias '~' to the full path.
* #param string $path the path to expand.
* #return string the expanded path.
*/
function expandHomeDirectory($path) {
$homeDirectory = getenv('HOME');
if (empty($homeDirectory)) {
$homeDirectory = getenv('HOMEDRIVE') . getenv('HOMEPATH');
}
return str_replace('~', realpath($homeDirectory), $path);
}
// Get the API client and construct the service object.
$client = getClient();
$service = new Google_Service_Drive($client);
// Print the names and IDs for up to 10 files.
$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 FILE_ID(%s)\n", $file->getName(), $file->getId());
}
}
//The error I get is in this block:
$fileMetadata = new Google_Service_Drive_DriveFile(array(
'name' => 'photo.jpg'));
$content = file_get_contents('photo.jpg');
$file = $service->files->create($fileMetadata, array(
'data' => $content,
'mimeType' => 'image/jpeg',
'uploadType' => 'multipart',
'fields' => 'id'));
printf("File ID: %s\n", $file->id);
Edit: Forgot to mention that the code works up untill the last block, it lists the files successfully, and then on the last 10 rows throws the error
I got the thing working. I think there was something with the definition of the scopes. BTW I found some examples which were very helpfull HERE
The working code is:
<?php
date_default_timezone_set('Europe/Sofia');
include_once __DIR__ . '/../vendor/autoload.php';
include_once "templates/base.php";
echo pageHeader("File Upload - Uploading a simple file");
/*************************************************
* Ensure you've downloaded your oauth credentials
************************************************/
if (!$oauth_credentials = getOAuthCredentialsFile()) {
echo missingOAuth2CredentialsWarning();
return;
}
/************************************************
* The redirect URI is to the current page, e.g:
* http://localhost:8080/simple-file-upload.php
************************************************/
$redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
$client = new Google_Client();
$client->setAuthConfig($oauth_credentials);
$client->setRedirectUri($redirect_uri);
$client->addScope("https://www.googleapis.com/auth/drive");
$service = new Google_Service_Drive($client);
// add "?logout" to the URL to remove a token from the session
if (isset($_REQUEST['logout'])) {
unset($_SESSION['upload_token']);
}
/************************************************
* If we have a code back from the OAuth 2.0 flow,
* we need to exchange that with the
* Google_Client::fetchAccessTokenWithAuthCode()
* function. We store the resultant access token
* bundle in the session, and redirect to ourself.
************************************************/
if (isset($_GET['code'])) {
$token = $client->fetchAccessTokenWithAuthCode($_GET['code']);
$client->setAccessToken($token);
// store in the session also
$_SESSION['upload_token'] = $token;
// redirect back to the example
header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}
// set the access token as part of the client
if (!empty($_SESSION['upload_token'])) {
$client->setAccessToken($_SESSION['upload_token']);
if ($client->isAccessTokenExpired()) {
unset($_SESSION['upload_token']);
}
} else {
$authUrl = $client->createAuthUrl();
}
/************************************************
* If we're signed in then lets try to upload our
* file. For larger files, see fileupload.php.
************************************************/
if ($_SERVER['REQUEST_METHOD'] == 'POST' && $client->getAccessToken()) {
// CREATE A NEW FILE
$file = new Google_Service_Drive_DriveFile(array(
'name' => 'sample',
'mimeType' => 'application/vnd.google-apps.presentation'
));
$pptx = file_get_contents("sample.docx"); // read power point pptx file
//declare opts params
$optParams = array(
'uploadType' => 'multipart',
'data' => $pptx,
'mimeType' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
);
//import pptx file as a Google Slide presentation
$createdFile = $service->files->create($file, $optParams);
//print google slides id
//print "File id: ".$createdFile->id;
$optParams2 = array(
'fileId' => $createdFile->id,
'mimeType' => 'application/pdf'
);
$response = $service->files->export($createdFile->id, 'application/pdf', array(
'alt' => 'media' ));
//print_r($response);
$content = $response->getBody()->getContents();
///rint_r($content);
$data = $content;
file_put_contents('test_ppt.pdf',$data);
}
?>
<div class="box">
<?php if (isset($authUrl)): ?>
<div class="request">
<a class='login' href='<?= $authUrl ?>'>Connect Me!</a>
</div>
<?php elseif($_SERVER['REQUEST_METHOD'] == 'POST'): ?>
<div class="shortened">
<p>Your call was successful! Check your drive for the following files:</p>
<ul>
</ul>
</div>
<?php else: ?>
<form method="POST">
<input type="submit" value="Click here to upload two small (1MB) test files" />
</form>
<?php endif ?>
</div>
<?= pageFooter(__FILE__) ?>
If you want to convert to other formats, just change the Mime types, following the references: HERE and HERE
Scopes define the scope of access that you request of a user. You have authenticated your code with the following permissions.
Google_Service_Drive::DRIVE_METADATA_READONLY
Which gives you read only access. The following is a list of scopes available to the Google drive api.
https://www.googleapis.com/auth/drive View and manage the files in your Google Drive
https://www.googleapis.com/auth/drive.appdata View and manage its own configuration data in your Google Drive
https://www.googleapis.com/auth/drive.file View and manage Google Drive files and folders that you have opened or created with this app
https://www.googleapis.com/auth/drive.metadata View and manage metadata of files in your Google Drive
https://www.googleapis.com/auth/drive.metadata.readonly View metadata for files in your Google Drive
https://www.googleapis.com/auth/drive.photos.readonly View the photos, videos and albums in your Google Photos
https://www.googleapis.com/auth/drive.readonly View the files in your Google Drive
https://www.googleapis.com/auth/drive.scripts Modify your Google Apps Script scripts' behavior
I would probably go with the first one https://www.googleapis.com/auth/drive.file. I am only guessing here but for PHP it may be something like Google_Service_Drive::DRIVE_FILE

Google Drive API every time asking for authentication code

I'm using google drive api to upload a file to google drive using php, but it every time asking me for authentication code fof my application.
I have followed the steps given in the URL below
https://developers.google.com/drive/web/quickstart/quickstart-php
My Code:
require_once 'src/Google/autoload.php';
$client = new Google_Client();
// Get your credentials from the console
$client->setClientId('clientid');
$client->setClientSecret('clientsecret');
$client->setRedirectUri('url');
$client->setScopes(array('https://www.googleapis.com/auth/drive'));
$service = new Google_Service_Drive($client);
$authUrl = $client->createAuthUrl();
try{
//Request authorization
print "Please visit:<br/>$authUrl<br/>\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);
//Insert a file
$file = new Google_Service_Drive_DriveFile();
$file->setTitle('document.txt');
$file->setDescription('A test document');
$file->setMimeType('text/plain');
$data = file_get_contents('document.txt');
$createdFile = $service->files->insert($file, array(
'data' => $data,
'mimeType' => 'text/plain',
));
print_r($createdFile);
}catch(apiServiceException $e){
echo $e->getMessage();
}
Response :
https://accounts.google.com/o/oauth2/auth?response_type=code&redirect_uri=REDIRECT_URL&client_id=CLIENT_ID&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive&access_type=online&approval_prompt=auto
I have did more debugging for this issue and last i can upload files to google drive using PHP.
But for this we have to authorize the code using manually according to google api
then we will get the refresh token and using that token we can upload file to google drive every time whout asking any key
I have added code here https://rgknowledgebase.wordpress.com/2015/06/05/php-upload-file-to-google-drive/

How to convert RTF document to Google Document?

I have got Google's sample code working with an RTF file my application has created. How can this RTF document be converted to a Google Document?
<?php
require_once 'google-api-php-client/src/Google_Client.php';
require_once 'google-api-php-client/src/contrib/Google_DriveService.php';
$client = new Google_Client();
// Get your credentials from the console
$client->setClientId('xxxxxx');
$client->setClientSecret('xxxxxx');
$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);
//Insert a file
$file = new Google_DriveFile();
$file->setTitle('5.25.14-M02000-Ramin');
$file->setDescription('A test document');
$file->setMimeType('application/rtf');
$data = file_get_contents('5.25.14-M02000-Ramin.rtf');
$createdFile = $service->files->insert($file, array(
'data' => $data,
'mimeType' => 'application/rtf',
));
print_r($createdFile);
?>
You need to send an optional parameter with your request.
convert boolean
Whether to convert this file to the corresponding Google Docs format. (Default: false)
Something like this maybe, but I'm not sure your code is using the old Google API PHP client Lib.
$createdFile = $service->files->insert($file, array(
'data' => $data,
'mimeType' => 'application/rtf',
'convert' => 'true'
));
Note: Yes I know you are following Files: insert example but unfortunately that uses the old Client lib. I have been told they are in the process of updating it. The new Google API PHP client lib can be found on GitHub. There is a file upload example there as well but its very basic. Fileupload.php and doesn't include the convert parameter either.

Categories