10

Let's take these URLs as an example:

  1. http://www.youtube.com/watch?v=8GqqjVXhfMU&feature=youtube_gdata_player
  2. http://www.youtube.com/watch?v=8GqqjVXhfMU

This PHP function will NOT properly obtain the ID in case 1, but will in case 2. Case 1 is very common, where ANYTHING can come behind the YouTube ID.

/**
 * get YouTube video ID from URL
 *
 * @param string $url
 * @return string YouTube video id or FALSE if none found. 
 */
function youtube_id_from_url($url) {
    $pattern = 
        '%^# Match any YouTube URL
        (?:https?://)?  # Optional scheme. Either http or https
        (?:www\.)?      # Optional www subdomain
        (?:             # Group host alternatives
          youtu\.be/    # Either youtu.be,
        | youtube\.com  # or youtube.com
          (?:           # Group path alternatives
            /embed/     # Either /embed/
          | /v/         # or /v/
          | /watch\?v=  # or /watch\?v=
          )             # End path alternatives.
        )               # End host alternatives.
        ([\w-]{10,12})  # Allow 10-12 for 11 char YouTube id.
        $%x'
        ;
    $result = preg_match($pattern, $url, $matches);
    if (false !== $result) {
        return $matches[1];
    }
    return false;
}

What I'm thinking is that there must be a way where I can just look for the "v=", no matter where it lies in the URL, and take the characters after that. In this manner, no complex RegEx will be needed. Is this off base? Any ideas for starting points?

user2428118
  • 7,935
  • 4
  • 45
  • 72
Shackrock
  • 4,601
  • 10
  • 48
  • 74
  • I think the main problem with this pattern is just the $ at the end of the pattern, which anchors the pattern at the end of the string being tested. This is why Case 1 doesn't match, because it doesn't end with the ID. – Bendoh Jun 27 '13 at 20:09

9 Answers9

30
if (preg_match('/youtube\.com\/watch\?v=([^\&\?\/]+)/', $url, $id)) {
  $values = $id[1];
} else if (preg_match('/youtube\.com\/embed\/([^\&\?\/]+)/', $url, $id)) {
  $values = $id[1];
} else if (preg_match('/youtube\.com\/v\/([^\&\?\/]+)/', $url, $id)) {
  $values = $id[1];
} else if (preg_match('/youtu\.be\/([^\&\?\/]+)/', $url, $id)) {
  $values = $id[1];
}
else if (preg_match('/youtube\.com\/verify_age\?next_url=\/watch%3Fv%3D([^\&\?\/]+)/', $url, $id)) {
    $values = $id[1];
} else {   
// not an youtube video
}

This is what I use to extract the id from an youtube url. I think it works in all cases.

Note that at the end $values = id of the video

Malte Schwerhoff
  • 12,684
  • 4
  • 41
  • 71
user1236048
  • 5,542
  • 7
  • 50
  • 87
  • 1
    This is far more general and catches the variety of of URL forms that you'll get from / to YouTube. +1 – Bendoh Feb 15 '13 at 18:21
  • @Bendoh why is this more general than the selected answer w/ `parse_str` - which seems like it catches every variable in the URL perfectly? – Shackrock Jun 22 '13 at 17:16
  • 1
    Selected answer won't capture URLs of the form /v/ or embed/, only the form that contains 'v' as a query parameter. It also pays no attention to the hostname of the link – it's just going to pull out the value of 'v' from any URL with a 'v' parameter in the query string. For example, http://www.youtube.com/v/ihCbVT637aM won't get parsed correctly. – Bendoh Jun 27 '13 at 20:08
  • @Bendoh - you're right... thanks. I've changed this to the "best answer." – Shackrock Jun 28 '13 at 18:58
  • would someone know the equivalent of this for javascript? – newton_guima Jan 31 '14 at 23:46
9

Instead of regex. I hightly recommend parse_url() and parse_str():

$url = "http://www.youtube.com/watch?v=8GqqjVXhfMU&feature=youtube_gdata_player";
parse_str(parse_url( $url, PHP_URL_QUERY ), $vars );
echo $vars['v'];    

Done

Starx
  • 77,474
  • 47
  • 185
  • 261
2

You could just use parse_url and parse_str:

$query_string = parse_url($url, PHP_URL_QUERY);
parse_str($query_string);
echo $v;
jeroen
  • 91,079
  • 21
  • 114
  • 132
1

I have used the following patterns because YouTube has a youtube-nocookie.com domain too:

'@youtube(?:-nocookie)?\.com/watch[#\?].*?v=([^"\& ]+)@i',
'@youtube(?:-nocookie)?\.com/embed/([^"\&\? ]+)@i',
'@youtube(?:-nocookie)?\.com/v/([^"\&\? ]+)@i',
'@youtube(?:-nocookie)?\.com/\?v=([^"\& ]+)@i',
'@youtu\.be/([^"\&\? ]+)@i',
'@gdata\.youtube\.com/feeds/api/videos/([^"\&\? ]+)@i',

In your case it would only mean to extend the existing expressions with an optional (-nocookie) for the regular YouTube.com URL like so:

if (preg_match('/youtube(?:-nocookie)\.com\/watch\?v=([^\&\?\/]+)/', $url, $id)) {

If you change your proposed expression to NOT contain the final $, it should work like you intended. I added the -nocookie as well.

/**
 * get YouTube video ID from URL
 *
 * @param string $url
 * @return string YouTube video id or FALSE if none found. 
 */
function youtube_id_from_url($url) {
    $pattern = 
        '%^# Match any YouTube URL
        (?:https?://)?  # Optional scheme. Either http or https
        (?:www\.)?      # Optional www subdomain
        (?:             # Group host alternatives
          youtu\.be/    # Either youtu.be,
        |youtube(?:-nocookie)?\.com  # or youtube.com and youtube-nocookie
          (?:           # Group path alternatives
            /embed/     # Either /embed/
          | /v/         # or /v/
          | /watch\?v=  # or /watch\?v=
          )             # End path alternatives.
        )               # End host alternatives.
        ([\w-]{10,12})  # Allow 10-12 for 11 char YouTube id.
        %x'
        ;
    $result = preg_match($pattern, $url, $matches);
    if (false !== $result) {
        return $matches[1];
    }
    return false;
}
teezee
  • 51
  • 3
0

SOLUTION for any YOUTUBE LINK:

http://youtube.com/v/dQw4w9WgXcQ
http://youtube.com/watch?v=dQw4w9WgXcQ
http://www.youtube.com/watch?feature=player&v=dQw4w9WgXcQ&var2=bla
http://youtu.be/dQw4w9WgXcQ

==

https://stackoverflow.com/a/20614061/2165415

Community
  • 1
  • 1
T.Todua
  • 53,146
  • 19
  • 236
  • 237
0

Here is one solution

/**
 * credits goes to: http://stackoverflow.com/questions/11438544/php-regex-for-youtube-video-id
 * update: mobile link detection
 */
public function parseYouTubeUrl($url)
{
     $pattern = '#^(?:https?://)?(?:www\.)?(?:m\.)?(?:youtu\.be/|youtube\.com(?:/embed/|/v/|/watch\?v=|/watch\?.+&v=))([\w-]{11})(?:.+)?$#x';
     preg_match($pattern, $url, $matches);
     return (isset($matches[1])) ? $matches[1] : false;
}

It can deal with mobile links too.

Ante Braovic
  • 457
  • 4
  • 13
0

Another easy way is using parse_str():

<?php
    $url = 'http://www.youtube.com/watch?v=8GqqjVXhfMU&feature=youtube_gdata_player';
    parse_str($url, $yt);

    // The associative array $yt now contains all of the key-value pairs from the querystring (along with the base 'watch' URL, but doesn't seem you need that)
    echo $yt['v']; // echos '8GqqjVXhfMU';
?>
Morgon
  • 3,269
  • 1
  • 27
  • 32
  • Looks like you're missing parse_url first, as other answers state. With parse_url it works. FYI – Shackrock Mar 07 '12 at 02:42
  • [ORIG: There's no need to parse_url. One could argue that it's cleaner, but - at least in PHP 5.3.6 - the URL preceding the querystring parameters is simply a key in the array.] -- EDIT: Ah dammit, this works when there's only one QS parameter, but the function must split on &. parse_url would be the more correct way. – Morgon Mar 07 '12 at 02:45
0

The parse_url suggestions are good. If you really want a regex you can use this:

/(?<=v=)[^&]+/`
Jacob Eggers
  • 9,062
  • 2
  • 25
  • 43
-1

Here is my function for retrieving Youtube ID !

function getYouTubeId($url) {
    if (!(strpos($url, 'v=') !== false)) return false;
    $parse = explode('v=', $url);
    $code = $parse[1];
    if (strlen($code) < 11) return false;
    $code = substr($code, 0, 11);
    return $code;
}
MaxSem
  • 3,457
  • 21
  • 34
Mr. Kent
  • 1
  • 1