Found this useful? Love this post

PHP server-side YouTube V3 OAuth API video upload guide

Dec 2014 – Please note this post is based on the 1.0.5 version of the API. If you are using the latest version you’ll need to update file paths as the file/folder structure has changed significantly.

Many bothans died to bring you this information. And when I say bothans, I refer of course to brain cells that have died as result of me smashing my head against the YouTube api.

To make this work, you’ll need to create a dummy web application that can capture the refresh token generated when you authorise your app. You can read a detailed explanation of what we’ll be doing and how the OAuth process works here.

This implementation has no requirements for any PHP frameworks (such as Zend). It is a barebones implementation based off the documentation for the YouTube V3 API utilising the Google PHP API client.

Creating your project

  1. You’ll need to head over to https://console.developers.google.com/ and create a new project.
  2. Then go and enable the YouTube Data API – (Your Project > APIS & AUTH > APIs)
  3. We’ll now need to create some credentials. Go to Your Project > APIS & AUTH > Credentials
  4. Click “Create new Client ID” and then under “Application Type” select “Web Application”.
  5. You’ll then need to enter your JavaScript origin and authorised redirect URI. I just set this to localhost, but you can set it to where ever you want.
  6. We’ve now created our client ID, we just need to fill in the Consent Screen. We can do this by navigating to Your Project > APIS & AUTH > Consent Screen. Once you’re on this page, ensure you fill out all the required fields (Email Address and Product Name).
  7. Hurray, we’ve created our project.

Getting your refresh token

I used the following PHP script as my dummy application to generate the OAuth token.

This script utilises Google APIs Client Library for PHP. You’ll need to download and install it a directory that can be read using the below script.

<?php

// Call set_include_path() as needed to point to your client library.
set_include_path($_SERVER['DOCUMENT_ROOT'] . '/directory/to/google/api/');
require_once 'Google/Client.php';
require_once 'Google/Service/YouTube.php';
session_start();

/*
 * You can acquire an OAuth 2.0 client ID and client secret from the
 * {{ Google Cloud Console }} <{{ https://cloud.google.com/console }}>
 * For more information about using OAuth 2.0 to access Google APIs, please see:
 * <https://developers.google.com/youtube/v3/guides/authentication>
 * Please ensure that you have enabled the YouTube Data API for your project.
 */
$OAUTH2_CLIENT_ID = 'XXXXXXX.apps.googleusercontent.com';
$OAUTH2_CLIENT_SECRET = 'XXXXXXXXXX';
$REDIRECT = 'http://localhost/oauth2callback.php';
$APPNAME = "XXXXXXXXX";


$client = new Google_Client();
$client->setClientId($OAUTH2_CLIENT_ID);
$client->setClientSecret($OAUTH2_CLIENT_SECRET);
$client->setScopes('https://www.googleapis.com/auth/youtube');
$client->setRedirectUri($REDIRECT);
$client->setApplicationName($APPNAME);
$client->setAccessType('offline');


// Define an object that will be used to make all API requests.
$youtube = new Google_Service_YouTube($client);

if (isset($_GET['code'])) {
    if (strval($_SESSION['state']) !== strval($_GET['state'])) {
        die('The session state did not match.');
    }

    $client->authenticate($_GET['code']);
    $_SESSION['token'] = $client->getAccessToken();

}

if (isset($_SESSION['token'])) {
    $client->setAccessToken($_SESSION['token']);
    echo '<code>' . $_SESSION['token'] . '</code>';
}

// Check to ensure that the access token was successfully acquired.
if ($client->getAccessToken()) {
    try {
        // Call the channels.list method to retrieve information about the
        // currently authenticated user's channel.
        $channelsResponse = $youtube->channels->listChannels('contentDetails', array(
            'mine' => 'true',
        ));

        $htmlBody = '';
        foreach ($channelsResponse['items'] as $channel) {
            // Extract the unique playlist ID that identifies the list of videos
            // uploaded to the channel, and then call the playlistItems.list method
            // to retrieve that list.
            $uploadsListId = $channel['contentDetails']['relatedPlaylists']['uploads'];

            $playlistItemsResponse = $youtube->playlistItems->listPlaylistItems('snippet', array(
                'playlistId' => $uploadsListId,
                'maxResults' => 50
            ));

            $htmlBody .= "<h3>Videos in list $uploadsListId</h3><ul>";
            foreach ($playlistItemsResponse['items'] as $playlistItem) {
                $htmlBody .= sprintf('<li>%s (%s)</li>', $playlistItem['snippet']['title'],
                    $playlistItem['snippet']['resourceId']['videoId']);
            }
            $htmlBody .= '</ul>';
        }
    } catch (Google_ServiceException $e) {
        $htmlBody .= sprintf('<p>A service error occurred: <code>%s</code></p>',
            htmlspecialchars($e->getMessage()));
    } catch (Google_Exception $e) {
        $htmlBody .= sprintf('<p>An client error occurred: <code>%s</code></p>',
            htmlspecialchars($e->getMessage()));
    }

    $_SESSION['token'] = $client->getAccessToken();
} else {
    $state = mt_rand();
    $client->setState($state);
    $_SESSION['state'] = $state;

    $authUrl = $client->createAuthUrl();
    $htmlBody = <<<END
  <h3>Authorization Required</h3>
  <p>You need to <a href="$authUrl">authorise access</a> before proceeding.<p>
END;
}
?>

