Upload and download files to storages like Google Drive and Dropbox

Hello,

I make database backup and website directory backup using cron job with the script that I am trying to write as an amateur and hobby.
In addition, I automatically back up these backups to the remote server via FTP after the backup.
The picture below shows the directory and file tree of the remote ftp server and the local server.

It is possible to download the selected directory and content from the remote server to the local server.
If the selected file is (zip, sql, gz), it is also possible to download the file to the local server.

It is also possible to manually back up the directory and its contents or the file to a remote ftp server.

In addition, I want to add cloud storage such as Google Drive and Dropbox, I want to add Google Drive first.

Is it possible to create a directory and file tree for Google Drive as in the picture?
Is it possible to upload and download it with its directory and content?

I found the library for Google Drive but the 200MB library has too much detail and links.

Can you help me in a simple way?

Here’s a step-by-step guide on how to achieve directory and file interactions with Google Drive:

Step 1:Setting up Google Drive API

  1. Go to the Google Developer Console.
  2. Create a new project.
  3. Enable the Google Drive API for the project.
  4. Create credentials (OAuth 2.0 Client ID) for a Desktop app.
  5. Download the credentials.json file.

Step 2: Install Google Client Library

You can use Composer to install the Google API PHP client library:

composer require google/apiclient:^2.0

Step 3: Authenticating

Before you can use the API, you need to authenticate. Here’s a basic script for that:

require 'vendor/autoload.php';

session_start();

$client = new Google_Client();
$client->setAuthConfig('path_to/credentials.json');
$client->addScope(Google_Service_Drive::DRIVE);
$client->setRedirectUri('http://your_redirect_uri');

if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
    $client->setAccessToken($_SESSION['access_token']);
    $drive_service = new Google_Service_Drive($client);
    // Your drive operations go here...
} else {
    $redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php';
    header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}

In oauth2callback.php:

require 'vendor/autoload.php';

$client = new Google_Client();
$client->setAuthConfigFile('path_to/credentials.json');
$client->setRedirectUri('http://your_redirect_uri');
$client->addScope(Google_Service_Drive::DRIVE);

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();
    $redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/';
    header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}

Step 4: Upload File to Google Drive

Here’s a basic example to upload a file:

$file = new Google_Service_Drive_DriveFile();
$file->setName("filename.ext");
$file->setMimeType("type-of-file");

$data = file_get_contents('path_to/your_file.ext');

$createdFile = $drive_service->files->create($file, array(
    'data' => $data,
    'mimeType' => 'type-of-file',
    'uploadType' => 'multipart'
));

Step 5: Download File from Google Drive

To download a file:

$fileId = "your-file-id";
$content = $drive_service->files->get($fileId, array("alt" => "media"));
file_put_contents('path_to/destination_filename.ext', $content->getBody());

Step 6: Handling Directories (Folders)

To create a folder:

$folder = new Google_Service_Drive_DriveFile();
$folder->setName('FolderName');
$folder->setMimeType('application/vnd.google-apps.folder');
$createdFolder = $drive_service->files->create($folder);

To list files in a folder:

$folderId = 'your-folder-id';
$results = $drive_service->files->listFiles(array(
    'q' => "'$folderId' in parents"
));
foreach ($results->getFiles() as $file) {
    echo $file->getName(), PHP_EOL;
}

Remember to handle exceptions and errors as needed. This is a basic guide, and depending on your needs, you might want to expand and refine these snippets.
Good Luck.

1 Like

Thank you very much for your very detailed explanation.

I wonder what I’m doing wrong?

I created Google Drive IP json file as follows

{
    "web": {
        "client_id": "45*******03-1d**************ok9o.apps.googleusercontent.com",
        "project_id": "gorev-5*****2",
        "auth_uri": "https://accounts.google.com/o/oauth2/auth",
        "token_uri": "https://oauth2.googleapis.com/token",
        "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
        "client_secret": "GO***X-Sr*****************JX5C"
    }
}

I ran composer into the google directory
Ekran görĂŒntĂŒsĂŒ 2023-10-31 212724

