How to Integrate Google Drive API with PHP – Upload/Download/Delete File on Drive

Recently, I worked on a project where we’re dealing with the Google Drive API. We wanted to perform create and upload operations on Google Drive from our application. As I did some work with Drive API, I thought it’s better to write an article on it. In this article, I show you how to integrate Google Drive API with PHP. I am going to cover the following topics.

  • Create a folder on Drive
  • Upload file to Google Drive
  • Download a file from Google Drive
  • Delete a file from Drive

To interact with the Drive API, you require to send the access token in each request. The access token needs to be created via Google OAuth. Google OAuth works only with the client ID and client secret. Let’s create these credentials in the next step.

Register an Application and Create Credentials

  • Go to the Google Developer Console.
  • Create a new project. You can also select existing projects.
  • Give a name to your project. Google console will generate a unique project ID for it.
  • Your project will appear on top of the left sidebar.
  • Click on Library and search for Google Drive API. Enable it.
  • Click on the Credentials. Select Oauth Client id under Create credentials. Choose the radio button for Web Application.
  • Give the Name. Under Authorized JavaScript origins enter your domain URL. In the Authorized redirect URIs add the link of the redirect URL. In my case I passed the URL http://localhost/drive-api/callback.php. I’ll create this file in a later part.
  • Click on the Create button. You will get client ID and client secret in the pop-up. Copy these details. We will need it in a moment.
drive-api-application

Create a Database and DB Class(class-db.php)

When we’ll run the OAuth flow, we should store the access token in the database table. The access token has an expiry time, so we’ll regenerate it in the background and update it in a table.

To perform this process, I’ll create the class-db.php and write a code in it. But before that, create a google_oauth table in the database using the below SQL.

CREATE TABLE `google_oauth` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `provider` varchar(255) NOT NULL,
 `provider_value` text NOT NULL,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

In the class-db.php file, I’ll write a few methods which have specific responsibilities.

  • get_access_token() : This method will give a user’s access token. Apart from access token, it also has values of refresh_token, expires_in.
  • get_refersh_token() : Extract a refresh_token from the column’s value. This token is required to regenerate the access token.
  • update_access_token() : It will insert/update the access token of the users in the database table.
<?php
class DB {
    private $dbHost     = "DB_HOST";
    private $dbUsername = "DB_USERNAME";
    private $dbPassword = "DB_PASSWORD";
    private $dbName     = "DB_NAME";
 
    public function __construct(){
        if(!isset($this->db)){
            // Connect to the database
            $conn = new mysqli($this->dbHost, $this->dbUsername, $this->dbPassword, $this->dbName);
            if($conn->connect_error){
                die("Failed to connect with MySQL: " . $conn->connect_error);
            }else{
                $this->db = $conn;
            }
        }
    }
 
    public function is_table_empty() {
        $result = $this->db->query("SELECT id FROM google_oauth WHERE provider = 'google'");
        if($result->num_rows) {
            return false;
        }
 
        return true;
    }
 
    public function get_access_token() {
        $sql = $this->db->query("SELECT provider_value FROM google_oauth WHERE provider = 'google'");
        $result = $sql->fetch_assoc();
        return json_decode($result['provider_value']);
    }
 
    public function get_refersh_token() {
        $result = $this->get_access_token();
        return $result->refresh_token;
    }
 
    public function update_access_token($token) {
        if($this->is_table_empty()) {
            $this->db->query("INSERT INTO google_oauth(provider, provider_value) VALUES('google', '$token')");
        } else {
            $this->db->query("UPDATE google_oauth SET provider_value = '$token' WHERE provider = 'google'");
        }
    }
}

Install Hybridauth and Google Drive API Library

The access token is generated by following an OAuth flow. And this OAuth flow can be integrated seamlessly with the Hybridauth library. You just need to configure the settings and the rest work will be done by the library itself.

As we are dealing with Google Drive, I’ll also install the Drive library for PHP given by Google.

Create a composer.json file and add the following lines to it.

