パターン修飾子

現在使用可能な PCRE 修飾子の一覧を以下に示します。 括弧の中の名前は、これらの修飾子に関する PCRE 内部の名前です。 修飾子中での空白文字および改行は無視されます。他の文字はエラーになります。

i (PCRE_CASELESS)
この修飾子を設定すると、パターンの中の文字は 大文字にも小文字にもマッチします。
m (PCRE_MULTILINE)
デフォルトで、PCRE は、検索対象文字列を(実際には複数行からなる 場合でも)単一の行からなるとして処理します。 「行頭」メタ文字 (^) は、対象文字列の最初にしかマッチしません。 一方、「行末」メタ文字 ($) は、文字列の最後、または (D 修飾子が設定されていない場合) 最後にある改行記号の前のみにしかマッチしません。 この動作は Perl と同じです。 この修飾子を設定すると、「行頭」および「行末」メタ文字は 対象文字列において、文字列の最初と最後に加えて、 各改行の直前と直後にそれぞれマッチします。 この動作は、Perl の /m 修飾子と同じです。 対象文字列の中に "\n" 文字がない場合や、 またはパターンに ^ または $ がない場合は、 この修飾子を設定しても意味はありません。
s (PCRE_DOTALL)
この修飾子を設定すると、パターン中のドットメタ文字は 改行を含む全ての文字にマッチします。 これを設定しない場合は、改行にはマッチしません。 この修飾子は、Perl の /s 修飾子と同じです。 [^a] のような否定の文字クラスは、 この修飾子の設定によらず、常に改行文字にマッチします。
x (PCRE_EXTENDED)
この修飾子を設定すると、エスケープするか 文字クラスの内部を除き、 パターンの空白文字は完全に無視されます。 文字クラスの外にあって、かつエスケープされていない # と次の改行文字の間の文字も無視されます。 この動作は、Perl の /x 修飾子と同じであり、複雑なパターンの内部に コメントを記述することが可能となります。 しかし、この修飾子は、データ文字にのみ適用されることに注意 してください。空白文字をパターンの特殊文字の並びの中、 例えば条件付きサブパターン (?( の内部に置くことはできません。
e (PREG_REPLACE_EVAL)
警告

この機能は PHP 5.5.0 で 非推奨 となり、 PHP 7.0.0 で 削除 されました。

この非推奨の修飾子を設定すると、preg_replace() は、置換文字列において後方参照に関する通常の置換を行った後、 PHP コードとして評価し、検索文字列を置換するためにその結果を 使用します。 置換された後方参照においては、 単引用符や二重引用符、バックスラッシュ (\)および NULL 文字は バックスラッシュでエスケープされます。
警告

マッチした後方参照ごとに addslashes() が実行されてから、 置換を行います。つまり、クォートした文字列として後方参照を利用した場合、 エスケープした文字がリテラルに変換されます。 しかし、エスケープされた文字については、通常は変換されず、 スラッシュが残ったままになります。 そのため、この修飾子はとても複雑なものになってしまいます。

警告

replacement が PHP のコードとして妥当な文字列であることを確認しましょう。 そうでない場合は、 preg_replace() を含む行で PHP のパースエラーが発生します。

警告

この修飾子を使うことはおすすめしません。 セキュリティに関する脆弱性を作ってしまいがちだからです。

<?php
$html 
$_POST['html'];

// 見出しを大文字にします
$html preg_replace(
    
'(<h([1-6])>(.*?)</h\1>)e',
    
'"<h$1>" . strtoupper("$2") . "</h$1>"',
    
$html
);

このサンプルを攻撃するのは簡単で、 <h1>{${eval($_GET[php_code])}}</h1> のような文字列を渡すだけで攻略できます。 攻撃者は任意の PHP コードを実行でき、 サーバーに対するほぼ完全なアクセス権を与えることになってしまいます。

この種のリモートコード実行脆弱性を回避するには、 preg_replace_callback() 関数を使うようにしなければなりません。

<?php
$html 
$_POST['html'];