in index.php

<?php
require_once __DIR__.'/vendor/autoload.php';

session_start();

$client = new Google\Client();
$client->setAuthConfig('client_secrets/client_secrets.json');
$client->addScope(Google\Service\Drive::DRIVE_METADATA_READONLY);

if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
  $client->setAccessToken($_SESSION['access_token']);
  $drive = new Google\Service\Drive($client);
  $files = $drive->files->listFiles(array())->getItems();
  echo json_encode($files);
} else {
  $redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php';
  header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}

?>

in oauth2callback.php

<?php 
require 'vendor/autoload.php';

$client = new Google\Client();
$client->setAuthConfig('client_secrets/client_secrets.json');
$client->setRedirectUri('http://localhost:8000/index.php');
$client->addScope(Google\Service\Drive::DRIVE);

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();
    $redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/';
    header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}

?>

index.php

Composer installation is like this

Thank you very much for the detailed explanation.

First I received many errors and I found the reason
It doesn’t work with php 8.1.13 version, I downloaded it to php 8.0.30 version

It redirected to the Google page but I got the following message
I wonder what’s missing?

Access denied: The request sent by this application is invalid
Error 400: redirect_uri_mismatch

400 error: redirect_uri_mismatch

You cannot sign in to this app because it does not comply with Google's OAuth 2.0 policy.

If you are the developer of the app, register the redirect URI in the Google Cloud Console.
Request details: redirect_uri=http://localhost/google/index.php

I added redirect urls but the problem persists

{
    "web": {
        "client_id": "45*******03-1d**************ok9o.apps.googleusercontent.com",
        "project_id": "gorev-5*****2",
        "auth_uri": "https://accounts.google.com/o/oauth2/auth",
        "token_uri": "https://oauth2.googleapis.com/token",
        "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
        "client_secret": "GO***X-Sr*****************JX5C",
        "redirect_uris": [
            "http://localhost:8000"
        ],
        "javascript_origins": [
            "http://localhost:8000"
        ]
    }
}

Sign-in-Google-Accounts4

@Adem you are trying to integrate Google Drive into your PHP application using the Google API Client for PHP. The errors you provided are related to PHP deprecation warnings from the Google API Client.

Here’s a step-by-step solution to address your concerns:

  1. Deprecation Warnings:
    The deprecation warnings you’re seeing are related to PHP version incompatibility with the Google API Client version you are using. They are not fatal errors but indicate that some methods in the Google API Client are not compatible with the PHP version you’re using.

    To address these warnings:

    • Update the Google API Client library by running composer update google/apiclient in your project directory. Make sure you have the latest compatible version.
    • Ensure that you are using a supported PHP version for the Google API Client version you are using. Check the library’s documentation or composer.json for version requirements.
  2. Google Drive Integration:
    The provided code for integrating Google Drive seems correct at a glance. However, here are some common pitfalls to check:

    • Ensure the client_secrets/client_secrets.json path is correct and the file is accessible from the script.
    • Ensure you’ve set up the OAuth 2.0 consent screen correctly in the Google Cloud Console. The redirect URI in the Google Cloud Console should match the one you’ve defined in your oauth2callback.php script.
    • Ensure your local server is running when you’re testing, since you’ve set the redirect URI to localhost:8000.
    • Ensure the scope you’re requesting (i.e., Google\Service\Drive::DRIVE_METADATA_READONLY) matches the scope you’ve allowed in your Google Cloud Console OAuth 2.0 setup.
  3. Testing:

    • When you visit index.php for the first time, it should redirect you to Google’s OAuth 2.0 consent screen. After allowing the necessary permissions, it should redirect you back to your application (specifically to oauth2callback.php) and then back to index.php with the Drive files listed.
  4. Security Note:

    • Never expose client_secret in public forums or any accessible places. If you think the secret has been compromised, please regenerate it from the Google Cloud Console immediately.
    • Always use HTTPS in production when integrating with OAuth 2.0 to ensure security.

