Cómo acceder a Google Drive usando PHP

Inicio / Cómo hacer para... / Cómo acceder a Google Drive usando PHP

El escenario que voy a analizar es este: Una aplicación desarrollada en PHP requiere acceder a archivos que sus usuarios tienen almacenados en sus propios documentos en Google Drive.

Configuración de la API De Google

1. Crear un proyecto en Google (yendo a https://console.developers.google.com/apis/credentials):

2. Habilitar el acceso a la API via OAuth (https://console.developers.google.com/apis/api/drive/overview?project=MI_PROYECTO):

3. Crear las credenciales de acceso vía OAuth:

Seleccionar OAuth:

4. Descargar las credenciales a un lugar seguro:

Ejemplo: descargar un archivo desde Google Drive usando PHP

5. Autorizar la URI de redireccionamiento

Uso de la API de Google desde PHP

Con esto hecho ya tenés lo básico para empezar a programar.

Si bien podés hacer todo en un solo archivo, no es muy recomendable, es mejor tener un archivo para cada paso del trabajo.

Ante todo, vas a necesitar la librería google/apiclient (Te recomiendo incorporarla con composer), acá podés ver un ejemplo de composer.json:

{
 "name": "leeway/google-drive",
 "require": {
 "google/apiclient": "^2.1"
 },
 "authors": [
 {
 "name": "Mauro Chojrin",
 "email": "mauro.chojrin@leewayweb.com"
 }
 ]
}

No olvides después correr el comando

composer install

Este codigo (config.php) va a ser común a todos los archivos .php que vendrán luego:

<?php
require_once 'vendor/autoload.php';
session_start();
$redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/paso2.php';
$client = new Google_Client();
$client->setAuthConfig('<PATH_AL_ARCHIVO_JSON_DE_CREDENCIALES>');
$client->setRedirectUri($redirect_uri);
$client->addScope("https://www.googleapis.com/auth/drive");

El primer paso:

Ofrecer al usuario un formulario para conectarse a su Drive (paso1.php):

<?php require_once 'config.php' ?>
<div class="request">
 <a class='login' href='<?php echo $client->createAuthUrl() ?>'>Conectame!</a>
</div>

Contar con una URL a la que Google informe que la autenticación fue exitosa (paso2.php):

<?php 
require_once 'config.php';

if (isset($_GET['code'])) {
 $token = $client->fetchAccessTokenWithAuthCode($_GET['code']);
 $client->setAccessToken($token);

 $_SESSION['upload_token'] = $token;

 header('Location: paso3.php');
}

Muy importante: este archivo (paso2.php) debe ser accesible para el cliente (Para eso es importante que su URL completa esté ingresada en la configuración de URI de redireccionamiento, sin eso nada de esto funcionará.

Paso 3 (Completar la autenticación):

<?php

require_once 'config.php';

if (!empty($_SESSION['upload_token'])) {
 $client->setAccessToken($_SESSION['upload_token']);
 if ($client->isAccessTokenExpired()) {
  unset($_SESSION['upload_token']);
  echo 'La sesion expiro. <a href="paso1.php">Volver a comenzar</a>';
  die;
 }
}
echo 'Autenticacion completa <a href="paso4.php">Descargar archivo</a>';

Paso 4:

Hacer lo que uno quiera en el drive autorizado :).

Ejemplo: descargar un archivo desde Google Drive usando PHP

<?php
require_once 'config.php';

echo '<p>Descargando el archivo "Mi archivo"</p>';
$service = new Google_Service_Drive($client);
$files = $service->files->listFiles([
 'q' => "name='Mi archivo'",
 'fields' => 'files(id,size)'
 ]);

if ( count($files) < 1 ) {
 echo 'No se encontro el archivo :(';
 die;
}
$fileId = $files[0]->id;
$fileSize = intval($files[0]->size);

$http = $client->authorize();

$fp = fopen('Mi archivo', 'w');

$chunkSizeBytes = 1 * 1024 * 1024;
$chunkStart = 0;

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());
 }
 fclose($fp);
echo '<p>Listo! Archivo disponible en: "'.realpath('Mi archivo').'"</p>';

Y listo, tenemos el archivo buscado descargado a nuestro disco.

Para probar esta aplicación (suponiendo que fuiste guardando cada porción de código en su propio archivo), iniciá el servidor de php:

php -S localhost:8080

y abrí en tu navegador:

http://localhost:8080/paso1.php

Claramente, no se trata de magia, lo que hay detrás de esto es un WebService, al que se está accediendo usando la clase Google_Service_Drive. Podes ver más información entrando a https://github.com/google/google-api-php-client.

Y ahora que sabés cómo manipular archivos que están en el drive… ¡cuidado con lo que hacés!

