2

I'm building a blog that should parse bbcode tags like this:

Input: <youtube=http://www.youtube.com/watch?v=VIDEO_ID&feature=channel>
Output:

<object width="400" height="245">
<param name="movie" value="http://www.youtube-    nocookie.com/v/VIDEO_ID&hl=en&fs=1&rel=0&showinfo=0"></param>
<param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param>
<embed src="http://www.youtube-nocookie.com/v/VIDEO_ID&hl=en&fs=1&rel=0&showinfo=0" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="400" height="245"></embed>
</object>

My function is incredibly simple so far, because I've gotten stuck on the easiest part! Right now, I have a master process function that calls difference process functions. In this case one of them is processYouTubeVideos(). So I call it like so:

$str = eregi_replace('\<youtube=([^>]*)\>', processYouTubeVideos("\\1"), $str);

processYouTubeVideos() receives the URLs from inside the youtube tag perfectly, but for some reason, when using explode() (or split) the delimiter is never found. Even using test values like "u" or "tube"...

function processYouTubeVideos ($str) {

    $params = explode("?", $str);
    $params = explode("&", $params[1]);

    return $params[0];

}
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
bloudermilk
  • 17,820
  • 15
  • 68
  • 98

3 Answers3

3

Try:

$str = preg_replace('/<youtube=([^>]*)>/e', 'processYouTubeVideos("$1")', $str);

The code that you're attempting to run won't work, because the function on the output string will be called on the target pattern rather than the output. That means that you're sending "\1" literarly to the function. Add var_dump($str); to the beginning of the function and try running your code again, and you'll see this clearly.

preg_replace has a special flag "e" that you can use to execute a function for each time a replacement is made. This works by inserting the subpattern at the marker position ($1) and then running something like eval() or create_function() on the code to execute it and retrieve the result. This then sent back to preg_replace() and the actual replacement is made.

Emil H
  • 39,840
  • 10
  • 78
  • 97
0

Both of the earlier answers are now well and truly deprecated.

The modern technique is to use preg_replace_callback(), then parse the url and isolate the targeted portion of the query string. I'll demonstrate using sprintf() with placeholders in the html template string.

The pattern itself doesn't go to any great effort to validate the bbcode tag, so if you need strong validation, the pattern will need refinement.

Code: (Demo)

$bbCode = <<<BBCODE
Here is some text <youtube=http://www.youtube.com/watch?v=VIDEO_ID&feature=channel> and some more text
BBCODE;

echo preg_replace_callback(
         '~<youtube=([^>]+)>~',
         function ($m) {
             parse_str(parse_url($m[1], PHP_URL_QUERY), $queryStringArray);
             $videoId = $queryStringArray['v'] ?? null;
             if (!$videoId) {
                 return $m[0];  // do not replace bbcode because could not isolate the video id
             }
             return sprintf(
                        '<object width="400" height="245">
                             <param name="movie" value="http://www.youtube-nocookie.com/v/%1$s&hl=en&fs=1&rel=0&showinfo=0"></param>
                             <param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param>
                             <embed src="http://www.youtube-nocookie.com/v/%1$s&hl=en&fs=1&rel=0&showinfo=0" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="400" height="245"></embed>
                         </object>',
                         $videoId
                    );
         },
         $bbCode
     );

Output:

Here is some text <object width="400" height="245">
                             <param name="movie" value="http://www.youtube-nocookie.com/v/VIDEO_ID&hl=en&fs=1&rel=0&showinfo=0"></param>
                             <param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param>
                             <embed src="http://www.youtube-nocookie.com/v/VIDEO_ID&hl=en&fs=1&rel=0&showinfo=0" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="400" height="245"></embed>
                         </object> and some more text
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
0

The processYouTubeVideos("\1") function is being run before the eregi_replace.

The following does what I believe you intend:

$str = eregi_replace('\<youtube=([^>]*)\>', "\\1", $str);
$str = processYouTubeVideos($str);

It performs the replace, and then sends the resulting value to processYouTubeVideos.

Jonathan Fingland
  • 56,385
  • 11
  • 85
  • 79