{
    "require": {
        "google/apiclient": "^2.10",
        "hybridauth/hybridauth" : "~3.0"
    },
    "scripts": {
        "pre-autoload-dump": "Google\\Task\\Composer::cleanup"
    },
    "extra": {
        "google/apiclient-services": [
            "Drive"
        ]
    }
}

Here, I used the cleanup process of Composer. This is because when you install the google/apiclient package, it downloads all the services of Google which are in the hundreds. We don’t need all of them but Drive.

After this, open the command prompt and run the command:

composer install

This command will install the packages of Hybridauth and Google Drive into your project directory.

Generate Access Token

The Hyridauth library will run the OAuth process for us. For this, you need to give a few values to the configuration array of a library.

Create a config.php file and use the code below in it.

<?php
require_once 'vendor/autoload.php';
require_once 'class-db.php';
 
define('GOOGLE_CLIENT_ID', 'PASTE_CLIENT_ID_HERE');
define('GOOGLE_CLIENT_SECRET', 'PASTE_CLIENT_SECRET_HERE');
 
$config = [
    'callback' => 'http://localhost/drive-api/callback.php',
    'keys'     => [
                    'id' => GOOGLE_CLIENT_ID,
                    'secret' => GOOGLE_CLIENT_SECRET
                ],
    'scope'    => 'https://www.googleapis.com/auth/drive',
    'authorize_url_parameters' => [
            'approval_prompt' => 'force', // to pass only when you need to acquire a new refresh token.
            'access_type' => 'offline'
    ]
];
 
$adapter = new Hybridauth\Provider\Google( $config );

In the above code, I passed my callback URL which should be changed in your case. I set the https://www.googleapis.com/auth/drive scope that gives the application access to perform operations on Google Drive. Replace the other placeholders with their actual values.

Next, create a callback.php file that initiates the OAuth, and stores the access token once the authorization is successful.

<?php
require_once 'config.php';
 
try {
    $adapter->authenticate();
    $token = $adapter->getAccessToken();
    $db = new DB();
    $db->update_access_token(json_encode($token));
    echo "Access token inserted successfully.";
}
catch( Exception $e ){
    echo $e->getMessage() ;
}

Head over to the browser and run this callback.php, you will be asked for Google authentication, complete it and you will see the access token get stored in the database table. It means you are ready to interact with the Google Drive API with PHP.

Create a Folder on Google Drive

With the help of the access token and Google REST API, you can perform certain operations on the Google drive. Let’s say you want to create a new folder on the Drive. It requires the following steps to be performed in the code.

  • Include configuration file which gives the access token and access to Google API services.
  • Use mimeType as application/vnd.google-apps.folder to create a drive folder.
  • Regenerate the access token if it expires and re-initiate the task.

Create a file create-folder.php and place the below code into it.

<?php
require_once 'config.php';
 
create_drive_folder('apifolder');
 
function create_drive_folder($folder) {
 
    $client = new Google_Client();
 
    $db = new DB();
 
    $arr_token = (array) $db->get_access_token();
    $accessToken = array(
        'access_token' => $arr_token['access_token'],
        'expires_in' => $arr_token['expires_in'],
    );
 
    $client->setAccessToken($accessToken);

    $service = new Google\Service\Drive($client);

    try {
        // Create a folder in root
        $postBody = new Google\Service\Drive\DriveFile([
            'name' => $folder,
            'mimeType' => 'application/vnd.google-apps.folder',
        ]);

        $result = $service->files->create($postBody);
        echo "Folder is created successfully.";
    } catch(Exception $e) {
        if( 401 == $e->getCode() ) {
            $refresh_token = $db->get_refersh_token();
 
            $client = new GuzzleHttp\Client(['base_uri' => 'https://accounts.google.com']);
 
            $response = $client->request('POST', '/o/oauth2/token', [
                'form_params' => [
                    "grant_type" => "refresh_token",
                    "refresh_token" => $refresh_token,
                    "client_id" => GOOGLE_CLIENT_ID,
                    "client_secret" => GOOGLE_CLIENT_SECRET,
                ],
            ]);
 
            $data = (array) json_decode($response->getBody());
            $data['refresh_token'] = $refresh_token;
 
            $db->update_access_token(json_encode($data));
 
            create_drive_folder($folder);
        } else {
            echo $e->getMessage(); //print the error
        }
    }
}

