Displaying YouTube Videos in PHP

Share this article

In this two-part article, we’re going to learn how to work with version 3 of the YouTube API and we’ll build a demo along the way. Let’s get started.

YouTube Logo

What We’re Building

We’re going to build a demo that lets the user browse popular videos on YouTube, search for a video, browse videos by categories, and select a video to watch.

I will be using Laravel 5 as my framework of choice, and Vagrant for my development environment. The final product will look something like this:

Final demo

Preparing the Project

After installing Laravel 5 on your machine, install google/apiclient:

composer require google/apiclient

To set up a new project on the Google Developers Console, check out this quick tip to get started.

Registering Environment Variables

After getting our credentials from the Google Developers Console, we need to register them inside our application.

// .env

APP_DEBUG=true

app_name='Your app name (optional)'
client_id='Your client id'
client_secret='Your client secret'
api_key='Your developer key'
// config/google.php

return [
    'app_name'      => env('app_name'),
    'client_id'     => env('client_id'),
    'client_secret' => env('client_secret'),
    'api_key'       => env('api_key')
];

Laravel automatically loads the environment variables from the .env file in the root of our application folder. Now that we have our configuration set up, we can start the login process.

Login & Authorization

Before logging in with the Google API, we need to talk about scopes, and why they are important to the authorization process.

Scopes

Scopes define the level of authorization accorded to the application, so be sure to only request what you need. YouTube’s API has four scopes:

  • https://www.googleapis.com/auth/youtube: Manage your YouTube account.
  • https://www.googleapis.com/auth/youtube.readonly: View your YouTube account.
  • https://www.googleapis.com/auth/youtube.upload: Upload YouTube videos and manage your YouTube videos.
  • https://www.googleapis.com/auth/youtubepartner-channel-audit: Retrieve the auditDetails part in a channel resource.

For our demo, I’m only going to use the first one, and we can extend it depending on our application’s needs. You can read more about authorization in the documentation.

// app/Services/GoogleLogin.php

namespace App\Services;

class GoogleLogin
{
  protected $client;

  public function __construct(\Google_Client $client)
  {
    $this->client = $client;

    $this->client->setClientId(\Config::get('google.client_id'));
    $this->client->setClientSecret(\Config::get('google.client_secret'));
    $this->client->setDeveloperKey(\Config::get('google.api_key'));
    $this->client->setRedirectUri(\Config::get('app.url') . "/loginCallback");
    $this->client->setScopes([
                                 'https://www.googleapis.com/auth/youtube',
                             ]);
    $this->client->setAccessType('offline');
  }

  public function isLoggedIn()
  {
    if (\Session::has('token')) {
      $this->client->setAccessToken(\Session::get('token'));
    }

    if ($this->client->isAccessTokenExpired()) {
      \Session::set('token', $this->client->getRefreshToken());
    }

    return !$this->client->isAccessTokenExpired();
  }

  public function login($code)
  {
    $this->client->authenticate($code);
    $token = $this->client->getAccessToken();
    \Session::put('token', $token);

    return $token;
  }
  
  public function getLoginUrl()
  {
    $authUrl = $this->client->createAuthUrl();

    return $authUrl;
  }
}

After constructing a Google_Client instance using our credentials, we set the desired scopes. The setAccessType method gives our application the ability to refresh the token when the user is not present.

Login Controller

// app/Http/routes.php

Route::get('/login', ['uses' => 'GoogleLoginController@index', 'as' => 'login']);
Route::get('/loginCallback', ['uses' => 'GoogleLoginController@store', 'as' => 'loginCallback']);
// app/Http/Controllers/GoogleLoginController.php

class GoogleLoginController extends Controller
{

  public function index(\App\Services\GoogleLogin $ga)
  {
    if ($ga->isLoggedIn()) {
      return \Redirect::to('/');
    }

    $loginUrl = $ga->getLoginUrl();

    return "<a href='{$loginUrl}'>login</a>";
  }

