preg_match():编译失败:偏移量为20的字符类中的无效范围

use*_*888 27 php regex preg-match

提前感谢您抽出时间帮助解决这个问题.

preg_match():编译失败:第278行偏移20 session.php的字符类中的无效范围

我不确定为什么这个停止工作几个月后工作可能是代码中的升级..

这是代码

    else{
     /* Spruce up username, check length */
     $subuser = stripslashes($subuser);
     if(strlen($subuser) < $config['min_user_chars']){
        $form->setError($field, "* Username below ".$config['min_user_chars']."characters");
     }
     else if(strlen($subuser) > $config['max_user_chars']){
        $form->setError($field, "* Username above ".$config['max_user_chars']."characters");
     }


     /* Check if username is not alphanumeric */
    /* PREG_MATCH CODE */

     else if(!preg_match("/^[a-z0-9]([0-9a-z_-\s])+$/i", $subuser)){        
        $form->setError($field, "* Username not alphanumeric");
     }


    /* PREG_MATCH CODE */


     /* Check if username is reserved */
     else if(strcasecmp($subuser, GUEST_NAME) == 0){
        $form->setError($field, "* Username reserved word");
     }
     /* Check if username is already in use */
     else if($database->usernameTaken($subuser)){
        $form->setError($field, "* Username already in use");
     }
     /* Check if username is banned */
     else if($database->usernameBanned($subuser)){
        $form->setError($field, "* Username banned");
     }
  }
Run Code Online (Sandbox Code Playgroud)

Mat*_*ndh 26

字符类范围通过使用 - 在字符类中的两个值([]在正则表达式中)来定义.[0-9]表示0到9之间的所有内容.在代码中的正则表达式中,您有几个字符类范围a-z,0-9.还有一类你可能并不打算放在那里,即_-\s.

"/^[a-z0-9]([0-9a-z_-\s])+$/i"
                   ^^^^ 
Run Code Online (Sandbox Code Playgroud)

在某些(大多数?)版本的PCRE(PHP使用的正则表达式库)中,这显然不被视为无效字符范围,但最近可能已更改,如果PCRE库在服务器上升级,则可能是原因.

Debuggex是一个很好的工具,可以帮助调试错误(好吧,PHP的错误消息告诉你错误所在的行字符,所以..)像这样(我不隶属,只是一个粉丝).

  • ...或者PHP本身已升级.根据RegexBuddy的说法,PHP 5.5要求将连字符转义或移动到列表的末尾,如果您希望它与文字连字符匹配.在那之前,显然,它只是假设你的意思是因为`_-\s`作为一个范围毫无意义. (4认同)
  • 在这里找到了同样的问题...在生产服务器中,没有使用最新的PHP更新代码一如既往地工作,在测试服务器中我得到了错误.在我的情况下,我需要保留空的空间[\ s]的参考,所以我逃脱了爆炸[\ - \s]并解决问题,并按预期工作.只是一个想法. (3认同)

Mor*_*jad 18

您的错误取决于您的正则表达式解释器。

您可以转义连字符以清楚了解其用法。表示使用\-代替-

您的最终代码:

/^[a-z0-9]([0-9a-z_\-\s])+$/i
Run Code Online (Sandbox Code Playgroud)


Wik*_*żew 11

这个问题确实很老,但是有一些与PHP 7.3相关的新开发以及较新的版本需要涵盖。PHP PCRE引擎迁移到PCRE2,PHP 7.3中使用的PCRElibrary版本为10.32,这是向后不兼容更改的来源:

  • 内部库API已更改
  • 'S'修饰符无效,模式会自动研究。没有实际影响。
  • “ X”修饰符是PCRE2中的默认行为。当前补丁将行为恢复为PCRE中的“ X”含义,但最好采用新行为,并默认情况下启用“ X”。所以目前也没有影响。
  • 由于发现了更新的Unicode引擎,导致某些行为发生了变化。PCRE2中为Unicode 10,而PCRE中为Unicode 7。某些行为更改可以通过无效的模式看到。

累积 到PHP 10.33更新日志:

  1. 使用PCRE2_EXTRA_BAD_ESCAPE_IS_LITERALset时,将转义序列(例如\s 在字符类中有效但不作为范围结尾的序列)视为文字。一个例子是[_-\s](但不是[\s-_]因为这在范围开始时给出了错误)。现在,独立于给出了“无效范围”错误PCRE2_EXTRA_BAD_ESCAPE_IS_LITERAL

在PHP 7.3之前,您可以在字符类中的任何位置使用连字符,只要将其转义即可,或者将其放在“不能解释为指示范围的位置”。在PHP 7.3中,似乎已将其PCRE2_EXTRA_BAD_ESCAPE_IS_LITERAL设置为false。因此,从现在开始,为了将连字符放入字符类中,请始终仅在开始或结束位置使用它

另请参阅此参考资料

简而言之,

PCRE2在模式验证方面更加严格,因此升级后,您现有的某些模式将无法再编译。

这是php.net中使用的简单代码段

preg_match('/ [\ w-。] + /',''); //这在PHP7.3中不起作用
preg_match('/ [\ w \-。] + /',''); //连字符需要转义

从上面的示例中可以看到,两行之间有一点点但实质性的区别。


Tar*_*dra 7

也许这个答案可以拯救那些创建阿拉伯语/波斯语鼻涕虫的人:

\n

对于 php 版本是7.3使用\\-而不是-

\n
\n

[^a-z0-9_\\s-

\n
\n

\n
\n

“/[\\s-_]+/”

\n
\n

因此,对于 php 7.3 的阿拉伯语 make_slug 函数:

\n
function make_slug($string, $separator = '-')\n{\n    $string = trim($string);\n    $string = mb_strtolower($string, 'UTF-8');\n\n    // Make alphanumeric (removes all other characters)\n    // this makes the string safe especially when used as a part of a URL\n    // this keeps latin characters and Persian characters as well\n    $string = preg_replace("/[^a-z0-9_\\s\\-\xd8\xa1\xd8\xa7\xd8\xa2\xd8\xa4\xd8\xa6\xd8\xa8\xd9\xbe\xd8\xaa\xd8\xab\xd8\xac\xda\x86\xd8\xad\xd8\xae\xd8\xaf\xd8\xb0\xd8\xb1\xd8\xb2\xda\x98\xd8\xb3\xd8\xb4\xd8\xb5\xd8\xb6\xd8\xb7\xd8\xb8\xd8\xb9\xd8\xba\xd9\x81\xd9\x82\xd9\x83\xda\xa9\xda\xaf\xd9\x84\xd9\x85\xd9\x86\xd9\x88\xd9\x87\xdb\x8c]/u", '', $string);\n\n    // Remove multiple dashes or whitespaces or underscores\n    $string = preg_replace("/[\\s\\-_]+/", ' ', $string);\n\n    // Convert whitespaces and underscore to the given separator\n    $string = preg_replace("/[\\s_]/", $separator, $string);\n\n    return $string;\n}\n
Run Code Online (Sandbox Code Playgroud)\n