How to create a YouTube video downloader using PHP?

Are you tired of trying different youtube downloaders and with all their limitations? Or you might be tired of seeing all the tutorials that are using the “https://youtube.com/get_video_info” parameter which doesn’t work anymore? Well, not anymore, let’s break the ice and build our own youtube video downloader today. So, without further talking, let’s get started!

YouTube Video downloader

Here is a quick overview of what we need in order to download a video.

  • Get video info
  • Extract the video stream URL
  • Download the file from the stream URL

Before we get started, we need to get info about the video we want to download from youtube. This method has been updated recently. That’s why most of the old tutorials about youtube video downloaders are broken. So, let’s take a look at the new method. Please save this function in a file called function.php

<?php
function getVideoInfo($video_id){

    $ch = curl_init();

    curl_setopt($ch, CURLOPT_URL, 'https://www.youtube.com/youtubei/v1/player?key=AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8');
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, '{  "context": {    "client": {      "hl": "en",      "clientName": "WEB",      "clientVersion": "2.20210721.00.00",      "clientFormFactor": "UNKNOWN_FORM_FACTOR",   "clientScreen": "WATCH",      "mainAppWebInfo": {        "graftUrl": "/watch?v='.$video_id.'",           }    },    "user": {      "lockedSafetyMode": false    },    "request": {      "useSsl": true,      "internalExperimentFlags": [],      "consistencyTokenJars": []    }  },  "videoId": "'.$video_id.'",  "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_ENCODING, 'gzip, deflate');

    $headers = array();
    $headers[] = 'Content-Type: application/json';
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

    $result = curl_exec($ch);
    if (curl_errno($ch)) {
        echo 'Error:' . curl_error($ch);
    }
    curl_close($ch);
    return $result;

}

In the code above, we created a PHP function called getVideoInfo. If you call the function with a youtube video id as a parameter, it will return all the information about the video in object format. Now that we have the code to get all information about a video, let’s build a youtube video downloader form right away.

YouTube Video Downloader Form

To provide users a nice interface to put a video URL, we should create an HTML form first. Create a file called index.php in the same folder you created the function.php before. Now, write the code below in your index.php file.

Note: You can download a form generator provided by blog desire for free from here.

<?php require './function.php'; $error = "";?>
<html lang="en" class="h-100">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <title>Download YouTube video</title>
    <!-- Font-->
    <link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@400&display=swap" rel="stylesheet">
    <!-- Bootstrap core CSS -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@4.3.1/dist/css/bootstrap.css" rel="stylesheet">
    <style>
        body {
            font-family: 'Montserrat', sans-serif;
        }
        .formSmall {
            width: 700px;
            margin: 20px auto 20px auto;
        }
    </style>

</head>
<body>
    <div class="container">
        <form method="post" action="" class="formSmall">
            <div class="row">
                <div class="col-lg-12">
                    <h7 class="text-align"> Download YouTube Video</h7>
                </div>
                <div class="col-lg-12">
                    <div class="input-group">
                        <input type="text" class="form-control" name="video_link" placeholder="Paste link.. e.g. https://www.youtube.com/watch?v=5cpIZ8zHHXw" <?php if(isset($_POST['video_link'])) echo "value='".$_POST['video_link']."'"; ?>>
                        <span class="input-group-btn">
                        <button type="submit" name="submit" id="submit" class="btn btn-primary">Go!</button>
                      </span>
                    </div><!-- /input-group -->
                </div>
            </div><!-- .row -->
        </form>

       <!-- Place Your Video Downloader Code Here -->
    </div>
</body>
</html>

You might have noticed that we have used a couple of PHP codes in the form. That’s because we want to keep track of user input in the input field. Now that we have an HTML form for user input and a function that returns any video information, we may proceed furthermore.

Generate a download link

We have a function that can return any video info and a form that accepts user input. Now, it’s our task to combine them both and get info about any video that a user may provide using our form. And after that, we should provide them a download button as well. Once again, here is what we need to do in order to achieve this.

  • Get user input using the $_POST method
  • Extract the video id from the user input
  • Call the getVideoInfo function and pass the extracted video id as a parameter
  • Extract the video stream URL from the response returned by the function
  • Create a download button using the Stream URL

To do so, we need to place some code in our index.php file and here they are

