在运行时使用在字符串中生成的字符串在PHP中使用preg_replace()时,可以使用preg_quote()来保护搜索字符串中的特殊正则表达式字符(例如'$'或'+' 。但是,在替换字符串中处理这个问题的正确方法是什么?拿这个代码,例如:避免处理替换字符串中的特殊preg字符
<?php
$haystack = '...a bit of sample text...';
$replacement = '\\HELLO WORLD$1.+-';
$replacement_quoted = preg_quote($replacement);
var_dump('--replacement', $replacement, '--replacement_quoted',
$replacement_quoted, '--haystack', $haystack);
$result1 = preg_replace("@(bit) (of) (sample)@is", "\${1}" . $replacement ."$3", $haystack);
$result2 = preg_replace("@(bit) (of) (sample)@is", "\${1}" . $replacement_quoted ."$3", $haystack);
$replacement_new1 = str_replace('$', '\$', $replacement);
$replacement_new2 = str_replace('\\', '\\\\', $replacement_new1);
$result3 = preg_replace("@(bit) (of) (sample)@is", "\${1}" . $replacement_new1 ."$3", $haystack);
$result4 = preg_replace("@(bit) (of) (sample)@is", "\${1}" . $replacement_new2 ."$3", $haystack);
var_dump('--result1 (not quoted)', $result1, '--result2 (quoted)', $result2,
'--result3 ($ escaped)', $result3, '--result4 (\ and $ escaped)', $result3);
?>
下面是输出:
string(13) "--replacement"
string(17) "\HELLO WORLD$1.+-"
string(20) "--replacement_quoted"
string(22) "\\HELLO WORLD\$1\.\+\-"
string(10) "--haystack"
string(26) "...a bit of sample text..."
string(22) "--result1 (not quoted)"
string(40) "...a bit\HELLO WORLDbit.+-sample text..."
string(18) "--result2 (quoted)"
string(42) "...a bit\HELLO WORLD$1\.\+\-sample text..."
string(21) "--result3 ($ escaped)"
string(39) "...a bit\HELLO WORLD$1.+-sample text..."
string(27) "--result4 (\ and $ escaped)"
string(39) "...a bit\HELLO WORLD$1.+-sample text..."
正如你所看到的,你不能赢得preg_quote()。如果您不调用它,只是传递未修改的字符串(result1),则无论相应的捕获组包含什么,看起来像捕获令牌(上面的$ 1)的任何内容都将被替换为 。如果你确实调用了它(result2),那么你对捕获组没有任何问题,但是任何其他特殊的PCRE字符(例如*)也会被转义,并且转义字符会在输出中生存。我也很感兴趣的是,两个版本都在输出中生成一个\。
只有通过手动引用字符,特别是$,才能使它起作用。这可以在result3和result4中看到。但是,继续使用\的奇怪现象,result3和\ result4会在输出中再次产生一个\。在替换字符串的开始处添加六个\字符只会在result1,result3和result4的最终输出中产生两个\,并且result2中会有三个字符。
所以,似乎大多数问题都通过手动转义$字符来处理。看起来\角色也需要逃脱,但我需要更多地思考那个角色,以确定什么是攻击。在任何情况下,这都非常难看 - 在令人讨厌的\ $ {1}语法和不得不手动转义某些字符之间,代码只是闻起来很烂并且容易出错。有什么我失踪?有没有一种干净的方式来做到这一点?
我提交了一个错误 - [(#52962)](http://bugs.php.net/bug.php?id=52962)。 – 2010-10-01 01:01:53