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

2022-08-30 08:54:48

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

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

经过几个月的工作,在我们的服务器上进行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");
     }
  }

答案 1

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

  • 内部库 API 已更改
  • “S”修饰符不起作用,模式是自动研究的。没有真正的影响。
  • “X”修饰符是 PCRE2 中的默认行为。当前的修补程序将行为恢复到 PCRE 中“X”的含义,但最好采用新行为并默认打开“X”。所以目前也没有影响。
  • 由于较新的Unicode引擎,发现了一些行为变化。它是PCRE2中的Unicode 10与PCRE中的Unicode 7。使用无效模式可以观察到某些行为更改。

根据 PHP 10.33 更新日志:

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

在 PHP 7.3 之前,如果您转义了字符类,或者将其放在“无法解释为指示范围的位置”,则可以在任何位置使用连字符。在 PHP 7.3 中,似乎被设置为 false。因此,从现在开始,为了将连字符放入字符类中,请始终仅在开头或结尾位置使用它PCRE2_EXTRA_BAD_ESCAPE_IS_LITERAL

另请参阅此参考

简而言之,

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

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

preg_match('/[\w-.]+/', ''); // this will not work in PHP7.3
preg_match('/[\w\-.]+/', ''); // the hyphen need to be escaped

从上面的示例中可以看出,这两条线之间存在一点但实质性的差异。


答案 2

字符类范围是通过使用 - 在字符类中的两个值之间定义的(在正则表达式中)。 表示介于 0 和 9 之间的所有内容(包括 0 和 9)。在代码的正则表达式中,您有几个字符类范围 、 。还有一个类,你可能不想放在那里,那就是。[][0-9]a-z0-9_-\s

"/^[a-z0-9]([0-9a-z_-\s])+$/i"
                   ^^^^ 

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

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


推荐