<?php if(isset($_POST['submit'])): ?>


    <?php 
    $video_link = $_POST['video_link'];
    preg_match('%(?:youtube(?:-nocookie)?\.com/(?:[^/]+/.+/|(?:v|e(?:mbed)?)/|.*[?&]v=)|youtu\.be/)([^"&?/ ]{11})%i', $video_link, $match);
    $video_id =  $match[1];
    $video = json_decode(getVideoInfo($video_id));
    $formats = $video->streamingData->formats;
    $adaptiveFormats = $video->streamingData->adaptiveFormats;
    $thumbnails = $video->videoDetails->thumbnail->thumbnails;
    $title = $video->videoDetails->title;
    $short_description = $video->videoDetails->shortDescription;
    $thumbnail = end($thumbnails)->url;
    ?>
    
    
    <div class="row formSmall">
        <div class="col-lg-3">
            <img src="<?php echo $thumbnail; ?>" style="max-width:100%">
        </div>
        <div class="col-lg-9">
            <h2><?php echo $title; ?> </h2>
            <p><?php echo str_split($short_description, 100)[0]; ?></p>
        </div>
    </div>
    
    <?php if(!empty($formats)): ?>
    
    
        <?php if(@$formats[0]->url == ""): ?>
        <div class="card formSmall">
            <div class="card-header">
                <strong>This video is currently not supported by our downloader!</strong>
                <small><?php 
                $signature = "https://example.com?".$formats[0]->signatureCipher;
                            parse_str( parse_url( $signature, PHP_URL_QUERY ), $parse_signature );
                            $url = $parse_signature['url']."&sig=".$parse_signature['s'];
                       ?>
                </small>
            </div>
        </div>
        <?php 
        die();
        endif;
        ?>
        
        <div class="card formSmall">
            <div class="card-header">
                <strong>With Video & Sound</strong>
            </div>
            
            <div class="card-body">
                <table class="table ">
                    <tr>
                        <td>URL</td>
                        <td>Type</td>
                        <td>Quality</td>
                        <td>Download</td>
                    </tr>
                    <?php foreach($formats as $format): ?>
                        <?php
                        
                        if(@$format->url == ""){
                            $signature = "https://example.com?".$format->signatureCipher;
                            parse_str( parse_url( $signature, PHP_URL_QUERY ), $parse_signature );
                            $url = $parse_signature['url']."&sig=".$parse_signature['s'];
                        }else{
                            $url = $format->url;
                        }
                        
                            
                        
                        
                        ?>
                        <tr>
                            <td><a href="<?php echo $url; ?>">Test</a></td>
                            <td>
                                <?php if($format->mimeType) echo explode(";",explode("/",$format->mimeType)[1])[0]; else echo "Unknown";?>
                            </td>
                            <td>
                                <?php if($format->qualityLabel) echo $format->qualityLabel; else echo "Unknown"; ?>
                            </td>
                            <td>
                                <a 
                                    href="downloader.php?link=<?php echo urlencode($url)?>&title=<?php echo urlencode($title)?>&type=<?php if($format->mimeType) echo explode(";",explode("/",$format->mimeType)[1])[0]; else echo "mp4";?>"
                                >
                                    Download
                                </a> 
                            </td>
                        </tr>
                    <?php endforeach; ?>
                </table>
            </div>
        </div>
        
        <!-- Your code here for additional formats -->
        
    <?php endif; ?>


<?php endif; ?>

Please replace the <!– Place Your Video Downloader Code Here –> part with the code snippet above. At this point, users can provide any video URL and they will get a download link for that particular video. Pretty cool right? But wait, this is not the end. We still need to create a downloader file.

Create the downloader file

You might be wondering why we’re going to create another downloader file when we already have the stream URL. Well, this file is to download the video from the Stream URL. This is the last file we will be creating for this tutorial. So, let’s just create another file called downloader.php in the same directory. Done? Now save the code below in your downloader.php file.

<?php
$downloadURL = urldecode($_GET['link']);
$type = urldecode($_GET['type']);
$title = urldecode($_GET['title']);
$fileName = $title.'.'.$type;


