Ben's Blog

I.T. ben January 06, 2013

Google drive API file upload script

If you want to upload file to Google Drive, you will naturally gravitate towards the Google Drive API. While reading about the APIs that Google publishes for almost anything, you will learn about their SDK. The SDK provides you with easy functions for interfacing with the API for various programming languages.

The problem is that the more I used the SDK the more confused I was. The documentation is often unclear, not all bindings are implemented across all languages. But above all, the thing that made me dislike the SDK is the fact that uploading a file to Google Drive took 5 times the amount of memory than the file itself. Meaning that the datastructure they use and how they pass it around is SUPER LAME. Not a huge deal if you’re uploading a few doc files but definitely crappy for GB range files. It’s just not right and completes the pattern of “meh” surrounding the SDK.

What is clear & consistently documented is every single API call you can make. It was time to go straight to the API. Sure there is still quite a bit of poking involved in getting something working exactly right but my experience with the API has been a lot better. It has also helped me understand the mindset & design so figuring out new things is much faster.

How?

HTTP, every API call uses it. You can use any technology that you are familiar with to do your HTTP call but I have a penchant for PHP + cURL.

The script

It will read a file in chunks and upload them consecutively. Do to so it uses the API’s resumable uploads. As such it will never consume more RAM that the configurable chunk size.

download

It still needs a few improvements at the moment but it’s functional.

What it solves

  • authentication: getting a new access token from a refresh token as needed
  • curl custom HTTP requests with custom headers
  • file chunking
  • Google Drive API resumable upload
  • passing JSON encoded requests in body
  • exponential backoff

Doesn’t sound like much but it took a while to piece it all together.