mchojrin

Director Académico y Docente at Leeway Academy
Hola! Soy Mauro Chojrin, estudié la Lic. en Ciencias de la Computación en la Universidad de Buenos Aires.

Me desempeño como docente de programación desde el año 1997.

Pasé por diferentes instituciones (Escuela Técnica ORT, Digital House, EducacionIT, ITMaster, Escuela DaVinci entre otros).

Actualmente coordino los cursos dictados en Leeway Academy y desarrollo sistemas usando PHP y framework Symfony

38 comentarios

  • eder

    Hola que tal buen día, me marca el siguiente error que me estara faltando:

    Warning: require_once(C:\xampp\htdocs\composer\vendor/composer/autoload_real.php): failed to open stream: No such file or directory in C:\xampp\htdocs\composer\vendor\autoload.php on line 5

    Fatal error: require_once(): Failed opening required ‘C:\xampp\htdocs\composer\vendor/composer/autoload_real.php’ (include_path=’C:\xampp\php\PEAR’) in C:\xampp\htdocs\composer\vendor\autoload.php on line 5

  • eder

    revisando si lo instale en xampp, creo que lo que me falta es hacer el archivo vendor/autoload.php pero no se como hacerlo o como generarlo.

  • eder

    Ahora me marca este error:

    Notice: Undefined variable: oauth_credentials in C:\xampp\htdocs\composer\config.php on line 5
    C:\xampp\htdocs\composer\vendor\google\auth\src\OAuth2.php on line 644

    • Bueno… parece que vamos avanzando 🙂

      La variable $oauth_credentials debe contener la ruta al archivo json que descargaste al crear las credenciales.

      Lo voy a especificar en el post. Gracias!

  • eder

    muchas gracias , tengo una duda en esta parte :

    Muy importante: este archivo (paso2.php) debe ser accesible desde Google (Para eso es importante que su URL completa esté ingresada en la configuración de URI de redireccionamiento, sin eso nada de esto funcionará.
    que dire

  • En realidad no es correcto decir que Google debe poder acceder, ya que el callback lo realiza el mismo visitante (Su navegador en rigor de verdad)… Podés ver todo esto si vas siguiendo las URLs que se generan en los links y a través de tu navegador.

    Es por eso que, para un entorno productivo, deberías poner una dirección accesible públicamente (Por ejemplo http://academy.leewayweb.com/google_callback.php)

    En el caso de una prueba como esta, la dirección que debe figurar en el cuadro de URI de redireccionamiento debe ser “http://localhost/paso2.php” (O la que uses para acceder a tu sitio en localhost).

    En mi caso sería http://localhost:8080/paso2.php

  • eder

    Gracias, ya la coloque y me pasa a la pantalla que dice:

    Te damos la bienvenida
    ederantonyo@gmail.com

    Ver y administrar los archivos en Google Drive
    ¿Quieres permitir a prueba hacer esto?

    Al hacer clic en Permitir, esta aplicación podrá usar tu información de conformidad con sus condiciones de servicio y políticas de privacidad. Puedes retirar esta aplicación (o cualquiera que esté conectada a tu cuenta) en Mi Cuenta

    ->Permitir y al darle en permitir ya no me manda a ningun lado :/ ¡Objeto no localizado! Error 404 localhost

    • Seguramente te quedó mal configurada la URI de redireccionamiento.

      Es fácil de ver. Empezá por hacerlo vos mismo desde tu navegador, intentá ingresar directamente al archivo paso2.php

      Una vez que lo logres, esa es la URI que tiene que estar en la configuración de Google.

  • eder

    bien en URIs de redirección autorizados tengo http://localhost/paso2.php

    y en pantalla de autorizacion de OAuth estan los siguientes campos como deben de ir y disculpa las molestias.
    en URL de pagina principal:
    URL de logotipo de producto:
    URL de la politica de privacidad
    URL de las condiciones de servicio:

  • eder
  • Hola Eder:

    ¡No es ninguna molestia! Haz todas las preguntas que necesites y trataré de ayudarte :). No llego a entender cuál es exactamente el problema que tienes… ¿qué tiene de malo esa URL?

  • Claudio

    Hola, estoy necesitando un script al que puedan acceder varios usuarios de google para buscar documentos dentro de una carpeta compartida. Es posible esto utilizando esta api?
    Puedo llegar a suponer (o exigir) que todos estos usuarios ya se encuentren logeados con su correspondiente cuenta.
    Me podrian guiar a un ejemplo?

    • Hola Claudio:

      ¿Cómo estás? No tengo un caso específico de lo que buscas, pero me imagino que se podría usar la API para resolver tu problema. ¿Hiciste alguna prueba con la que hayas tenido dificultades?

      Acá veo una pregunta similar a la tuya.

      ¿Eso resuelve tu problema?

  • Daniel

    Hola, ejecuto paso1, me sale Conectame! – al hacer click me lleva a elegir una cuenta de gmail.
    Luego de elegida muestra el siguiente error:

    Fatal error: Cannot use lexical variable $eventName as a parameter name in C:\wamp64\www\vendor\guzzlehttp\guzzle\src\Event\Emitter.php on line 48

    Espero me puedas guiar.
    Muchas gracias

  • Daniel

    Hola Mauro, esto es lo que muestra composer.json luego de actualizar y reinstalar composer:

    {
    “require”: {
    “guzzlehttp/guzzle”: “^6.0”
    }
    }

  • Daniel

    Así está el config.php

    setAuthConfig(‘client_secret08.09.18.json’);
    $client->setRedirectUri($redirect_uri);
    $client->addScope(“https://www.googleapis.com/auth/drive”);
    ?>

    y el autoload.php

    <?php

    // autoload.php @generated by Composer

    require_once __DIR__ . '/composer/autoload_real.php';

    return ComposerAutoloaderInitcefa83e962c7304c4fad88596dfee348::getLoader();

    • Bien.

      El autoload que muestras es el generado por composer. Eso está ok.

      Lo que parece faltar (a juzgar por el código que muestras) es el require_once 'vendor/autoload.php' en el archivo config.php.

  • Daniel

    Disculpa Mauro, creo haber copiado bien el config.php – pero en el post muestra menos código, nuevamente te lo paso al config.php

    setAuthConfig(”);
    $client->setAuthConfig(‘client_secret08.09.18.json’);
    $client->setRedirectUri($redirect_uri);
    $client->addScope(“https://www.googleapis.com/auth/drive”);
    ?>

  • Daniel

    require_once ‘vendor/autoload.php’;
    session_start();
    $redirect_uri = ‘http://’ . $_SERVER[‘HTTP_HOST’] . ‘/paso2.php’;
    $client = new Google_Client();
    //$client->setAuthConfig(”);
    $client->setAuthConfig(‘client_secret08.09.18.json’);
    $client->setRedirectUri($redirect_uri);
    $client->addScope(“https://www.googleapis.com/auth/drive”);

    • Así parece estar ok… ¿podés fijarte si tenés el archivo vendor/google/apiclient/src/Google/Client.php?

      Otra cosa que veo raro es que te de el error en el paso1.php… Ese archivo debería ejecutarse únicamente al comienzo (es el que genera el link “conectame”).

      Una vez seleccionada la cuenta debería llevarte a paso2.php (Lo que está en la varaible $redirect_uri).

      Si nada de esto te funciona diría que trates de debugearlo usando XDebug o similar.

      Ya sin ver el código en su contexto me temo que no voy a poder ayudarte… si querés que lo veamos juntos podemos coordinar una sesión de consulta.

      Saludos

  • Daniel

    Mauro, no tengo esa carpeta, ni archivo. Tengo el problema en composer.
    Al ejecutar el: composer-setup.exe – y desde un ventana de command de windows, ejecutar el
    composer install – me pide el archivo composer.json — este es el archivo que no encuentro para la
    instalación – por lo tanto si le pongo cualquier composer.json, en vendor/ aparecen cualquier carpetas
    que nada tienen que ver y por lo tanto la que vos describes no está.
    Estuve leyendo en getcomposer.org, pero no me doy cuenta de que código incluir en ese archivo composer.json.
    Si sabes como solucionar esto, te agradecería me tires un hilo.
    Muchísimas gracias

    • Ok, ok… bueno, por lo menos ahora sabemos cuál es el problema :).

      Para empezar, veo que estás usando Windows… Me ha pasado recientemente de tener problemas para usar las herramientas de CLI en Windows (Composer por ejemplo).

      Mi recomendación es que uses todo desde la terminal de Windows. O mejor, si podés instalar y usar cygwin vas a tener una terminal POSIX (Casi como si estuvieses en Linux).

      Lo que deberías hacer es ejecutar composer install desde el directorio donde tenés el proyecto.

      Otra forma que podría servirte es, desde algún directorio que quieras (Mis Documentos, por ejemplo) y siempre desde la terminal, usar el comando composer init e ir definiendo las dependencias desde ahí.

      Una vez que tengas el directorio vendor y dentro de él google/apiclient entonces vas a poder empezar a crear los scripts propios del ejemplo.

      Saludos

  • Daniel

    Mauro, limpie todo, reinstale y puedo ejecutarlo:
    pasa a: Conectar
    luego: accounts.google.com — muestra el inicio de sesión con el nombre del proyecto
    me logeo con la cuenta de correo y password
    y muestra lo siguiente:

    Fatal error: Uncaught GuzzleHttp\Exception\RequestException: cURL error 60: SSL certificate problem: unable to get local issuer certificate (see http://curl.haxx.se/libcurl/c/libcurl-errors.html) in C:\wamp64\www\vendor\guzzlehttp\guzzle\src\Handler\CurlFactory.php:187 Stack trace: #0 C:\wamp64\www\vendor\guzzlehttp\guzzle\src\Handler\CurlFactory.php(150): GuzzleHttp\Handler\CurlFactory::createRejection(Object(GuzzleHttp\Handler\EasyHandle), Array) #1 C:\wamp64\www\vendor\guzzlehttp\guzzle\src\Handler\CurlFactory.php(103): GuzzleHttp\Handler\CurlFactory::finishError(Object(GuzzleHttp\Handler\CurlHandler), Object(GuzzleHttp\Handler\EasyHandle), Object(GuzzleHttp\Handler\CurlFactory)) #2 C:\wamp64\www\vendor\guzzlehttp\guzzle\src\Handler\CurlHandler.php(43): GuzzleHttp\Handler\CurlFactory::finish(Object(GuzzleHttp\Handler\CurlHandler), Object(GuzzleHttp\Handler\EasyHandle), Object(GuzzleHttp\Handler\CurlFactory)) #3 C:\wamp64\www\vendor\guzzlehttp\guzzle\src\Handler\Proxy.php(28): GuzzleHttp\Handler\CurlHandler->__invoke(Ob in C:\wamp64\www\vendor\guzzlehttp\guzzle\src\Handler\CurlFactory.php on line 187

    • Bien, vamos avanzando 🙂

      Tuve un problema similar recientemente y, en mi caso, lo resolví apagando el Firewall de Windows.

      En tu caso, no creo que eso funcione ya que composer te funciona ok (Yo no podía instalar librerías vía composer ni hacer git pull)…

      Acá tenés información de un problema similar al tuyo.

      Suerte!

  • Daniel

    Mauro, estoy tratando de ver la solución al tema.
    Mientras te comento una inquietud. Me gustaría utilizar google drive para almacenar archivos (ej: .pdf) y desde una aplicación web en php, buscar un archivo determinado por su nombre.
    Ejemplo: usuario se logea en una página y la misma muestra que tiene 3 (tres) archivos, (los datos vienen de phpmyadmin):
    1.pdf
    2.pdf
    3.pdf
    al seleccionar uno, (ej: 2.pdf), tendría que buscar ese archivo en google drive y mostrar el contenido del mismo.
    Espero me entiendas.

  • Daniel

    Mauro, sigo avanzando poco a poco.
    Llego bien hasta el paso3.php (Autenticación completa: Descargar archivo) – en el paso4.php puse un nombre archivo que tengo en drive (‘q’ => “name=’Julieta.pdf'”) y me sale el siguiente error:

    Fatal error: Uncaught Google_Service_Exception: { “error”: { “errors”: [ { “domain”: “usageLimits”, “reason”: “dailyLimitExceededUnreg”, “message”: “Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup.”, “extendedHelp”: “https://code.google.com/apis/console” } ], “code”: 403, “message”: “Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup.” } } in C:\wamp64\www\vendor\google\apiclient\src\Google\Http\REST.php:118 Stack trace: #0 C:\wamp64\www\vendor\google\apiclient\src\Google\Http\REST.php(94): Google_Http_REST::decodeHttpResponse(Object(GuzzleHttp\Psr7\Response), Object(GuzzleHttp\Psr7\Request), ‘Google_Service_…’) #1 C:\wamp64\www\vendor\google\apiclient\src\Google\Task\Runner.php(181): Google_Http_REST::doExecute(Object(GuzzleHttp\Client), Object(GuzzleHttp\Psr7\Request), ‘Google_Service_…’) #2 C:\wamp64\www\vendor\google\apiclient\src\Google\Http\REST.php(58): Google_Task_Runner->run() #3 C:\wamp64\www\vendor\google\apiclient\src\Goo in C:\wamp64\www\vendor\google\apiclient\src\Google\Http\REST.php on line 118

    • Vaya… no me había cruzado antes con ese error… Por lo que he podido leer puede deberse a dos cosas:

      1. Uso de un token vencido (Fijate la documentación sobre métodos de refresco de token)
      2. Efectivamente estás haciendo demasiados requests en poco tiempo (Para verificar esto simplemente volvé a probar tu código después de un rato de no hacer requests). Si este fuera el caso una opción que podés probar es agrupar requests de modo de no excederte de los límites establecidos.

      Algo más de info podés ver acá

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.