if (!empty($downloadURL) && substr($downloadURL, 0, 8) === 'https://') {
    header("Cache-Control: public");
    header("Content-Description: File Transfer");
    header("Content-Disposition: attachment;filename=\"$fileName\"");
    header("Content-Transfer-Encoding: binary");

    readfile($downloadURL);

}

and boom, you are good to go with your own youtube video downloader!

Bonus!

You can replace the <!– Your code here for additional formats –> in your index.php with the code below to provide users all additional formats of the video to download!

<div class="card formSmall">
    <div class="card-header">
        <strong>Videos video only/ Audios audio only</strong>
    </div>
    <div class="card-body">
        <table class="table ">
            <tr>
                <td>Type</td>
                <td>Quality</td>
                <td>Download</td>
            </tr>
            <?php foreach ($adaptiveFormats as $video) :?>
                <?php
                try{
                    $url = $video->url;
                }catch(Exception $e){
                    $signature = $video->signatureCipher;
                    parse_str( parse_url( $signature, PHP_URL_QUERY ), $parse_signature );
                    $url = $parse_signature['url'];
                }
                
                ?>
                <tr>
                    <td><?php if(@$video->mimeType) echo explode(";",explode("/",$video->mimeType)[1])[0]; else echo "Unknown";?></td>
                    <td><?php if(@$video->qualityLabel) echo $video->qualityLabel; else echo "Unknown"; ?></td>
                    <td><a href="downloader.php?link=<?php print urlencode($url)?>&title=<?php print urlencode($title)?>&type=<?php if($video->mimeType) echo explode(";",explode("/",$video->mimeType)[1])[0]; else echo "mp4";?>">Download</a> </td>
                </tr>
            <?php endforeach;?>
        </table>
    </div>
</div>

Demo and Source Code

You can check a demo version of the YouTube Video Downloader from here. Or you can download the source code from here

Please Note: Some video doesn’t return a Stream URL, the script currently doesn’t support such videos. But I’m working on it and will update the tutorial as soon as I can find a solution for such videos.

I hope you found this article helpful. If so, a share from you will make my day. If you face any problems, please let me know in the comment section. Stay safe, have a great day.

Update:

For anyone, who wants to accept a youtube short link like “https://youtu.be/5cpIZ8zHHXw”, should update your downloaded index.php file with the code given for this file in this article. Because this article has been updated but the source code is still old.

Hope this helps. If you still need further assistance, you can let me know via email or a comment. Thanks

Blog Desire is Up for Sale!
Ready for a new chapter? Blog Desire could be yours!

Inquire Now Inquire Now!

Khokon M.

Full Stack Web Developer, Content Writer.

Leave a Reply