<!doctype html>
<html>
<head>
    <title>My Uploads</title>
</head>
<body>
<?php echo $htmlBody?>
</body>
</html>

Once you’ve got the script above and the Google Client Library API in place, load the script in your browser. You should be prompted to Authorise access before you can continue. Once you click on this link you should be taken through the steps to authorise your currently logged in Google account to access your new application.

Once it’s all done you should be redirected back to the localhost page, except now you will see a JSON string along the top of the page. Save this string somewhere for use later on. You might also notice if you’ve already uploaded videos to YouTube, a list of your videos on the page – just to confirm the access token works!

Saving your credentials

Now that you’ve received your refresh tokens create a text file called “the_key.txt” with the following information you’ve just received, it should look something similar to the format below:

{"access_token":"XXXXXXXXX","token_type":"Bearer", "expires_in":3600, "refresh_token":"XXXXXXX", "created":000000}

I suggest you write your refresh token down somewhere for safe keeping.

 

Creating the upload script

The script below is a very basic implementation. It requires the following file structure:

  • Google/
  • upload.php (the script below)
  • the_key.txt (the file we created in the previous section)
  • tutorial.mp4 (the video to upload)

The script will automatically update your “the_key.txt” file if your access_token is out of date.

Set the include path to ensure the Google API works correctly (line 3).

Replace the following variables with your own information:

  • $application_name
  • $client_secrect
  • $client_id
  • $videoPath
  • $videoTitle
  • $videoDescription
  • $videoCategory
  • $videoTags

 

$key = file_get_contents('the_key.txt');

set_include_path($_SERVER['DOCUMENT_ROOT'] . '/path-to-your-director/');
require_once 'Google/Client.php';
require_once 'Google/Service/YouTube.php';

$application_name = 'XXXXXX'; 
$client_secret = 'XXXXXXX';
$client_id = 'XXXXXXX.apps.googleusercontent.com';
$scope = array('https://www.googleapis.com/auth/youtube.upload', 'https://www.googleapis.com/auth/youtube', 'https://www.googleapis.com/auth/youtubepartner');
		
$videoPath = "tutorial.mp4";
$videoTitle = "A tutorial video";
$videoDescription = "A video tutorial on how to upload to YouTube";
$videoCategory = "22";
$videoTags = array("youtube", "tutorial");


