I'm running into an issue where I have a sheet which has been uploaded using the Sheets PHP API and now I need to change the permissions of that sheet. It doesn't matter to me if the permissions are set at upload or changed later. Here's what my upload code looks like
function createSheet(){
$client = getClient();
$service = new Google_Service_Sheets($client);
$spreadsheet = new Google_Service_Sheets_Spreadsheet([
'properties' => [
'title' => "test_sheet3",
]
]);
$spreadsheet = $service->spreadsheets->create($spreadsheet, [
'fields' => 'spreadsheetId'
]);
printf("Spreadsheet ID: %s\n", $spreadsheet->spreadsheetId);
return $spreadsheet->spreadsheetID;
}
I've been poking around this google documentation but every time I try and include any of the settings in the properties JSON ex:
'properties' => [
'title' => "test_sheet3",
'type' => 'group'
]
]);
I get the error
"Invalid JSON payload received. Unknown name \"type\" at 'spreadsheet.properties': Cannot find field."
So I'm not completely sure if my syntax is incorrect, or they should be added to a different JSON attachment that isn't the properties JSON.
I would like to propose the following modification.
Modification points:
You can give the permissions using the method of "Permissions: create" in Drive API. This has already been mentioned in your question. In this case, the request parameters cannot be included in the method of "spreadsheets.create" in Sheets API. Please request it using the method of "Permissions: create" in Drive API.
When above points are reflected to your script, it becomes as follows.
Modified script:
$client = getClient();
$service = new Google_Service_Sheets($client);
$spreadsheet = new Google_Service_Sheets_Spreadsheet([
'properties' => [
'title' => "test_sheet3",
]
]);
$spreadsheet = $service->spreadsheets->create($spreadsheet, [
'fields' => 'spreadsheetId'
]);
printf("Spreadsheet ID: %s\n", $spreadsheet->spreadsheetId);
// I added below script
$drive = new Google_Service_Drive($client);
$newPermission = new Google_Service_Drive_Permission();
$newPermission->setEmailAddress('####gmail.com');
$newPermission->setType('group');
$newPermission->setRole('writer');
$res = $drive->permissions->create($spreadsheet->spreadsheetId, $newPermission);
// print_r($res);
return $spreadsheet->spreadsheetID;
Note:
In this case, as a test, I used the scope of https://www.googleapis.com/auth/drive. For this, please use the following script. And when you modified the scopes, please the file including the refresh token and reauthorize the scopes. By this, the modified scopes can be reflected to the access token. Please be careful this.
$client->setScopes(array(Google_Service_Sheets::SPREADSHEETS, Google_Service_Drive::DRIVE));
When you want to use group to type, please set the email address.
If you want to give the permissions to an user, please modify $newPermission->setType('group'); to $newPermission->setType('user'); and please use the email address.
Reference:
Permissions: create
Related
I am using PHP to upload image to firebase storage. the picture is being uploaded but it is not being accessible as i have to manually create " access token " to make it accessible.
here is the code im using
$bucketName = "example.appspot.com";
$objectName = 'Photos/test.jpeg';
$storage = new StorageClient();
$bucket = $storage->bucket($bucketName);
$object = $bucket->upload(fopen('sign.jpeg', 'r'),
[
'name' => $objectName
]
);
That is indeed working as expected: since your upload is not going through a Firebase SDK, there is not method to generate a download URL.
The common workaround is to create a signed URL with an expiration time far into the future, which is the closest equivalent that Cloud Storage has to Firebase's download URL.
In addition to #Frank's answer, you could also assign the publicRead ACL to the uploaded file and compose the public URL manually:
$bucketName = "example.appspot.com";
$objectName = 'Photos/test.jpeg';
$storage = new StorageClient();
$bucket = $storage->bucket($bucketName);
$object = $bucket->upload(fopen('sign.jpeg', 'r'), [
'name' => $objectName
'predefinedAcl' => 'publicRead'
]);
$publicUrl = "https://{$bucket->name()}.storage.googleapis.com/{$object->name()}";
I have made an indirect way to generate and store the access token.
$payload = file_get_contents('https://firebasestorage.googleapis.com/v0/b/example.appspot.com/o/Photos%2Fpic.jpeg');
$data = json_decode($payload);
echo $data->downloadTokens;
This code has created the access token and it shows the downloadToken on screen.
Thank you everyone for your answers.
I have Google Sheets API set up and working (I can read and update existing spreadsheets if it's shared to my credentials) and I need to export some data from my website to google sheet. In order to keep users off seeing other people's sheets, I need to create a new spreadsheet when user wants to export data. I managed to create new spreadsheet like this:
public function init(){
$user = Socialite::driver('google')->stateless()->user();
$token = [
'access_token' => $user->token,
'refresh_token' => $user->refreshToken,
'expires_in' => $user->expiresIn
];
$client = new \Google_Client();
$client->setApplicationName('Sheets');
$client->setScopes([\Google_Service_Sheets::SPREADSHEETS]);
$client->setAccessType('offline');
$client->setAuthConfig('../credentials.json');
$client->setAccessToken($token);
$service = new Google_Service_Sheets($client);
$serviceDrive = new Google_Service_Drive($client);
$spreadsheet = new Google_Service_Sheets_Spreadsheet([
'properties' => [
'title' => 'Testing Sheet'
]
]);
$spreadsheet = $service->spreadsheets->create($spreadsheet, [
'fields' => 'spreadsheetId'
]);
$this->insertPermission($serviceDrive, $spreadsheet->spreadsheetId, $user->email, 'user', 'owner');
}
When I dd($spreadsheet) I can see that it's actually created and I can retrieve its id. But the thing is, if I try to open it, I get a notification that I need to get access as I don't have it. I searched for a solution a lot and tried several ways. I tried to pass a role like this:
$spreadsheet = $service->spreadsheets->create($spreadsheet, [
'fields' => 'spreadsheetId',
'role' => 'owner'
'email' => 'useremail#gmail.com'
]);
Also tried to insert permission using this method:
function insertPermission($service, $fileId, $value, $type, $role) {
$newPermission = new Google_Service_Drive_Permission();
$newPermission->setEmailAddress($value);
$newPermission->setType($type);
$newPermission->setRole($role);
try {
return $service->permissions->create($fileId, $newPermission);
} catch (Exception $e) {
print "An error occurred: " . $e->getMessage();
}
return NULL;
}
But this method gives me an error when calling create() function which says "code": 403, "message": "Insufficient Permission: Request had insufficient authentication scopes.". Is there a way to give to authenticated user an access to newly created spreadsheet and where is my mistake?
You are trying to give permission with the Drive API
Your code only contains $client->setScopes([\Google_Service_Sheets::SPREADSHEETS]);
To use both the Sheets and the Drive API with the same client, assign to the client BOTH respective scopes
I am trying to create folder using google drive api. I am able to get file id at the end. but i am not able to my folder in google drive. it seems some permission issue?
$scopes = array(
'https://www.googleapis.com/auth/drive',
'https://www.googleapis.com/auth/drive.appdata','https://www.googleapis.com/auth/drive.apps.readonly',
'https://www.googleapis.com/auth/drive.metadata','https://www.googleapis.com/auth/drive.file',
'https://www.googleapis.com/auth/drive.readonly','https://www.googleapis.com/auth/drive.photos.readonly'
);
$creds = new Google_Auth_AssertionCredentials(
$serviceAccountName,
$scopes,
file_get_contents($keyFile)
);
$client = new Google_Client();
$client->setApplicationName($appName);
$client->setClientId($clientId);
$client->setAssertionCredentials($creds);
$service = new Google_Service_Drive($client);
$fileMetadata = new Google_Service_Drive_DriveFile(array(
'name' => 'Invoices',
'permissions' => array('type'=>'anyone','role'=>'reader','allowFileDiscovery'=>1),
'mimeType' => 'application/vnd.google-apps.folder'));
$file = $service->files->create($fileMetadata, array());
printf("File ID: %s\n", $file->id);
The files that are being created belong to the API account email (something like api-service-account#yourproject.iam.gserviceaccount.com. If you go to the drive URL:
https://docs.google.com/document/d/{ID}, you will get a "Permission Denied, request access" page.
The service account email is not related to your user email.
In order to create files with your user, you need to create an OAauth token authorization.
Create the OAuth credentials following the steps "Step 1: Turn on the Drive API" on this page
Modify your script, by following the example on this page, you can have:
use Google_Client;
use Google_Service_Drive;
use Google_Service_Drive_DriveFile;
...
$file = 'root/to/your/credentials.json';
$client = new Google_Client();
$client->setScopes([
'https://www.googleapis.com/auth/drive',
'https://www.googleapis.com/auth/drive.appdata',
'https://www.googleapis.com/auth/drive.apps.readonly',
'https://www.googleapis.com/auth/drive.metadata',
'https://www.googleapis.com/auth/drive.file',
'https://www.googleapis.com/auth/drive.readonly',
'https://www.googleapis.com/auth/drive.photos.readonly'
]);
$client->setAuthConfig($file);
$authUrl = $client->createAuthUrl();
printf("Open the following link in your browser:\n%s\n", $authUrl);
// You will need to open this url
print 'Enter verification code: ';
$authCode = trim(fgets(STDIN));
$accessToken = $client->authenticate($authCode);
file_put_contents($credentialsPath, $accessToken);
printf("Credentials saved to %s\n", $credentialsPath);
$client->setAccessToken(json_decode($accessToken, true));
$service = new Google_Service_Drive($client);
$metadata = new Google_Service_Drive_DriveFile([
'name' => 'testing drive',
'mimeType' => "application/vnd.google-apps.document"
]);
$file = $service->files->create($metadata, []);
print_r($file);
The file should be in your Drive home directory.
By the way, I suggest you try the new version google/apiclient:2.0.2 (which is still on Beta, but works okay).
Mayrop answer is partially right.
The files that are being created belong to the API account email (something like api-service-account#yourproject.iam.gserviceaccount.com.
You need to give permission to owner of that account like
$newPermission = new Google_Service_Drive_Permission();
$value="email id";
$type="user";
$role="writer";
$newPermission->setValue($value);
$newPermission->setType($type);
$newPermission->setRole($role);
try {
$res= $service->permissions->insert($fileId, $newPermission);
print_r($res);
} catch (Exception $e) {
print "An error occurred: " . $e->getMessage();
}
You will see that folder in Shared with me. You can also add in your drive manually.
You can also disable sending notification via email using
$service->permissions->insert($fileId, $newPermission,array('sendNotificationEmails'=>false));
Hope this will work for you.
Yes, It seems permissions issue. Try removing
'permissions' => array('type'=>'anyone','role'=>'reader','allowFileDiscovery'=>1),
from
$fileMetadata = new Google_Service_Drive_DriveFile(array(
'name' => 'Invoices',
'permissions' => array('type'=>'anyone','role'=>'reader','allowFileDiscovery'=>1),
'mimeType' => 'application/vnd.google-apps.folder'));
so I have worked over it, and finally got the full working solution for Google Drive V3 in Php. As follows:
You can go through this gist for full code and better understanding:
https://gist.github.com/KartikWatts/22dc9eb20980b5b4e041ddcaf04caf9e
First of all adding to the answer from #Hitu Bansal:
This code works fine:
$this->newPermission = new Google_Service_Drive_Permission();
$value=<YOUR EMAIL ADDRESS>;
$type="user";
$role="reader";
$this->newPermission->setEmailAddress($value);
$this->newPermission->setType($type);
$this->newPermission->setRole($role);
$this->newPermission->allowFileDiscovery;
try {
$res= $this->service->permissions->create($folder_id, $this->newPermission);
print_r($res);
catch (Exception $e) {
print "An error occurred: " . $e->getMessage();
}
If, instead you want to share the link with anyone: You may use
$type="anyone";
$this->newPermission->setType($type);
$this->newPermission->setRole($role);
$this->newPermission->allowFileDiscovery;
$this->newPermission->view;
NOTE:
In this case, setEmailAddress() shall be removed.
IMPORTANT: In case of 'anyone', the folder will not be visible in your personal drive for sure, but you can still visit and interact with the folder as per given roles by visiting the link making use of the folder_id that you know already. So, you can visit the link as: https://drive.google.com/drive/u/5/folders/**{folder_id}** It will be publically accessible now.
For more clear reference to the parameters along with a description, this is really helpful: https://developers.google.com/drive/api/v3/reference/permissions#methods
NOTE: In my personal opinion, a better way to work with Google Drive API is to create the folder first manually (if workflow allows it), then upload the files using the folder_id of that created folder. Remember, In case folder is created manually, permission shall be provided to the Service Account email-id before.
While permission issue is the main cause of this problem. What I did to make the folders or files appear after I uploaded it with service account was to specify the parent folder. If you upload / create folder / files without parent folder ID, that object's owner will be the service account that you are using.
By specifying parent ID, it will use the inherited permissions.
Here's the code I use in php (google/apiclient)
$driveFile = new Google\Service\Drive\DriveFile();
$driveFile->name = 'New Folder';
$driveFile->mimeType = 'application/vnd.google-apps.folder';
$driveFile->parents = ['123456789qwertyuiop'];
$result = $service->files->create($driveFile);
Using the code below
define('DRIVE_SCOPE', 'https://www.googleapis.com/auth/drive');
define('SERVICE_ACCOUNT_EMAIL', 'xxx.iam.gserviceaccount.com');
define('SERVICE_ACCOUNT_PKCS12_FILE_PATH', 'xxx');
function buildService($userEmail) {
$key = file_get_contents(SERVICE_ACCOUNT_PKCS12_FILE_PATH);
$auth = new Google_Auth_AssertionCredentials(
SERVICE_ACCOUNT_EMAIL,
array(DRIVE_SCOPE),
$key);
//$auth->sub = $userEmail;
$client = new Google_Client();
$client->setAssertionCredentials($auth);
return new Google_Service_Drive($client);
}
$service = buildService('xxx.apps.googleusercontent.com');
$fileMetadata = new Google_Service_Drive_DriveFile(array(
'name' => 'Invoices',
'mimeType' => 'application/vnd.google-apps.folder'
));
$file = $service->files->create($fileMetadata, array(
'fields' => 'id'
));
printf("Folder ID: %s\n", $file->id);
I have been trying to create a folder on my drive account through PHP. I believe everything is configured correctly and I am getting a result
Folder ID: 0B2nllBpB_k0NQWFNUjlSc0NUdE0
But the folder is not being created on my drive account. The same goes with creating files as well. It keeps returning an ID but nothing is actually created. What exactly am I doing wrong?
Your current code is authenticating as the service account and creating a file. The resultant file would then only be accessible to the service account, not your Google user. You can confirm this by doing a list of files instead of a create in your code, you'll get back the files you've previously created.
Your code has sub= commented out. Uncommented that line and make sure you've followed the domain-wide delegation instructions so that your code can authenticate and act as your Google user.
struggling to understand the oauth2 token and refresh token processes
ive got this code
$url = 'https://www.googleapis.com/oauth2/v3/token';
$data = array('client_id' => 'clientid', 'client_secret' => 'secret','refresh_token' => 'token','grant_type' => 'refresh_token');
$options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded",
'method' => 'POST',
'approval_prompt'=>'force',
'access_type'=>'offline',
'content' => http_build_query($data),
),
);
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
that code above gives me an access token , and i followed this link suggested by one fellow stackoverflower, pinoyyid, BUT , im confunsed on how to correctly use the resulting access token to access drive and copy a file...
all the process ive seen usually involves $client = new Google_Client() and im not sure on how to use the whole POST http://..... thing, so basically i need to figure out if i use the access token i got with the code above in a new instance of google client, or i simply do a post to a url with necesary info ( which im not clear on also ) any help/clarification is appreciated guys really
EDIT #1
what i want to achieve is to allow the end user to access my drive via my webpage, to let them copy a spreadsheet in my drive , and access it via my website, to store data on the spreadsheet,the spreadsheet will always be on my drive, never on the end user
EDIT #2
code as per your posts is as follows, using the service account,,,,the files are inside that gmail account which i created on the api console a service account
<?php
require 'Google/autoload.php';
$client = new Google_Client();
// Replace this with your application name.
$client->setApplicationName("TEST");
// Replace this with the service you are using.
$service = new Google_Service_Drive($client);
// This file location should point to the private key file.
$key = file_get_contents($_SERVER['DOCUMENT_ROOT'] . '/number-privatekey.p12');
$user_to_impersonate = 'admin#testpr.com';
$cred = new Google_Auth_AssertionCredentials(
'number#developer.gserviceaccount.com',
array('https://www.googleapis.com/auth/drive'), ****//this here has to be drive not drive.file
$key,
'notasecret',
'http://oauth.net/grant_type/jwt/1.0/bearer',
$user_to_impersonate
);
$client->setAssertionCredentials($cred);
if ($client->getAuth()->isAccessTokenExpired()) {
$client->getAuth()->refreshTokenWithAssertion();
}
$originFileId = "longnumber";
$copyTitle = 'copied';
$newfile = copyFile($service, $originFileId, $copyTitle);
print_r($newfile);
function copyFile($service, $originFileId, $copyTitle)
{
$copiedFile = new Google_Service_Drive_DriveFile();
$copiedFile->setTitle($copyTitle);
try {
return $service->files->copy($originFileId, $copiedFile);
} catch (Exception $e) {
print "An error occurred: " . $e->getMessage();
}
return NULL;
}
?>
so got it working just now, ty all for your time guys really and edited my post to reflect the dang thing
If you want to give the end user access to your drive, you have to give your application authority to make API calls on behalf of a user (in this case you) in your domain. For this you have to set up a service account and generate a p12 key in the Google Developers Console. You have to enter the https://www.googleapis.com/auth/drive API scope in your Admin Console as well.
Full explanation and examples can be found here: https://developers.google.com/api-client-library/php/auth/service-accounts.
To achieve this you also need the Google API's client library: https://github.com/google/google-api-php-client (also mentioned in the Google manual).
Code example to let users make API calls on behalf of one of your accounts: https://developers.google.com/api-client-library/php/guide/aaa_oauth2_service