Recent Comments

  1. AlexRsk says:
    February 2, 2013 at 11:19 pm

    Dear man! You really save my health and time!
    God bless you for this solution!

    Reply
    • Ben says:
      February 4, 2013 at 11:11 am

      Happy to have helped!

      Let me know if you make improvements to it, it’s definitely not a final solution.

      Take care.

      Reply
  2. gail says:
    April 10, 2013 at 1:27 am

    thank you for this program 🙂
    unfortunately though, i am having a problem whenever i run this on my browser. this error appears:

    #!/usr/bin/php
    Notice: Undefined variable: argv in C:xampphtdocsgoogle_drive_uploaderindex.php on line 28

    Notice: Undefined variable: argv in C:xampphtdocsgoogle_drive_uploaderindex.php on line 29
    usage: [folder_id] where is the full path to the file that you want to upload to Google Drive. and [folder_id] is the the folder where you want to upload the file (optional, defaults to root)

    how could i solve this? please and thank you!

    Reply
    • gail says:
      April 10, 2013 at 1:30 am

      and just in case,i pasted your code into NetBeans and ran it from there…

      Reply
      • Ben says:
        April 10, 2013 at 10:51 am

        Hey,

        are you running this as a console script? It looks like you’re loading it as a webpage. When you run a PHP script manually you can pass extra parameters to the command you use to invoke your script. They end up in a super variable called “argv”, this is common across several programming languages.

        In the case of the Google Drive uploader, I’m counting on the folder ID to be passed to the script as a parameter so it knows where to upload the file.

        Your script should be invoked as such:
        ./google_drive_uploader.php [folder_id]

        Having this behind a web servers means you can’t pass parameters via argv hence the undefined variable error. If you absolutely need to run this from a web server you will want to rewrite it a bit so it takes its folder id from somewhere else, maybe a $_GET variable, maybe hardcode it if it’s static.

        I hope this helps.

        Reply
        • gail says:
          April 11, 2013 at 12:45 am

          thank you!

          Reply
  3. MK says:
    April 18, 2013 at 2:01 pm

    Looks great thanks for doing this. Top quality guy 🙂 I’m a little bit of a programming newbie, can’t figure out how to solve this error I keep getting:

    So far I’ve:
    >Via google API console created an installed application
    > Got the Client/ID secret from that
    > The refresh token is where I’m a bit confused, I used the following to set the original refresh token:
    https://accounts.google.com/o/oauth2/auth?response_type=code&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&client_id={myid}&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive&access_type=offline&approval_prompt=force

    But maybe this is where I’m going wrong?

    And here is the error:
    root@199:/var/www# php drive.php worker.php
    > mime type detected: text/x-php
    > retrieving access token
    > getting new one
    PHP Notice: Undefined property: stdClass::$access_token in /var/www/drive.php on line 253
    ERROR: problems getting an access token

    Reply
    • Ben says:
      April 19, 2013 at 8:42 am

      The refresh/access token handling logistic is very convoluted and had me confused and taking guesses for the longest time. It’s ok to bang your head against the wall a bit trying to figure it out.

      So you’ve set the configuration variables at the top of the file right? ($client_id, $client_secret & $refresh_token)

      Where did you get them from? Which process did you follow?

      It’s important because there are different types of client IDs you can create and also because of encoding.

      Reply
      • MK says:
        April 19, 2013 at 6:28 pm

        Cheers mate, makes me feel a little better about all this head banging 🙂

        Yeah, all these values have been set. I got the $client_id, $client_secret values from the Google Console > API Access and created a “Client ID for installed applications”.

        The $refresh_token was the confusing bit, the only way I got this was by trying to install the php sample upload code provided in the api documentation -that didn’t work for me either but it spat out a URL that had a refresh token and that’s the one I used!

        Appreciate the help!

        Reply
        • MK says:
          April 19, 2013 at 9:20 pm

          Just read that comment back and it sounded like I solved it, but still banging my head haha. Must be an issue with the refresh token if you have the same console api setup as me, how did you get your token? any ideas where this might be going wrong buddy?

          Reply
          • Ben says:
            April 21, 2013 at 5:59 am

            The refresh token that you have gotten, is it possible that it needs to be json decoded before you can use it?

          • MK says:
            April 22, 2013 at 5:29 pm

            Unlikely because it was provided via a URL and appeared in an input box.

            I’ll take another stab at it tonight and see if I get anywhere, you should work for google man, this whole process is a huge headache!

            – Thanks

          • Ben says:
            April 22, 2013 at 7:17 pm

            It really is a headache, that’s why I went out of my way to publish this online.

            Can I ask you for exactly where you got your refresh token from? I can try and reproduce these steps on my end and see what I get.

            As noted in my reply to Jakup below, I followed a pretty unorthodox process to get mine.

          • Ben says:
            April 22, 2013 at 7:21 pm

            Also just for kicks, you should try to json_decode what you got and plug the result in, you never know 🙂

  4. Jakup says:
    April 22, 2013 at 12:43 pm

    How can I obtain a refresh token?

    Reply
    • Ben says:
      April 22, 2013 at 1:19 pm

      Use this script:
      https://developers.google.com/drive/quickstart-php

      Add a line to print_r( $accessToken ) after it has been retrieved.

      It will contain the refresh token as well, except it will be JSON encoded so make sure to json_decode() it before using it in my script.

      Super tricky & convoluted, there might be a better way to retrieve a refresh token but that’s the only process I managed to get working. At least you only have to do it once for the refresh token.

      Reply
  5. Jay says:
    April 22, 2013 at 2:59 pm

    Nice script but I am getting this error:
    > mime type detected: regular file
    > retrieving access token
    > from cache
    > creating file with Google
    ERROR: could not create resumable file
    Array
    (
    [code] => 400
    [headers] => Array
    (
    [server] => HTTP Upload Server Built on Apr 8 2013 13:06:58 (1365451618)
    [content-type] => application/json
    [date] => Mon, 22 Apr 2013 20:03:13 GMT
    [pragma] => no-cache
    [expires] => Fri, 01 Jan 1990 00:00:00 GMT
    [cache-control] => no-cache, no-store, must-revalidate
    [content-length] => 285
    )

    [body] => {
    “error”: {
    “errors”: [
    {
    “domain”: “global”,
    “reason”: “badContent”,
    “message”: “Media type ‘regular file’ is not supported. Valid media types: [*/*]”
    }
    ],
    “code”: 400,
    “message”: “Media type ‘regular file’ is not supported. Valid media types: [*/*]”
    }
    }

    Reply
    • Ben says:
      April 22, 2013 at 3:42 pm

      Did you change the mime types I had hardcoded in the script?

      Reply
      • Jay says:
        April 22, 2013 at 3:43 pm

        no I used same script…

        Reply
        • Jay says:
          April 22, 2013 at 3:45 pm

          Also noticed that the access token changes everytime I rm /tmp/access_token_* … I thought it has a lifetime of 3600s..

          Reply
          • Ben says:
            April 22, 2013 at 7:09 pm

            It does have a lifetime, that is how long you can keep using it until Google asks you to get another one with your refresh token.

            That being said, if you ask for another access token before the current one expires, Google is happy to oblige even before it expires (I believe the old one then becomes invalid).

        • Ben says:
          April 22, 2013 at 7:15 pm

          And you are uploading an actual mp4 video? Setting up your tokens is supposed to be the hardest part, at least you have that behind you 🙂

          Reply
  6. James Attard says:
    April 23, 2013 at 5:21 am

    A better way to get refresh and access token is described in my blog: http://www.jamesattard.com/2013/04/generate-google-api-refresh-and-access.html .

    Moreover Ben, I got inspired by your script, it is indeed well written but the MIME part looks broken, and managed to make it work by eliminating that part completely. In the future I might code my own algorithm to detect the MIME.

    Reply
    • Ben says:
      April 23, 2013 at 12:04 pm

      Interesting! Yeah mime types are hardcoded here, it’s curious you got away with just removing them.

      Thanks for following up with solutions & improvements, I’m sure it will help someone.

      Reply
  7. ryan says:
    April 23, 2013 at 11:27 pm

    Thanks for the script, I am really in need of this right now, but I am having a problem, I get this when i run from the command line

    > mime type detected: text/plain
    > retrieving access token
    > getting new one
    PHP Notice: Undefined property: stdClass::$access_token in /mnt/hgfs/shared/PROJECTS/axs.com/google_drive_uploader.php on line 254
    ERROR: problems getting an access token

    any help is greatly appreciated, thanks

    Reply
    • Ben says:
      April 24, 2013 at 7:03 pm

      So, like many others here, you are having token issues 🙂

      How did you go about retrieving the refresh token that you plugged in the script?

      Reply
  8. Lucas says:
    September 14, 2013 at 1:02 pm

    use file key 🙂 http://systemsarchitect.net/automated-backups-to-google-drive-with-php-api/

    Reply
  9. L3opold says:
    November 24, 2013 at 8:47 am

    Hi mate,
    First of all, i want to thank you for this awesome job.

    I use cURL and PHP for youtube upload and i’ve a problem with the parsed_response function.
    I think it’s not the same thing that Google drive because youtube anwser me strange thing.
    In fact, Range are not in headers, and i receive two Code : 100 Continue just before a 308 Resume Incomplete.

    Can you help me to improve this function ?

    Thanks in advance

    Reply
  10. L3opold says:
    November 24, 2013 at 8:58 am

    To improve my last comment (i let u fusion),
    My header is good (without range anyway), i’ve a code (100 stange code by the way), but my body response looks like :
    HTTP /1.1 308 Resume Incomplete
    Range: bytes=0-524288
    X-Range-MD5 ….
    ….
    ….

    Maybe i make a mistake and that’s why Youtube gives me two response code. Anyway my upload works but if you can help me to figure out i really apreciate it.

    Thanks again 😉

    Reply
    • Ben says:
      November 24, 2013 at 9:05 pm

      Yeah so… this might not be the answer you are looking for but I’m pretty sure that it’s a bug on Google’s side.

      As far as I know you should never ever get 2 response codes back from an HTTP server. So that’s kind of a dead giveaway that something is fishy; now I’m guilty of not reporting the bug to them. We have a few other issues we’ve told them about and they move at a glacial pace.

      So as far as fixing your problem, it’s simple, if you see 2 response codes, disregard the first one :). The reason my code does not account for this phenomenon is that they actually didn’t have this erroneous behavior previously. It was introduced a few months ago and I just hardcoded around it.

      I hope this helps.

      Reply
      • L3opold says:
        November 27, 2013 at 10:48 am

        Hi,
        I found by looking over and over on diffirent API like Facebook, or Dailymotion and i found this line in the middle of a request function :
        // disable the ‘Expect: 100-continue’ behaviour. This causes CURL to wait for 2 seconds if the server does not support this header.
        $existing_headers[] = ‘Expect:’;

        By the way, i fixe the problem like u said by avoid first response.

        Thank you again you are awesome 😉

        Reply
  11. Laura says:
    March 25, 2014 at 9:22 pm

    It took some doing, but using refresh token generation contributed by James above and removing the mime types and I got this working. Thank you so much, you guys really helped me out!

    Reply
  12. Deepak says:
    June 27, 2014 at 6:14 am

    Salute to you saved my day.
    If you would have provided the option to donate i would have done that too.
    Thanks !!!!!

    Reply
  13. Sergio says:
    July 29, 2014 at 10:40 am

    Hi Ben. I had the issue that described L3opold: I was receiving two codes in the same response (first 100, and then 308). So I needed to modify your script and finally I got it working. I modified the parse_response function to get only the last response code. Here it is: https://github.com/sjvc/backup-linux-to-google-drive/blob/master/google_drive_uploader.php. I also modified chunk size as I needed.

    Thanks for sharing it!

    Reply
    • Ben says:
      July 29, 2014 at 3:57 pm

      And thanks for improving it! I’ve been reluctant to update parse_response() so far hoping that Google’s erroneous behavior was temporary but it’s been about a year now so maybe we should just get used to it :).

      Reply
  14. Soumen karak says:
    November 30, 2015 at 12:00 pm

    Is there any way to login in google through back end script, without any user interface .
    Actual i want to upload file in google drive without any user login .
    anonymous user also can upload file in same google drive .
    Is it possible ? If possible how .
    please contact me in email.
    Email:- bapankarak@gmail.com

    Reply
  15. Didar says:
    March 15, 2016 at 3:01 am

    Thank you!

    Reply
  16. Lakhan says:
    May 5, 2016 at 8:48 am

    Hi ,
    I am Getting this error
    “usage: [folder_id] where is the full path to the file that you want to upload to Google Drive. and [folder_id] is the the folder where you want to upload the file (optional, defaults to root)”

    can u pls help me ?

    Reply
    • ben says:
      May 5, 2016 at 1:51 pm

      It looks like you are trying to call this from a web browser. This is a script meant to be called from the command line. You could probably tweak it to be ran from the web browser but you’ll have to get your hands dirty 🙂 Take a look at all the arguments given with $argv and try to hardcode them instead, or get them through $_GET or $_POST variables maybe.

      Good luck!

      Reply
  17. mas says:
    July 22, 2016 at 11:09 am

    how to get the url of file uploaded in drive

    Reply
    • ben says:
      July 22, 2016 at 10:10 pm

      Take a look at the create_google_file() function, right now it returns the location of where to upload the file. Either this location has the file ID which you can use to build a client accessible URL, or maybe you can improve the function such that it returns more information about the file it just created than just the upload location.

      If you look at the API call that the function makes: https://developers.google.com/drive/v2/reference/files/insert you’ll see that what is returned is a complete file ressource (https://developers.google.com/drive/v2/reference/files#resource) which will contain all the properties about a file.

      I hope this helps.

      Reply
  18. Mads Genefke says:
    October 26, 2016 at 9:39 pm

    Hi Ben.

    I am pretty new to programming. Right now i am trying to make an app which records a video and uploads it to the Google Drive, but i can only manage to take pictures and upload not videoes

    Maybe you would look into it?

    Here is my script

    http://pastebin.com/SuCsNhMz

    Reply
  19. Tomáš says:
    February 26, 2017 at 11:16 am

    How would I specify a parent folder where to upload the file?

    Reply
    • Tomáš says:
      February 26, 2017 at 1:19 pm

      Oh, I see, on line 38:

      $folder_id = “” ;

      one needs ot copy a hash value from the url of the folder where one wants to upload the file and put inside the quotes.

      Reply
      • ben says:
        February 26, 2017 at 6:42 pm

        Yup 🙂 proper documentation is here: https://developers.google.com/drive/v2/reference/files/insert

        Good luck!

        Reply
  20. Anonymous says:
    November 10, 2017 at 5:35 am

    hi,

    the file is missing from your server. Please reupload.
    Thanks

    Reply
    • ben says:
      November 10, 2017 at 9:59 pm

      I’ve been moving servers around and this fell through the cracks. Thanks for letting me know 🙂 the file is back up.

      Reply
  21. Arjan says:
    February 22, 2018 at 5:08 pm

    Ben, with the API being now (hopefully) further develloped.

    Do you feel your script still holds sufficient value after 5 years ?
    Or should we use the drive API v3 these days ?

    Reply
    • ben says:
      February 22, 2018 at 5:41 pm

      Well, I’m not even aware of a v2 sunset date. My bet is that Google itself has quite a few dependencies on it. So I don’t know, if you want your script to run for the next 10 years, sure you should probably use v3. If you’re learning the API and setting up something new, yeah, might as well learn v3. Otherwise v2 is just fine.

      In my experience there are only minor differences between v2 and v3. This script is still a good reference point if you want to build something v3 from the ground up. Some of the concepts and implementations are the same.

      Reply
  22. jitu says:
    April 10, 2018 at 7:29 am

    hi i am not undersatnd http://ruparnatechnology.com/google_drive_uploader.php

    please try to solve with me

    Reply
    • ben says:
      April 10, 2018 at 11:50 am

      Jitu.

      this script is meant to be ran from the command line, not from a web browser.

      Reply
  23. Violetlotous says:
    March 12, 2019 at 3:58 pm

    Thanks for share. It’s error if file > 100Mb. Please help me fix it.

    Reply
    • ben says:
      March 12, 2019 at 4:39 pm

      What error do you get?

      Reply
  24. Pingback: Cargar archivo a través de PHP en Google Drive usando la API sin consentimiento RePHP

Leave a Comment

Cancel reply

This blog is solar powered

Interactive

Handwriting Capture
Mandalagaba
IPv6 link-local to MAC converter
IPv6 MAC to link-local converter
Markov Text Generation
Markov Word Generation
Markov Music Generation
Duplogrifier
Flood Fill Algorithms
Homestead Metrics
RGB Playground
Web Games

Categories

  • aesthetics111
    • plots54
    • specular holography6
  • Books3
  • I.T.202
    • 3D modeling / printing21
    • AI6
    • all out geekery36
    • electronics27
    • homestead automation6
    • maniacal paranoia25
    • plotters49
    • unix / linux29
    • video games4
    • web development29
    • web games3
  • Lego / Duplo67
  • life in the U.S.42
  • miscellaneous202
  • nature encounters114
  • old vinyls3
  • organs2
  • self sustainability560
    • agriculture105
    • apiculture38
    • apple20
    • building131
    • canning3
    • crochet6
    • foraging6
    • hunting10
    • maple syrup47
    • poultry39
    • preserving2
    • solar power28
    • water23
    • wood84
  • trip to a new life6
Theme by Bloompixel. Proudly Powered by WordPress