try{
	// Client init
	$client = new Google_Client();
	$client->setApplicationName($application_name);
	$client->setClientId($client_id);
	$client->setAccessType('offline');
	$client->setAccessToken($key);
	$client->setScopes($scope);
	$client->setClientSecret($client_secret);

	if ($client->getAccessToken()) {

		/**
		 * Check to see if our access token has expired. If so, get a new one and save it to file for future use.
		 */
		if($client->isAccessTokenExpired()) {
			$newToken = json_decode($client->getAccessToken());
			$client->refreshToken($newToken->refresh_token);
			file_put_contents('the_key.txt', $client->getAccessToken());
		}

		$youtube = new Google_Service_YouTube($client);



		// Create a snipet with title, description, tags and category id
		$snippet = new Google_Service_YouTube_VideoSnippet();
		$snippet->setTitle($videoTitle);
		$snippet->setDescription($videoDescription);
		$snippet->setCategoryId($videoCategory);
		$snippet->setTags($videoTags);

		// Create a video status with privacy status. Options are "public", "private" and "unlisted".
		$status = new Google_Service_YouTube_VideoStatus();
		$status->setPrivacyStatus('private');

		// Create a YouTube video with snippet and status
		$video = new Google_Service_YouTube_Video();
		$video->setSnippet($snippet);
		$video->setStatus($status);

		// Size of each chunk of data in bytes. Setting it higher leads faster upload (less chunks,
		// for reliable connections). Setting it lower leads better recovery (fine-grained chunks)
		$chunkSizeBytes = 1 * 1024 * 1024;

		// Setting the defer flag to true tells the client to return a request which can be called
		// with ->execute(); instead of making the API call immediately.
		$client->setDefer(true);

		// Create a request for the API's videos.insert method to create and upload the video.
		$insertRequest = $youtube->videos->insert("status,snippet", $video);

		// Create a MediaFileUpload object for resumable uploads.
		$media = new Google_Http_MediaFileUpload(
			$client,
			$insertRequest,
			'video/*',
			null,
			true,
			$chunkSizeBytes
		);
		$media->setFileSize(filesize($videoPath));


		// Read the media file and upload it chunk by chunk.
		$status = false;
		$handle = fopen($videoPath, "rb");
		while (!$status && !feof($handle)) {
			$chunk = fread($handle, $chunkSizeBytes);
			$status = $media->nextChunk($chunk);
		}

		fclose($handle);

		/**
		 * Video has successfully been upload, now lets perform some cleanup functions for this video
		 */
		if ($status->status['uploadStatus'] == 'uploaded') {
			// Actions to perform for a successful upload
			// $uploaded_video_id = $status['id'];
		}

		// If you want to make other calls after the file upload, set setDefer back to false
		$client->setDefer(true);

	} else{
		// @TODO Log error
		echo 'Problems creating the client';
	}

} catch(Google_Service_Exception $e) {
	print "Caught Google service Exception ".$e->getCode(). " message is ".$e->getMessage();
	print "Stack trace is ".$e->getTraceAsString();
}catch (Exception $e) {
	print "Caught Google service Exception ".$e->getCode(). " message is ".$e->getMessage();
	print "Stack trace is ".$e->getTraceAsString();
}

Suggestions

As you can see, the script is very primitive, among other things, this script should not be located in a publicly accessible directory due to the obvious abuse that could occur. In my situation, I created a queue of files to upload and setup a cron to execute the script once an hour that would then check a directory for any files of a certain type (mp4) and then loop through and upload to YouTube. The method I described hasn’t been tested on files more than 10 x 400mb in size so I’m not sure what the impacts would be on your server for more files / larger sizes etc.

Hopefully that’s enough to get your started, if you have any questions feel free to ask :)

Subscribe

You'll only get 1 email per month containing new posts (I hate spam as much as you!). You can opt out at anytime.

Categories

Leave a Reply

Your email address will not be published. Required fields are marked *

Preview Comment

