Google Drive PHP API returns deleted files - php

I'm trying to sync files between Amazon S3 and Google Drive with a service.
I created a service account and shared a folder with its email.
Then with the automated service I built, I created some folders.
Everything was fine until I tried to delete these folders from Google Drive UI. They disappeared from the UI, but my service still receives them as if they were present.
Here is the code I'm using to list the files/folders:
private function retrieveAllGoogleDriveFiles($service) {
$result = array();
$pageToken = NULL;
do {
try {
$parameters = array();
if ($pageToken) {
$parameters['pageToken'] = $pageToken;
}
$parameters['q'] = "trashed=false";
$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;
}
Here is the authorization mechanism I'm using:
$credentials = new Google_Auth_AssertionCredentials(
'1234567890-somehashvalueshere123123#developer.gserviceaccount.com',
array('https://www.googleapis.com/auth/drive'),
$private_key,
'notasecret',
'http://oauth.net/grant_type/jwt/1.0/bearer'
);
$googleClient = new Google_Client();
$googleClient->setAssertionCredentials($credentials);
if ($googleClient->getAuth()->isAccessTokenExpired()) {
$googleClient->getAuth()->refreshTokenWithAssertion();
}
$googleService = new Google_Service_Drive($googleClient);
$files_list = $this->retrieveAllGoogleDriveFiles($googleService);
The case where a user deletes a file/folder from Google Drive is real to me and I should make the sync back to S3 and remove the file/folder from there also.
Thanks in advance.

When a folder is shared among multiple users, it is the owner who has the ability to delete a folder, not the other users.
Essentially what is happening is by hitting 'remove', the user is removing it from their Drive (unsubscribing), they are not deleting the folder. This is why it appears still appears in your service accounts file list.
One possible solution solution is to do a change owner so the non-service account owns the file. In that case, remove really will be a trash/delete sort of operation. However, without understanding your use case/underlying problem to solve, it is hard to through out solutions. Some of these things may be easier if the users are enterprise/work accounts rather than private/personal accounts.

Related

How to transfer single file to Google Cloud Storage Through Script

So I'll preface this by stating that my boss is asking me to set up a Google Cloud Storage back up process without having the Google Bucket instance or the .json key file for Google Cloud Platform. Basically, I'm writing a script to batch the process to our Linux and Windows instances of Google Cloud Platform machines to take the back up file that will be stored daily, send it to the Google Cloud Storage, then the delete the file from the system (so that the backup file doesn't take up space on the instance). Since all of this is relatively newer to me, I was hoping to get some advice on whether the key (.json private key) is needed for this process and how to include it; obviously, I don't have the key but I want to add a placeholder until we set that up.
I found Google's documentation pretty helpful but a tad overwhelming. Here is the link to what I have used for reference: https://cloud.google.com/storage/docs/uploading-objects#storage-upload-object-code-sample
Here is my code:
<?php
require_once 'vendor/autoload.php';
use Google\Cloud\Storage\StorageClient;
// Set up storage client with keyfilepath or .json key necessary?
// Set the parameters for Google cloud bucket name, filename, and path to file.
$bucketName = "fishbowl-storage";
$fileNameA = "backup_filename";
$fileNameB = "quickbook_filename";
$dataBackupSource = "";
$dataQBBackupSource = "";
// Set the function that will upload the file to google Cloud Storage.
function upload_object($bucketName, $fileName, $source)
{
// Create the storage client and store the file in the cloud.
$storage = new StorageClient();
$file = fopen($source, 'r');
$bucket = $storage->bucket($bucketName);
$file = $bucket->upload($file, [
'name' => $fileName
]);
// Print the success message to the user.
printf('Uploaded %s to gs://%s/%s' . PHP_EOL, basename($source), $bucketName, $fileName);
}
// Check the OS to determine whether Linux or Windows.
if(php_uname('s') == "Linux"){
// Set the file path to grab back up.
$dataBackupSource = "../Fishbowl/backup";
$dataQBBackupSource = "../Fishbowl/otherbackup";
// Use try/catch statement to catch issues with private key.
try{
// run the function to place both backup files in the Google Cloud Storage Bucket instance.
upload_object($bucketName, $fileNameA, $dataBackupSource);
upload_object($bucketName, $fileNameB, $dataQBBackupSource);
// Delete the old file stored in the path.
if(!unlink($fileNameA)){
print ("The file cannot be deleteted or isn't present in this directory...");
}
else{
print ("The file " . $fileNameA . " has been deleted.");
}
}
catch (Exception $e){
print "This process failed for the following reason: " . $e;
return false;
}
}
else if(php_uname('s') == "Windows NT"){
// Set the file path to grab back up.
$dataBackupSource = "../Fishbowl/backup";
$dataQBBackupSource = "../Fishbowl/otherbackup";
// Use try/catch statement to catch issues with private key.
try{
// run the function to place both backup files in the Google Cloud Storage Bucket instance.
upload_object($bucketName, $fileNameA, $dataBackupSource);
upload_object($bucketName, $fileNameB, $dataQBBackupSource);
// Delete the old file stored in the path.
if(!unlink($fileNameA)){
print ("The file cannot be deleteted or isn't present in this directory...");
}
else{
print ("The file " . $fileNameA . " has been deleted.");
}
}
catch (Exception $e){
print "This process failed for the following reason: " . $e;
return false;
}
}
else{
print "The operating system has another name...";
}
?>
TLDR: Do I need the JSON Key to be included in my script to pass a file to the Google Cloud Storage and, if so, where do I put it?
I think that this is the documentation that you are looking for. Basically you need to use the Cloud Client Libraries for the Google Cloud Storage API.These are the steps that you need to follow
1.Installing the client library
composer require google/cloud-storage
2.Setting up authentication. In this step you will create the service account and the Key
After setting the environment variable, you don't need to explicitly specify your credentials in code when using a Google Cloud client library as is mention here
3.Use the Client library. In this case you want to upload a file.
use Google\Cloud\Storage\StorageClient;
/**
* Upload a file.
*
* #param string $bucketName the name of your Google Cloud bucket.
* #param string $objectName the name of the object.
* #param string $source the path to the file to upload.
*
* #return Psr\Http\Message\StreamInterface
*/
function upload_object($bucketName, $objectName, $source)
{
$storage = new StorageClient();
$file = fopen($source, 'r');
$bucket = $storage->bucket($bucketName);
$object = $bucket->upload($file, [
'name' => $objectName
]);
printf('Uploaded %s to gs://%s/%s' . PHP_EOL, basename($source),
$bucketName, $objectName);
}

Google Speech to Text api client return without exception but no actual results

I am using sample code from googles site and this throws no exceptions but returns no results.
If I use the API explorer the same data works just fine. I have tried different files (all from google sample code) different settings. All of which give me the same result, Nothing.
function transcribe_sync($content)
{
// set string as audio content
$audio = (new RecognitionAudio())
->setContent($content);
// set config
$encoding = AudioEncoding::LINEAR16;
$sampleRateHertz = 32000;
$languageCode = 'en-US';
$config = (new RecognitionConfig())
->setEncoding($encoding)
->setSampleRateHertz($sampleRateHertz)
->setAudioChannelCount(1)
->setMaxAlternatives(1)
->setLanguageCode($languageCode);
// create the speech client
$client = new SpeechClient();
try {
$response = $client->recognize($config, $audio);
echo $response->getResults()
}
catch (\Exception $e) {
$this->handleError('Error determining recognition. ' . $e->getMessage());
}
finally {
$client->close();
}
My resolution to this issues was the way I was passing the file (don't think the file was being populated correctly or at all). It was weird that I did not get an error. Because of the length of my audio files, I ended up integrating google storage to upload the file () and used:
$audio = (new RecognitionAudio())->setUri("gs://...");
... longRunningRecognize($config, $audio);
Hope this helps someone.

Xero Create new Tracking Option

I can't seem to get tracking options created, the Category itself is creating fine.
However firstly - I should point out I believe there is a bug in the Xero-API for PHP, when debugging adding an option according to the documentation here the PUT should be
https://api.xero.com/api.xro/2.0/TrackingCategories/{TrackingCategoryID}/Options
However in the php lib it is
https://api.xero.com/api.xro/2.0/TrackingCategories/{TrackingCategoryID}/TrackingOptions
Even when that is resolved, I get no error however not tracking Option is created, any ideas?
$options = ['US', 'UK'];
$title = 'Region';
$trackingCategory = null;
if(!$trackingCategory) {
$trackingCategory = new \XeroPHP\Models\Accounting\TrackingCategory($xero);
$trackingCategory->setName($title);
$trackingCategory->save();
}
try {
foreach($options as $option) {
$to = new \XeroPHP\Models\Accounting\TrackingCategory\TrackingOption($xero);
$to->setName($option);
$trackingCategory->setOption($option);
$trackingCategory->save();
}
} catch(\Exception $e) {
$this->logger()->info($e->getTraceAsString());
$this->logger()->info("TRACKING: ". $e->getMessage());
return false;
}
So this would appear it is a bug as reported here
The source has not been fixed, however the above link resolves the problem for anyone else searching.
Changing TrackingOptions to Options in XeroPHP worked soughta... but I was still getting a different error. Ended up creating the Option manually
Note: $this->_xero_oauth_object is my \XeroPHP\Application\PublicApplication from authentication
// Create the URL object based on an absolute URL
$url = new \XeroPHP\Remote\URL($this->_xero_oauth_object, "https://api.xero.com/api.xro/2.0/TrackingCategories/{TrackCategoryGuid}/Options");
// Pass this to the request as a PUT request
$request = new \XeroPHP\Remote\Request($this->_xero_oauth_object, $url, \XeroPHP\Remote\Request::METHOD_PUT);
// Probably a better way but I just copied and paste the XML from the Xero API docs.
$request->setBody("<Options><Option><Name>My New Option Name</Name></Option></Options>");
// I wrapped this in a try - if it exists, there will be an error as you cant have duplicates.
try {
$request->send();
} catch (Exception $e) {
\Log::warn("Xero error: " . print_r($request->getResponse(), true));
}
// now option is created, new add the option to the tracking category
$tracking = new \XeroPHP\Models\Accounting\TrackingCategory($this->_xero_oauth_object);
$tracking->setTrackingCategoryID('3fceedc7-764e-490a-ac27-25684473af78');
// tracking category name - not sure if I need this
$tracking->setName('Contractor');
// match the option name above
$tracking->setOption('My New Option Name');

File not visible in Drive after API upload and inserting permissions using php

I'm crowbarring the google api into a laravel app.
The file appears to upload correctly but remains invisible in the Drive GUI.
Many searches later and I've got this code to set the permissions of the newly created file:
$id = id of created file
$value = 'my#email.address.com';
$type = "anyone";
$role = "writer";
$drive->insertPermission($id, $value, $type, $role);
function insertPermission($fileId, $value, $type, $role) {
$service = $this->service;
$newPermission = new \Google_Service_Drive_Permission();
$newPermission->setType($type);
$newPermission->setRole($role);
try {
return $service->permissions->create($fileId, $newPermission);
} catch (Exception $e) {
print "An error occurred: " . $e->getMessage();
}
return NULL;
}
This seems to work. No errors are thrown. But I still can't see the file when I search in my drive. Any ideas?
As pushpendra pointed out I need to change
$type="anyone"; to $type="user";
and
$role="writer"; to $role="reader";
Also - in the end I solved this by creating a folder in the drive UI and sharing that folder with the service account. The service account is able to create/update files in that shared folder and I get a notification when it does so.

zend gdata and google spreadsheet not connecting

ive been using Zend Gdata for a while now, and today im getting an error of
Notice: Undefined offset: ClientLogin.php on line 150
via php, this has been working for a while now, and today without changing anything it stopped working, im guessing some deprecated service on behalf of google with the zend gdata maybe the Zend_Gdata_ClientLogin::getHttpClient( ) method or something, can any one confirm or help me with this issue. the code im using to connect is as follows:
require_once('Zend/Loader.php');
Zend_Loader::loadClass('Zend_Gdata');
Zend_Loader::loadClass('Zend_Gdata_ClientLogin');
Zend_Loader::loadClass('Zend_Gdata_Docs');
Zend_Loader::loadClass('Zend_Gdata_Spreadsheets');
require_once 'Zend/Gdata.php';
require_once 'Zend/Gdata/AuthSub.php';
require_once 'Zend/Gdata/Spreadsheets.php';
require_once 'Zend/Gdata/Spreadsheets/DocumentQuery.php';
require_once 'Zend/Gdata/Spreadsheets/ListQuery.php';
require_once 'Zend/Loader.php';
$sourceUser = "myemail";
$sourcePass = "mysuperawesomepassword";
$service = Zend_Gdata_Spreadsheets::AUTH_SERVICE_NAME;
$sourceClient = Zend_Gdata_ClientLogin::getHttpClient($sourceUser, $sourcePass, $service);
$connection = new Zend_Gdata_Spreadsheets($sourceClient);
i am using the zend gdata with the google spreadsheets
also the error points specifically to this line
$sourceClient = Zend_Gdata_ClientLogin::getHttpClient($sourceUser, $sourcePass, $service);
as i said, i was using this for a while now, and nothing has changed on my end
I uses ClientLogin for a server to server application.
needed to switch to oAuth2 in a hurry today. I merged some examples I found to get the authorisation token using a 'Service account'
function get_token() {
$client_email = '0-1.apps.googleusercontent.com';
$client_email = '0-1#developer.gserviceaccount.com';
$private_key = file_get_contents('abc.p12');
$scopes = array('https://spreadsheets.google.com/feeds');
$credentials = new Google_Auth_AssertionCredentials(
$client_email,
$scopes,
$private_key,
'notasecret', // Default P12 password
'http://oauth.net/grant_type/jwt/1.0/bearer' // Default grant type
);
$client = new Google_Client();
$client->setAssertionCredentials($credentials);
if ($client->getAuth()->isAccessTokenExpired()) {
$client->getAuth()->refreshTokenWithAssertion();
}
$tokenData = json_decode($client->getAccessToken());
return $tokenData->access_token;
}
I needed to use the developer email not the app email, same email must be added as a user to the spreadsheet
the generated token can then be used with php-google-spreadsheet-client
$accessToken = get_token();
$serviceRequest = new DefaultServiceRequest($accessToken);
ServiceRequestFactory::setInstance($serviceRequest);
$spreadsheetService = new Google\Spreadsheet\SpreadsheetService();
$spreadsheetFeed = $spreadsheetService->getSpreadsheets();
$spreadsheet = $spreadsheetFeed->getByTitle('Hello World');
In the end I'm ending with something like this(very raw code so far, but enought for those who's seaching for solution. You need php google spreadsheet client of https://github.com/asimlqt/php-google-spreadsheet-client). Thats tiny example of inserting one row to my spreadsheet (sorry about my code, but showing just working example)
Thanks for bram brambring showing better way to authorization - answer by bram brambring
<?php
/*
* Google Spreadsheet class to work with google spreadsheets obviously ;D [using OAuth 2.0, as Zend Gdata is not anymore working]
*/
require_once('/Google/Spreadsheet/ServiceRequestInterface.php');
require_once('/Google/Spreadsheet/DefaultServiceRequest.php');
require_once('/Google/Spreadsheet/ServiceRequestFactory.php');
require_once('/Google/Spreadsheet/Spreadsheet.php');
require_once('/Google/Spreadsheet/SpreadsheetFeed.php');
require_once('/Google/Spreadsheet/SpreadsheetService.php');
require_once('/Google/Spreadsheet/Exception.php');
require_once('/Google/Spreadsheet/UnauthorizedException.php');
require_once('/Google/Spreadsheet/Spreadsheet.php');
require_once('/Google/Spreadsheet/Util.php');
require_once('/Google/Spreadsheet/Worksheet.php');
require_once('/Google/Spreadsheet/WorksheetFeed.php');
require_once('/Google/Spreadsheet/ListFeed.php');
require_once('/Google/Spreadsheet/ListEntry.php');
require_once('/Google/Spreadsheet/CellFeed.php');
require_once('/Google/Spreadsheet/CellEntry.php');
require_once('/Google/Config.php');
require_once('/Google/Client.php');
require_once('/Google/Auth/Abstract.php');
require_once('/Google/Auth/OAuth2.php');
require_once('/Google/Http/Request.php');
require_once('/Google/Utils.php');
require_once('/Google/IO/Abstract.php');
require_once('/Google/IO/Curl.php');
require_once('/Google/Http/CacheParser.php');
require_once('/Google/Logger/Abstract.php');
require_once('/Google/Logger/Null.php');
require_once('/Google/Exception.php');
require_once('/Google/Auth/Exception.php');
require_once('/Google/Auth/AssertionCredentials.php');
require_once('/Google/Cache/Abstract.php');
require_once('/Google/Cache/File.php');
require_once('/Google/Signer/Abstract.php');
require_once('/Google/Signer/P12.php');
use Google\Spreadsheet\DefaultServiceRequest;
use Google\Spreadsheet\ServiceRequestFactory;
class Google_Spreadsheet
{
private $default = array(
'worksheetCols' => 12,
'worksheetRows' => 25
);
private $spreadsheetKey;
private $spreadsheetName;
private $worksheetName;
private $spreadsheetFeed;
public $initialized = true;
public function __construct($spreadsheetKey, $worksheetName, $spreadsheetName = '')
{
$this->spreadsheetKey = $spreadsheetKey;
$this->worksheetName = $worksheetName;
$this->spreadsheetName = $spreadsheetName;
$this->initialized = $this->initialize();
return true;
}
private function getToken() {
$client_email = '318977712937456456454656563tcfjblgoi#developer.gserviceaccount.com';
$private_key = file_get_contents('API Project-f10e456456b60.p12');
$scopes = array('https://spreadsheets.google.com/feeds');
$credentials = new Google_Auth_AssertionCredentials(
$client_email,
$scopes,
$private_key,
'notasecret', // Default P12 password
'http://oauth.net/grant_type/jwt/1.0/bearer' // Default grant type
);
$client = new Google_Client();
$client->setAssertionCredentials($credentials);
if ($client->getAuth()->isAccessTokenExpired()) {
$client->getAuth()->refreshTokenWithAssertion();
}
$tokenData = json_decode($client->getAccessToken());
return $tokenData->access_token;
}
public function initialize(/*$reInitialized = false*/)
{
// load OAuth2 token data - exit if false
$tokenData = $this->getToken();
$serviceRequest = new DefaultServiceRequest($tokenData);
ServiceRequestFactory::setInstance($serviceRequest);
$spreadsheetService = new Google\Spreadsheet\SpreadsheetService();
try {
$spreadsheetFeed = $spreadsheetService->getSpreadsheets();
} catch (\Google\Spreadsheet\UnauthorizedException $e) {
Google_Spreadsheet::warnAdmin($e->getMessage());
return false;
}
$this->spreadsheetFeed = $spreadsheetFeed;
return true;
}
public function insertRow($rowData, $default_fields = array()) {
$spreadsheetFeed = $this->spreadsheetFeed;
$spreadsheet = $this->spreadsheetKey ? $spreadsheetFeed->getByKey($this->spreadsheetKey) : $spreadsheetFeed->getByTitle($this->spreadsheetName);
if(!$spreadsheet && !empty($this->spreadsheetName)) {
$spreadsheet = $spreadsheetFeed->getByTitle($this->spreadsheetName);
}
if(!$spreadsheet) {
Google_Spreadsheet::warnAdmin('No spreadsheet', serialize($rowData));
return false;
}
$worksheetFeed = $spreadsheet->getWorksheets();
$worksheet = $worksheetFeed->getByTitle($this->worksheetName);
if(!$worksheet) {
//create worksheet if not exist
$worksheet = $spreadsheet->addWorksheet($this->worksheetName, $this->default['worksheetRows'], $this->default['worksheetCols']);
$cellFeed = $worksheet->getCellFeed();
for( $i= 1 ; $i <= $this->default['worksheetCols']; $i++ ) {
if(isset($default_fields[$i])) {
$cellFeed->editCell(1, $i, $default_fields[$i]);
}
else {
$cellFeed->editCell(1, $i, "head");
}
$cellFeed->editCell(2,$i,"content");
}
}
if(!$worksheet) {
Google_Spreadsheet::warnAdmin('No worksheet', serialize($rowData));
return false;
}
$listFeed = $worksheet->getListFeed();
$data = array();
foreach ($listFeed->getEntries() as $entry) {
$values = $entry->getValues();
$data[] = $values;
break; //only first row needed, as we need keys
}
$keys = array();
if(!count($data)) {
Google_Spreadsheet::warnAdmin('No data', serialize($rowData));
return false;
}
foreach ($data[0] as $key => $value) {
$keys[] = $key;
}
$newRow = array();
$count = 0;
foreach($keys as $key) {
if(isset($rowData[$count])) {
$newRow["$key"] = $rowData[$count];
}
else {
$newRow["$key"] = '';
}
$count++;
}
$listFeed->insert($newRow);
return true;
}
static function warnAdmin($reason = '', $content = '') {
//temporal function to warn myself about all the stuff happening wrong :)
}
}
And in main model I'm using:
$spreadsheet = new Google_Spreadsheet("spreadsheet name or ID", $worksheetname, "My spreadsheet name");
if(!$spreadsheet->initialized) {
Google_Spreadsheet::warnAdmin('cannot initialize spreadsheet', serialize($rowValues));
}
if(!$spreadsheet->initialized || !$spreadsheet->insertRow($rowValues, $this->default_fields)) {
Google_Spreadsheet::warnAdmin('failed to insert row ');
}
#Edit, thanks to bram brambring for his token solution, seems more easier than my. Working like a charm now, I hope his way it gonna refresh token normally. THANK YOU DUDE!
Been stuck with this issue aswell, seems like google's ClientLogin was finally removed
Important: Do not use ClientLogin for new applications. Instead, use
the more secure OAuth authentication protocol. ClientLogin is a
deprecated authentication protocol and is being turned down on April
20, 2015. At that time, ClientLogin requests will no longer be
answered. If you have existing applications that use ClientLogin, we
encourage you to migrate to OAuth. The ClientLogin support in this
library will be removed in the next major release.
Going to try remake my spreadsheets with OAuth now, this may be the solution: removed cuz no more reputation, will post link into commets
edit; having some troubles with magnetikonline, so gonna try this solution: removed cuz no more reputation, will post link into comments
edit2; /'\ this solution is much better, I must go now, but I've got some success with this library, it works much better as far as I see and provide more functionality, try it.
For your problem with token, try https://github.com/asimlqt/php-google-oauth . THis way also worked for me and its much easier, I reveived array with my token info(if u gonna try that token with second library, ur token gonna be array, while u need only $accessToken['access_token'] part in order to make $serviceRequest = new DefaultServiceRequest($accessToken);
Another big tutorial I found: http://konstantinshkut.com/blog/2014/11/01/how_to_get_data_from_google_spreadsheet_in_yii_php_application (thats for second solution, asimlqt/php-google-spreadsheet-client), step 6 helps a lot to understand how my file must be looking.
I also have had php scripts using Zend for Google Spreadsheets. They have been running great for years, but stopped working today at noon for no reason. What has changed on Google's side and how to easily fix it?
That deprecated ClientLogin, it works again!
It was such a surprise on the eve of the conference Google I / O?
I had to write a self-made solution. Third-party libraries were in basically unusable,
I wrote about 10 methods, I think it is better than the alternatives, which are too complex and cumbersome. You can buy from me))
Not yet ready to put on github)

Categories