Ответ 1
Для любопытных, как работает регулярное выражение Алана Мура (и да, это действительно работает), я позволил себе прокомментировать его, чтобы его могли читать простые смертные:
function process_data_alan($text) //
{
$re = '%# Collapse ws everywhere but in blacklisted elements.
(?> # Match all whitespans other than single space.
[^\S ]\s* # Either one [\t\r\n\f\v] and zero or more ws,
| \s{2,} # or two or more consecutive-any-whitespace.
) # Note: The remaining regex consumes no text at all...
(?= # Ensure we are not in a blacklist tag.
(?: # Begin (unnecessary) group.
(?: # Zero or more of...
[^<]++ # Either one or more non-"<"
| < # or a < starting a non-blacklist tag.
(?!/?(?:textarea|pre)\b)
)*+ # (This could be "unroll-the-loop"ified.)
) # End (unnecessary) group.
(?: # Begin alternation group.
< # Either a blacklist start tag.
(?>textarea|pre)\b
| \z # or end of file.
) # End alternation group.
) # If we made it here, we are not in a blacklist tag.
%ix';
$text = preg_replace($re, " ", $text);
return $text;
}
Я здесь новый, но я сразу вижу, что Алан неплохо подходит к регулярному выражению. Я бы добавил только следующие предложения.
- Существует ненужная группа захвата, которую можно удалить.
- Хотя ОП не сказал этого, элемент
<SCRIPT>
должен быть добавлен в черный список<PRE>
и<TEXTAREA>
. - Добавление модификатора "исследования"
'S'
PCRE "ускоряет" это регулярное выражение примерно на 20%. - В lookahead есть группа чередования, которая созрела для применения эффективности эффективности Friedl unrolling-the-loop.
- В более серьезной заметке эта же группа чередования: (т.е.
(?:[^<]++|<(?!/?(?:textarea|pre)\b))*+
) подвержена чрезмерной рекурсии PCRE на больших целевых строках, что может привести к переполнению стека, в результате чего исполняемый файл Apache/PHP будет молча выполнять seg-fault и авария без предупреждения. (Узел Win32 Apachehttpd.exe
особенно восприимчив к этому, потому что он имеет всего 256 КБ стека по сравнению с исполняемыми файлами * nix, которые обычно создаются с использованием стека 8 МБ и более.) Филипп Хейзел (автор механизма регулярного выражения PCRE, используемого в PHP) обсуждает эту проблему в документации: PCR ОБСУЖДЕНИЕ ИСПОЛЬЗОВАНИЯ STACK. Хотя Алан правильно применил ту же ошибку, что и Филипп в этом документе (применяя притяжательный плюс к первому альтернативу), все еще будет много рекурсии, если HTML файл большой и имеет много нечерных тегов. например В моем ящике Win32 (с исполняемым файлом, имеющим стек 256 КБ), script взрывается тестовым файлом всего 60 КБ. Также обратите внимание, что PHP, к сожалению, не соответствует рекомендациям и устанавливает ограничение по рекурсии по умолчанию слишком высоко на 100000. (Согласно документам PCRE, это должно быть установлено равным размеру стека, разделенному на 500).
Вот улучшенная версия, которая быстрее оригинала, обрабатывает больший ввод и изящно выходит из строя с сообщением, если входная строка слишком велика для обработки:
// Set PCRE recursion limit to sane value = STACKSIZE / 500
// ini_set("pcre.recursion_limit", "524"); // 256KB stack. Win32 Apache
ini_set("pcre.recursion_limit", "16777"); // 8MB stack. *nix
function process_data_jmr1($text) //
{
$re = '%# Collapse whitespace everywhere but in blacklisted elements.
(?> # Match all whitespans other than single space.
[^\S ]\s* # Either one [\t\r\n\f\v] and zero or more ws,
| \s{2,} # or two or more consecutive-any-whitespace.
) # Note: The remaining regex consumes no text at all...
(?= # Ensure we are not in a blacklist tag.
[^<]*+ # Either zero or more non-"<" {normal*}
(?: # Begin {(special normal*)*} construct
< # or a < starting a non-blacklist tag.
(?!/?(?:textarea|pre|script)\b)
[^<]*+ # more non-"<" {normal*}
)*+ # Finish "unrolling-the-loop"
(?: # Begin alternation group.
< # Either a blacklist start tag.
(?>textarea|pre|script)\b
| \z # or end of file.
) # End alternation group.
) # If we made it here, we are not in a blacklist tag.
%Six';
$text = preg_replace($re, " ", $text);
if ($text === null) exit("PCRE Error! File too big.\n");
return $text;
}
p.s. Я знаком с этой проблемой PHP/Apache seg-fault, так как я был вовлечен в помощь сообществу Drupal, когда они боролись с этой проблемой. Смотрите: Оптимизация параметра CSS заставляет php cgi выполнить segfault в функции pcre "match" . Мы также испытали это с помощью парсера BBCode в проекте программного обеспечения форума FluxBB.
Надеюсь, что это поможет.