48 Comments

  1. Kalpesh Meniya
    https://www.domsammut.com/?p=1142#comment-1717

    Kalpesh Meniya

    How to Upload You tube Video in our Created Website
    Please Give me Code of Video upload in website

    • Dom Sammut
      https://www.domsammut.com/?p=1142#comment-1718

      Dom Sammut

      Hi Kalpesh,

      This tutorial doesn’t cover that scope and it won’t be something I’ll be providing a guide for in the future. This tutorial is to simple provide the fundamentals that you can then base your project on.

      Cheers
      Dom

  2. ecmedia
    https://www.domsammut.com/?p=1142#comment-1713

    ecmedia

    Hi Dom,
    very strange, I’ve tried to post a reply but it doesn’t show up… and the system says I have already posted the comment!

    • Dom Sammut
      https://www.domsammut.com/?p=1142#comment-1714

      Dom Sammut

      Hey ecmedia,

      All comments on the blog are moderated before they are published live on the site. I’ll look to make this clearer in the coming weeks to avoid confusion in the future. Thanks for the feedback :)

      Cheers
      Dom

      • Ecmedia
        https://www.domsammut.com/?p=1142#comment-1723

        Ecmedia

        Hi Dom, yes, it’s a bit unclear because I can see my comment preview while typing, but when I post the comment, it disappears…
        I think that one possible solution is to leave visible (only to me) my comment, with an “under moderation” label … this could solve the problem! :)

  3. Leonardo
    https://www.domsammut.com/?p=1142#comment-1708

    Leonardo

    Hi, Thank you for the code it works.

    Could you tell me how I can get the id of the video?

    Thanks

    • Dom Sammut
      https://www.domsammut.com/?p=1142#comment-1709

      Dom Sammut

      Hey Leonardo,

      Thank you for the feedback :)

      You should be able to get the ID in the following bit of code:

      /**
      * Video has successfully been upload, now lets perform some cleanup functions for this video
      */
      if ($status->status['uploadStatus'] == 'uploaded') {
           // Actions to perform for a successful upload
           echo $status['id']
      }
      

      You can do a var_dump($status); to see all the data returned. From there you can use this information to make additional calls to the API if desired.

      Cheers
      Dom

      • Leonardo
        https://www.domsammut.com/?p=1142#comment-1710

        Leonardo

        Thank you so much for your quick answer. Thanks for taking the time in the first place. Everything workd great.

        Leonardo

  4. Rohit
    https://www.domsammut.com/?p=1142#comment-1696

    Rohit

    Hi Dom Sammut,

    When I implemented this code I got the folowing error,

    Caught Google service Exception 0 message is Failed to start the resumable uploadStack trace is #0 /xx/xx/Google/Http/MediaFileUpload.php(138): Google_Http_MediaFileUpload->getResumeUri() #1 /xx/xx/upload.php(91): Google_Http_MediaFileUpload->nextChunk(‘??? ftypmp42???…’) #2 {main}

    could you please tell me why I am getting this error?

    I also tried var_dump(filesize($videoPath)); its returning int(1096758), small file around 1.1 mb. what will be the issue

    • Dom Sammut
      https://www.domsammut.com/?p=1142#comment-1699

      Dom Sammut

      Hi Rohit,

      Can you confirm you’re using version 1.0.5 of the API? This tutorial covers that version of the API. Since then the API has changed and I have not updated this tutorial to reflect the latest version of the API.

      Cheers
      Dom

      • Rohit
        https://www.domsammut.com/?p=1142#comment-1700

        Rohit

        Hi Dom Sammut,

        Yes, I am using that version itself. After seeing your reply for Syed Shahzaib Ali, I downloaded that version and updates the code in my project. Please see the below response when I var_dump in getResumeUri() in MediaFileUpload.php,

        ["responseBody":protected]=>
          string(255) "{
         "error": {
          "errors": [
           {
            "domain": "youtube.header",
            "reason": "youtubeSignupRequired",
            "message": "Unauthorized",
            "locationType": "header",
            "location": "Authorization"
           }
          ],
          "code": 401,
          "message": "Unauthorized"
         }
        

        It will be great, if you can give me an advice.

        Thanks.

        • Dom Sammut
          https://www.domsammut.com/?p=1142#comment-1703

          Dom Sammut

          Hi Rohit,

          As per the error you’ve detailed, it appears you don’t have a YouTube account. You’ll need to create a YouTube channel / account.

          Cheers
          Dom

  5. Vimal K
    https://www.domsammut.com/?p=1142#comment-1694

    Vimal K

    Hi Dom,

    I want to allow anyone register on my site, to upload their videos on my own youtube user channel not user’ Youtube Channel. please confirm whether its possible?

    • Dom Sammut
      https://www.domsammut.com/?p=1142#comment-1695

      Dom Sammut

      Hi Vimal,

      It is possible, this tutorial doesn’t cover that scope though.

      Cheers
      Dom

      • Vimal K
        https://www.domsammut.com/?p=1142#comment-1697

        Vimal K

        Hi Dom,

        Thanks for your reply. Do you know any helpful link( or any detailed documentation ) for the same. It would be very much appreciated if you can provide me that, since I googled, I haven’t got any.

        Thanks.

        • Dom Sammut
          https://www.domsammut.com/?p=1142#comment-1698

          Dom Sammut

          Hi Vimal,

          Unfortunately I don’t have documentation regarding this topic, good luck in your search and let me know how you go.

          Cheers
          Dom

  6. Evan
    https://www.domsammut.com/?p=1142#comment-1686

    Evan

    Hi,

    I checked if my video successfully uploaded by using this line of code “$status->status[‘uploadStatus’] == ‘uploaded'” but i cant find the video on my youtube channel. Is their something that I need to set up with my youtube account?

    Thanks!

    • Dom Sammut
      https://www.domsammut.com/?p=1142#comment-1687

      Dom Sammut

      Hey Evan,

      In part one of the tutorial when we created our project, you need to be logged into the same google account that is used for your YouTube channel. When you harvested the refresh token it should loop through channels and lists associated with the account and dump out the uploaded videos (very roughly).

      If you’re like me, you might have a couple of Google accounts so make sure you’ve authenticated the correct one :)

      Let me know how you go.

      Cheers
      Dom

  7. Ecmedia
    https://www.domsammut.com/?p=1142#comment-1681

    Ecmedia

    Hi Dom, and thank you for this useful tutorial!

    What do you suggest to do as “// Actions to perform for a successful upload”? Thanks!

    • Dom Sammut
      https://www.domsammut.com/?p=1142#comment-1682

      Dom Sammut

      It really depends on the environment in which the video was uploaded. Could include things like:

      • Removing the video from the server
      • Sending notifications to server admin / end user who uploaded video
      • Writing to log files
      • Making additional calls to the YouTube API.

      Cheers
      Dom

      • Ecmedia
        https://www.domsammut.com/?p=1142#comment-1690

        Ecmedia

        Hi Dom, thank you. Yes, it was what I expected.
        But I have a new question for you. Starting from today, I get this error:


        Caught Google service Exception 0 message is Failed to start the resumable upload (HTTP 400: youtube.video, Bad Request)Stack trace is #0 /home2/xxx/public_html/google-api-php-client/src/Google/Http/MediaFileUpload.php(134): Google_Http_MediaFileUpload->getResumeUri() #1 /home2/xxx/_upload_video.php(98): Google_Http_MediaFileUpload->nextChunk('\x00\x00\x00\x14ftypqt \x00\x00\x00...') #2 {main}

        What could be the reason? Despite this error, the video is uploaded correctly into YouTube…

        • Dom Sammut
          https://www.domsammut.com/?p=1142#comment-1691

          Dom Sammut

          Hi Ecmedia,

          That’s a bit weird that your getting this error and still successfully having your video upload to YouTube. A couple of questions:

          • What is the size of the video (s) you’re uploading?
          • What is the filetype of your video?
          • Does specifying the type when you setup the $media variable prevent the error from occurring (type is set to video/* currently)?

            $media = new Google_Http_MediaFileUpload(
                $client,
                $insertRequest,
                'video/TYPE',
                null,
                true,
                $chunkSizeBytes
            );

          Let me know how you go.

          Cheers
          Dom

          • ecmedia
            https://www.domsammut.com/?p=1142#comment-1712

            ecmedia

            Hi Dom,
            sorry for the late answer, but I found some days ago that deleting all videos from Youtube channel solved my problem, so I thought there was a problem with the Channel.
            But yesterday my user uploaded a duplicated (not original) video and the error has reappeared, and the upload to Youtube stopped working.
            I deleted duplicated videos from Youtube Channel and the upload to Youtube started working again, but the error was still there.

            The videos are various sizes (from 200kb to 50mb) and types (mp4, mov and avi). I’ve tried to set the specific type but nothing changed.
            I’ve tried to use API version 1.0.5 beta but it doesn’t work at all :/

            But… I found that my script tried to upload to Youtube all videos that have not youtube id in my database (I insert youtube id after a successful upload to Youtube), therefore I discovered that the error was related to a previous uploaded video and not to that I was uploading at that time. I deleted all old videos from my database table, and now it seems to work correctly.
            So I think that this kind of error refers to a not completely uploaded (to FTP) video (or not uploaded at all). Is it possible?

            • Dom Sammut
              https://www.domsammut.com/?p=1142#comment-1715

              Dom Sammut

              Hey ecmedia,

              Great to here you solved the earlier problem. In regards to the new issue – notice you dropped the contents of the error in your first comment (I didn’t publish the other one since it’s pretty similar). The error you got was:

              Caught Google service Exception 0 message is Failed to start the resumable upload (HTTP 400: youtube.video, Bad Request)Stack trace is #0 /x/x/public_html/google-api-php-client/src/Google/Http/MediaFileUpload.php(134): Google_Http_MediaFileUpload->getResumeUri() #1 /x/x/public_html/wp-content/themes/x/_upload_video_step2.php(98): Google_Http_MediaFileUpload->nextChunk('\x00\x00\x00\x14ftypqt \x00\x00\x00...') #2 {main}

              It sounds like you’re using the latest version of the API?

              Without seeing the actual script you use I’m just speculating, but from what you’ve described I’d say it is possible that the error refers to a incomplete uploaded video.

              I know the system I built to upload videos from end-users, I did a check on the video size against the DB to check that there was no matching size value to minimise the change of a duplicate upload. I also did this in conjunction with a title test (if either value was the identical I’d modify the title to ensure it would still get up on YouTube).

              Cheers
              Dom

  8. rakhmat
    https://www.domsammut.com/?p=1142#comment-1679

    rakhmat

    i am using the the local server to upload a video from my site to you tube but it throw the flowing error.”The session state did not match.”

    • Dom Sammut
      https://www.domsammut.com/?p=1142#comment-1680

      Dom Sammut

      Which part of the tutorial are you getting stuck on? Have you successfully acquired your refresh token using the first part of the tutorial?

      Cheers
      Dom

      • rakhmat
        https://www.domsammut.com/?p=1142#comment-1701

        rakhmat

        how to get the token? and i have the following redirect URL
        $REDIRECT = ‘http://localhost/oauth2callback.php’;
        and more how to get app name ,
        please briefer me where to put client library and how to user yours code and where it i place
        thanks.

        • Dom Sammut
          https://www.domsammut.com/?p=1142#comment-1702

          Dom Sammut

          Hi Rakhmat,

          The tutorial outlines this pretty throughly. The app name and redirect url is what you specified when you created your app in the “Creating your project” section. You need to place the client library in a directory that can be readable by your script, you also need to specify the path to the library in the include_path statement.

          Cheers
          Dom

          • rakhmat
            https://www.domsammut.com/?p=1142#comment-1704

            rakhmat

            i have following error ….
            i have user my code as
            http://localhost/google-api-php-client-master/upload.php
            but when i see on the youtube it show the “Processing has started”.

            ( ! ) Fatal error: Maximum execution time of 30 seconds exceeded in D:\wamp\www\google-api-php-client-master\src\Google\IO\Curl.php on line 102
            Call Stack
            # Time Memory Function Location
            1 0.0018 399656 {main}( ) ..\upload.php:0
            2 23.8314 5500648 Google_Http_MediaFileUpload->nextChunk( ) ..\upload.php:89
            3 23.8321 5503728 Google_IO_Abstract->makeRequest( ) ..\MediaFileUpload.php:162
            4 23.8326 5503792 Google_IO_Curl->executeRequest( ) ..\Abstract.php:133

            Thanks..

            • Dom Sammut
              https://www.domsammut.com/?p=1142#comment-1705

              Dom Sammut

              Hi Rakhmat,

              The tutorial uses version 1.0.5 of the Google API PHP Client, it appears you’re using a later version in which a large portion of the codebase has changed and this tutorial is not applicable.

              Cheers
              Dom

            • rakhmat
              https://www.domsammut.com/?p=1142#comment-1706

              rakhmat

              now i have this error
              ( ! ) Fatal error: Maximum execution time of 30 seconds exceeded in D:\wamp\www\google-api-php-client-1.0.5-beta\src\Google\IO\Curl.php on line 79
              Call Stack
              # Time Memory Function Location
              1 0.0007 399984 {main}( ) ..\upload.php:0
              2 0.1735 5395592 Google_Http_MediaFileUpload->nextChunk( ) ..\upload.php:89
              3 1.8181 5401528 Google_IO_Abstract->makeRequest( ) ..\MediaFileUpload.php:166
              4 1.8182 5401584 Google_IO_Curl->executeRequest( ) ..\Abstract.php:125

            • Dom Sammut
              https://www.domsammut.com/?p=1142#comment-1707

              Dom Sammut

              Hi Rakhmat,

              Try setting your max execution time to a greater period than 30 seconds.

              e.g. ini_set('max_execution_time', 300);

              Cheers
              Dom

  9. Jarvis
    https://www.domsammut.com/?p=1142#comment-1678

    Jarvis

    I found your solution is the only solution to provide server to server direct upload to Youtube since V3 has deprecated this feature. Thank you so much!

  10. ccwebs
    https://www.domsammut.com/?p=1142#comment-1676

    ccwebs

    Hi Dom,

    I was following the instructions for the “Getting your refresh token” and what is returned does not contain the “refresh_token”.

    {"access_token":"XXXXXXXXX","token_type":"Bearer", "expires_in":3600, "created":000000}

    This causes an exception later when checking to see if the token has expired. The exception occurs on the line that says, “$client -> refreshToken($newToken -> refresh_token);” because the value passed is NULL in the following code:

    if ($client -> isAccessTokenExpired()) {
    $newToken = json_decode($client -> getAccessToken());
    $client -> refreshToken($newToken -> refresh_token);
    file_put_contents("the_key.txt", $client -> getAccessToken());
    }

    Exception

    Caught Google service Exception 400 message is Error refreshing the OAuth2 token, message: '{ "error" : "invalid_request", "error_description" : "Missing required parameter: refresh_token" }

    Any idea what I am doing wrong here?

    Thanks in advance!

    • Dom Sammut
      https://www.domsammut.com/?p=1142#comment-1677

      Dom Sammut

      Hi ccwebs,

      Yes, if you’re not getting a refresh token in your response, you’ll run into issues like the one you’ve experienced.

      Maybe try running the process again. Remove the authenticated app from your google account you granted access to (or just use a different account when running Getting your refresh token). Alternatively, create a new project and try again. Double check also you’ve got all the correct settings in your project as it seems weird that Google is not returning a refresh token. (I checked my script this morning and it still returns the refresh token).

      Let me know how it goes.

      Cheers
      Dom

      • JSM
        https://www.domsammut.com/?p=1142#comment-1689

        JSM

        ccwebs,
        You will get a refresh_token when you initially authorize your application. If you run Dom’s first script a second time, you will get a json response without a refresh_token. If you didn’t save the json original response that contained the refresh_token in the_key.txt, then you won’t be able to renew the access_token and when it expires, you’ll be stuck.

        Dom’s advice is correct, you need to de-authorize the app and then authorize it again. I hope this helps anyone else who runs into this problem.

      • ccwebs
        https://www.domsammut.com/?p=1142#comment-1719

        ccwebs

        Thanks Dom, this helped. The issue is that my token got mangled. After re-authorizing all is well. Thank you for this article, it was a huge help.

        • Dom Sammut
          https://www.domsammut.com/?p=1142#comment-1720

          Dom Sammut

          No problem, thanks for the feedback and glad to have helped you out :)

  11. Syed Shahzaib Ali
    https://www.domsammut.com/?p=1142#comment-1669

    Syed Shahzaib Ali

    Dom Bro,
    I am Receiving this error , while running First Code.
    “The session state did not match.”
    and also this Error : “An client error occurred: Error calling GET https://www.googleapis.com/youtube/v3/channels?part=contentDetails&mine=true: (403) Access Not Configured. The API is not enabled for your project, or there is a per-IP or per-Referer restriction configured on your API key and the request does not match these restrictions. Please use the Google Developers Console to update your configuration.”

    • Dom Sammut
      https://www.domsammut.com/?p=1142#comment-1670

      Dom Sammut

      Hi Syed,

      Can you confirm that you’ve enabled the required APIs in your project and you’re running version 1.0.5 of the Google PHP API (My tutorial is based on this version of the API, it has since changed significantly and most likely wont work with the latest version).

      Cheers
      Dom

    • Rakesh Kumar
      https://www.domsammut.com/?p=1142#comment-1671

      Rakesh Kumar

      this is working and very nice work so easy to integrate nice work :)

  12. Ahmad Nawaz
    https://www.domsammut.com/?p=1142#comment-1591

    Ahmad Nawaz

    please tell me how to add download option in youtube api v.3
    with different quality videos like mp3, 720hd, 360p median and 240p low quality

    • Dom Sammut
      https://www.domsammut.com/?p=1142#comment-1600

      Dom Sammut

      Hi Ahmad,

      Unfortunately my tutorial doesn’t cover this element of the YouTube API, however I believe there is adequate documentation provided by Google on this type of functionality using the V3 API.

      Cheers
      Dom

  13. Dat Nguyen
    https://www.domsammut.com/?p=1142#comment-1550

    Dat Nguyen

    Thank you, it work.

  14. Fabio
    https://www.domsammut.com/?p=1142#comment-1422

    Fabio

    Hi,

    I get the following error when I try to upload files larger than about 60 Mb.

    Caught Google service Exception 0 message is Failed to start the resumable upload (HTTP 400: youtube.video, Bad Request)Stack trace is #0 /var/www/public_html/api/src/Google/Http/MediaFileUpload.php(134): Google_Http_MediaFileUpload->getResumeUri() #1 /var/www/public_html/upload.php(89): Google_Http_MediaFileUpload->nextChunk(‘??? ftypmp42???…’) #2 {main}

    It’s not a token issue because I upload smaller files perfectly.
    Any ideas?

    Thanks!

  15. alibrisun
    https://www.domsammut.com/?p=1142#comment-1332

    alibrisun

    HI,
    i’m try to get youtube videos. i’m unable to auth getting this error


    {
    "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."
    }
    }

    my sample code is

    session_start();
            require_once '/var/www/html/app/Vendor/Google/Client.php';
            require_once '/var/www/html/app/Vendor/Google/Service/YouTube.php';
            
    
            /************************************************
              ATTENTION: Fill in these values! Make sure
              the redirect URI is to this page, e.g:
              http://localhost:8080/user-example.php
             ************************************************/
             $client_id = 'XXXXXXXXXXX-XXXXXXXXXXXXXXXXXXXXXXXXXXXXX.apps.googleusercontent.com';
             $client_secret = 'XXXXXXXXXXXX-vEivhTVy8';
             $redirect_uri = 'http://marketplace.XXXXXXXXXX/youtubes';
    
            /************************************************
              Make an API request on behalf of a user. In
              this case we need to have a valid OAuth 2.0
              token for the user, so we need to send them
              through a login flow. To do this we need some
              information from our API console project.
             ************************************************/
            $client = new Google_Client();
            $client->setClientId($client_id);
            $client->setClientSecret($client_secret);
            $client->setDeveloperKey('AIzaSyB7asIOWC3rtq_Mz77SmUiT4bREOjVnbx8'); 
            $client->setApplicationName('marketplace');
            $client->setRedirectUri($redirect_uri);
            $client->addScope('https://www.googleapis.com/auth/yt-analytics.readonly','https://www.googleapis.com/auth/youtube');
            $client->setAccessType('offline');
    
            /************************************************
              When we create the service here, we pass the
              client to it. The client then queries the service
              for the required scopes, and uses that when
              generating the authentication URL later.
             ************************************************/
            $service = new Google_Service_YouTube($client);
    
            /************************************************
              If we're logging out we just need to clear our
              local access token in this case
             ************************************************/
            if (isset($_REQUEST['logout'])) {
              unset($_SESSION['access_token']);
            }
    
            /************************************************
              If we have a code back from the OAuth 2.0 flow,
              we need to exchange that with the authenticate()
              function. We store the resultant access token
              bundle in the session, and redirect to ourself.
             ************************************************/
            if (isset($_GET['code'])) {
              $client->authenticate($_GET['code']);
              $_SESSION['access_token'] = $client->getAccessToken();
              $redirect = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
              header('Location: ' . filter_var($redirect, FILTER_SANITIZE_URL));
            }
    
            /************************************************
              If we have an access token, we can make
              requests, else we generate an authentication URL.
             ************************************************/
            if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
              $client->setAccessToken($_SESSION['access_token']);
    
            } else {
              $authUrl = $client->createAuthUrl();
            }
    
            /************************************************
              If we're signed in and have a request to shorten
              a URL, then we create a new URL object, set the
              unshortened URL, and call the 'insert' method on
              the 'url' resource. Note that we re-store the
              access_token bundle, just in case anything
              changed during the request - the main thing that
              might happen here is the access token itself is
              refreshed if the application has offline access.
             ************************************************/
            if ($client->getAccessToken()) {
                try {
                // Call the channels.list method to retrieve information about the
                // currently authenticated user's channel.
                $channelsResponse = $service->channels->listChannels('contentDetails', array(
                  'mine' => 'true',
                ));
    
                $htmlBody = '';
                foreach ($channelsResponse['items'] as $channel) {
                  // Extract the unique playlist ID that identifies the list of videos
                  // uploaded to the channel, and then call the playlistItems.list method
                  // to retrieve that list.
                  $uploadsListId = $channel['contentDetails']['relatedPlaylists']['uploads'];
    
                  $playlistItemsResponse = $service->playlistItems->listPlaylistItems('snippet', array(
                    'playlistId' => $uploadsListId,
                    'maxResults' => 50
                  ));
    
                  $htmlBody .= "Videos in list $uploadsListId";
                  foreach ($playlistItemsResponse['items'] as $playlistItem) {
                    echo "";
                    print_r($playlistItem);
                    echo "";
                        //$htmlBody .= sprintf('%s (%s)', $playlistItem['snippet']['title'],
                      //$playlistItem['snippet']['resourceId']['videoId']);
                  }
                  $htmlBody .= '';
                }
              } catch (Google_ServiceException $e) {
                $htmlBody .= sprintf('A service error occurred: %s',
                  htmlspecialchars($e->getMessage()));
              } catch (Google_Exception $e) {
                $htmlBody .= sprintf('An client error occurred: %s',
                  htmlspecialchars($e->getMessage()));
              }
    
              $_SESSION['access_token'] = $client->getAccessToken();
    
            }else {
    
                $state = mt_rand();
                $client->setState($state);
                $_SESSION['state'] = $state;
    
                  $authUrl = $client->createAuthUrl();
                  $htmlBody = "
                  Authorization Required
                  You need to authorize access before proceeding.";
            }
            echo $htmlBody;
    

    can anyone help me.. thanks in advance

    • Dom Sammut
      https://www.domsammut.com/?p=1142#comment-1333

      Dom Sammut

      Hi alibrisun,

      It appears you’re not even attempting to upload a video to YouTube and your code doesn’t really relate to the tutorial. Unfortunately I’m not providing support for anything except direct issues people might experience with this tutorial due to time constraints.

      However, a quick pointer with the error you received. You can check your API quota usage at https://console.developers.google.com and then in the left hand column navigate to APIs & auth and click APIs, you’ll then see all the APIs available, including the ones you’ve enabled. On the right hand side of each API it will list the Quota and how much you have used.

      Cheers
      Dom

css.php