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.
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.
Thanks for share. It’s error if file > 100Mb. Please help me fix it.
What error do you get?
hi i am not undersatnd http://ruparnatechnology.com/google_drive_uploader.php
please try to solve with me
Jitu.
this script is meant to be ran from the command line, not from a web browser.
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 ?
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.
hi,
the file is missing from your server. Please reupload.
Thanks
I’ve been moving servers around and this fell through the cracks. Thanks for letting me know 🙂 the file is back up.
How would I specify a parent folder where to upload the file?
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.
Yup 🙂 proper documentation is here: https://developers.google.com/drive/v2/reference/files/insert
Good luck!
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
how to get the url of file uploaded in drive
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.
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 ?
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!
Thank you!
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
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!
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 :).
Salute to you saved my day.
If you would have provided the option to donate i would have done that too.
Thanks !!!!!
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!
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 😉
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.
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 😉
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
use file key 🙂 http://systemsarchitect.net/automated-backups-to-google-drive-with-php-api/
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
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?
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.
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.
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: [*/*]"
}
}
Did you change the mime types I had hardcoded in the script?
no I used same script…
Also noticed that the access token changes everytime I rm /tmp/access_token_* … I thought it has a lifetime of 3600s..
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).
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 🙂
How can I obtain a refresh token?
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.
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
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.
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!
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?
The refresh token that you have gotten, is it possible that it needs to be json decoded before you can use it?
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
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.
Also just for kicks, you should try to json_decode what you got and plug the result in, you never know 🙂
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!
and just in case,i pasted your code into NetBeans and ran it from there…
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.
thank you!
Dear man! You really save my health and time!
God bless you for this solution!
Happy to have helped!
Let me know if you make improvements to it, it’s definitely not a final solution.
Take care.