Cannot upload file to google drive using service account - google-drive-api

I am trying to use service account of goolge drive api to upload the file to 'my' central Google Drive.
I get the sample code from the Google drive API, however, when I run the code, exactly, when insert file into drive using Google_DriveService, the Google chrome show that "This webpage is not available".
Here is my php code:
<?php
require_once "google-api-php-client/src/Google_Client.php";
require_once "google-api-php-client/src/contrib/Google_DriveService.php";
require_once "google-api-php-client/src/contrib/Google_Oauth2Service.php";
session_start();
/**
* Build and returns a Drive service object authorized with the service accounts.
*
* #return Google_DriveService service object.
*/
function buildService() {
$DRIVE_SCOPE = 'https://www.googleapis.com/auth/drive';
$SERVICE_ACCOUNT_EMAIL = '<email>#developer.gserviceaccount.com';
$SERVICE_ACCOUNT_PKCS12_FILE_PATH = '<filename>.p12';
$key = file_get_contents($SERVICE_ACCOUNT_PKCS12_FILE_PATH);
$auth = new Google_AssertionCredentials(
$SERVICE_ACCOUNT_EMAIL,
array($DRIVE_SCOPE),
$key);
$client = new Google_Client();
$client->setUseObjects(true);
$client->setAssertionCredentials($auth);
return new Google_DriveService($client);
}
function uploadFile($service, $mime, $src) {
//Insert a file
$file = new Google_DriveFile();
$file->setMimeType($mime);
$data = file_get_contents($src);
try {
//ERROR HERE: cannot insert (upload) file
$createdFile = $service->files->insert($file,
array(
'data' => $data,
'mimeType' => $mime,
'convert' => true,
)
);
return $createdFile;
} catch (Exception $e) {
print "An error occurred: " . $e->getMessage();
}
}
//test upload file to server
$service =buildService();
$mineType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
$path = "toupload.docx";
$file = uploadFile($service,$mineType, $path);
?>

Related

vimeo direct upload form

According to Vimeo it is possible to send the upload directly to their server, without having to use the hosting server of the site.
https://help.vimeo.com/hc/en-us/articles/224970068-Can-I-upload-directly-to-Vimeo-and-skip-my-server-entirely-
With documentation:
https://developer.vimeo.com/api/upload/videos#http-post-uploading
But, I did not find any examples or I could understand how to do this
Resolved
Download API Vimeo: API Vimeo
Load API: File: vimeo_init.php
ini_set('display_errors', 'On');
error_reporting(E_ALL);
// Load the autoloader
if (file_exists('/vimeo/autoload.php')) {
// Composer
require_once('/vimeo/autoload.php');
} else {
// Custom
require_once(__DIR__ . '/vimeo/autoload.php');
}
// Load the configuration file.
if (!function_exists('json_decode')) {
throw new Exception(
'We could not find `json_decode`. `json_decode` is found in PHP 5.2 and up, but not found on many Linux ' .
'systems due to licensing conflicts. If you are running Ubuntu try `sudo apt-get install php5-json`.'
);
}
$config = json_decode(file_get_contents(__DIR__ . '/vimeo_config.json'), true);
if (empty($config['client_id']) || empty($config['client_secret'])) {
throw new Exception(
'We could not locate your client id or client secret in "' . __DIR__ . '/vimeo_config.json". Please create one, ' .
'and reference config.json.example'
);
}
return $config;
Config API KEY: File vimeo_config.json
{
"client_id" : "",
"client_secret" : "",
"access_token" : ""
}
File POST PHP: File Upload Video
use Vimeo\Vimeo;
use Vimeo\Exceptions\VimeoUploadException;
$config = require(__DIR__ . '/vimeo_init.php');
$files = array($_FILES['video_arquivo']['tmp_name']); //array_shift($files);
if (empty($config['access_token'])) {
throw new Exception(
'You can not upload a file without an access token. You can find this token on your app page, or generate ' .
'one using `auth.php`.'
);
}
$lib = new Vimeo($config['client_id'], $config['client_secret'], $config['access_token']);
$uploaded = array();
foreach ($files as $file_name) {
try {
$uri = $lib->upload($file_name, array(
'name' => 'titulo',
'description' => 'descricao'
));
$video_data = $lib->request($uri);
if ($video_data['status'] == 200) {
$video_vimeo = $video_data['body']['link'];
}
$uploaded[] = array('file' => $file_name, 'api_video_uri' => $uri, 'link' => $link);
} catch (VimeoUploadException $e) {
$result["is_valid"] = false;
$result["message"] = $e->getMessage();
}
}