Here, I have passed the folder name as ‘apifolder’. Change this to whatever you wish. Run this code and you should see the folder created on Google Drive.

This code creates a directory in the root location of Drive. If you wish to create a folder inside another directory then pass the id of that folder to the parents key as follows. 

// create a folder inside parent folder
$postBody = new Google\Service\Drive\DriveFile([
    'name' => 'apifolder',
    'parents' => ['PARENT_FOLDER_ID'],
    'mimeType' => 'application/vnd.google-apps.folder',
]);

If you are curious about how to get an id of a folder, click on the desired folder and copy the last string from the URL. It may have the format https://drive.google.com/drive/u/0/folders/ID_HERE.

Upload File to Google Drive

This is the most obvious operation one may want to perform. People prefer to use the Google Drive service to store their files.

The below code will be used to upload any type of file on the drive. For instance, I assume you have a 1.jpg file into the local system which you want to upload on a drive. Change this filename as per your document. Also, pass the folder id under which this file should get uploaded.

<?php
require_once 'config.php';

$drive_folder_id = 'FOLDER_ID_HERE';
create_file_in_drive_folder($drive_folder_id);
 
function create_file_in_drive_folder($drive_folder_id) {
 
    $client = new Google_Client();
 
    $db = new DB();
 
    $arr_token = (array) $db->get_access_token();
    $accessToken = array(
        'access_token' => $arr_token['access_token'],
        'expires_in' => $arr_token['expires_in'],
    );
 
    $client->setAccessToken($accessToken);

    $service = new Google\Service\Drive($client);

    try {
        $file = getcwd(). '/1.jpg';
        $filename = basename($file);
        $filetype = mime_content_type($file);

        $resource = new Google\Service\Drive\DriveFile([
            'name' => $filename,
            'parents' => [$drive_folder_id],
        ]);

        $result = $service->files->create($resource, [
            'data' => file_get_contents($file),
            'mimeType' => $filetype,
            'uploadType' => 'multipart',
        ]);
        echo "File is uploaded successfully.";
    } catch(Exception $e) {
        if( 401 == $e->getCode() ) {
            $refresh_token = $db->get_refersh_token();
 
            $client = new GuzzleHttp\Client(['base_uri' => 'https://accounts.google.com']);
 
            $response = $client->request('POST', '/o/oauth2/token', [
                'form_params' => [
                    "grant_type" => "refresh_token",
                    "refresh_token" => $refresh_token,
                    "client_id" => GOOGLE_CLIENT_ID,
                    "client_secret" => GOOGLE_CLIENT_SECRET,
                ],
            ]);
 
            $data = (array) json_decode($response->getBody());
            $data['refresh_token'] = $refresh_token;
 
            $db->update_access_token(json_encode($data));
 
            create_file_in_drive_folder($drive_folder_id);
        } else {
            echo $e->getMessage(); //print the error
        }
    }
}

Upon running this code, your file should be found under the desired location. Just in case, if it fails we are printing the error which helps to get us on track.

Download File from Google Drive

In this section, we write a code that will download the file from Google Drive and store it on your local system. I’ll download a drive file in chunks so it will not be a problem even if you are downloading a relatively large file.

<?php
require_once 'config.php';

download_drive_file('DRIVE_FILE_NAME'); // say 1.jpg

