Я не особо разбираюсь в кодировке, но мне нужно написать простой оператор preg_replace на PHP, который поможет мне с плагином WordPress. По сути, мне нужен код, который будет искать строку, извлекать идентификатор видео и возвращать код внедрения с вставленным в него идентификатором видео.
Другими словами, я ищу это:
[youtube=https://thewikihow.com/video_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 на английский, чтобы я мог учиться. :-)
Спасибо! Майк






$str = preg_replace('/\[youtube=.*?v=([a-z0-9_-]+?)&.*?\]/i', 'param name = "movie" value = "http://www.youtube.com/v/&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
&.*?\] - the junk up to the ending ]
/i - end the RE and make it case-insensitive for the hell of it
Хорошее объяснение атомов регулярного выражения. Тем не менее, Паоло прав - этот шаблон не должен принимать любые символы как часть идентификатора видео на YouTube.
$embedString = 'youtube=https://thewikihow.com/video_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 до любого количества этих символов в совпадении.Предупреждение. Если текст после .*? не найден сразу, механизм регулярных выражений продолжит поиск по всей строке, возможно, перейдя к следующему тегу [youtube...]. Часто лучше использовать [^\]]*?, чтобы ограничить поиск внутри скобок.
На основании ответа RoBorgs:
$str = preg_replace('/\[youtube=[^\]]*?v=([^\]]*?)&[^\]]*?\]/i', ...)
[^\]] соответствует любому символу, кроме ']'.
БУДЬ ОСТОРОЖЕН! Если это система в стиле BBCode с пользовательским вводом, эти два других решения сделают вас уязвимыми для XSS-атак.
У вас есть несколько способов защитить себя от этого. Попросите регулярное выражение явно запретить символы, которые могут вызвать у вас проблемы (или разрешить только те, которые действительны для идентификатора видео YouTube), или фактически дезинфицируйте ввод и используйте вместо него preg_match, что я проиллюстрирую ниже, выходя из регулярного выражения RoBorg.
<?php
$input = "[youtube=https://thewikihow.com/video_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=https://thewikihow.com/video_\"><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/&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
}
Я бы избегал регулярных выражений в этом случае, если это вообще возможно, потому что: кто гарантирует, что строка запроса в первом URL-адресе всегда будет в этом формате?
Я бы использовал parse_url($originalURL, PHP-URL-QUERY);, а затем перебирал бы возвращенный массив, находя правильную пару «имя = значение» для части v строки запроса:
что-то типа:
$originalURL = 'https://thewikihow.com/video_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, непроверено.
Чтобы не придираться, но не следует ли вам заставить его искать только буквенно-цифровые символы / символы подчеркивания в качестве значения v? Таким образом, люди не могут там оказаться глупыми.