Написание простого preg_replace в PHP - PullRequest
2 голосов
/ 10 октября 2008

Я не большой программист, но мне нужно написать простую инструкцию preg_replace на PHP, которая поможет мне с плагином WordPress. По сути, мне нужен код, который будет искать строку, извлекать идентификатор видео и возвращать код для вставки с вставленным в него идентификатором видео.

Другими словами, я ищу это:

[youtube=http://www.youtube.com/watch?v=VIDEO_ID_HERE&hl=en&fs=1]

И хотите заменить его следующим (с сохранением идентификатора видео):

param name="movie" value="http://www.youtube.com/v/VIDEO_ID_HERE&hl=en&fs=1&rel=0

Если возможно, я был бы всегда благодарен, если бы вы могли объяснить, как вы использовали различные слэши, знаки кареты и звезды Клини в шаблоне поиска, то есть перевести его с grep на английский, чтобы я мог учиться. : -)

Спасибо!
Mike

Ответы [ 5 ]

6 голосов
/ 10 октября 2008

БУДЬТЕ ОСТОРОЖНЫ! Если это система в стиле BBCode с пользовательским вводом, эти два других решения сделают вас уязвимыми для атак XSS.

У вас есть несколько способов защитить себя от этого. Попросите регулярное выражение явно запретить символы, которые могут вызвать у вас проблемы (или разрешить только те, которые действительны для идентификатора видео на YouTube), или фактически очистить ввод и использовать вместо этого preg_match, что я проиллюстрирую ниже при выходе из регулярного выражения Роборга. *

<?php

$input = "[youtube=http://www.youtube.com/watch?v=VIDEO_ID_HERE&hl=en&fs=1]";

if ( preg_match('/\[youtube=.*?v=(.*?)&.*?\]/i', $input, $matches ) )
{
    $sanitizedVideoId = urlencode( strip_tags( $matches[1] ) );
    echo 'param name="movie" value="http://www.youtube.com/v/' . $sanitizedVideoId . '&hl=en&fs=1&rel=0';
} else {
    //  Not valid input
}

Вот пример атаки такого типа в действии

<?php

$input = "[youtube=http://www.youtube.com/watch?v=\"><script src=\"http://example.com/xss.js\"></script>&hl=en&fs=1]";

//  Is vulnerable to XSS
echo preg_replace('/\[youtube=.*?v=(.*?)&.*?\]/i', 'param name="movie" value="http://www.youtube.com/v/$1&hl=en&fs=1&rel=0', $input );
echo "\n";

//  Prevents XSS
if ( preg_match('/\[youtube=.*?v=(.*?)&.*?\]/i', $input, $matches ) )
{
    $sanitizedVideoId = urlencode( strip_tags( $matches[1] ) );
    echo 'param name="movie" value="http://www.youtube.com/v/' . $sanitizedVideoId . '&hl=en&fs=1&rel=0';
} else {
    //  Not valid input
}
2 голосов
/ 10 октября 2008
$str = preg_replace('/\[youtube=.*?v=([a-z0-9_-]+?)&.*?\]/i', 'param name="movie" value="http://www.youtube.com/v/$1&hl=en&fs=1&rel=0', $str);

         /     - Start of RE
         \[    - A literal [  ([ is a special character so it needs escaping)
         youtube= - Make sure we've got the right tag
         .*?   - Any old rubbish, but don't be greedy; stop when we reach...
         v=    - ...this text
         ([a-z0-9_-]+?) - Take some more text (just z-a 0-9 _ and -), and don't be greedy.  Capture it using ().  This will get put in $1
         &.*?\] - the junk up to the ending ]
         /i - end the RE and make it case-insensitive for the hell of it
1 голос
/ 13 октября 2008

Я бы избегал регулярных выражений в этом случае, если это вообще возможно, потому что: кто гарантирует, что строка запроса в первом URL всегда будет в этом формате?

Я бы использовал parse_url($originalURL, PHP-URL-QUERY);, а затем перебрал возвращаемый массив, чтобы найти правильную пару 'имя = значение' для части v строки запроса: что-то вроде:

$originalURL = 'http://www.youtube.com/watch?v=VIDEO_ID_HERE&hl=en&fs=1';

foreach( parse_url( $originalURL, PHP_URL_QUERY) as $keyvalue )
{
    if ( strlen( $keyvalue ) > 2 && substr( $keyvalue, 0, 2 ) == 'v=' )
    {
        $videoId = substr( $keyvalue, 2 );
        break;
    }
}

$newURL = sprintf( 'http://www.youtube.com/v/%s/whatever/else', url_encode( $videoId ) );

p.s. записано в текстовом поле SO, не проверено.

0 голосов
/ 10 октября 2008

Предупреждение. Если текст после .*? не найден сразу, механизм регулярных выражений продолжит поиск по всей строке, возможно, перейдя к следующему тегу [youtube...]. Часто лучше использовать [^\]]*?, чтобы ограничить поиск в скобках.

На основании ответа Роборгса:

$str = preg_replace('/\[youtube=[^\]]*?v=([^\]]*?)&[^\]]*?\]/i', ...)

[^\]] будет соответствовать любому символу, кроме ']'.

0 голосов
/ 10 октября 2008
$embedString = 'youtube=http://www.youtube.com/watch?v=VIDEO_ID_HERE&hl=en&fs=1';
preg_match('/v=([^&]*)/',$embedstring,$matches);
echo 'param name="movie" value="http://www.youtube.com/v/'.$matches[1].'&hl=en&fs=1&rel=0';

Попробуйте это.

Регулярное выражение /v=([^&]*)/ работает следующим образом:

  • ищет v=
  • затем сохраняет совпадение с шаблоном в скобках в $matches
  • [^&] указывает, что соответствует любому символу , кроме амперсанд ('&')
  • * говорит, что мы хотим от 0 до любого количества символов в матче
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...