This Post Has 74 Comments

    1. Khokon M.

      Thanks bro, I’ll definitely check this out

  1. ghostavo

    download speeds are too slow! I am getting only 70KBps in a 50Mbps connection!.
    why is that?

    1. Khokon M.

      We can’t control the delivery speed of the server. It’s not entirely related to your internet speed.

        1. Khokon M.

          A new script is coming up, please stay tuned. Cheers

          1. ghostavo

            okay cool , I already subscribe on your Blog.
            please be fast <3.

          2. Khokon M.

            Sure, thank you 😊

          3. ghostavo

            anything new about youtube downloader ?
            and how about tiktok downloder ?

          4. Khokon M.

            Hi, the new YouTube downloader is about to be released next week. I appreciate your patience and I will provide you with updates asap.

          5. ghostavo

            hi, anything new ?

  2. subhajit

    Hi thank you so much for the script, it works fine. But there are some issues I found in the code which are
    1. The code does not support any youtube short videos.
    2. There are some videos the code cant download and showed this (This video is currently not supported by our downloader!) that other downloaders on the internet can download. If you can fix these issues then the code will be perfect.
    But still thank you so much for creating this it works better than other codes on the internet.

    1. Khokon M.

      Hi Subhajit, thank you for your feedback. I’ll consider the points you’ve mentioned.

  3. shijil

    It works, but the download speeds are too slow! I am getting less than 100KBps in a 100Mbps connection! Without faster downloads there is no meaning in using this. Is there a way to improve the speed ?

    1. Khokon M.

      Hi, we cannot modify the speed of the server.

  4. bhuvnesh

    Hi, its not working now. All the time mp4 url (googlevideo.com) says access denied 403 error. I have tried many videos but none work. While the same youtube videos are working on other youtube downloaders like killerplayer.com

    1. Khokon M.

      Hi, did you downloaded the source code or did you restructured the code from the blog post. In case you restructured the code, make sure you didn’t have any typos while building the link part.

  5. Farhan Ali

    Hey the downloader.php does not working please Check it once

    1. Khokon M.

      Sure, I will check it and will provide you update. Thanks for reporting the issue

  6. Zain Ali

    This video is not supported by our downloader, have you found the solution?

    1. Khokon M.

      Hi Zain, thanks for your comment. No, I haven’t found yet, actually I didn’t find a chance to give a deep effort on this after I published the article. But I hope I will asap.

  7. sheikh

    hi, broo this code note work in mobile video download and add .html extension??

    1. Khokon M.

      Hi, as I’ve mentioned in the article, some videos are not supported in my current version of codes. Also, you don’t need to add a .html extension because it’s a PHP file.

    1. Khokon M.

      Hi, it’s because the demo isn’t updated with the short links. Please check the short link portion from the bottom of the article and update your local code accordingly. Hope this helps

  8. Жданов Павел

    When I click on the Download button, the file is saved to the ‘/home’ folder on the server.

  9. Жданов Павел

    Thank you for your work! It works great!
    I installed your script on the server. How to make a file saved in a folder on the server? The folder does not need to be selected, it will be registered permanently.

    1. Khokon M.

      Do you want to save the videos on your server or do you want to modify the default download folder of local machine while downloading?
      Thanks

      1. Жданов Павел

        When I click on the Download button, the file is saved to the ‘/home’ folder on the server.

        1. Khokon M.

          You might try to read/write files in PHP. But most provably, you’ll get a server timeout error.

  10. joaob2000

    This video is not supported by our downloader, do you already have a solution for this problem?

    1. Khokon M.

      Not yet, I didn’t have much chance to work on this after I published the article. But I will work on this asap and will post an update as soon as I have a solution for this.

  11. joaob2000

    Hello, do you have a specific method to allow the user to download the video in mp3 format, I see that your script only displays mp4, webm formats, and how do I display the size in MB in the description of each format if possible?

    1. Khokon M.

      Hi,
      if you add the bonus code that I have given in the article, you’ll be able to download the mp3 format as well.
      But, showing the file size in advance will require a bit of extra time and work.

  12. wimaxhabib

    Since today morning I see code doesn’t work. Please fix it. And give us solution.

    1. Khokon

      Can you share a screenshot of what type of error are you getting?
      Thanks

        1. Khokon

          Did you update the code from the blog post to support short youtube video links?

  13. Farhan Ali

    Some videos are not supported, why?
    Please make a solution for this

    1. Khokon

      Because their response type is different compared to other responses. I’ll surely update the article if I find a solution for those type of videos.
      Thanks

  14. ida

    Sir,
    I was searching for the documentation of the above api. But I was unsuccessful.
    Kindly share the link of that webpage sir.

  15. newbiefromnewbie

    i just wanna ask about this:
    “`
    url == “”): ?>

    This video is currently not supported by our downloader!

    signatureCipher;
    parse_str( parse_url( $signature, PHP_URL_QUERY ), $parse_signature );
    $url = $parse_signature[‘url’].”&sig=”.$parse_signature[‘s’];
    ?>

    “`
    do you mean if youtube url doesn’t have url in its format, we can’t download the video?
    but what is your purpose on your second code which is like this ? :
    “`
    if (@$format->url == “”) {
    $signature = “https://example.com?” . $format->signatureCipher;
    parse_str( parse_url( $signature, PHP_URL_QUERY ), $parse_signature );
    $url = $parse_signature[‘url’].”&sig=”.$parse_signature[‘s’];
    } else {
    $url = $format->url;
    }
    “`

    just confused.

    1. MD Khokon Mia

      Hi,
      Thanks for pointing out this one. Basically, for our unsupported videos, they send us a signature cipher. So, on the second part, I was checking if I can find any way to decrypt the signature cipher to get download links for those videos as well. I included that so if anyone wants to work with those videos, they can continue from where I left it.
      Hope this helps.
      thanks

      1. newbiefromnewbie

        ahh okay, i see.
        btw how do you get that api key? is it youtube api key v1?

        1. MD Khokon Mia

          It’s the default youtube player API

  16. Rauf Quliyev

    youtu.be link dont working. pls help me

  17. Rauf Quliyev

    With Video & Sound

    Hello there. How can I show all quality here?

    1. MD Khokon Mia

      The script should show all quality. And on the bonus script, it should show all quality in video format and audio format separately. Hope this helps.

      1. Farhan Ali

        This script doesn’t provide mp3 format,
        Please include it also and display video size

        Please

        1. MD Khokon Mia

          If you include the additional bonus code, it will include the mp3 format as well.
          Please check that and let me know if you still need any assistance.

  18. ida

    What are the server requirements and modifications sir,
    Thanks in advance

    1. MD Khokon Mia

      PHP 7.4+ on apache server are recommended.

  19. J. B. Lovelin Dhoni

    Brother, a small problem, I copied your code and hosted on some where here(http://videonition.epizy.com/?i=1)
    All is going good, but when I download the video it comes as broken for me, when I downloaded on your demo version, it’s the video is clear is crystal. What I am telling is the video downloaded on my website is 7.00 mb but downloaded on your demo version it is like 15.00 mb, both same quality. I used this video https://youtu.be/dbV3qODiBGc
    Plz tell me whether I should change my phone version or modify anything. Plz download this video on my website and yours and see the difference.

  20. jass singh

    Awesome tutorial.
    One question, can i use some pcs of code to build a downloader of my own , i will give credits too.

  21. J. B. Lovelin Dhoni

    I gotta confess, that it is not working as I expected. Cruciotech is right, update the main code at your leisure time plz.

    1. MD Khokon Mia

      Hi, just updated the code in the article. Hope this help. Thanks

      1. wimaxhabib

        Since today morning I see code doesn’t working. Please fix it. Give us solution.

  22. cruciotech

    I have pasted your function on my function.php but it gives me a 500 error, plz don’t get tensed for wasting your time.
    I always fail on php. Maybe if you have the kindness to change the main code on this blog with that code.

    1. MD Khokon Mia

      Sure. I’ll update the code

  23. J. B. Lovelin Dhoni

    Thanks bro, but clear my doubt, should I need to pass the $full_url parameter into get video Id function. Like should I need to have both $video_id and $full_url as the parameters in my function or does it need some tweaks.

    1. MD Khokon Mia

      You just need to pass your video url, it can be full url or a short url, and the function will give you the video id.

  24. cruciotech

    Super bro, can you update the code to accept all types YouTube link formats just like a guy commented abow and also plz tell how to get the api key which you coded on function.php

    1. MD Khokon Mia

      Sure, I’ll update the article shortly. Thanks for the suggestion.

  25. J. B. Lovelin Dhoni

    bro ,wonderful piece of work
    can you give me a idea how to tweak the function.php code as to accept the short YouTube links like “https://youtu.be/zSbicGH3qCg”
    Instead of “https://m.youtube.com/watch?v=n7Ns6_NxEZg&feature=youtu.be”

    1. MD Khokon Mia

      Hi, thanks for your support.
      Here is a piece of code that will generate a video id from almost any format.
      $url = “YOUR_VIDEO_URL”;
      preg_match(‘%(?:youtube(?:-nocookie)?\.com/(?:[^/]+/.+/|(?:v|e(?:mbed)?)/|.*[?&]v=)|youtu\.be/)([^”&?/ ]{11})%i’, $url, $match);
      $youtube_id = $match[1];

      1. Rauf Quliyev

        Where do we add this code you wrote?

        1. MD Khokon Mia

          Can you just replace these few lines on your index.php file?

          $video_link = $_POST['video_link'];
          preg_match('%(?:youtube(?:-nocookie)?\.com/(?:[^/]+/.+/|(?:v|e(?:mbed)?)/|.*[?&]v=)|youtu\.be/)([^"&?/ ]{11})%i', $video_link, $match);
          $video_id = $match[1];

          this should solve your problem. If you need further help, please reach me at info@blogdesire.com
          I will be more than happy to assist you.
          thank you

  26. mrandroid

    Thanks brother, btw any updates for some no streams url video?

    1. MD Khokon Mia

      Not yet, I’ll update the tutorial and will notify you once I have the solution.
      Thanks