Using Google API SDK to Read Files from Google Drive

Nov 18, 2021 4 minute read

Introduction

Recently, we were performing some work for a client. The client wanted us to showcase pictures of recent projects their company had completed. We use Google Workspace for our organization which means we use Google Drive. We wanted to give the client the ability to upload photos to a folder in our Google Drive and then have those images displayed on their website. We use AWS exclusively for hosting our client's websites and we also make use of Amazon S3 for storing all of our client's assets. So if the client uploads their pictures to Google Drive, and we use S3 to host our client asset files, we needed a way for the files to get from Google Drive to AWS.

We developed 2 ways of handling this task.

  1. Using a Laravel scheduled task to read files from Google Drive and write to S3
  2. Using a Lambda function that will read from Google Drive and write to S3 on a cron schedule

This blog will be focusing on #1 above, using a Laravel Scheduled Task.

Configuring Google Drive API

We will be using the Google Drive v3 API to access our drive content. The first thing we need to do is grant programmatic access to our Google Drive account.

Head over to your Google Cloud Console and create a service account for your Google Drive access in your current project

Create Service Account

Once the service account is created, generate a private key in json and download the private key locally. We'll need this later.

Then enable access to the Google Drive API

Enable Google Drive

At this point, we have a service account and have given the account access to the Google Drive API but we still haven't given the account access to OUR Google Drive. In our case, I created a Google Drive folder for the client and shared it with them. We also need to give the service account access to that same folder.

Share With People

Now we're ready to head over to our Laravel project. We will be using the Google API SDK so install that via composer

1composer require google/apiclient

Making the API Calls

Next, we need to place our credentials.json file into our storage/app directory. This will allow the API to authenticate as our service account.

Let's create a class called GoogleDriveController.php in our app\Classes directory. Let's create a getFilesFromGoogleDrive function where we can test this out. First, we'll make a connection to the Google Drive Client.

1 
2public function getFilesFromGoogleDrive()
3{
4 if (!file_exists(config('services.google_drive.credentials_file'))) {
5 throw new \Exception('Cannot find credentials file');
6 }
7 
8 $scopes = [];
9 
10 $client = new \Google_Client();
11 $client->setScopes($scopes);
12 $client->setAuthConfig(config('services.google_drive.credentials_file'));
13 $client->setAccessType('offline');
14 $client->setRedirectUri(Request::url());
15 
16}

The Google Drive Client API needs to know how to authenticate us and also what scopes we are requesting access to. You can find more about Google Drive scopes here.

Now that we have our client established, let's make some calls to the Google Drive API. We'll add to the getFilesFromGoogleDrive method above

1// Access the Google Drive Service
2$service = new \Google_Service_Drive($client);
3 
4// List of options for retreiving files
5$optParams = [
6 'pageSize' => 100,
7 'fields' => 'nextPageToken, files(id, name)',
8];
9 
10 $files = [];
11$pageToken = null;
12 
13do {
14 try {
15 if ($pageToken !== null) {
16 $optParams['pageToken'] = $pageToken;
17 }
18 
19 $response = $service->files->listFiles($optParams);
20 
21 $files = array_merge($files, $response->files);
22 
23 $pageToken = $response->getNextPageToken();
24 } catch (Exception $exception) {
25 $pageToken = null;
26 }
27} while ($pageToken !== null);

Here's what we just did. First, we set up our Google Drive Service by instantiating it and passing our auth client. Once we have that established we use the listFiles method and give it the parameters we want to retrieve. we are wrapping this in a do while loop so we are sure to get all files in case there are multiple pages. Each iteration of the loop passes the nextPageToken keeping track of where we are. When the files are returned we merge them with the existing $files variable. After it's done retrieving the files we will have an array containing all the file ids and names.

Let's say we wanted to get an individual file and its contents. We can do that by calling the get() method on the Google Drive service

1$fileId = 'Xw4r04304s2324234l'; // File ID
2$content = '';
3 
4$file = $service->files->get($fileId, ['alt' => 'media']);
5 
6while (!$file->getBody()->eof()) {
7 $content .= $file->getBody()->read(1024);
8}

The get() will return the file metadata but if you want to download the file, supply the ['alt' => 'media'] option when calling the method to get the actual contents.

Pulling it all together

Now that we have the ability to crawl our Google Drive folder and retrieve the files, we can create a Laravel scheduled task to retrieve those files on a given interval

Conclusion

In this blog, you learned how to create a Google Drive service account and link it to a shared folder in your Google Drive. You were then able to use the Google API SDK in your project to list the contents of your Google Drive and download files from it. You can further expand on this by adding your own methods to add or delete files and folders.