UPS php api - create order

I am trying to integrate UPS php api to generate online order for sending stuff.
I am able to validate address and get rates for stuff transfer but i am not able to find any solution for generating order and labels for courir, can somebody help me in getting that.
UPS Developer Kit and API is quite a good reference to all API related development, including in PHP. It can be downloaded from here: https://www.ups.com/upsdeveloperkit/downloadresource?loc=en_US
Here is some code example, for the PHP ship accept code (from the API zip):
<?php
//Configuration
$access = " Add License Key Here";
$userid = " Add User Id Here";
$passwd = " Add Password Here";
$accessSchemaFile = " Add AccessRequest Schema File";
$requestSchemaFile = " Add ShipAcceptRequest Schema File";
$responseSchemaFile = "Add ShipAcceptResponse Schema File";
$endpointurl = ' Add URL Here';
$outputFileName = "XOLTResult.xml";
try
{
//create AccessRequest data object
$das = SDO_DAS_XML::create("$accessSchemaFile");
$doc = $das->createDocument();
$root = $doc->getRootDataObject();
$root->AccessLicenseNumber=$access;
$root->UserId=$userid;
$root->Password=$passwd;
$security = $das->saveString($doc);
//create ShipAcceptRequest data oject
$das = SDO_DAS_XML::create("$requestSchemaFile");
$requestDO = $das->createDataObject('','RequestType');
$requestDO->RequestAction='01';
//$requestDO->RequestOption='01';
$doc = $das->createDocument();
$root = $doc->getRootDataObject();
$root->Request = $requestDO;
$root->ShipmentDigest = 'test-Invalid-digest';
$request = $das->saveString($doc);
//create Post request
$form = array
(
'http' => array
(
'method' => 'POST',
'header' => 'Content-type: application/x-www-form-urlencoded',
'content' => "$security$request"
)
);
//print form request
print_r($form);
$request = stream_context_create($form);
$browser = fopen($endpointurl , 'rb' , false , $request);
if(!$browser)
{
throw new Exception("Connection failed.");
}
//get response
$response = stream_get_contents($browser);
fclose($browser);
if($response == false)
{
throw new Exception("Bad data.");
}
else
{
//save request and response to file
$fw = fopen($outputFileName,'w');
fwrite($fw , "Response: \n" . $response . "\n");
fclose($fw);
//get response status
$resp = new SimpleXMLElement($response);
echo $resp->Response->ResponseStatusDescription . "\n";
}
}
catch(SDOException $sdo)
{
echo $sdo;
}
catch(Exception $ex)
{
echo $ex;
}
?>

How can I see hidden app data in Google Drive?

