403 : Insufficient Permission while creating an folder in google drive api php - php

I'm implementing google drive api to implement in my application. I did that all code configuration from google-drive-client-php documentation. But I got an this permission error. Please give me any hint for this:
$client = new Google_Client();
$client->setAuthConfig('client_secrets.json');
$client->setAccessType("offline");
$client->setScopes("https://www.googleapis.com/auth/drive");
if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
$client->setAccessToken($_SESSION['access_token']);
$drive = new Google_Service_Drive($client);
$fileMetaData = new Google_Service_Drive_DriveFile(array(
'name' => 'RootFolder',
'mimeType' => 'application/vnd.google-apps.folder'));
$parentFolder = $drive->files->create($fileMetaData, array(
'fields' => 'id'
));
$permission = new Google_Service_Drive_Permission();
$permission->setValue('me');
$permission->setType('anyone');
$permission->setRole('writer');
$drive->permissions->insert($parentFolder->getId(), $permission);
echo "<pre>";
echo json_encode($parentFolder);
} else {
$redirect_uri = 'https://' . $_SERVER['HTTP_HOST'] . '/callback.php';
header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}
Thank u :)

so you are requesting ...
$client->addScope(Google_Service_Drive::DRIVE_METADATA_READONLY);
while you actually might require ...
$client->addScope(Google_Service_Drive::DRIVE);
for reference, here's the mapping of the API scopes:
/** View and manage the files in your Google Drive. */
const DRIVE = "https://www.googleapis.com/auth/drive";
/** View and manage its own configuration data in your Google Drive. */
const DRIVE_APPDATA = "https://www.googleapis.com/auth/drive.appdata";
/** View and manage Google Drive files and folders that you have opened or created with this app. */
const DRIVE_FILE = "https://www.googleapis.com/auth/drive.file";
/** View and manage metadata of files in your Google Drive. */
const DRIVE_METADATA = "https://www.googleapis.com/auth/drive.metadata";
/** View metadata for files in your Google Drive. */
const DRIVE_METADATA_READONLY = "https://www.googleapis.com/auth/drive.metadata.readonly";
/** View the photos, videos and albums in your Google Photos. */
const DRIVE_PHOTOS_READONLY = "https://www.googleapis.com/auth/drive.photos.readonly";
/** View the files in your Google Drive. */
const DRIVE_READONLY = "https://www.googleapis.com/auth/drive.readonly";
/** Modify your Google Apps Script scripts' behavior. */
const DRIVE_SCRIPTS = "https://www.googleapis.com/auth/drive.scripts";

I got an solution for my problem
Remove
$permission->setValue('me');
and change this Permission method to
$drive->permissions->insert($parentFolder->getId(), $permission);
To
$drive->files->create($fileMetaData, array('fields' => 'id'));
Here in the google drive api insert an setValue() method is deprecated so it was not work.

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.

How to upload to google drive with service account and php

