1. TOPTOP
  2. Webサービス
  3. PHP

PHPの正規表現でパターンマッチを使ったときに気がついたこと 「先頭と末尾の一致」と「uフラグ」について

|

ecoteki-image

PHPでWebアプリケーションの脆弱性やセキュリティの学習したいので、PHP逆引きレシピ 第2版(新しいタブで開く) という本のP.751を読んでおります。そのときに気がついたことが2点ありましたので、記録を残しておきます。ちなみに本で示されている、お手本のPHPコードは以下の通りです。

if (preg_match('/\A[a-zA-Z0-9]{1,10}\z/u', $input) == 0) {
 die('1~10文字までの英数字を入力してください');
}

ですが、説明しやすいよう本のコードにアレンジを加えてGitHub(新しいタブで開く)にコードをアップしました。

「先頭と末尾の一致」の一致について

まずexample1のコードをご覧ください。こちら本で示されたケースと同じです。パターンマッチさせる文字列を固定させるために、行頭に”\A”を、行末に”\z”を使っています。一方、example2のコードは同じことをするために行頭に”^”を、行末に”$”を使用しています。

両者をそれぞれ実行すると、”ご入力ありがとうございます” という文字列が返ってきます。そのためどちらを使っても同じように見えますが、Webアプリケーションのセキュリティ上は、example1の方が望ましいと考えられます。

理由は”\A”と”\z”を使用した場合、対象文字列が複数行であるかどうかに関わらず、パターンマッチさせることが可能になるからです。一方、”^”と”$”を使用した場合、対象文字列に改行コードが含まれたとき、対象文字列から外れてしまい、パターンマッチできない可能性があります。

uフラグ(パターン修飾子)について

お手本のコードを見るとパターンマッチをさせるための”//(スラッシュ)”の末尾に”u”という文字があります。これはパターン修飾子(フラグ)のことを指します。

example3とexample4のコードをご覧ください。両者を実行すると結果は同じです。どちらも”1から10文字までの英数字を入力してください”と返ってきます。見た目の違いは最後のスラッシュの次に”u”の文字列が付いているかどうかだけです。

ただしこの”u”の文字についてPHPの公式ドキュメントでパターン修飾子のページ(新しいタブで開く)を読むと、次のような記述があります。

パターンと対象文字列は、 UTF-8 として処理されます。 無効な対象文字列を preg_* 関数に渡しても、何もマッチしません。 無効なパターンを渡すと、E_WARNING レベルのエラーが発生します。

例えば、対象文字列の中にShift_JIS(新しいタブで開く)などのUTF-8以外の文字コードの文字が含まれると、何もマッチせず”E_WARNING”レベルのエラーが発生するというところでしょう。

要するに本で示されているパターンマッチは、「特殊なコード(改行コードやUTF-8以外のこど)も漏らさずマッチさせるぞ!」という意図があることがよく分かります。