Sunday , April 27 2025 11:55 AM
Home / Tutorials / PHP / Server-side YouTube V3 OAuth API (CakePHP)

Server-side YouTube V3 OAuth API (CakePHP)

To make this work, you’ll need to create a dummy web application that can capture the refresh token generated when you authorize your app.here am using this as a cakePHP component.

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. Cool, 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 using Composer because google strictly need Composer.

<?php


set_include_path($_SERVER['DOCUMENT_ROOT'] . '/y/');


require_once 'vendor/autoload.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 = 'YOURCLIENT_ID.apps.googleusercontent.com'; // Enter your Client ID here
$OAUTH2_CLIENT_SECRET = 'YOUR_CLIENT_SECRET'; // Enter your Client Secret here
$REDIRECT = filter_var('http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'], FILTER_SANITIZE_URL);
$APPNAME = "YOUR_APP_NAME";

$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');
$client->setApprovalPrompt('force');
    
// 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 "Access Token: " . $_SESSION['token'];
}

// 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- sample data shows from your channel</title>
</head>
<body>
<?php echo $htmlBody;?>
</body>
</html>

Saving your credentials

Now that you’ve received your refresh tokens create a text file called “token.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}

Creating the upload script

The script below is a very basic implementation. It requires the following file structure (app/Vendor):

  • Google/
  • auth.php (for genenrate refresh token above script)
  • token.txt (the file we created in the previous section) give 777 permission ($sudo chmod 777 token.txt)
<?php
App::uses('Component', 'Controller');

App::import('Vendor','vendor', array('file' => 'youtube/vendor/autoload.php'));





class YoutubeComponent extends Component {


	public function  addvideo($data)
	{
		debug($data);

		$key = file_get_contents($_SERVER['DOCUMENT_ROOT'] . '/gopuonline/app/Vendor/youtube/vendor/token.txt');

		$client_id = 'YOUR_ID.apps.googleusercontent.com';
		$client_secret = 'YOUR_CLIENT_SECRET';
		$APPNAME = "YOUR_APP_NAME";

		$path = $_SERVER['DOCUMENT_ROOT'] . '/gopuonline/app/webroot/upload/demo/video/process/'.$data['link'];
		debug($path);
		$videoPath = $path;
		$videoTitle = $data['title'];
		debug($videoTitle);
		$videoDescription = $data['title'];
		$videoCategory = "22";
		$videoTags = "hi,data,sample";

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

			if ($client->getAccessToken()) {

				if ($client->isAccessTokenExpired()) {
					$newToken = json_decode($client->getAccessToken());
					$client->refreshToken($newToken->refresh_token);
					$key = $_SERVER['DOCUMENT_ROOT'] . '/gopuonline/app/Vendor/youtube/vendor/token.txt';
					debug($key);
					file_put_contents($key, $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(explode(",",$videoTags));
				$snippet->setDefaultLanguage("en");
				$snippet->setDefaultAudioLanguage("en");

				$recordingDetails = new Google_Service_YouTube_VideoRecordingDetails();
				$recordingDetails->setLocationDescription("India");
				$recordingDetails->setRecordingDate("2016-01-20T12:34:00.000Z");
				$locationdetails = new Google_Service_YouTube_GeoPoint();
				$locationdetails->setLatitude("38.8833");
				$locationdetails->setLongitude("77.0167");
				$recordingDetails->setLocation($locationdetails);

// Create a video status with privacy status. Options are "public", "private" and "unlisted".
				$status = new Google_Service_YouTube_VideoStatus();
				$status->setPrivacyStatus("public");
				$status->setPublicStatsViewable(false);
				$status->setEmbeddable(false); // Google defect still not editable https://code.google.com/p/gdata-issues/issues/detail?id=4861

// Create a YouTube video with snippet and status
				$video = new Google_Service_YouTube_Video();
				$video->setSnippet($snippet);
				$video->setRecordingDetails($recordingDetails);
				$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,recordingDetails", $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 uploaded, now lets perform some cleanup functions for this video
				 */
				if ($status->status['uploadStatus'] == 'uploaded') {
					// Actions to perform for a successful upload
//					$htmlBody .= "<h3>Video Uploaded</h3><ul>";
//					$htmlBody .= sprintf('<li>%s (%s)</li>',
//						$status['snippet']['title'],
						$key = $status['id'];



					echo json_encode($status);
					// print("<pre>".print_r($status,true)."</pre>");


				}

// 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();
		}


debug($htmlBody);

}
}


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

Check Also

RAMBleed Attack – Flip Bits to Steal Sensitive Data from Computer Memory

A team of cybersecurity researchers yesterday revealed details of a new side-channel attack on dynamic …