  public function store(\App\Services\GoogleLogin $ga)
  {
    // User rejected the request
    if(\Input::has('error')){
      dd(\Input::get('error'));
    }

    if (\Input::has('code')) {
      $code = \Input::get('code');
      $ga->login($code);

      return \Redirect::to('/');
    } else {
      throw new \InvalidArgumentException("Code attribute is missing.");
    }//else
  }
}

The GoogleLoginController@index method will test if the user is logged in and if so, will redirect them to the home page. Otherwise, we generate a new login URL.

After passing the authorization phase, Google will redirect the user to the callback URL defined in the Google Developers Console with the code parameter. This code is used in exchange for a token.

Listing Videos

The Google_Service_YouTube class is our door to the YouTube API. It provides access to all YouTube data. The class takes a Google_Client instance as a parameter. It makes sense to create a provider to bind our implementation so that we don’t have to repeat the same code everywhere. You can read more about service providers in the documentation.

php artisan make:provider YouTubeServiceProvider

This command will create a new class inside our app/Providers folder. We need to add our service provider to the list of providers inside config/app.php.

// config/app.php

'providers' => [
  'App\Providers\YouTubeServiceProvider',
]
// app/Providers/YouTubeServiceProvider.php

public function register()
{
  $app = $this->app;

  $this->app->bind('GoogleClient', function () {
    $googleClient = new \Google_Client();
    $googleClient->setAccessToken(\Session::get("token"));

    return $googleClient;
  });

  $this->app->bind('youtube', function () use ($app) {
    $googleClient = \App::make('GoogleClient');
    $youtube = new \Google_Service_YouTube($googleClient);

    return $youtube;
  });
}

The https://www.googleapis.com/youtube/v3/videos endpoint returns the list of videos, and it can be accessed using our YouTube class via $youtube->videos.

// app/Http/Controllers/YouTubeAPIController.php

public function videos()
{
  $youtube = \App::make('youtube');
  $videos = $youtube->videos->listVideos('snippet', ['chart' => 'mostPopular']);

  dump($video);
}

Videos Screenshot

The first parameter to the listVideos method is called part and it defines the information contained in the result. You may add statistics to get data about votes count, likes, etc. We’ll talk more about the partparameter later in this article.You can read more about the supported values in the documentation.

The second parameter must contain a filter for the videos. In this case, we are getting the most popular videos on YouTube. You may also request your liked or disliked videos, etc. You can read more about filters in the documentation.

// app/Http/Controllers/YouTubeAPIController.php

public function videos()
{
  $options = ['chart' => 'mostPopular', 'maxResults' => 16];
  if (\Input::has('page')) {
    $options['pageToken'] = \Input::get('page');
  }

  $youtube = \App::make('youtube');
  $videos = $youtube->videos->listVideos('id, snippet', $options);

  return view('videos', ['videos' => $videos]);
}

This method is self explanatory. The page parameter is for pagination as we’ll see next.

// resources/views/videos.blade.php

<ul class="list-unstyled video-list-thumbs row">
@foreach($videos as $video)
    <li class="col-lg-3 col-sm-4 col-xs-6">
        <a href="https://www.youtube.com/watch?v={{ $video->getId() }}" title="{{ $video['snippet']['title'] }}" target="_blank">
            <img src="{{ $video['snippet']['thumbnails']['medium']['url'] }}" alt="{{ $video['snippet']['title'] }}" />
            <h2 class="truncate">{{ $video['snippet']['title'] }}</h2>
        </a>
    </li>
@endforeach
</ul>

<ul class="pagination pagination-lg">
    <li @if($videos->getPrevPageToken() == null) class="disabled" @endif>
      <a href="/videos?page={{$videos->getPrevPageToken()}}" aria-label="Previous">
        <span aria-hidden="true">Previous &laquo;</span>
      </a>
    </li>
    <li @if($videos->getNextPageToken() == null) class="disabled" @endif>
      <a href="/videos?page={{$videos->getNextPageToken()}}" aria-label="Next">
        <span aria-hidden="true">Next &raquo;</span>
      </a>
    </li>