Also the redirect_uri_mismatch error is related to the redirect_uri you’ve specified in your code not matching the one you’ve set in the Google Cloud Console for your OAuth 2.0 client ID.

Here’s how to resolve this:

  1. Google Cloud Console:

    • Go to the Google Cloud Console.
    • Navigate to your project.
    • Go to the “Credentials” tab.
    • Click on the OAuth 2.0 client ID you’re using in your application.
    • Under “Authorized redirect URIs”, ensure you have the exact same URI as specified in your oauth2callback.php file.
  2. In Your Application:

    • In the oauth2callback.php file, you have specified:
      $client->setRedirectUri('http://localhost:8000/index.php');
      
    • So, the exact same URI (http://localhost:8000/index.php) should be listed in the “Authorized redirect URIs” section in the Google Cloud Console.
  3. In your client_secrets.json file:

    • The “redirect_uris” and “javascript_origins” you’ve specified in your client_secrets.json file (http://localhost:8000) do not match the redirect_uri you’ve set in the oauth2callback.php file (http://localhost:8000/index.php).
    • Update the redirect_uris in your client_secrets.json to match:
      "redirect_uris": [
          "http://localhost:8000/index.php"
      ]
      

After making these changes, try the flow again. Ensure you clear any sessions or cookies if necessary to start the OAuth flow from the beginning.
Good luck

1 Like

Thank you very much for your long and detailed explanations.

Does it disable using Google Drive with PHP?
Are we wasting our efforts to use Google Drive with PHP?
How to use Google Drive on PHP websites?

If the use of Google Drive with PHP is removed, the following problems do not matter. It should be used with whatever is valid.

I’m doing something wrong again

I will put a .htaccess file into the json “client_secrets” directory and write “deny from all” in it.
I think this will be safe

in .json

{
    "web": {
        "client_id": "45***************k9o.apps.googleusercontent.com",
        "project_id": "gorev-*****",
        "auth_uri": "https://accounts.google.com/o/oauth2/auth",
        "token_uri": "https://oauth2.googleapis.com/token",
        "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
        "client_secret": "GOC**************5C",
        "redirect_uris": [
            "http://localhost:8080/index.php",
            "http://localhost:8080/oauth2callback.php"
        ],
        "javascript_origins": [
            "http://localhost:8080"
        ]
    }
}

in index.php

require_once __DIR__.'/vendor/autoload.php';

session_start();


$client = new Google\Client();
$client->setAuthConfig('client_secrets/client_secrets.json');
$client->addScope(Google\Service\Drive::DRIVE_METADATA_READONLY);

if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
  $client->setAccessToken($_SESSION['access_token']);
  $drive = new Google\Service\Drive($client);
  $files = $drive->files->listFiles(array())->getItems();
  echo json_encode($files);
} else {
  $redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php';
  header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}

in oauth2callback.php

require 'vendor/autoload.php';


$client = new Google\Client();
$client->setAuthConfig('client_secrets/client_secrets.json');
$client->setRedirectUri('http://localhost:8080/oauth2callback.php');
$client->addScope(Google\Service\Drive::DRIVE);

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();
    $redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/';
    header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}

It redirected me, I entered my e-mail and then the browser gave the following message.
URL http://localhost:8080/

The page is not redirecting correctly

Firefox detected that the request for this address was redirected by the server in a never-ending manner.

This problem can sometimes be caused by disabling or rejecting cookies.

