在運行時使用在字符串中生成的字符串在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