开发者

Need help with preg_replace interpreting {variables} with parameters

I want to replace

{youtube}Video_ID_Here{/youtube}

with the embed code for a youtube video.

So far I have

preg_replace('/{youtube}(.*){\/youtube}/iU',...)

and it works 开发者_如何转开发just fine.

But now I'd like to be able to interpret parameters like height, width, etc. So could I have one regex for this whether is does or doesn't have parameters? It should be able to inperpret all of these below...

{youtube height="200px" width="150px" color1="#eee" color2="rgba(0,0,0,0.5)"}Video_ID_Here{/youtube}

{youtube height="200px"}Video_ID_Here{/youtube}

{youtube}Video_ID_Here{/youtube}

{youtube width="150px" showborder="1"}Video_ID_Here{/youtube}


Try this:

function createEmbed($videoID, $params)
{
    // $videoID contains the videoID between {youtube}...{/youtube}
    // $params is an array of key value pairs such as height => 200px

    return 'HTML...'; // embed code
}

if (preg_match_all('/\{youtube(.*?)\}(.+?)\{\/youtube\}/', $string, $matches)) {
    foreach ($matches[0] as $index => $youtubeTag) {
        $params = array();

        // break out the attributes
        if (preg_match_all('/\s([a-z0-9]+)="([^\s]+?)"/', $matches[1][$index], $rawParams)) {
            for ($x = 0; $x < count($rawParams[0]); $x++) {
                $params[$rawParams[1][$x]] = $rawParams[2][$x];
            }
        }

        // replace {youtube}...{/youtube} with embed code
        $string = str_replace($youtubeTag, createEmbed($matches[2][$index], $params), $string);
    }
}

this code matches the {youtube}...{/youtube} tags first and then splits out the attributes into an array, passing both them (as key/value pairs) and the video ID to a function. Just fill in the function definition to make it validate the params you want to support and build up the appropriate HTML code.


You probably want to use preg_replace_callback, as the replacing can get quite convoluted otherwise.

preg_replace_callback('/{youtube(.*)}(.*){\/youtube}/iU',...)

And in your callback, check $match[1] for something like the /(width|showborder|height|color1)="([^"]+)"/i pattern. A simple preg_match_all inside a preg_replace_callback keeps all portions nice & tidy and above all legible.


I would do it something like this:

preg_match_all("/{youtube(.*?)}(.*?){\/youtube}/is", $content, $matches);

for($i=0;$i<count($matches[0]);$i++)
{
  $params = $matches[1][$i];
  $youtubeurl = $matches[2][$i];

  $paramsout = array();

  if(preg_match("/height\s*=\s*('|\")([0-9]+px)('|\")/i", $params, $match)
  {
    $paramsout[] = "height=\"{$match[2]}\"";
  }

  //process others

  //setup new code
  $tagcode = "<object ..." . implode(" ", $paramsout) ."... >"; //I don't know what the code is to display a youtube video

  //replace original tag
  $content = str_replace($matches[0][$i], $tagcode, $content);
}

You could just look for params after "{youtube" and before "}" but you open yourself up to XSS problems. The best way would be look for a specific number of parameters and verify them. Don't allow things like < and > to be passed inside your tags as someone could put do_something_nasty(); or something.


I'd not use regex at all, since they are notoriously bad at parsing markup.

Since your input format is so close to HTML/XML in the first place, I'd rely on that

$tests = array(
    '{youtube height="200px" width="150px" color1="#eee" color2="rgba(0,0,0,0.5)"}Video_ID_Here{/youtube}'
  , '{youtube height="200px"}Video_ID_Here{/youtube}'
  , '{youtube}Video_ID_Here{/youtube}'
  , '{youtube width="150px" showborder="1"}Video_ID_Here{/youtube}'
  , '{YOUTUBE width="150px" showborder="1"}Video_ID_Here{/youtube}' // deliberately invalid
);

echo '<pre>';
foreach ( $tests as $test )
{
  try {
    $youtube = SimpleXMLYoutubeElement::fromUserInput( $test );

    print_r( $youtube );
  }
  catch ( Exception $e )
  {
    echo $e->getMessage() . PHP_EOL;
  }
}
echo '</pre>';

class SimpleXMLYoutubeElement extends SimpleXMLElement
{
  public static function fromUserInput( $code )
  {
    $xml = @simplexml_load_string(
        str_replace( array( '{', '}' ), array( '<', '>' ), strip_tags( $code ) ), __CLASS__
    );
    if ( !$xml || 'youtube' != $xml->getName() )
    {
      throw new Exception( 'Invalid youtube element' );
    }
    return $xml;
  }

  public function toEmbedCode()
  {
    // write code to convert this to proper embode code
  }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