I have an Android app that stores my notes in hidden app data. I want to export my notes so the question is simple:
How can I access the hidden app data in Google Drive for a specific app?
Indeed, Google does not let you access this hidden app-data folder directly.
But, if you can get your hands on the app's client ID/client secret/digital signature that is used for authentication against Google's servers - then yes, you can basically emulate the app and access the hidden data in your Google Drive using the Drive API.
How it works in Android
Usually, when an android application wants to access a Google API (such as Drive, Games or Google Sign-In - not all are supported) it communicates with the Google Play services client library, which in turn obtains an access token from Google on behalf of the app. This access token is then sent with each request to the API, so that Google knows who is using it and what he is allowed to do with your account (OAuth 2.0). In order to get this access token for the first time, the Google Play service sends an HTTPS POST request to android.clients.google.com/auth with these fields (along with other details):
Token - a "master token" which identifies the Google account and basically allows full access to it
app - the application package name, such as com.whatsapp
client_sig - the application's digital signature (sent as SHA1)
device - the device's Android ID
service - the scopes (permissions) that the app wants to have
So before we can start using the Drive API in the name of a specific app, we need to know its signature and our account's master token. Fortunately, the signature can be easily extracted from the .apk file:
shell> unzip whatsapp.apk META-INF/*
Archive: whatsapp.apk
inflating: META-INF/MANIFEST.MF
inflating: META-INF/WHATSAPP.SF
inflating: META-INF/WHATSAPP.DSA
shell> cd META-INF
shell> keytool -printcert -file WHATSAPP.DSA # can be CERT.RSA or similar
.....
Certificate fingerprints:
SHA1: 38:A0:F7:D5:05:FE:18:FE:C6:4F:BF:34:3E:CA:AA:F3:10:DB:D7:99
Signature algorithm name: SHA1withDSA
Version: 3
The next thing we need is the master token. This special token is normally received and stored on the device when a new google account is added (for example, when first setting up the phone), by making a similar request to the same URL. The difference is that now the app that's asking for permissions is the Play services app itself (com.google.android.gms), and Google is also given additional Email and Passwd parameters to log in with. If the request is successful, we will get back our master token, which could then be added to the user's app request.
You can read this blogpost for more detailed information about the authentication process.
Putting it all together
Now, we can write a code for authentication using these two HTTP requests directly - a code that can browse any app's files with any Google account. Just choose your favorite programming language and client library. I found it easier with PHP:
require __DIR__ . '/vendor/autoload.php'; // Google Drive API
// HTTPS Authentication
$masterToken = getMasterTokenForAccount("your_username#gmail.com", "your_password");
$appSignature = '38a0f7d505fe18fec64fbf343ecaaaf310dbd799';
$appID = 'com.whatsapp';
$accessToken = getGoogleDriveAccessToken($masterToken, $appID, $appSignature);
if ($accessToken === false) return;
// Initializing the Google Drive Client
$client = new Google_Client();
$client->setAccessToken($accessToken);
$client->addScope(Google_Service_Drive::DRIVE_APPDATA);
$client->addScope(Google_Service_Drive::DRIVE_FILE);
$client->setClientId(""); // client id and client secret can be left blank
$client->setClientSecret(""); // because we're faking an android client
$service = new Google_Service_Drive($client);
// Print the names and IDs for up to 10 files.
$optParams = array(
'spaces' => 'appDataFolder',
'fields' => 'nextPageToken, files(id, name)',
'pageSize' => 10
);
$results = $service->files->listFiles($optParams);
if (count($results->getFiles()) == 0)
{
print "No files found.\n";
}
else
{
print "Files:\n";
foreach ($results->getFiles() as $file)
{
print $file->getName() . " (" . $file->getId() . ")\n";
}
}
/*
$fileId = '1kTFG5TmgIGTPJuVynWfhkXxLPgz32QnPJCe5jxL8dTn0';
$content = $service->files->get($fileId, array('alt' => 'media' ));
echo var_dump($content);
*/
function getGoogleDriveAccessToken($masterToken, $appIdentifier, $appSignature)
{
if ($masterToken === false) return false;
$url = 'https://android.clients.google.com/auth';
$deviceID = '0000000000000000';
$requestedService = 'oauth2:https://www.googleapis.com/auth/drive.appdata https://www.googleapis.com/auth/drive.file';
$data = array('Token' => $masterToken, 'app' => $appIdentifier, 'client_sig' => $appSignature, 'device' => $deviceID, 'google_play_services_version' => '8703000', 'service' => $requestedService, 'has_permission' => '1');
$options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\nConnection: close",
'method' => 'POST',
'content' => http_build_query($data),
'ignore_errors' => TRUE,
'protocol_version'=>'1.1',
//'proxy' => 'tcp://127.0.0.1:8080', // optional proxy for debugging
//'request_fulluri' => true
)
);
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
if (strpos($http_response_header[0], '200 OK') === false)
{
/* Handle error */
print 'An error occured while requesting an access token: ' . $result . "\r\n";
return false;
}
$startsAt = strpos($result, "Auth=") + strlen("Auth=");
$endsAt = strpos($result, "\n", $startsAt);
$accessToken = substr($result, $startsAt, $endsAt - $startsAt);
return "{\"access_token\":\"" . $accessToken . "\", \"refresh_token\":\"TOKEN\", \"token_type\":\"Bearer\", \"expires_in\":360000, \"id_token\":\"TOKEN\", \"created\":" . time() . "}";
}
function getMasterTokenForAccount($email, $password)
{
$url = 'https://android.clients.google.com/auth';
$deviceID = '0000000000000000';
$data = array('Email' => $email, 'Passwd' => $password, 'app' => 'com.google.android.gms', 'client_sig' => '38918a453d07199354f8b19af05ec6562ced5788', 'parentAndroidId' => $deviceID);
$options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\nConnection: close",
'method' => 'POST',
'content' => http_build_query($data),
'ignore_errors' => TRUE,
'protocol_version'=>'1.1',
//'proxy' => 'tcp://127.0.0.1:8080', // optional proxy for debugging
//'request_fulluri' => true
)
);
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
if (strpos($http_response_header[0], '200 OK') === false)
{
/* Handle error */
print 'An error occured while trying to log in: ' . $result . "\r\n";
return false;
}
$startsAt = strpos($result, "Token=") + strlen("Token=");
$endsAt = strpos($result, "\n", $startsAt);
$token = substr($result, $startsAt, $endsAt - $startsAt);
return $token;
}
And finally, the results -
Files:
gdrive_file_map (1d9QxgC3p4PTXRm_fkAY0OOuTGAckykmDfFls5bAyE1rp)
Databases/msgstore.db.crypt9 (1kTFG5TmgIGTPJuVynWfhkXxLPgz32QnPJCe5jxL8dTn0)
16467702039-invisible (1yHFaxfmuB5xRQHLyRfKlUCVZDkgT1zkcbNWoOuyv1WAR)
Done.
NOTE: This is an unofficial, hacky solution, and so it might have a few problems. For example, the access token is alive only for one hour, after which it won't be refreshed automatically.
A working example as of September 2020
Note: this is actually an addition for Tomer's answer
Things changed since Tomer's original answer was posted.
Currently, to get the master token and avoid the Error=BadAuthentication, you need two things:
Replace Passwd field with EncryptedPasswd and encrypt its value by RSA with google public key (the exact technique was reversed by some guy) - this can be done using phpseclib.
Make HTTPS connection to Google server with the same SSL/TLS options as in one of the supported Android systems. This includes TLS versions and exact list of supported ciphers in right order. If you change the order or add/remove ciphers you'll get Error=BadAuthentication. It took me a whole day to figure this out...
Luckily, PHP >=7.2 comes with openssl-1.1.1 that has all the necessary ciphers to emulate Android 10 client.
So here is rewriten getMasterTokenForAccount() function that sets the ciphers and uses EncryptedPasswd instead of plain Passwd. And below is encryptPasswordWithGoogleKey() implementation that does the encryption.
phpseclib is necessary and can be installed with composer: composer require phpseclib/phpseclib:~2.0
function getMasterTokenForAccount($email, $password)
{
$url = 'https://android.clients.google.com/auth';
$deviceID = '0000000000000000';
$data = array('Email' => $email, 'EncryptedPasswd' => encryptPasswordWithGoogleKey($email, $password), 'app' => 'com.google.android.gms', 'client_sig' => '38918a453d07199354f8b19af05ec6562ced5788', 'parentAndroidId' => $deviceID);
$options = array(
'ssl' => array(
'ciphers' => 'TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:ECDHE+AESGCM:ECDHE+CHACHA20:DHE+AESGCM:DHE+CHACHA20:ECDH+AESGCM:DH+AESGCM:ECDH+AES:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!eNULL:!MD5:!DSS'),
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\nConnection: close",
'method' => 'POST',
'content' => http_build_query($data),
'ignore_errors' => TRUE,
'protocol_version'=>'1.1',
//'proxy' => 'tcp://127.0.0.1:8080', // optional proxy for debugging
//'request_fulluri' => true
)
);
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
if (strpos($http_response_header[0], '200 OK') === false)
{
/* Handle error */
print 'An error occured while trying to log in: ' . $result . "\r\n";
return false;
}
$startsAt = strpos($result, "Token=") + strlen("Token=");
$endsAt = strpos($result, "\n", $startsAt);
$token = substr($result, $startsAt, $endsAt - $startsAt);
return $token;
}
function encryptPasswordWithGoogleKey($email, $password)
{
define('GOOGLE_KEY_B64', 'AAAAgMom/1a/v0lblO2Ubrt60J2gcuXSljGFQXgcyZWveWLEwo6prwgi3iJIZdodyhKZQrNWp5nKJ3srRXcUW+F1BD3baEVGcmEgqaLZUNBjm057pKRI16kB0YppeGx5qIQ5QjKzsR8ETQbKLNWgRY0QRNVz34kMJR3P/LgHax/6rmf5AAAAAwEAAQ==');
$google_key_bin = base64_decode(GOOGLE_KEY_B64);
$modulus_len = unpack('Nl', $google_key_bin)['l'];
$modulus_bin = substr($google_key_bin, 4, $modulus_len);
$exponent_len = unpack('Nl', substr($google_key_bin, 4 + $modulus_len, 4))['l'];
$exponent_bin = substr($google_key_bin, 4 + $modulus_len + 4, $exponent_len);
$modulus = new phpseclib\Math\BigInteger($modulus_bin, 256);
$exponent = new phpseclib\Math\BigInteger($exponent_bin, 256);
$rsa = new phpseclib\Crypt\RSA();
$rsa->loadKey(['n' => $modulus, 'e' => $exponent], phpseclib\Crypt\RSA::PUBLIC_FORMAT_RAW);
$rsa->setEncryptionMode(phpseclib\Crypt\RSA::ENCRYPTION_OAEP);
$rsa->setHash('sha1');
$rsa->setMGFHash('sha1');
$encrypted = $rsa->encrypt("{$email}\x00{$password}");
$hash = substr(sha1($google_key_bin, true), 0, 4);
return strtr(base64_encode("\x00{$hash}{$encrypted}"), '+/', '-_');
}
The user cannot directly access data in the hidden app folders, only the app can access them. This is designed for configuration or other hidden data that the user should not directly manipulate. (The user can choose to delete the data to free up the space used by it.)
The only way the user can get access to it is via some functionality exposed by the specific app.
public void retrieveContents(DriveFile file) {
Task<DriveContents> openFileTask =
getDriveResourceClient().openFile(file, DriveFile.MODE_READ_ONLY);
openFileTask.continueWithTask(new Continuation<DriveContents, Task<Void>>() {
#Override
public Task<Void> then(#NonNull Task<DriveContents> task) throws Exception {
DriveContents contents = task.getResult();
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(contents.getInputStream()))) {
StringBuilder builder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
builder.append(line).append("\n");
}
Log.e("result ", builder.toString());
}
Task<Void> discardTask = MainActivity.this.getDriveResourceClient().discardContents(contents);
// [END drive_android_discard_contents]
return discardTask;
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
}
});
}
public void retrieveContents(DriveFile file) {
Task<DriveContents> openFileTask =
getDriveResourceClient().openFile(file, DriveFile.MODE_READ_ONLY);
openFileTask.continueWithTask(new Continuation<DriveContents, Task<Void>>() {
#Override
public Task<Void> then(#NonNull Task<DriveContents> task) throws Exception {
DriveContents contents = task.getResult();
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(contents.getInputStream()))) {
StringBuilder builder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
builder.append(line).append("\n");
}
Log.e("result ", builder.toString());
}
Task<Void> discardTask = MainActivity.this.getDriveResourceClient().discardContents(contents);
// [END drive_android_discard_contents]
return discardTask;
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
}
});
}
to get all the file in app data try the code
private void listFiles() {
Query query =
new Query.Builder()
.addFilter(Filters.or(Filters.eq(SearchableField.MIME_TYPE, "text/html"),
Filters.eq(SearchableField.MIME_TYPE, "text/plain")))
.build();
getDriveResourceClient()
.query(query)
.addOnSuccessListener(this,
new OnSuccessListener<MetadataBuffer>() {
#Override
public void onSuccess(MetadataBuffer metadataBuffer) {
//mResultsAdapter.append(metadataBuffer);
for (int i = 0; i <metadataBuffer.getCount() ; i++) {
retrieveContents(metadataBuffer.get(i).getDriveId().asDriveFile());
}
}
}
)
.addOnFailureListener(this, new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.e(TAG, "Error retrieving files", e);
MainActivity.this.finish();
}
});
}
also you can download the content of file bye the following code
public void retrieveContents(DriveFile file) {
Task<DriveContents> openFileTask =
getDriveResourceClient().openFile(file, DriveFile.MODE_READ_ONLY);
openFileTask.continueWithTask(new Continuation<DriveContents, Task<Void>>() {
#Override
public Task<Void> then(#NonNull Task<DriveContents> task) throws Exception {
DriveContents contents = task.getResult();
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(contents.getInputStream()))) {
StringBuilder builder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
builder.append(line).append("\n");
}
Log.e("result ", builder.toString());
}
Task<Void> discardTask = MainActivity.this.getDriveResourceClient().discardContents(contents);
// [END drive_android_discard_contents]
return discardTask;
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
}
});
}