// 見出しを大文字にします
$html preg_replace_callback(
    
'(<h([1-6])>(.*?)</h\1>)',
    function (
$m) {
        return 
"<h$m[1]>" strtoupper($m[2]) . "</h$m[1]>";
    },
    
$html
);

注意:

この修飾子を使用するのは、preg_replace()のみです。 他の PCRE 関数では無視されます。

A (PCRE_ANCHORED)
この修飾子を設定すると、パターンは強制的に固定 (anchored) となります。 つまり、検索対象文字列の先頭でのみマッチするように制限されます。 パターン自体の中に適当な指定を行うことでも同様の効果を得ることが可能です。 Perl ではパターン中に指定する方法しか使用できません。
D (PCRE_DOLLAR_ENDONLY)
この修飾子を設定すると、パターン内のドルメタ文字は、検索対象文字列の 終わりにのみマッチします。この修飾子を設定しない場合、ドル記号は、 検索対象文字列の最後の文字が改行文字であれば、その直前にもマッチします。 この修飾子は、m を設定している場合に無視されます。 Perl には、この修飾子に等価なものはありません。
S
あるパターンを複数回使用する場合は、マッチングにかかる時間を 高速化することを目的として、パターンの分析に幾分か時間をかけても 良いでしょう。この修飾子を設定すると、追加のパターン分析が 行われます。現在、パターン分析は、最初の文字が単一ではなく、 かつ固定でないパターンに対してのみ有用です。
U (PCRE_UNGREEDY)
この修飾子を設定すると、量指定子の「貪欲さ」が反転します。 つまり、量指定子は、デフォルトで貪欲でなく、 疑問符を後ろに付けてはじめて貪欲になるようになります。 この修飾子は Perl 互換では有りません。 同様の設定は、(?U) 修飾子を パターン内で設定 するか、(.*? のように)量指定子の後に疑問符を 付けるかすることで行うこともできます。

注意:

通常は、非貪欲モードでは pcre.backtrack_limit 文字を超えるマッチができません。

X (PCRE_EXTRA)
この修正子は、Perl 非互換な PCRE の機能を有効にします。 パターン内で後ろに文字が続くバックスラッシュで特別な意味がないものは、 将来的な拡張の際の互換性の維持のため、エラーになります。 デフォルトでは、Perl のように文字が後ろに続くバックスラッシュ で特に意味がないものは、リテラルとして処理されます。 この修飾子により制御される機能は、現在の所、これだけです。
J (PCRE_INFO_JCHANGED)
(?J) 内部オプションは、ローカルのオプション PCRE_DUPNAMES の設定を変更します。 サブパターンで重複した名前を使用できるようになります。
u (PCRE_UTF8)
この修正子は、Perl 非互換な PCRE の機能を有効にします。パターンと対象文字列は、 UTF-8 として処理されます。 無効な対象文字列を preg_* 関数に渡しても、何もマッチしません。 無効なパターンを渡すと、E_WARNING レベルのエラーが発生します。 5オクテットおよび6オクテットの UTF-8 シーケンスは、PHP 5.3.4 以降 (PCRE 7.3 2007-08-28 以降) では無効とみなされます。 以前のバージョンでは、これらも UTF-8 として有効だとみなされていました。

add a note add a note

User Contributed Notes 8 notes

up
28
hfuecks at nospam dot org
12 years ago
Regarding the validity of a UTF-8 string when using the /u pattern modifier, some things to be aware of;