</ul>

Our view is very basic – we only output the video title, thumbnail and a link. Our API response also contains likes, dislikes, view count, etc, so you may use them to enrich your page using some special markup. The pagination links give the user the ability to navigate through videos. You may have noticed that it’s done through tokens and not the normal page parameter.

When you click on a video, you will be redirected to watch the video on YouTube using the ID. Why not get the video details and create a page containing the player along with more info about the video?

Single Video Page

Getting a single video is just a matter of specifying an option to the same endpoint from before. Since the result is a single item, we set the maxResults parameter to 1, and we remove the chart attribute because it’s not relevant in this request.

// app/Http/routes.php

Route::get('/video/{id}', ['uses' => 'YouTubeAPIController@video', 'as' => 'video']);
// app/Http/Controllers/YouTubeAPIController.php

public function video($id){
  $options = ['maxResults' => 1, 'id' => $id];

  $youtube = \App::make('youtube');
  $videos = $youtube->videos->listVideos('id, snippet, player, contentDetails, statistics, status', $options);

  if(count($videos->getItems()) == 0){
    return redirect('404');
  }

  return view('video', ['video' => $videos[0]]);
}

Video

Because it’s a single item page, I tried to pull as much information as I can using the part parameter. If the item doesn’t exist, we redirect the user to the 404 not found page. Otherwise, we render our view with the first item from the list.

// resources/views/video.blade.php

<div class="row">
    <h2>{{ $video["snippet"]["title"] }}</h2>
</div>

<div class="row">
    <iframe type='text/html' src='http://www.youtube.com/embed/{{ $video->getId() }}' width='100%' height='500' frameborder='0' allowfullscreen='true'></iframe>
</div>

<div class="row">
    (<span>{{ $video["statistics"]["likeCount"] }} <i class="glyphicon glyphicon-thumbs-up"></i></span>)
    (<span>{{ $video["statistics"]["dislikeCount"] }} <i class="glyphicon glyphicon-thumbs-down"></i></span>)
    (<span>{{ $video["statistics"]["favoriteCount"] }} <i class="glyphicon glyphicon-heart"></i></span>)
    (<span>{{ $video["statistics"]["commentCount"] }} <i class="glyphicon glyphicon-bullhorn"></i></span>)
</div>

<hr/>

<div class="row">
    <p>{{ $video["snippet"]["description"] }}</p>
</div>

Because we asked the YouTube API for the player part, we can directly access it using $video['player']['embedHtml'], but if you want to customize the player dimensions you can build it using the video ID as we did in our example.

One thing to note: every request has a cost of one call, and when you ask for the snippet, statistics, etc, you add up new costs. You can read more about quotas and costs in the documentation.

Video

Wrapping Up

In this first part, we introduced the YouTube API and built a small demo to query the list of most popular videos on YouTube with the pagination links, and a page to view a single video. In the next part we will be exploring video categories and the search functionality, so stay tuned. You can check the final result on Github, and if you have any questions or comments, you can post them below.

Frequently Asked Questions (FAQs) about Displaying YouTube Videos with PHP

How can I extract the video ID from a YouTube URL using PHP?

Extracting the YouTube video ID from a URL can be done using PHP’s parse_url and parse_str functions. First, use parse_url to extract the query string from the URL. Then, use parse_str to parse the query string into an array. The video ID will be the value of the ‘v’ key in the array. Here’s a simple example:

$url = 'https://www.youtube.com/watch?v=3e1GHCA3GPo';
parse_str(parse_url($url, PHP_URL_QUERY), $vars);
$videoId = $vars['v'];
echo $videoId; // Outputs: 3e1GHCA3GPo

How can I embed a YouTube video in a PHP page?

Embedding a YouTube video in a PHP page involves using the YouTube embed URL with the video ID. The embed URL is ‘https://www.youtube.com/embed/‘ followed by the video ID. You can use this URL in an iframe to embed the video. Here’s an example:

