Edited at

【PHP】preg_match()関数を用いた正規表現のマッチングの挙動が7.2系から7.3系で変わってる(PCREのバージョン変更)


preg_match()関数でエラーがでた

何気なくローカルの開発環境でLaravel用Homesteadのバージョンをあげて、過去のプロジェクトのテスト(PHPUnit)を走らせてみた際、

いままで出てなかったエラーが発生。

preg_match(): Compilation failed: invalid range in character class at offset **

発生個所的にバリデーションのテストを書いてるところで、正規表現のルールでエラーがでてるっぽい。

なんでいきなり??ってことで調査開始


PHP7.2系(7.1系)とPHP7.3系の挙動

簡単な半角英数字とハイフンを通す正規表現の処理を書いてみました。

<?php

$str = 'RANDOMWORD-123';
var_dump(preg_match('/^[a-zA-Z0-9\s--]+$/', $str));

以下がPHP7.1系PHP7.3系の結果


FireShot Capture 013 - Online PHP editor - output for 42BcG - 3v4l.org.png

https://3v4l.org/42BcG


んーなんで??バージョン上げたからってそんなにクリティカルなエラーが出るようになるもんなの・・・?

って思いながらググるとStack Overflowでこたえっぽいの発見

php - preg_match(): Compilation failed: invalid range in character class at offset 20 - Stack Overflow


A character class range is defined by using - between two values in a character class ([] in regex). [0-9] means everything between 0 and 9, inclusive. In the regular expression in your code, you have several character class ranges, a-z, 0-9. There is also one class that you probably didn't mean to put there, namely _-\s.

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

^^^^

This is apprently not considered an invalid character range in some (most?) versions of PCRE (the regular expression library PHP uses), but it might have changed recently, and if the PCRE library was upgraded on the server, that might be the reason.


以下部分Google翻訳


PCRE(PHPが使用する正規表現ライブラリ)のバージョンですが、最近変更された可能性があります。PCREライブラリがサーバー上でアップグレードされた場合は、それが理由である可能性があります。


らしいです。

どうやらPHP7.3系からなので

https://www.php.net/ChangeLog-7.php#7.3.0


PCRE:

Implemented https://wiki.php.net/rfc/pcre2-migration.

Upgrade PCRE2 to 10.32.

Fixed bug #75355 (preg_quote() does not quote # control character).

Fixed bug #76512 (\w no longer includes unicode characters).

Fixed bug #76514 (Regression in preg_match makes it fail with PREG_JIT_STACKLIMIT_ERROR).

Fixed bug #76909 (preg_match difference between 7.3 and < 7.3).


このあたりの修正・更新対応が入ったからなんですかね・・・?


エラーが発生しないように正規表現の書き方を修正

とにかくStack Overflowで指摘されているようにハイフン(-)が原因みたいなので位置を変えてみます

<?php

$str = 'RANDOMWORD-123';
var_dump(preg_match('/^[a-zA-Z0-9\s--]+$/', $str)); // ハイフン(-)の位置を変えた

以下PHP7.1(7.1.25)PHP7.3(7.2.17)での実行結果


FireShot Capture 010 - Online PHP editor - output for RAoU5 - 3v4l.org.png

https://3v4l.org/hCfWq


エラーがでなくなりました


おわり


  • 原因がわりとわからなかった

  • 詳しい人詳細を教えてください。。。


参考URL