I’m looking to push our MySQL backups from our webserver to Google Drive using a PHP script and the Google Drive API that will be setup as a cron job.
I understand this to be a server-to-server application therefore requiring a Google Service Account (I’m aware it might be possible with a User Account and refreshing the access token – but I don’t think this is the correct use-case as I’d like little to no user interaction?).
I have setup a Google Service Account in the Cloud Console. Using my regular account, I’ve shared a directory with the service account and I’m attempting to use the following script to upload a test file:
function getClient() { $client = new Google_Client(); if ($credentials_file = checkServiceAccountCredentialsFile()) { // set the location manually $client->setAuthConfig($credentials_file); } else { echo missingServiceAccountDetailsWarning(); return; } $client->setApplicationName('Backups'); $client->setScopes(Google_Service_Drive::DRIVE); $guzzleClient = new GuzzleHttpClient(array( 'curl' => array( CURLOPT_SSL_VERIFYPEER => false, ), )); $client->setHttpClient($guzzleClient); return $client; }
$file_to_upload = 'test.txt'; if(file_exists($file_to_upload)) { // Get the API client and construct the service object. $client = getClient(); $service = new Google_Service_Drive($client); $folder_id = '#####################-##########'; $file = new Google_Service_Drive_DriveFile(); $file->setName($file_to_upload); $file->setParents(array($folder_id)); $result = $service->files->create( $file, array( 'data' => file_get_contents("test.txt"), 'mimeType' => 'text/plain', 'uploadType' => 'multipart' ) ); }
This returns the following exception:
Fatal error: Uncaught Google_Service_Exception: { "error": { "errors": [ { "domain": "global", "reason": "notFound", "message": "File not found: #####################-##########.", "locationType": "parameter", "location": "fileId" } ], "code": 404, "message": "File not found: #####################-##########." } }
I understand this to be a permissions error – the folder ID is correct and matches the directory that has been shared with the service account:
I have not added the service account client ID and https://www.googleapis.com/auth/drive scope to the GSuite admin console – is this a required step that I’ve missed? (I don’t currently have access to the admin console).
I noticed that service accounts are available for regular non-GSuite accounts, so how would this work as they wouldn’t be able to add the scope?
I’m happy for the service account to own the files it uploads, but would like the regular user to have the ability to manually delete them – as the regular user owns the shared folder will this be possible?
Are there any other pre-existing solutions that can backup files from a web server to Google Drive?
Advertisement
Answer
About permission error:
Assuming that you made the service account a valid editor of the folder on your Drive, you can upload files to this folder with the service account, but there is an important setting:
Since the folder is not located on the personal Drive of the service account, you need to set the option
supportsAllDrives
totrue
– see documentation for Files:Create.Otherwise the folder cannot be found which leads to the error message you received.
About authorizing scopes in the Admin console:
This step is only necessary when you use domain-wide delegation – that is if you let the service account represent another user (e.g. you) and act on his behalf.
Mind that using domain-wide impersonation is not possible for non-G Suite (now called Google Workspace) account, thus there is no use for those users to authorize the respective scopes in the Admin console.
For usage of service accounts without domain-wide delegation (as in your case) you only need to enable the respective API (Drive) for the respective GCP project and include the scope in your code.
Mind that your error were due to permission issues you would likely obtian a 403 error code instead of 404.