1. If the pattern itself contains an invalid UTF-8 character, you get an error (as mentioned in the docs above - "UTF-8 validity of the pattern is checked since PHP 4.3.5"

2. When the subject string contains invalid UTF-8 sequences / codepoints, it basically result in a "quiet death" for the preg_* functions, where nothing is matched but without indication that the string is invalid UTF-8

3. PCRE regards five and six octet UTF-8 character sequences as valid (both in patterns and the subject string) but these are not supported in Unicode ( see section 5.9 "Character Encoding" of the "Secure Programming for Linux and Unix HOWTO" - can be found at http://www.tldp.org/ and other places )

4. For an example algorithm in PHP which tests the validity of a UTF-8 string (and discards five / six octet sequences) head to: http://hsivonen.iki.fi/php-utf8/

The following script should give you an idea of what works and what doesn't;

<?php
$examples
= array(
   
'Valid ASCII' => "a",
   
'Valid 2 Octet Sequence' => "\xc3\xb1",
   
'Invalid 2 Octet Sequence' => "\xc3\x28",
   
'Invalid Sequence Identifier' => "\xa0\xa1",
   
'Valid 3 Octet Sequence' => "\xe2\x82\xa1",
   
'Invalid 3 Octet Sequence (in 2nd Octet)' => "\xe2\x28\xa1",
   
'Invalid 3 Octet Sequence (in 3rd Octet)' => "\xe2\x82\x28",

   
'Valid 4 Octet Sequence' => "\xf0\x90\x8c\xbc",
   
'Invalid 4 Octet Sequence (in 2nd Octet)' => "\xf0\x28\x8c\xbc",
   
'Invalid 4 Octet Sequence (in 3rd Octet)' => "\xf0\x90\x28\xbc",
   
'Invalid 4 Octet Sequence (in 4th Octet)' => "\xf0\x28\x8c\x28",
   
'Valid 5 Octet Sequence (but not Unicode!)' => "\xf8\xa1\xa1\xa1\xa1",
   
'Valid 6 Octet Sequence (but not Unicode!)' => "\xfc\xa1\xa1\xa1\xa1\xa1",
);

echo
"++Invalid UTF-8 in pattern\n";
foreach (
$examples as $name => $str ) {
    echo
"$name\n";
   
preg_match("/".$str."/u",'Testing');
}

echo
"++ preg_match() examples\n";
foreach (
$examples as $name => $str ) {
   
   
preg_match("/\xf8\xa1\xa1\xa1\xa1/u", $str, $ar);
    echo
"$name: ";

    if (
count($ar) == 0 ) {
        echo
"Matched nothing!\n";
    } else {
        echo
"Matched {$ar[0]}\n";
    }
   
}

echo
"++ preg_match_all() examples\n";
foreach (
$examples as $name => $str ) {
   
preg_match_all('/./u', $str, $ar);
    echo
"$name: ";
   
   
$num_utf8_chars = count($ar[0]);
    if (
$num_utf8_chars == 0 ) {
        echo
"Matched nothing!\n";
    } else {
        echo
"Matched $num_utf8_chars character\n";
    }
   
}
?>
up
11
Daniel Klein
5 years ago
If the _subject_ contains utf-8 sequences the 'u' modifier should be set, otherwise a pattern such as /./ could match a utf-8 sequence as two to four individual ASCII characters. It is not a requirement, however, as you may have a need to break apart utf-8 sequences into single bytes. Most of the time, though, if you're working with utf-8 strings you should use the 'u' modifier.

If the subject doesn't contain any utf-8 sequences (i.e. characters in the range 0x00-0x7F only) but the pattern does, as far as I can work out, setting the 'u' modifier would have no effect on the result.
up
11
phpman at crustynet dot org dot uk
6 years ago
The description of the "u" flag is a bit misleading. It suggests that it is only required if the pattern contains UTF-8 characters, when in fact it is required if either the pattern or the subject contain UTF-8. Without it, I was having problems with preg_match_all returning invalid multibyte characters when given a UTF-8 subject string.

It's fairly clear if you read the documentation for libpcre:

       In  order  process  UTF-8 strings, you must build PCRE to include UTF-8
       support in the code, and, in addition,  you  must  call  pcre_compile()
       with  the  PCRE_UTF8  option  flag,  or the pattern must start with the
       sequence (*UTF8). When either of these is the case,  both  the  pattern
       and  any  subject  strings  that  are matched against it are treated as
       UTF-8 strings instead of strings of 1-byte characters.

[from http://www.pcre.org/pcre.txt]
up
7
michal dot kocarek at brainbox dot cz
8 years ago
In case you're wondering, what is the meaning of "S" modifier, this paragraph might be useful:

When "S" modifier is set, PHP calls the pcre_study() function from the PCRE API before executing the regexp. Result from the function is passed directly to pcre_exec().

For more information about pcre_study() and "Studying the pattern" check the PCRE manual on http://www.pcre.org/pcre.txt

PS: Note that function names "pcre_study" and "pcre_exec" used here refer to PCRE library functions written in C language and not to any PHP functions.
up
6
varrah NO_GARBAGE_OR_SPAM AT mail DOT ru
12 years ago
Spent a few days, trying to understand how to create a pattern for Unicode chars, using the hex codes. Finally made it, after reading several manuals, that weren't giving any practical PHP-valid examples. So here's one of them:

For example we would like to search for Japanese-standard circled numbers 1-9 (Unicode codes are 0x2460-0x2468) in order to make it through the hex-codes the following call should be used:
preg_match('/[\x{2460}-\x{2468}]/u', $str);

Here $str is a haystack string
\x{hex} - is an UTF-8 hex char-code
and /u is used for identifying the class as a class of Unicode chars.

Hope, it'll be useful.
up
4
ebarnard at marathonmultimedia dot com
10 years ago
When adding comments with the /x modifier, don't use the pattern delimiter in the comments. It may not be ignored in the comments area. Example:

<?php
$target
= 'some text';
if(
preg_match('/
                e # Comments here
               /x'
,$target)) {
    print
"Target 1 hit.\n";
}
if(
preg_match('/
                e # /Comments here with slash
               /x'
,$target)) {
    print
"Target 1 hit.\n";
}
?>

prints "Target 1 hit." but then generates a PHP warning message for the second preg_match():

Warning:  preg_match() [function.preg-match]: Unknown modifier 'C' in /ebarnard/x-modifier.php on line 11
up
1
damian dot driscoll at gmail dot com
2 months ago
The PCRE_INFO_JCHANGED modifier works in version 5.6.31 but not in 5.6.16, which generates an 'unknown modifier J' warning.
up
0
arash dot dalir at gmail dot com
3 months ago
the PCRE_INFO_JCHANGED modifier is apparently not accepted as a global option (after the closing delimiter) in PHP versions <= 5.4 (not checked in PHP 5.5) but allowed in PHP 5.6 (also not checked in PHP 7.X)

The following pattern doesn't work in PHP 5.4, but it works in PHP 5.6:

<?php
//test.php
preg_match_all('/(?<dup_name>\d{1,4})\-(?<dup_name>\d{1,2})/J', '1234-23', $matches);
var_dump($matches);

/*
output in PHP 5.4:
Warning: preg_match_all(): Unknown modifier 'J' in test.php on line 3
NULL
--------------
output PHP 5.6:
array(4) {
    [0]=> array(1)  { [0]=> string(7) "1234-23" }
    ["dup_name"]=> array(1) { [0]=> string(2) "23" }
    [1]=> array(1) { [0]=> string(4) "1234" }
    [2]=> array(1) { [0]=> string(2) "23" }
}
*/
?>

in order to resolve this issue in PHP 5.4, one can use the (?J) pattern modifier, which indicates the pattern (from that point forward) allows duplicate names for subpatterns.

code which works in PHP 5.4:
<?php

preg_match_all
('/(?J)(?<dup_name>\d{1,4})\-(?<dup_name>\d{1,2})/', '1234-23', $matches);
var_dump($matches);

/*
output in PHP 5.4:
array(4) {
    [0]=> array(1) { [0]=> string(7) "1234-23" }
    ["dup_name"]=> array(1) { [0]=> string(2) "23" }
    [1]=> array(1) { [0]=> string(4) "1234" }
    [2]=> array(1) { [0]=> string(2) "23" }
}
--------------
output in PHP 5.6 (the same as with /J):
array(4) {
    [0]=> array(1)  { [0]=> string(7) "1234-23" }
    ["dup_name"]=> array(1) { [0]=> string(2) "23" }
    [1]=> array(1) { [0]=> string(4) "1234" }
    [2]=> array(1) { [0]=> string(2) "23" }
}
*/
?>
To Top