Что такое безопасный ограничитель регулярных выражений PCRE для использования в атрибуте элемента ввода шаблона HTML5? - PullRequest
12 голосов
/ 02 марта 2012

Кажется, что спецификация HTML5 (и, следовательно, ECMA262) позволяет <input type="text" pattern="[0-9]/[0-9]" /> соответствовать строке '0/0', даже если косая черта не экранирована. Веб-приложения, такие как Drupal, хотели бы обеспечить проверку на стороне сервера для браузеров, которые не поддерживают HTML5, например:

<?php
preg_match('/^(' . $pattern . ')$/', $value);
?>

К сожалению, строка '[0-9] / [0-9]' не является допустимым регулярным выражением PRCE. Похоже, что большинство, если не все браузеры, поддерживающие HTML5, поддерживают и pattern="[0-9]/[0-9]" , и pattern="[0-9]\/[0-9]", в связи с чем возникает вопрос - что мы можем использовать в качестве разделителя для запуска этого шаблона с регулярным выражением в стиле Perl?

Мы подали отчет об ошибке по спецификации W3C но браузеры здесь не правы? Нужно ли уточнять спецификацию HTML5? Есть ли обходной путь, который мы можем использовать в PHP?

Ответы [ 6 ]

4 голосов
/ 24 июня 2014

Я рекомендую использовать "\xFF" байт в качестве разделителя шаблона, потому что это не разрешено в строке UTF-8, поэтому мы можем быть уверены, что это не произойдет в шаблоне.И поскольку preg_match не понимает UTF-8, это не вызовет проблем.

Пример: preg_match("\xFF$pattern\$\xFFADmsu", $subject);

Обратите внимание на ADmsu модификаторы и добавление $.Модификатор u требует допустимых байтов UTF-8 только в шаблоне, но не в разделителях вокруг него.

4 голосов
/ 02 марта 2012

Это допустимое регулярное выражение, если вы используете # вместо / в качестве разделителя.Пример:

preg_match('#^('.$pattern.')$#', $value);
3 голосов
/ 02 марта 2012

Одна из проблем с PCRE заключается в том, что почти любой разделитель допустим для маркеров начала и конца, в зависимости от того, что облегчает оставшуюся часть побега.Так что # foo # разрешено, / foo / разрешено,! Foo!законно (я думаю) и т. д. Неограниченное регулярное выражение, я бы сказал, чрезвычайно опасно именно по этой причине.Это похоже на ошибку спецификации HTML5, которую он не указывает.

Может быть, в PHP отсканируйте строку и выберите разделитель из белого списка, которого нет в строке?(Например, если нет / использовать это, если есть использование #, если это там, используйте%, и т. Д.)

2 голосов
/ 02 марта 2012

Я думаю chr(0) будет работать просто отлично. Редактировать: нет. Но chr(1) работает.

0 голосов
/ 30 августа 2018

Просто заключите его в скобки или скобки (да, это странно!):

<?php
preg_match('(^' . $pattern . '$)', $value);
?>

В руководстве говорится, что вы можете использовать все соответствующие пары: http://php.net/manual/en/regexp.reference.delimiters.php

Не легко вво-первых, но это явно касается ЛЮБОГО персонажа, которого вы можете использовать между ними.Например, '(^(foo|bar)$)' работает как конечное регулярное выражение: ^(foo|bar)$, без каких-либо потенциально опасных выходов.

0 голосов
/ 02 марта 2012

Учитывая, что приложение PHP (в данном случае Drupal) генерирует поле ввода, кажется, что обходной путь должен был бы сделать что-то вроде:

$pattern = '[0-9]/[0-9]';
...
$cleanPattern = preg_replace('/\//', '\\/', $pattern);
preg_match('/' . $cleanPattern . '/', $subject, $matches);

Я не мог придуматьслучай, когда это не сработает, с /, используемым в качестве литерала в выражении.

Спецификация HTML5 ссылается на ECMA262 для спецификации допустимого шаблона:

ЕслиЕсли указано значение атрибута, оно должно совпадать с производством шаблона JavaScript.[ ECMA262 ]

Поскольку в ECMA262 определен BNF, полный синтаксический анализатор (вместо использования PCRE) представляется наиболее безопасным подходом.

...