Your code seems mostly correct, but the redirect loop could be happening due to the following reasons:

  1. Session Handling: Ensure that your session is being handled correctly. After getting the access token and setting it to the session, the next request should recognize the session and not go into the OAuth flow again. Verify that your session is not expiring or getting reset on every request.
  2. Redirect Logic: In the oauth2callback.php script, after the user is authenticated and you obtain the access token, you’re redirecting the user to the root (http://localhost:8080/). If this is the same location as index.php, the logic there checks the session for an access token and, if not found, redirects to oauth2callback.php again. This could be causing your loop.

To solve this, consider changing the redirect after authentication to directly go to a different page that lists the files or performs whatever action you want with the Google Drive.

  1. .htaccess Security: Your idea of putting a .htaccess file in the directory containing sensitive information like client_secrets.json and adding deny from all is a good security measure. This will prevent direct access to that JSON file from the web.
  2. Cookie Settings: As the Firefox message indicates, ensure that your browser is set to accept cookies from localhost. The session in PHP uses cookies, so if cookies are blocked, it might cause issues with the session, leading to endless redirects.

Lastly, make sure you’ve correctly set up your OAuth 2.0 client ID in the Google Cloud Console with the correct redirect URIs. Any mismatch here could also result in unexpected behavior.

1 Like

I found the problem
“$_SESSION” was not working because “session_start()” was not added to index.php

Now it gave the following error

Error code

$files = $drive->files->listFiles(array())->getItems();

I replaced the error code with the following code I found on the internet.

  /*
  $files = $drive->files->listFiles(array())->getItems();
  echo json_encode($files);
  */
if (count($drive->files->listFiles()) == 0) {
    print "No files found.\n";
} else {
    foreach ($drive->files->listFiles() as $file) {
        $res['name'] = $file->getName();
        $res['id'] = $file->getId();
        $files[] = $res;
    }
 echo '<pre>' . print_r($files, true) . '</pre>';

It gave the following results
There are folder and file names in the array, but there are also other things.

    [15] => Array
        (
            [name] => 114351.png
            [id] => 1acZNmO6GiTv8ZIt9BqjXg8h_Tb6rh8ar
        )

    [16] => Array
        (
            [name] => sx620hs_100a.7z
            [id] => 1pxDmfjD7bQ1A67qmQD6AwGLO-gs3Z-f0
        )

    [17] => Array
        (
            [name] => a530_100a.7z
            [id] => 1uvYN9kvDh6LfumzaafmkRZP-kpfvhI5c
        )

    [18] => Array
        (
            [name] => CHDK
            [id] => 0B08pqRtyrObjTy11Y003Sk1lYTQ
        )

    [19] => Array
        (
            [name] => g7x_100b.7z
            [id] => 0B08pqRtyrObjeGVIYU13UFFTLW8
        )

There is something I don’t understand
You need to log in to Gmail to upload files to Google Drive.
How will the file be uploaded when run automatically with cron jop on the real website?

@Adem :

  1. Regarding the Error: The method getItems() does not exist in the latest versions of the Google API client library for PHP. The method you’ve found to retrieve the files seems to be the correct approach for the version you’re using.

  2. Listing Files: The code you provided will indeed fetch the files from the Google Drive of the authenticated user. If you only want the name and id, the approach you’ve chosen is correct. You can further filter or process this array as you need.

  3. About Automation with Cron Jobs: When you run scripts to interact with Google Drive through a cron job, you can’t use the standard OAuth2 flow which requires manual intervention (logging into Gmail). Instead, you’ll use a “service account”.

Here’s a simplified way of how to use a service account for Google Drive operations:

  • Service Account Setup:

    1. Go to the Google Cloud Console.
    2. Create a new project or select an existing project.
    3. Enable the Drive API for your project.
    4. In the sidebar, click on “Credentials”, then click on “Create Credentials” and select “Service account”.
    5. Follow the process to create a service account and download its credentials (a JSON file).
    6. Share the desired Google Drive folders or files with the service account’s email address. You can find this email in the downloaded JSON file or in the service account details on the Google Cloud Console.
  • PHP Code Setup:

    1. Instead of the OAuth2 flow, you’ll authenticate directly using the service account credentials:
    require 'vendor/autoload.php';
    
    $client = new Google\Client();
    $client->setAuthConfig('path_to_service_account_json_file.json');
    $client->addScope(Google\Service\Drive::DRIVE);
    
    $drive = new Google\Service\Drive($client);
    
    1. The rest of your code will remain largely the same. Since the service account is already authenticated and has access to the shared folders/files on Google Drive, you don’t need manual intervention.

Using a service account lets you automate Google Drive operations without requiring manual login. Remember, service accounts are separate entities from your Google account. Any files they create won’t be seen by you unless shared, and vice versa.

Good Luck, and I am happy that you are finally getting it to work.

1 Like

Now, can we just add the above code into index.php and perform file upload, list and download operations?

{
  "type": "service_account",
  "project_id": "web***********08",
  "private_key_id": "9****ea",
  "private_key": "-----BEGIN PRIVATE KEY-----\nMI********JQDul\n-----END PRIVATE KEY-----\n",
  "client_email": "web********@********.iam.gserviceaccount.com",
  "client_id": "11*****87",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://oauth2.googleapis.com/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/web********%40********.iam.gserviceaccount.com",
  "universe_domain": "googleapis.com"
}

I created a folder in Google Drive
I right clicked and selected the share option.
I used the email address in the json file and saved it.

with library
I created a folder
I uploaded a picture
I listed the folder

However, I cannot go to Drive in Gmail and see what I created and uploaded in the folder I shared.
Is this normal?

Yes, what you are experiencing is normal when using a service account. Service accounts have their own Google Drive space that is separate from your personal Google Drive. When you create and upload files using a service account, those files are owned by the service account, not by your personal Google account.

To see files created by a service account in your personal Google Drive:

  1. Share from Service Account: The service account has to explicitly share the files or folders with your personal Google account. This can be done through the Google Drive API by setting the appropriate permissions.

  2. Access via Shared With Me: Once shared, you should be able to see the shared files or folders in the “Shared with me” section of your personal Google Drive.

If you have already shared a folder from your personal Drive with the service account, and the service account uploads files to that folder, you should be able to see those files in the shared folder directly, without having to go through “Shared with me”.

Remember that when a service account uploads files to a folder in your Drive that was shared with it, the files are still owned by the service account. If you want the files to be owned by your personal account, you would have to transfer ownership, which can only be done from within the same domain for Google Workspace accounts and is not available for consumer accounts.

Here’s a brief example of how you might share a file with your personal account using the service account in PHP:

$service = new Google_Service_Drive($client);
$fileId = 'your_uploaded_file_id';  // ID of the file you want to share

$permissions = new Google_Service_Drive_Permission(array(
    'type' => 'user',
    'role' => 'writer',
    'emailAddress' => '[email protected]'
));

try {
    $service->permissions->create($fileId, $permissions);
} catch (Exception $e) {
    echo "An error occurred: " . $e->getMessage();
}

This will grant your personal account “writer” access to the file uploaded by the service account. You can adjust the role to ‘reader’ if you only need read access.

To list and manage these files through your personal Google Drive interface, ensure that the service account has shared those files with your personal Google account. Otherwise, you will need to interact with them through the API or by directly logging in using the service account credentials, if that’s an option.

Good luck.

1 Like

Your knowledge of Google Drive is appreciated.

Thank you very much for your very detailed explanation. Since I am a newbie in Google Drive, it is a little difficult for me to understand all the terms.

I gave permission to the file and folder with the code you gave.
An email has been sent for each file.
I saw the file and folder.
I deleted the file and folder, but it was not deleted in the service account, only in my shares.
No problem.
I will create a page to delete files and folders in the service account
I learned the logic of this job thanks to you, thank you very much again.

Hello,

There is something in the library that caught my attention, but I don’t fully understand it. Can you help me?


I downloaded the file “google-api-php-client–PHP8.2.zip”
The zip content is as follows. There is a src and vendor folder. Do I need to import only the vendor folder?

Also, there is an option to remove unused, for me, how should I edit this json?


I tried this json but it gave an error, I think it was “guzzlehttp”

It would be nice to remove unused ones to reduce file size.

I only use google service
I downloaded version 8.2
Need to get vendor and src
google drive library 222MB
I ran the following code from the command window

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

Google Drive library size reduced to 8.12MB
I do not use YouTube, but when I remove YouTube, Google Drive does not work. I do not know why
Maybe he needs an amateur like me :grinning: :grinning:

Sponsor our Newsletter | Privacy Policy | Terms of Service