How can I get a list of all the files I have in my Google Drive using PHP?

I want to list all the files from my Google drive using my "DriveFiles.php" file where I can display the files and its details.
I am a beginner so a complete code will be helpful.
Thanks.
My code:
<?php
require_once 'google-api-php-client/src/Google_Client.php';
require_once 'google-api-php-client/src/contrib/Google_DriveService.php';
require_once 'google-api-php-client/src/io/Google_HttpRequest.php';
require_once 'google-api-php-client/src/contrib/Google_Oauth2Service.php';
// initialize a client with application credentials and required scopes.
$client = new Google_Client();
$client->setClientId('CLIENT_ID');
$client->setClientSecret('CLIENT_SECRET');
$client->setRedirectUri('REDIRECT_URI');
$client->setScopes(array(
'https://www.googleapis.com/auth/drive',
'https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/userinfo.profile'));
$client->setUseObjects(true);
if (isset($_GET['code'])) {
session_start();
print_r($_SESSION);
$client->authenticate($_GET['code']);
$_SESSION['token'] = $client->getAccessToken();
$client->setAccessToken($_SESSION['token']);
// initialize the drive service with the client.
$services = new Google_DriveService($client);
retrieveAllFiles($services);
}
if(!$client->getAccessToken()){
$authUrl = $client->createAuthUrl();
echo '<a class="login" href="'.$authUrl.'">Login</a>';
}
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;
}
?>
When i execute i get an error :
Fatal error: Uncaught exception 'Google_Exception' with message 'Cant add services after having authenticated' in D:\GT_local\Public\google-api-php-client\src\Google_Client.php:115 Stack trace: #0 D:\GT_local\Public\google-api-php-client\src\contrib\Google_DriveService.php(1258): Google_Client->addService('drive', 'v2') #1 D:\GT_local\Public\quickstart.php(55): Google_DriveService->__construct(Object(Google_Client)) #2 {main} thrown in "FILE_LOCATION(C://google-api-php-client\src\Google_Client.php on line 115)"
WHAT SHOULD I DO?
files.list docs contain a working sample with pagination: You can use DrEdit as a boilerplate project.

