在HTML5模式输入元素属性上使用什么是安全的PCRE正则表达式分隔符


What is a safe PCRE regex delimiter to use on HTML5 pattern input element attribute?

HTML5规范(以及ECMA262)似乎允许<input type="text" pattern="[0-9]/[0-9]" />匹配字符串"0/0",即使没有转义正斜杠。像Drupal这样的Web应用程序希望为不支持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中使用的变通方法?

如果使用#而不是/作为分隔符,则这是一个有效的正则表达式。示例:

preg_match('#^('.$pattern.')$#', $value);

我建议使用"'xFF"字节作为模式分隔符,因为它在UTF-8字符串中是不允许的,所以我们可以确保它不会出现在模式中。而且因为preg_match不理解UTF-8,所以不会造成任何麻烦。

示例:preg_match("'xFF$pattern'$'xFFADmsu", $subject);

请注意ADmsu修饰符和添加$u修饰符仅在模式中需要有效的UTF-8字节,但在周围的分隔符中不需要。

PCRE的一个问题是,几乎任何分隔符对于开始和结束标记都是合法的,这取决于是什么让其余的转义更容易。所以#foo#是合法的,/foo/是合法的!foo!是合法的(我认为)等等。正是因为这个原因,我想说,不受限制的正则表达式是极其危险的。这听起来像是一个HTML5规范的错误,但它没有具体说明。

也许在PHP中,扫描字符串并从字符串中不存在的白名单中选择一个分隔符?(例如,如果没有/使用那个,如果有使用#,如果有,使用%,等等)

我认为chr(0)可以正常工作。编辑:没有。但是chr(1)确实有效。

只需将其括在括号或圆括号中(是的,这很奇怪!):

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

手册指出,您可以使用所有对应的配对:http://php.net/manual/en/regexp.reference.delimiters.php

一开始并不容易,但它清楚地处理了你可能在两者之间使用的任何角色。例如,'(^(foo|bar)$)'充当最后一个正则表达式:^(foo|bar)$,没有任何潜在的危险转义。

假设一个PHP应用程序(在本例中为Drupal)正在生成输入字段,那么似乎有一个变通方法是按照以下方式执行:

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

我想不出有哪种情况不起作用,因为/被用作表达式中的文字。

HTML5规范遵循ECMA262的法律模式规范:

如果指定,则属性的值必须与JavaScriptPattern产品相匹配。[cma62]

由于ECMA262中定义了BNF,因此完整的解析器(而不是使用PCRE)似乎是最安全的方法。

您也可以使用T-Regx并让它相应地选择分隔符:

<?php
pattern("^($pattern)$")->match($value);

它添加了模式中未使用的任何分隔符。