$videoId = '3e1GHCA3GPo';
echo '<iframe width="560" height="315" src="https://www.youtube.com/embed/'.$videoId.'" frameborder="0" allowfullscreen></iframe>';

How can I display multiple YouTube videos on a PHP page?

To display multiple YouTube videos, you can use an array of video IDs. Loop through the array and create an iframe for each video. Here’s an example:

$videoIds = ['3e1GHCA3GPo', 'dQw4w9WgXcQ', '3tmd-ClpJxA'];
foreach ($videoIds as $videoId) {
echo '<iframe width="560" height="315" src="https://www.youtube.com/embed/'.$videoId.'" frameborder="0" allowfullscreen></iframe>';
}

How can I control the start time of a YouTube video in PHP?

The start time of a YouTube video can be controlled by adding the ‘start’ parameter to the embed URL. The value of the ‘start’ parameter is the start time in seconds. Here’s an example:

$videoId = '3e1GHCA3GPo';
$startTime = 30; // Start at 30 seconds
echo '<iframe width="560" height="315" src="https://www.youtube.com/embed/'.$videoId.'?start='.$startTime.'" frameborder="0" allowfullscreen></iframe>';

How can I display a YouTube video thumbnail in PHP?

YouTube video thumbnails can be accessed using the video ID. The URL for the thumbnail is ‘https://img.youtube.com/vi/‘ followed by the video ID and ‘/0.jpg’. Here’s an example:

$videoId = '3e1GHCA3GPo';
echo '<img src="https://img.youtube.com/vi/'.$videoId.'/0.jpg">';

How can I make a YouTube video autoplay in PHP?

To make a YouTube video autoplay, add the ‘autoplay’ parameter to the embed URL and set its value to 1. Here’s an example:

$videoId = '3e1GHCA3GPo';
echo '<iframe width="560" height="315" src="https://www.youtube.com/embed/'.$videoId.'?autoplay=1" frameborder="0" allowfullscreen></iframe>';

How can I hide YouTube video controls in PHP?

To hide the controls of a YouTube video, add the ‘controls’ parameter to the embed URL and set its value to 0. Here’s an example:

$videoId = '3e1GHCA3GPo';
echo '<iframe width="560" height="315" src="https://www.youtube.com/embed/'.$videoId.'?controls=0" frameborder="0" allowfullscreen></iframe>';

How can I loop a YouTube video in PHP?

To loop a YouTube video, add the ‘loop’ parameter to the embed URL and set its value to 1. Note that the ‘playlist’ parameter must also be set to the video ID for the loop to work. Here’s an example:

$videoId = '3e1GHCA3GPo';
echo '<iframe width="560" height="315" src="https://www.youtube.com/embed/'.$videoId.'?loop=1&playlist='.$videoId.'" frameborder="0" allowfullscreen></iframe>';

How can I mute a YouTube video in PHP?

To mute a YouTube video, add the ‘mute’ parameter to the embed URL and set its value to 1. Here’s an example:

$videoId = '3e1GHCA3GPo';
echo '<iframe width="560" height="315" src="https://www.youtube.com/embed/'.$videoId.'?mute=1" frameborder="0" allowfullscreen></iframe>';

How can I display a YouTube video with a custom size in PHP?

The size of the YouTube video can be customized by changing the ‘width’ and ‘height’ attributes of the iframe. Here’s an example:

$videoId = '3e1GHCA3GPo';
$width = 800;
$height = 600;
echo '<iframe width="'.$width.'" height="'.$height.'" src="https://www.youtube.com/embed/'.$videoId.'" frameborder="0" allowfullscreen></iframe>';

Younes RafieYounes Rafie
View Author

Younes is a freelance web developer, technical writer and a blogger from Morocco. He's worked with JAVA, J2EE, JavaScript, etc., but his language of choice is PHP. You can learn more about him on his website.

apiBrunoSlaravelOOPHPPHPvideoYoutube
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week