Down you can see my code and it uploads files to my google drive. Now I am trying to use service account to let the people to upload files to my Google drive without their google accounts (Visitors will submit html form with their file and my app will upload that file to my drive ). But I am stuck with it. Can not find even just one working example. Any ideas?
$client = new Google\Client();
$client->setAuthConfig('credentials.json');
$client->addScope(Google\Service\Drive::DRIVE);
$redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
$client->setRedirectUri($redirect_uri);
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));
}
if (!empty($_SESSION['upload_token'])) {
$client->setAccessToken($_SESSION['upload_token']);
if ($client->isAccessTokenExpired()) {
unset($_SESSION['upload_token']);
}
} else {
$authUrl = $client->createAuthUrl();
}
echo $client->getAccessToken();
if ($_SERVER['REQUEST_METHOD'] == 'GET' && $client->getAccessToken()) {
// We'll setup an empty 1MB file to upload.
DEFINE("TESTFILE", 'test.jpg');
if (!file_exists(TESTFILE)) {
$fh = fopen(TESTFILE, 'w');
fseek($fh, 1024 * 1024);
fwrite($fh, "!", 1);
fclose($fh);
}
// This is uploading a file directly, with no metadata associated.
$file = new Google\Service\Drive\DriveFile();
$service = new Google_Service_Drive($client);
$file->setName("Hello World!");
$result = $service->files->create(
$file,
[
'data' => file_get_contents(TESTFILE),
'mimeType' => 'application/octet-stream',
'uploadType' => 'media'
]
);
$permissionService = new Google_Service_Drive_Permission();
$permissionService->role = "reader";
$permissionService->type = "anyone"; // anyone with the link can view the file
$service->permissions->create($result->id, $permissionService);
The following code will show you how to set up service account authorization.
Remember though the files will be uploaded to the service accounts drive account. If you want them uploaded to your personal drive account. You need to share a directory on your drive account with the service account. You do that though the web app like you would any other user, using the service account email address. Its the property that looks like an email.
You should just be able to remove the auth you have now and then use this. You will however need set the parents in the upload metadata to be that of that directory you want the fill uploaded to.
// Load the Google API PHP Client Library.
require_once __DIR__ . '/vendor/autoload.php';
// Use the developers console and download your service account
// credentials in JSON format. Place the file in this directory or
// change the key file location if necessary.
putenv('GOOGLE_APPLICATION_CREDENTIALS='.__DIR__.'/service-account.json');
/**
* Gets the Google client refreshing auth if needed.
* Documentation: https://developers.google.com/identity/protocols/OAuth2ServiceAccount
* Initializes a client object.
* #return A google client object.
*/
function getGoogleClient() {
return getServiceAccountClient();
}
/**
* Builds the Google client object.
* Documentation: https://developers.google.com/api-client-library/php/auth/service-accounts
* Scopes will need to be changed depending upon the API's being accessed.
* array(Google_Service_Analytics::DRIVE)
* List of Google Scopes: https://developers.google.com/identity/protocols/googlescopes
* #return A google client object.
*/
function getServiceAccountClient() {
try {
// Create and configure a new client object.
$client = new Google_Client();
$client->useApplicationDefaultCredentials();
$client->addScope(array(Google_Service_Analytics::DRIVE));
return $client;
} catch (Exception $e) {
print "An error occurred: " . $e->getMessage();
}
}
Doing something like this will then get you the same service object.
$service = new Google_Service_Drive(getGoogleClient());

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

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();
}

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:

PHP Google Drive API installation and file upload

Hi guys i'm trying uploading file trought G drive API.
Can't find out why it returns error:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Gdrive{
function initialize(){
$credentials = $this->GetOAuth2Credentials($_GET['code']);
$_SESSION['credentials'] = $credentials;
}
/**
* Exchange an authorization code for OAuth 2.0 credentials.
*
* #param String $authorizationCode Authorization code to exchange for an
* access token and refresh token. The refresh token is only returned by
* Google on the very first exchange- when a user explicitly approves
* the authorization request.
* #return OauthCredentials OAuth 2.0 credentials object
*/
function GetOAuth2Credentials($authorizationCode) {
$client = new apiClient();
$client->setClientId(Config::5112+++++.apps.****5971157#developer.gserviceaccount.com);
$client->setRedirectUri(Config::site_url());
/**
* Ordinarily we wouldn't set the $_GET variable. However, the API library's
* authenticate() function looks for authorization code in the query string,
* so we want to make sure it is set to the correct value passed into the
* function arguments.
*/
$_GET['code'] = $authorizationCode;
$jsonCredentials = json_decode($client->authenticate());
$oauthCredentials = new OauthCredentials(
$jsonCredentials->access_token,
isset($jsonCredentials->refresh_token)?($jsonCredentials->refresh_token):null,
$jsonCredentials->created,
$jsonCredentials->expires_in,
Config::CLIENT_ID,
Config::CLIENT_SECRET
);
return $oauthCredentials;
}
function SaveNewFile($inputFile) {
try {
$mimeType = 'text/plain';
$file = new Google_DriveFile();
$file->setTitle($inputFile->title);
$file->setDescription($inputFile->description);
$file->setMimeType($mimeType);
// Set the parent folder.
if ($inputFile->parentId != null) {
$parentsCollectionData = new DriveFileParentsCollection();
$parentsCollectionData->setId($inputFile->parentId);
$file->setParentsCollection(array($parentsCollectionData));
}
$createdFile = $this->service->files->insert($file, array(
'data' => $inputFile->content,
'mimeType' => $mimeType,
));
return $createdFile;
} catch (apiServiceException $e) {
/*
* Log error and re-throw
*/
error_log('Error saving new file to Drive: ' . $e->getMessage(), 0);
throw $e;
}
}
}
when i invoke the initialize() method it returns error:
Message: Undefined index: code
Fatal error: Class 'apiClient' not found
what should be? i'm doing right in my code ? does i need more code to make it works? i created web application project on google api console.
need i to include google php sdk? in the google docs it is not mentioned for google drive api :/
You are probably using an older version of the PHP client library. Make sure you have the latest source and follow the instructions in the Google Drive SDK quickstart page to learn how to write a complete PHP app to upload a file to Drive:
https://developers.google.com/drive/quickstart
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();
please use those require files and Google_Client().

Categories