YouTube is almost the numero one platform for hosting videos. It allows users to publish and share videos on a social network.
Downloading YouTube videos is sometimes required. You must read through the YouTube terms and conditions before downloading videos and act according to the permissions given. For example, you may wish to download to have a backup of older videos that will be replaced or removed.
This quick example provides a YouTube Video downloader script in PHP. It has a video URL defined in a PHP variable. It also establishes a key to access the YouTube video meta via API.
Configure the key and store the video URL to get the video downloader link using this script.
<?php
$apiKey = "API_KEY";
$videoUrl = "YOUTUBE_VIDEO_URL";
preg_match('%(?:youtube(?:-nocookie)?\.com/(?:[^/]+/.+/|(?:v|e(?:mbed)?)/|.*[?&]v=)|youtu\.be/)([^"&?/ ]{11})%i', $videoUrl, $match);
$youtubeVideoId = $match[1];
$videoMeta = json_decode(getYoutubeVideoMeta($youtubeVideoId, $apiKey));
$videoTitle = $videoMeta->videoDetails->title;
$videoFormats = $videoMeta->streamingData->formats;
foreach ($videoFormats as $videoFormat) {
$url = $videoFormat->url;
if ($videoFormat->mimeType)
$mimeType = explode(";", explode("/", $videoFormat->mimeType)[1])[0];
else
$mimeType = "mp4";
?>
<a
href="video-downloader.php?link=<?php echo urlencode($url)?>&title=<?php echo urlencode($videoTitle)?>&type=<?php echo $mimeType; ?>">
Download Video</a>
<?php
}
function getYoutubeVideoMeta($videoId, $key)
{
$ch = curl_init();
$curlUrl = 'https://www.youtube.com/youtubei/v1/player?key=' . $key;
curl_setopt($ch, CURLOPT_URL, $curlUrl);
curl_setopt($ch, CURLOPT_ENCODING, 'gzip, deflate');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
$curlOptions = '{"context": {"client": {"hl": "en","clientName": "WEB",
"clientVersion": "2.20210721.00.00","clientFormFactor": "UNKNOWN_FORM_FACTOR","clientScreen": "WATCH",
"mainAppWebInfo": {"graftUrl": "/watch?v=' . $videoId . '",}},"user": {"lockedSafetyMode": false},
"request": {"useSsl": true,"internalExperimentFlags": [],"consistencyTokenJars": []}},
"videoId": "' . $videoId . '", "playbackContext": {"contentPlaybackContext":
{"vis": 0,"splay": false,"autoCaptionsDefaultOn": false,
"autonavState": "STATE_NONE","html5Preference": "HTML5_PREF_WANTS","lactMilliseconds": "-1"}},
"racyCheckOk": false, "contentCheckOk": false}';
curl_setopt($ch, CURLOPT_POSTFIELDS, $curlOptions);
$headers = array();
$headers[] = 'Content-Type: application/json';
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$curlResult = curl_exec($ch);
if (curl_errno($ch)) {
echo 'Error:' . curl_error($ch);
}
curl_close($ch);
return $curlResult;
}
?>
This example code works in the following flow to output the link to download the YouTube video.
The below video downloader script is called by clicking the “Download video” link in the browser.
It receives the video title and extension to define the output video file name. It also gets the video link from which it reads the video to be downloaded to the browser.
This script sets the content header in PHP to output the YouTube video file.
video-downloader.php
<?php
// this PHP script reads and downloads the video from YouTube
$downloadURL = urldecode($_GET['link']);
$downloadFileName = urldecode($_GET['title']) . '.' . urldecode($_GET['type']);
if (! empty($downloadURL) && substr($downloadURL, 0, 8) === 'https://') {
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Disposition: attachment;filename=\"$downloadFileName\"");
header("Content-Transfer-Encoding: binary");
readfile($downloadURL);
}
?>
The quick example has a sample to hardcode the YouTube video URL to a PHP variable.
But, the below code will allow users to enter the video URL instead of the hardcode.
An HTML form will post the entered video URL to process the PHP cURL request to the YouTube API.
After posting the video URL, the PHP flow is the same as the quick example. But, the difference is, that it displays more links to download videos in all the adaptive formats.
index.php
<form method="post" action="">
<h1>PHP YouTube Video Downloader Script</h1>
<div class="row">
<input type="text" class="inline-block" name="youtube-video-url">
<button type="submit" name="submit" id="submit">Download Video</button>
</div>
</form>
<?php
if (isset($_POST['youtube-video-url'])) {
$videoUrl = $_POST['youtube-video-url'];
?>
<p>
URL: <a href="<?php echo $videoUrl;?>"><?php echo $videoUrl;?></a>
</p>
<?php
}
if (isset($_POST['submit'])) {
preg_match('%(?:youtube(?:-nocookie)?\.com/(?:[^/]+/.+/|(?:v|e(?:mbed)?)/|.*[?&]v=)|youtu\.be/)([^"&?/ ]{11})%i', $videoUrl, $match);
$youtubeVideoId = $match[1];
require './youtube-video-meta.php';
$videoMeta = json_decode(getYoutubeVideoMeta($youtubeVideoId, $key));
$videoThumbnails = $videoMeta->videoDetails->thumbnail->thumbnails;
$thumbnail = end($videoThumbnails)->url;
?>
<p>
<img src="<?php echo $thumbnail; ?>">
</p>
<?php $videoTitle = $videoMeta->videoDetails->title; ?>
<h2>Video title: <?php echo $videoTitle; ?></h2>
<?php
$shortDescription = $videoMeta->videoDetails->shortDescription;
?>
<p><?php echo str_split($shortDescription, 100)[0];?></p>
<?php
$videoFormats = $videoMeta->streamingData->formats;
if (! empty($videoFormats)) {
if (@$videoFormats[0]->url == "") {
?>
<p>
<strong>This YouTube video cannot be downloaded by the downloader!</strong><?php
$signature = "https://example.com?" . $videoFormats[0]->signatureCipher;
parse_str(parse_url($signature, PHP_URL_QUERY), $parse_signature);
$url = $parse_signature['url'] . "&sig=" . $parse_signature['s'];
?>
</p>
<?php
die();
}
?>
<h3>With Video & Sound</h3>
<table class="striped">
<tr>
<th>Video URL</th>
<th>Type</th>
<th>Quality</th>
<th>Download Video</th>
</tr>
<?php
foreach ($videoFormats as $videoFormat) {
if (@$videoFormat->url == "") {
$signature = "https://example.com?" . $videoFormat->signatureCipher;
parse_str(parse_url($signature, PHP_URL_QUERY), $parse_signature);
$url = $parse_signature['url'] . "&sig=" . $parse_signature['s'];
} else {
$url = $videoFormat->url;
}
?>
<tr>
<td><a href="<?php echo $url; ?>">View Video</a></td>
<td><?php if($videoFormat->mimeType) echo explode(";",explode("/",$videoFormat->mimeType)[1])[0]; else echo "Unknown";?></td>
<td><?php if($videoFormat->qualityLabel) echo $videoFormat->qualityLabel; else echo "Unknown"; ?></td>
<td><a
href="video-downloader.php?link=<?php echo urlencode($url)?>&title=<?php echo urlencode($videoTitle)?>&type=<?php if($videoFormat->mimeType) echo explode(";",explode("/",$videoFormat->mimeType)[1])[0]; else echo "mp4";?>">
Download Video</a></td>
</tr>
<?php } ?>
</table>
<?php
// if you wish to provide formats based on different formats
// then keep the below two lines
$adaptiveFormats = $videoMeta->streamingData->adaptiveFormats;
include 'adaptive-formats.php';
?>
<?php
}
}
?>
This program will output the following once it has the video downloader response.
The quick example already shows the PHP cURL script used to access the YouTube endpoint to read the file meta.
The above code snippet has a PHP require_once statement for having the cURL post handler.
TheĀ youtube-video-meta.php file has this handler to read the video file meta. It receives the unique id of the video and the key used in the PHP cURL parsing.
In a recently posted article, we have collected file meta to upload to Google Drive.
The landing page shows another table of downloads to get the video file in the available adaptive formats.
The PHP script accesses the adaptiveFormats property of the Youtube video meta-object to display these downloads.
adaptive-formats.php
<h3>YouTube Videos Adaptive Formats</h3>
<table class="striped">
<tr>
<th>Type</th>
<th>Quality</th>
<th>Download Video</th>
</tr>
<?php
foreach ($adaptiveFormats as $videoFormat) {
try {
$url = $videoFormat->url;
} catch (Exception $e) {
$signature = $videoFormat->signatureCipher;
parse_str(parse_url($signature, PHP_URL_QUERY), $parse_signature);
$url = $parse_signature['url'];
}
?>
<tr>
<td><?php if(@$videoFormat->mimeType) echo explode(";",explode("/",$videoFormat->mimeType)[1])[0]; else echo "Unknown";?></td>
<td><?php if(@$videoFormat->qualityLabel) echo $videoFormat->qualityLabel; else echo "Unknown"; ?></td>
<td><a
href="video-downloader.php?link=<?php print urlencode($url)?>&title=<?php print urlencode($videoTitle)?>&type=<?php if($videoFormat->mimeType) echo explode(";",explode("/",$videoFormat->mimeType)[1])[0]; else echo "mp4";?>">Download
Video</a></td>
</tr>
<?php }?>
</table>