So this is supposed to be a quick article detailing how I used a PHP function to upload a video file to Google Drive. Note that this example does not involve installing the Google Client Library for PHP. So no classes or built-in functions that you didn't write or know what they're doing.
Why?
The objective here is to upload a video file to my Google Drive. This assumes you have already "Enabled the Drive API" via your Google Developers console as well as gotten your OAuth 2.0 access/refresh tokens and specified the appropriate scopes.
The scopes I chose were to do with getting a working example rather than the recommended scope, though you may only need the first (untested):
https://www.googleapis.com/auth/drive.file https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile
- https://www.googleapis.com/auth/drive.file
- https://www.googleapis.com/auth/userinfo.email
- https://www.googleapis.com/auth/userinfo.profile
How?
I've listed below 3 methods, the first follows the manual (or the logic thereof as I don't use the client library) and is a function sending two requests, the second is the appropriate multipart function which uploads and names the file in a single request, and the third is a 'nice-to-have' upload to the specified folder.
Method #1: two requests
1. Send the media file
2. Update the name of the file you just uploaded
$GAPIS = 'https://www.googleapis.com/'; function uploadFile($access_token, $file, $mime_type, $name) { global $GAPIS; $ch1 = curl_init(); // don't do ssl checks curl_setopt($ch1, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch1, CURLOPT_SSL_VERIFYHOST, false); // do other curl stuff curl_setopt($ch1, CURLOPT_URL, $GAPIS . 'upload/drive/v3/files?uploadType=media'); curl_setopt($ch1, CURLOPT_BINARYTRANSFER, 1); curl_setopt($ch1, CURLOPT_POST, 1); curl_setopt($ch1, CURLOPT_POSTFIELDS, file_get_contents($file)); curl_setopt($ch1, CURLOPT_RETURNTRANSFER, true); // set authorization header curl_setopt($ch1, CURLOPT_HTTPHEADER, array('Content-Type: '.$mime_type, 'Content-Length: ' . filesize($file), 'Authorization: Bearer ' . $access_token) ); // execute cURL request $response=curl_exec($ch1); if($response === false){ $output = 'ERROR: '.curl_error($ch1); } else{ $output = $response; } // close first request handler curl_close($ch1); // now let's get the ID of the file we just created // and submit the file metadata $this_response_arr = json_decode($response, true); if(isset($this_response_arr['id'])){ $this_file_id = $this_response_arr['id']; $ch2 = curl_init(); // don't do ssl checks curl_setopt($ch2, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch2, CURLOPT_SSL_VERIFYHOST, false); // do other curl stuff curl_setopt($ch2, CURLOPT_URL, $GAPIS . 'drive/v3/files/'.$this_file_id); curl_setopt($ch2, CURLOPT_CUSTOMREQUEST, 'PATCH'); // initialize fields to submit $post_fields = array(); // remove extension $this_file_name = explode('.', $name); // submit name field $post_fields['name']=$this_file_name[0]; curl_setopt($ch2, CURLOPT_POSTFIELDS, json_encode($post_fields)); // return response as a string curl_setopt($ch2, CURLOPT_RETURNTRANSFER, true); // set authorization header curl_setopt($ch2, CURLOPT_HTTPHEADER, array('Content-Type: application/json', 'Authorization: Bearer ' . $access_token) ); // execute cURL request $response=curl_exec($ch2); if($response === false){ $output = 'ERROR: '.curl_error($ch2); } else{ $output = $response; } // close second request handler curl_close($ch2); } return $output; }
- $GAPIS = 'https://www.googleapis.com/';
- function uploadFile($access_token, $file, $mime_type, $name) {
- global $GAPIS;
- $ch1 = curl_init();
- // don't do ssl checks
- curl_setopt($ch1, CURLOPT_SSL_VERIFYPEER, false);
- curl_setopt($ch1, CURLOPT_SSL_VERIFYHOST, false);
- // do other curl stuff
- curl_setopt($ch1, CURLOPT_URL, $GAPIS . 'upload/drive/v3/files?uploadType=media');
- curl_setopt($ch1, CURLOPT_BINARYTRANSFER, 1);
- curl_setopt($ch1, CURLOPT_POST, 1);
- curl_setopt($ch1, CURLOPT_POSTFIELDS, file_get_contents($file));
- curl_setopt($ch1, CURLOPT_RETURNTRANSFER, true);
- // set authorization header
- curl_setopt($ch1, CURLOPT_HTTPHEADER, array('Content-Type: '.$mime_type, 'Content-Length: ' . filesize($file), 'Authorization: Bearer ' . $access_token) );
- // execute cURL request
- $response=curl_exec($ch1);
- if($response === false){
- $output = 'ERROR: '.curl_error($ch1);
- } else{
- $output = $response;
- }
- // close first request handler
- curl_close($ch1);
- // now let's get the ID of the file we just created
- // and submit the file metadata
- $this_response_arr = json_decode($response, true);
- if(isset($this_response_arr['id'])){
- $this_file_id = $this_response_arr['id'];
- $ch2 = curl_init();
- // don't do ssl checks
- curl_setopt($ch2, CURLOPT_SSL_VERIFYPEER, false);
- curl_setopt($ch2, CURLOPT_SSL_VERIFYHOST, false);
- // do other curl stuff
- curl_setopt($ch2, CURLOPT_URL, $GAPIS . 'drive/v3/files/'.$this_file_id);
- curl_setopt($ch2, CURLOPT_CUSTOMREQUEST, 'PATCH');
- // initialize fields to submit
- $post_fields = array();
- // remove extension
- $this_file_name = explode('.', $name);
- // submit name field
- $post_fields['name']=$this_file_name[0];
- curl_setopt($ch2, CURLOPT_POSTFIELDS, json_encode($post_fields));
- // return response as a string
- curl_setopt($ch2, CURLOPT_RETURNTRANSFER, true);
- // set authorization header
- curl_setopt($ch2, CURLOPT_HTTPHEADER, array('Content-Type: application/json', 'Authorization: Bearer ' . $access_token) );
- // execute cURL request
- $response=curl_exec($ch2);
- if($response === false){
- $output = 'ERROR: '.curl_error($ch2);
- } else{
- $output = $response;
- }
- // close second request handler
- curl_close($ch2);
- }
- return $output;
- }
Usage:
$mime_type = 'video/mp4'; // could be 'image/jpeg', etc. $new_name = 'My Video'; $the_file_and_path = '../videos/my_video.mp4'; $result = uploadFile($my_access_token, $the_file_and_path, $mime_type, $new_name);
- $mime_type = 'video/mp4';  // could be 'image/jpeg', etc.
- $new_name = 'My Video';
- $the_file_and_path = '../videos/my_video.mp4';
- $result = uploadFile($my_access_token, $the_file_and_path, $mime_type, $new_name);
Method #2: Mulitipart single request
This is my recommended version. In this function, we are sending the metadata before the media:
$GAPIS = 'https://www.googleapis.com/'; function uploadFile($access_token, $file, $mime_type, $name) { global $GAPIS; $ch1 = curl_init(); // don't do ssl checks curl_setopt($ch1, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch1, CURLOPT_SSL_VERIFYHOST, false); $my_beautiful_body = ' --joes_awesome_divider Content-Type: application/json; charset=UTF-8 { "name": "'.$name.'" } --joes_awesome_divider Content-Type: '.$mime_type.' '.file_get_contents($file).' --joes_awesome_divider-- '; // do other curl stuff curl_setopt($ch1, CURLOPT_URL, $GAPIS . 'upload/drive/v3/files?uploadType=multipart'); curl_setopt($ch1, CURLOPT_POST, 1); curl_setopt($ch1, CURLOPT_POSTFIELDS, $my_beautiful_body); curl_setopt($ch1, CURLOPT_RETURNTRANSFER, true); // set authorization header curl_setopt($ch1, CURLOPT_HTTPHEADER, array('Content-Type: multipart/related; boundary=joes_awesome_divider', 'Authorization: Bearer ' . $access_token) ); // execute cURL request $response=curl_exec($ch1); if($response === false){ $output = 'ERROR: '.curl_error($ch1); } else{ $output = $response; } // close first request handler curl_close($ch1); return $output; }
- $GAPIS = 'https://www.googleapis.com/';
- function uploadFile($access_token, $file, $mime_type, $name) {
- global $GAPIS;
- $ch1 = curl_init();
- // don't do ssl checks
- curl_setopt($ch1, CURLOPT_SSL_VERIFYPEER, false);
- curl_setopt($ch1, CURLOPT_SSL_VERIFYHOST, false);
- $my_beautiful_body = '
- --joes_awesome_divider
- Content-Type: application/json; charset=UTF-8
- {
- "name": "'.$name.'"
- }
- --joes_awesome_divider
- Content-Type: '.$mime_type.'
- '.file_get_contents($file).'
- --joes_awesome_divider--
- ';
- // do other curl stuff
- curl_setopt($ch1, CURLOPT_URL, $GAPIS . 'upload/drive/v3/files?uploadType=multipart');
- curl_setopt($ch1, CURLOPT_POST, 1);
- curl_setopt($ch1, CURLOPT_POSTFIELDS, $my_beautiful_body);
- curl_setopt($ch1, CURLOPT_RETURNTRANSFER, true);
- // set authorization header
- curl_setopt($ch1, CURLOPT_HTTPHEADER, array('Content-Type: multipart/related; boundary=joes_awesome_divider', 'Authorization: Bearer ' . $access_token) );
- // execute cURL request
- $response=curl_exec($ch1);
- if($response === false){
- $output = 'ERROR: '.curl_error($ch1);
- } else{
- $output = $response;
- }
- // close first request handler
- curl_close($ch1);
- return $output;
- }
Usage:
$mime_type = 'video/mp4'; // could be 'image/jpeg', etc. $new_name = 'My Video'; $the_file_and_path = '../videos/my_video.mp4'; $result = uploadFile($my_access_token, $the_file_and_path, $mime_type, $new_name);
- $mime_type = 'video/mp4';  // could be 'image/jpeg', etc.
- $new_name = 'My Video';
- $the_file_and_path = '../videos/my_video.mp4';
- $result = uploadFile($my_access_token, $the_file_and_path, $mime_type, $new_name);
Method #3: As method 2 but with specified folder
To get the folder ID, simply browse to the Google Drive folder in your browser and note the last string in the URL. So in https://drive.google.com/drive/folders/<SomeAlphaNumericCharactersAndThenSome>, the value where "<SomeAlphaNumericCharactersAndThenSome>" sits will be your folder ID.
$GAPIS = 'https://www.googleapis.com/'; function uploadFile($access_token, $file, $mime_type, $name, $folder) { global $GAPIS; $ch1 = curl_init(); // don't do ssl checks curl_setopt($ch1, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch1, CURLOPT_SSL_VERIFYHOST, false); $my_beautiful_body = ' --joes_awesome_divider Content-Type: application/json; charset=UTF-8 { "name": "'.$name.'", "parents": ["'.$folder.'"] } --joes_awesome_divider Content-Type: '.$mime_type.' '.file_get_contents($file).' --joes_awesome_divider-- '; // do other curl stuff curl_setopt($ch1, CURLOPT_URL, $GAPIS . 'upload/drive/v3/files?uploadType=multipart'); curl_setopt($ch1, CURLOPT_POST, 1); curl_setopt($ch1, CURLOPT_POSTFIELDS, $my_beautiful_body); curl_setopt($ch1, CURLOPT_RETURNTRANSFER, true); // set authorization header curl_setopt($ch1, CURLOPT_HTTPHEADER, array('Content-Type: multipart/related; boundary=joes_awesome_divider', 'Authorization: Bearer ' . $access_token) ); // execute cURL request $response=curl_exec($ch1); if($response === false){ $output = 'ERROR: '.curl_error($ch1); } else{ $output = $response; } // close first request handler curl_close($ch1); return $output; }
- $GAPIS = 'https://www.googleapis.com/';
- function uploadFile($access_token, $file, $mime_type, $name, $folder) {
- global $GAPIS;
- $ch1 = curl_init();
- // don't do ssl checks
- curl_setopt($ch1, CURLOPT_SSL_VERIFYPEER, false);
- curl_setopt($ch1, CURLOPT_SSL_VERIFYHOST, false);
- $my_beautiful_body = '
- --joes_awesome_divider
- Content-Type: application/json; charset=UTF-8
- {
- "name": "'.$name.'",
- "parents": ["'.$folder.'"]
- }
- --joes_awesome_divider
- Content-Type: '.$mime_type.'
- '.file_get_contents($file).'
- --joes_awesome_divider--
- ';
- // do other curl stuff
- curl_setopt($ch1, CURLOPT_URL, $GAPIS . 'upload/drive/v3/files?uploadType=multipart');
- curl_setopt($ch1, CURLOPT_POST, 1);
- curl_setopt($ch1, CURLOPT_POSTFIELDS, $my_beautiful_body);
- curl_setopt($ch1, CURLOPT_RETURNTRANSFER, true);
- // set authorization header
- curl_setopt($ch1, CURLOPT_HTTPHEADER, array('Content-Type: multipart/related; boundary=joes_awesome_divider', 'Authorization: Bearer ' . $access_token) );
- // execute cURL request
- $response=curl_exec($ch1);
- if($response === false){
- $output = 'ERROR: '.curl_error($ch1);
- } else{
- $output = $response;
- }
- // close first request handler
- curl_close($ch1);
- return $output;
- }
Usage:
$mime_type = 'video/mp4'; $new_name = 'My Video'; $the_file_and_path = '../videos/my_video.mp4'; $folder_id = 'l4S9F71BMqlXWtl4uGvy2etd_hrNwmroi'; $result = uploadFile($my_access_token, $the_file_and_path, $mime_type, $new_name, $folder_id);
- $mime_type = 'video/mp4';
- $new_name = 'My Video';
- $the_file_and_path = '../videos/my_video.mp4';
- $folder_id = 'l4S9F71BMqlXWtl4uGvy2etd_hrNwmroi';
- $result = uploadFile($my_access_token, $the_file_and_path, $mime_type, $new_name, $folder_id);
Response(s)
The response should be a JSON with the file metadata (yours will be different but this is just an example). You may want to extract the ID so that you can manage the file further.
{ "kind": "drive#file", "id": "1srXLU-lotsofalphanumericcharacters_", "name": "my_video.mp4", "mimeType": "video/mp4" }
- {
- "kind": "drive#file",
- "id": "1srXLU-lotsofalphanumericcharacters_",
- "name": "my_video.mp4",
- "mimeType": "video/mp4"
- }
Additional:
Why not? Let's add a description and some security where we disable download, sharing, etc. to the viewers (except the owner). In other words, ticking the owner settings under the advanced sharing settings programmatically:
- Prevent editors from changing access and adding new people :: Set by "writersCanShare" = false
- Disable options to download, print and copy for commenters and viewers :: Set by "copyRequiresWriterPermission" = true
To do this, set the metadata to the following in the above function:
{ "name": "'.$name.'", "parents": ["'.$folder.'"], "description": "'.$desc.'", "copyRequiresWriterPermission": true, "writersCanShare": false }
- {
- "name": "'.$name.'",
- "parents": ["'.$folder.'"],
- "description": "'.$desc.'",
- "copyRequiresWriterPermission": true,
- "writersCanShare": false
- }
Source(s):
- Google Drive API v3
- Google OAuth 2.0 Playground
- Google Developers Console - APIs
- RFC 2387 - The MIME Multipart/Related Content-type
- Google Drive API v3 | Files Update
- JoelLipman.com - Google Authentication - OAuth 2.0 using PHP/cURL