How to move files and folders using google drive API?

I am trying to use Google drive API to carry out simple tasks like
Moving files across folders.
List item
Moving folders.
As far as I could find Google drive API does not provide a way to move files across folders.
With /parent and /children API parent folder of a file can be specified but it does not work for a folder. Moreover the parent attribute associated with a file does not move it under that folder. It just associates a parent attribute with the file(which is not at all useful for my case)
Drive API V3 has this:
Moving files between folders
To add or remove parents for an existing file, use the addParents and removeParents query parameters on the files.update method.
Both parameters may be used to move a file from one folder to another:
https://developers.google.com/drive/v3/web/folder#inserting_a_file_in_a_folder
To move FILE-A from FOLDER-1 to FOLDER-2, you can use the delete and add calls at https://developers.google.com/drive/v2/reference/parents to remove FOLDER-1 as a parent and add FOLDER-2.
You can also do a Patch on the file with the updated parents array.
Here is the one step method to move file to the new folder using Patch and the PHP client library:
/**
* Move a file.
*
* #param Google_Service_Drive_DriveFile $service Drive API service instance.
* #param string $fileId ID of the file to move.
* #param string $newParentId Id of the folder to move to.
* #return Google_Service_Drive_DriveFile The updated file. NULL is returned if an API error occurred.
*/
function moveFile($service, $fileId, $newParentId) {
try {
$file = new Google_Service_Drive_DriveFile();
$parent = new Google_Service_Drive_ParentReference();
$parent->setId($newParentId);
$file->setParents(array($parent));
$updatedFile = $service->files->patch($fileId, $file);
return $updatedFile;
} catch (Exception $e) {
print "An error occurred: " . $e->getMessage();
}
}
Update: If you want to use Drive API v3, use below code documented here:
/**
* Move a file.
*
* #param Google_Service_Drive_DriveFile $service Drive API service instance.
* #param string $fileId ID of the file to move.
* #param string $newParentId Id of the folder to move to.
* #return Google_Service_Drive_DriveFile The updated file. NULL is returned if an API error occurred.
*/
function moveFile($service, $fileId, $newParentId) {
try {
$emptyFileMetadata = new Google_Service_Drive_DriveFile();
// Retrieve the existing parents to remove
$file = $service->files->get($fileId, array('fields' => 'parents'));
$previousParents = join(',', $file->parents);
// Move the file to the new folder
$file = $service->files->update($fileId, $emptyFileMetadata, array(
'addParents' => $newParentId,
'removeParents' => $previousParents,
'fields' => 'id, parents'));
return $file;
} catch (Exception $e) {
print "An error occurred: " . $e->getMessage();
}
}
You can actually still do it in one step really just set the request as so in Javascript:
Body must have:
body.parents = [{ 'id': parentId }];
Request should be:
var request = gapi.client.request({
'path': 'drive/v2/files/'+fileId,
'method': 'PUT',
'params': {'uploadType': 'multipart', 'alt': 'json'},
'headers': {
'Authorization': TOKEN
},
'body': body
});
And then to execute:
request.execute(function(resp) { });
This sample code uses Google Drive API v3.
Gfk = Google File Key ( can be the id of either a file or a folder ).
Methods:
moveTo | Moves a file/folder from its first parent folder to a given destination folder. The file/folder gets removed from its original first parent folder;
addParents and removeParents | Only adds or removes one or move parents. addParents does NOT remove any original parent, only adds.
class Gfiles {
private $service;
public function setService(\Google_Client $client) : self {
$this->service = (new \Google_Service_Drive($client))->files;
return $this;
}
public function moveTo(string $gfk, string $to_gfk) : \Google_Service_Drive_DriveFile {
$body = new \Google_Service_Drive_DriveFile();
// Gets the first parent. You should further implement this if you wish a different behaviour.
$from_gfk = $this->service->get($gfk, ['fields' => 'parents'])->parents[0];
$this->service->update($gfk, $body, ['addParents' => $to_gfk]);
$this->service->update($gfk, $body, ['removeParents' => $from_gfk]);
return $this->service->get($gfk, ['fields' => 'parents']);
}
/**
* $parents_gfk expects an array like ['gfk parent 1', 'gfk parent 2'].
*/
private function updateParents(string $method, string $gfk, array $parents_gfk) : \Google_Service_Drive_DriveFile {
$body = new \Google_Service_Drive_DriveFile();
$parents = join(',', $parents_gfk);
$this->service->update($gfk, $body, [$method => $parents]);
return $this->service->get($gfk, ['fields' => 'parents']);
}
public function addParents(string $gfk, array $parents_gfk) : \Google_Service_Drive_DriveFile {
return $this->updateParents('addParents', $gfk, $parents_gfk);
}
public function removeParents(string $gfk, array $parents_gfk) : \Google_Service_Drive_DriveFile {
return $this->updateParents('removeParents', $gfk, $parents_gfk);
}
}
I have used this code:
File file = driveService.files().get(fileId).execute()
File targetFolder = driveService.files().get(folderId).execute()
ParentReference newParent = new ParentReference()
newParent.setSelfLink(targetFolder.getSelfLink())
newParent.setParentLink(targetFolder.parents[0].getSelfLink())
newParent.setId(folderId)
newParent.setKind(targetFolder.getKind())
newParent.setIsRoot(false)
def parentsList = new ArrayList<ParentReference>()
parentsList.add(newParent)
file.setParents(parentsList)
File updatedFile = driveService.files().update(fileId, file).execute()