function download_drive_file($filename = '') {

    $client = new Google_Client();

    $db = new DB();

    $arr_token = (array) $db->get_access_token();
    $accessToken = array(
        'access_token' => $arr_token['access_token'],
        'expires_in' => $arr_token['expires_in'],
    );

    $client->setAccessToken($accessToken);

    $service = new Google\Service\Drive($client);    

    try {
        // Check for $filename and include the file ID and size
        $files = $service->files->listFiles([
            'q' => "name='$filename'",
            'fields' => 'files(id,size)'
        ]);

        if(count($files) == 0) {
            echo "No files found.";
            return;
        }

        // Determine the file's size and ID
        $fileId = $files[0]->id;
        $fileSize = intval($files[0]->size);

        // Get the authorized Guzzle HTTP client
        $http = $client->authorize();

        // Open a file for writing
        $fp = fopen(time().'-'.$filename, 'w');

        // Download in 1 MB chunks
        $chunkSizeBytes = 1 * 1024 * 1024;
        $chunkStart = 0;

        // Iterate over each chunk and write it to our file
        while ($chunkStart < $fileSize) {
            $chunkEnd = $chunkStart + $chunkSizeBytes;
            $response = $http->request(
                'GET',
                sprintf('/drive/v3/files/%s', $fileId),
                [
                    'query' => ['alt' => 'media'],
                    'headers' => [
                        'Range' => sprintf('bytes=%s-%s', $chunkStart, $chunkEnd)
                    ]
                ]
            );
            $chunkStart = $chunkEnd + 1;
            fwrite($fp, $response->getBody()->getContents());
        }

        // close the file pointer
        fclose($fp);

        echo "File is downloaded to your filesystem.";
    } catch(Exception $e) {
        if( 401 == $e->getCode() ) {
            $refresh_token = $db->get_refersh_token();
 
            $client = new GuzzleHttp\Client(['base_uri' => 'https://accounts.google.com']);
 
            $response = $client->request('POST', '/o/oauth2/token', [
                'form_params' => [
                    "grant_type" => "refresh_token",
                    "refresh_token" => $refresh_token,
                    "client_id" => GOOGLE_CLIENT_ID,
                    "client_secret" => GOOGLE_CLIENT_SECRET,
                ],
            ]);
 
            $data = (array) json_decode($response->getBody());
            $data['refresh_token'] = $refresh_token;
 
            $db->update_access_token(json_encode($data));
 
            download_drive_file($filename);
        } else {
            echo $e->getMessage(); //print the error
        }
    }
}

Delete File from Google Drive

When someone performs uploading/downloading a file, obviously they want to delete the file as well. We can delete the file proving the file name of the drive.

<?php
require_once 'config.php';

delete_file_from_drive('FILE_NAME_HERE'); // say 1.jpg
 
function delete_file_from_drive($filename = '') {
 
    $client = new Google_Client();
 
    $db = new DB();
 
    $arr_token = (array) $db->get_access_token();
    $accessToken = array(
        'access_token' => $arr_token['access_token'],
        'expires_in' => $arr_token['expires_in'],
    );
 
    $client->setAccessToken($accessToken);

    $service = new Google\Service\Drive($client);

    try {
        // Check for $filename and include the file ID and size
        $files = $service->files->listFiles([
            'q' => "name='$filename'",
            'fields' => 'files(id)'
        ]);

        if(count($files) == 0) {
            echo "No files found.";
            return;
        }

        // Determine the file's ID
        $fileId = $files[0]->id;

        $result = $service->files->delete($fileId);

        echo "File is deleted from Google Drive.";
    } catch(Exception $e) {
        if( 401 == $e->getCode() ) {
            $refresh_token = $db->get_refersh_token();
 
            $client = new GuzzleHttp\Client(['base_uri' => 'https://accounts.google.com']);
 
            $response = $client->request('POST', '/o/oauth2/token', [
                'form_params' => [
                    "grant_type" => "refresh_token",
                    "refresh_token" => $refresh_token,
                    "client_id" => GOOGLE_CLIENT_ID,
                    "client_secret" => GOOGLE_CLIENT_SECRET,
                ],
            ]);
 
            $data = (array) json_decode($response->getBody());
            $data['refresh_token'] = $refresh_token;
 
            $db->update_access_token(json_encode($data));
 
            delete_file_from_drive($filename);
        } else {
            echo $e->getMessage(); //print the error
        }
    }
}

Conclusion

In this tutorial, I explained how to integrate Google Drive API with PHP. I wrote a code to perform the most obvious operations like creating a folder, and upload/download/delete files on a Drive. I hope this article should help you to incorporate Drive API into your application. I would like to hear your thoughts and suggestions in the comment section below.

Related Articles

If you liked this article, then please subscribe to our YouTube Channel for video tutorials.

Leave a Reply

Your email address will not be published.