Using a oauth2 connection I have a working script (listing documents from Google Drive), I only need to add a download/export function.
Note: access_token / refresh_token are already set (different script)
//error_reporting(E_ALL);
require_once('vendor/autoload.php');
require_once('vendor/google/apiclient/src/Google/Client.php');
require_once('vendor/google/apiclient-services/src/Google/Service/Drive.php');
session_start();
$client_id = '<client_id>';
$client_secret = '<client_secret>';
$redirect_uri = '<redirect_uri>';
$client = new Google_Client();
$client->setApplicationName("Google Calendar");
$client->setClientId($client_id);
$client->setClientSecret($client_secret);
$client->setRedirectUri($redirect_uri);
$client->setAccessType('offline'); // Gets us our refreshtoken
$client->addScope("https://www.googleapis.com/auth/drive");
## Step 1: Set token ##
$array = array(
'access_token' => 'xxxxxxxxxxxxx', //set access token
'token_type' => 'Bearer',
'expires_in' => 0,
'created' => 0,
'refresh_token' => 'xxxxxxxxxxxxx', //set refresh token
);
$_SESSION['token'] = $array;
## Step 2: If token is active, list documents ##
if (isset($_SESSION['token'])) {
$client->setAccessToken($_SESSION['token']);
// Get the API client and construct the service object.
$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 (%s)\n<br>", $file->getName(), $file->getId());
}
}
}
Unfortunately I'm unable to create a direct download link (for non public files). I have found the following documentation but I'm lost on how I can apply this:
https://developers.google.com/drive/v3/reference/files/get
https://developers.google.com/drive/v3/web/manage-downloads
The PHP example from "manage-downloads" results in an error:
Undefined variable: driveService in ... my_drive_script.php
Simply adding a link works, but only for shared documents (or if I'm logged in under the same user).
$fileid = $file->getId();
printf("<a href='https://docs.google.com/document/d/$fileid/export?format=doc'>Download doc</a>");
I have used the link format from http://www.labnol.org/internet/direct-links-for-google-drive/28356/
It should be possible to download non public files, right?
Related
I am working on making some voting collection statistics sheets programmatically. The next step fro me is figuring out how to protect certain cells using the API from being edited. In this example, I actually want to go ahead and protect all of the first three columns. I have been unable to find documentation for this. Any assistance is greatly appreciated.
<?php
/*
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
include_once __DIR__ . '/includes/google/vendor/autoload.php';
$client = getClient();
$service = new Google_Service_Sheets($client);
// TODO: Assign values to desired properties of `requestBody`:
//$requestBody = new Google_Service_Sheets_Spreadsheet();
$spreadsheet = new Google_Service_Sheets_Spreadsheet([
'properties' => [
'title' => 'US Senate 2'
]
]);
$spreadsheet = $service->spreadsheets->create($spreadsheet, [
'fields' => 'spreadsheetId'
]);
$fileId=$spreadsheet->spreadsheetId;
echo $fileId;
// TODO: Change code below to process the `response` object:
echo '<pre>', var_export($spreadsheet, true), '</pre>', "\n";
//Give permissions
/*
$client2 = new \Google_Client();
$client2->setApplicationName('Give permissions');
$client2->setScopes([\Google_Service_Drive::DRIVE]);
$client2->setAccessType('offline');
$client2->setAuthConfig('../credentials.json');
$client2->setPrompt('select_account consent');
$service2 = new Google_Service_Drive($client2);
$newPermission = new Google_Service_Drive_Permission();
$newPermission->setEmailAddress("user#example.com");
$newPermission->setType('user');
$newPermission->setRole('writer');
$fileId=$spreadsheet->spreadsheetId;
$service2->permissions->create($fileId, $newPermission);
*/
//Add data from the dataTables
$client3 = new \Google_Client();
$client3->setApplicationName('Add data from datatables');
$client3->setScopes([\Google_Service_Sheets::SPREADSHEETS]);
$client3->setAccessType('offline');
$client3->setAuthConfig('credentials.json');
$tokenPath = 'token.json';
if (file_exists($tokenPath)) {
$accessToken = json_decode(file_get_contents($tokenPath), true);
$client3->setAccessToken($accessToken);
}
$service3 = new Google_Service_Sheets($client3);
$spreadsheetId = $fileId;
$range = 'Sheet1';
$headers = array(
"Candidate",
"Election",
"Id",
"Votes"
);
$row1[]="Collins";
$row1[]="US Senate";
$row1[]="1010010";
$row1[]="0";
$values = [
$headers,
$row1,
// Additional rows ...
];
$body = new Google_Service_Sheets_ValueRange([
'values' => $values
]);
$params = [
'valueInputOption' => 'RAW'
];
$insert = [
"insertDataOption" => "INSERT_ROWS"
];
$result = $service3->spreadsheets_values->append(
$spreadsheetId,
$range,
$body,
$params,
$insert
);
echo "<a href='https://docs.google.com/spreadsheets/d/".$fileId."' target='_blank'>https://docs.google.com/spreadsheets/d/".$fileId."</a>";
function getClient()
{
$redirect_uri = 'http://localhost:8000/' . $_SERVER['PHP_SELF'];
$client = new Google_Client();
$client->setApplicationName('Google Sheets API PHP Quickstart');
//$client->setScopes(Google_Service_Sheets::SPREADSHEETS_READONLY);
$client->addScope("https://www.googleapis.com/auth/drive");
$client->addScope("https://www.googleapis.com/auth/drive.file");
$client->addScope("https://www.googleapis.com/auth/spreadsheets");
$client->setRedirectUri($redirect_uri);
$client->setAuthConfig('credentials.json');
$client->setAccessType('offline');
$client->setPrompt('select_account consent');
// Load previously authorized token from a file, if it exists.
// The file token.json stores the user's access and refresh tokens, and is
// created automatically when the authorization flow completes for the first
// time.
$tokenPath = 'token.json';
if (file_exists($tokenPath)) {
$accessToken = json_decode(file_get_contents($tokenPath), true);
$client->setAccessToken($accessToken);
}
// If there is no previous token or it's expired.
if ($client->isAccessTokenExpired()) {
// Refresh the token if possible, else fetch a new one.
if ($client->getRefreshToken()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
} 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);
$client->setAccessToken($accessToken);
// Check to see if there was an error.
if (array_key_exists('error', $accessToken)) {
throw new Exception(join(', ', $accessToken));
}
}
// Save the token to a file.
if (!file_exists(dirname($tokenPath))) {
mkdir(dirname($tokenPath), 0700, true);
}
file_put_contents($tokenPath, json_encode($client->getAccessToken()));
}
return $client;
}
I believe your goal and your situation as follows.
You want to protect the columns "A", "B" and "C" of a sheet in Google Spreadsheet using googleapis for php.
You can get and put values for Google Spreadsheet using Sheets API.
Modification point:
In this case, please use "addProtectedRange" with the method of "spreadsheets.batchUpdate" in Sheets API.
Modified script:
$spreadsheetId = "###"; // please set Spreadsheet ID.
$sheetId = "###"; // Please set sheet ID.
$requests = [
new Google_Service_Sheets_Request([
'addProtectedRange' => [
'protectedRange' => [
'range' => [
'sheetId' => $sheetId,
'startRowIndex' => 0,
'startColumnIndex' => 0,
'endColumnIndex' => 3,
],
'description' => 'sample description'
]
]
])
];
$batchUpdateRequest = new Google_Service_Sheets_BatchUpdateSpreadsheetRequest([
'requests' => $requests
]);
$result = $service3->spreadsheets->batchUpdate($spreadsheetId, $batchUpdateRequest);
When above script is run, the columns "A" to "C" of $sheetId in $spreadsheetId are protected.
Note:
$service3 is from your script.
Please set the range as the GridRange. Ref
In above script, the editor is the owner.
Reference:
Method: spreadsheets.batchUpdate
AddProtectedRangeRequest
GridRange
I have problem with creating folder on my google drive by using Google Drive API.
The script successfully display me all files i have on my google drive from this part of code.
// 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.<br>";
} else {
print "Files:<br>";
foreach ($results->getFiles() as $file) {
printf("%s (%s)<br>", $file->getName(), $file->getId());
}
}
but doesn't create folder from this part of code
// Create Test folder
$fileMetadata = new Google_Service_Drive_DriveFile(array(
'name' => 'Test',
'mimeType' => 'application/vnd.google-apps.folder'));
$file = $service->files->create($fileMetadata, array(
'fields' => 'id'));
printf("<br>Folder ID: %s<br>", $file->id);
There is full code of my php script.
<?php
require __DIR__ . '/google-api-php-client/vendor/autoload.php';
function getClient()
{
$client = new Google_Client();
$client->setApplicationName('Test Google Drive API');
$client->setScopes(Google_Service_Drive::DRIVE_METADATA_READONLY);
$client->setAuthConfig('client_secret.json');
// Load previously authorized token from a file, if it exists.
// The file token.json stores the user's access and refresh tokens, and is
// created automatically when the authorization flow completes for the first
// time.
$tokenPath = 'token.json';
if (file_exists($tokenPath)) {
$accessToken = json_decode(file_get_contents($tokenPath), true);
$client->setAccessToken($accessToken);
}
// If there is no previous token or it's expired.
if ($client->isAccessTokenExpired()) {
// Refresh the token if possible, else fetch a new one.
if ($client->getRefreshToken()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
} 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);
$client->setAccessToken($accessToken);
// Check to see if there was an error.
if (array_key_exists('error', $accessToken)) {
throw new Exception(join(', ', $accessToken));
}
}
// Save the token to a file.
if (!file_exists(dirname($tokenPath))) {
mkdir(dirname($tokenPath), 0700, true);
}
file_put_contents($tokenPath, json_encode($client->getAccessToken()));
}
return $client;
}
// 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.<br>";
} else {
print "Files:<br>";
foreach ($results->getFiles() as $file) {
printf("%s (%s)<br>", $file->getName(), $file->getId());
}
}
// Create Test folder
$fileMetadata = new Google_Service_Drive_DriveFile(array(
'name' => 'Test',
'mimeType' => 'application/vnd.google-apps.folder'));
$file = $service->files->create($fileMetadata, array(
'fields' => 'id'));
printf("<br>Folder ID: %s<br>", $file->id);
error: Fatal error: Uncaught exception 'Google_Service_Exception' with message '{ "error": { "errors": [ { "domain": "global", "reason": "insufficientPermissions", "message": "Insufficient Permission: Request had insufficient authentication scopes." } ], "code": 403, "message": "Insufficient Permission: Request had insufficient authentication scopes." } }
Hope on your help. Thanks.
I got oauth2 working - when a user logs into my application, they have to log into their Google account. Then they can make manually sync all events from my website's calendar to their Google Calendar.
BUT, how can I make it so that my server will be able to modify their Google Calendar (add, edit, delete) events without them actually being present at the computer? Because right now, it uses $_SESSION to check if the user is logged into their Google account.
For example, here is how to insert/add an event via API into Google Calendar:
$client = new Google_Client();
$client->setAuthConfig('client_secrets.json');
$client->addScope(Google_Service_Calendar::CALENDAR);
$client->setAccessType("offline");
$service = new Google_Service_Calendar($client);
if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
$event = new Google_Service_Calendar_Event(array(
'summary' => 'Google I/O 2015',
'location' => '800 Howard St., San Francisco, CA 94103',
'description' => 'A chance to hear more about Google\'s developer products.',
'start' => array(
'dateTime' => '2015-05-28T09:00:00-07:00',
'timeZone' => 'America/Los_Angeles',
),
'end' => array(
'dateTime' => '2015-05-28T17:00:00-07:00',
'timeZone' => 'America/Los_Angeles',
),
));
$event = $service->events->insert('primary', $event);
} else {
$redirect_uri = '/oauth.php';
header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
exit();
}
But as you can see, that requires an access_token which is stored in $_SESSION, and if there is no access token, then it will redirect them to login into their Google Account.
How can my server access their Google Calendar account in the background and add/edit/remove events?
You must create "application" in console.developers.google.com and create "authorization credentials" for it.
You will get a json file which you need to use for auth
Read here for more detail https://developers.google.com/api-client-library/php/auth/web-app#creatingcred
You can use this https://github.com/googleapis/google-api-php-client
So edit will look like
include_once 'google.api.php';
$eventId = '010101010101010101010101';
$calendarID='xyxyxyxyxyxyxyxyxy#group.calendar.google.com';
// Get Event for edit
$event = $service->events->get($calendarID, $eventId);
$event->setSummary('New title');
$event->setDescription('New describtion');
$event->setStart(
new Google_Service_Calendar_EventDateTime(['dateTime' => date("c", strtotime("2018-09-20 09:40:00")),'timeZone' => 'Europe/Moscow'])
);
$event->setEnd(
new Google_Service_Calendar_EventDateTime(['dateTime' => date("c", strtotime("2018-09-20 10:40:00")),'timeZone' => 'Europe/Moscow'])
);
$updatedEvent = $service->events->update($calendarID, $eventId, $event);
Where google.api.php will be something like this
require_once __DIR__ .'/vendor/autoload.php';
function getClient()
{
$client = new Google_Client();
$client->setApplicationName('Google Calendar API PHP Quickstart');
$client->setScopes(Google_Service_Calendar::CALENDAR);
$client->setAuthConfig('credentials.json');
$client->setAccessType('offline');
// Load previously authorized credentials from a file.
$credentialsPath = 'token.json';
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;
}
// Get the API client and construct the service object.
$client = getClient();
$service = new Google_Service_Calendar($client);
// Print the next 10 events on the user's calendar.
$calendarId = 'primary';
$optParams = array(
'maxResults' => 10,
'orderBy' => 'startTime',
'singleEvents' => true,
'timeMin' => date('c'),
);
$results = $service->events->listEvents($calendarId, $optParams);
if (empty($results->getItems())) {
print "No upcoming events found.\n";
} else {
print "Upcoming events:\n";
foreach ($results->getItems() as $event) {
$start = $event->start->dateTime;
if (empty($start)) {
$start = $event->start->date;
}
printf("%s (%s)\n", $event->getSummary(), $start);
}
}
I am working on downloading a particular file shared with me in Google Drive. I developed the script to get the list of files and folders in my account. In that folders, I need to get the files list. While trying to do this I am getting the below error,
Notice: Undefined property: Google_Service_Drive::$children
My Code:
$client = new Google_Client();
$client->setApplicationName('Google Drive API');
$client->setScopes(Google_Service_Drive::DRIVE);
$client->setAuthConfig('credentials.json');
$client->setAccessType('offline');
$service = new Google_Service_Drive($client);
$optParams = array(
"pageSize" => 10,
"fields" => "nextPageToken, files(id, name)",
"q" => "sharedWithMe and name contains 'Folder Name'"
);
$results = $service->files->listFiles($optParams);
if (count($results->getFiles()) == 0) {
print "No files found.\n";
} else {
print "Files:\n";
foreach ($results->getFiles() as $files) {
printf("%s (%s)\n", $files->getName(), $files->getId());
$folderId = $files->getId();
$parameters = array();
$children = $service->children->listChildren($folderId, $parameters);
}
}
I need the fileId in the folder, so I can download it.
Let me know if I am missing any scope or anything wrong on my code.
Your suggestions will be very helpful.
Thanks in advance.
i'm using php library google-api-php-client-2.2.0
i'm trying to automate update of a google drive spreadsheet with values each hour by executing php script via crontab
here is how i get my client to work with google drive service
function getClient() {
$client = new Google_Client();
$client->setApplicationName(APPLICATION_NAME);
$client->setScopes(SCOPES);
$client->setAuthConfig(CLIENT_SECRET_PATH);
$client->setAccessType('offline');
$client->setIncludeGrantedScopes(true);
// Load previously authorized credentials from a file.
$credentialsPath = expandHomeDirectory(CREDENTIALS_PATH);
if (file_exists($credentialsPath)) {
$accessToken = json_decode(file_get_contents($credentialsPath), true);
$client->setAccessToken($accessToken);
if ($client->isAccessTokenExpired()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
file_put_contents($credentialsPath, json_encode($client->getAccessToken()));
$accessToken = json_decode(file_get_contents($credentialsPath), true);
$client->setAccessToken($accessToken);
}
}
return $client;
}
and below is a code which searches for the correct google drive file and updates it once found
define('APPLICATION_NAME', 'Drive API PHP Quickstart');
define('CREDENTIALS_PATH', __DIR__ . '/drive-php-quickstart.json');
define('CLIENT_SECRET_PATH', __DIR__ . '/client_secret.json');
define('SCOPES', implode(' ', array(Google_Service_Drive::DRIVE)));
$client = getClient();
$service = new Google_Service_Drive($client);
$optParams = array(
'pageSize' => 10,
'fields' => 'nextPageToken, files(id, name)'
);
$results = $service->files->listFiles($optParams);
$data = get_results_as_string($all); // this is data to be updated with
if (count($results->getFiles()) == 0) {
print "No files found.\n";
}else{
foreach ($results->getFiles() as $file) {
if ($file->getName() == $GOOGLE_SPREADSHEET_NAME){
$fileId = $file->getId();
$emptyFile = new Google_Service_Drive_DriveFile();
$service->files->update($fileId, $emptyFile, array(
'data' => $data,
'mimeType' => 'text/csv',
'uploadType' => 'media',
'fields' => 'id')
);
}
}
}
i expect that when access token i grab from CLIENT_SECRET_PATH file expires - i will fetch (since i have appropriate check for this) new access token from refresh token i have in the same file.
i overwrite the file with what has been fetched and go further with updates and routine.
however this works for around of ~12 hours (i'm running this once per hour) and then stops to be working.
appreciate if you could help on this please
i figured this out, below lines are to look up thru the files:
$optParams = array(
'pageSize' => 10,
'fields' => 'nextPageToken, files(id, name)'
);
default pageSize value which is 10 is way too little. after some time doc ID you're looking for won't be returned within first 10 results. variable is configurable within range [1;1000]
i put 1000 and it has solved the issue for me.