note 39713 deleted from function.preg-replace by crell
| From: | crell@php.net | Date: | Fri, 01 Jul 2022 19:47:47 +0000 |
| Subject: | note 39713 deleted from function.preg-replace by crell | ||
| References: | 1 | Groups: | php.notes |
| Request: | Send a blank email to php-notes+get-218857@lists.php.net to get a copy of this message | ||
Note Submitter: steven -a-t- acko dot net
----
People using the /e modifier with preg_replace should be aware of the following weird behaviour. It
is not a bug per se, but can cause bugs if you don't know it's there.
The example in the docs for /e suffers from this mistake in fact.
With /e, the replacement string is a PHP expression. So when you use a backreference in the
replacement expression, you need to put the backreference inside quotes, or otherwise it would be
interpreted as PHP code. Like the example from the manual for preg_replace:
preg_replace("/(<\/?)(\w+)([^>]*>)/e",
"'\\1'.strtoupper('\\2').'\\3'",
$html_body);
To make this easier, the data in a backreference with /e is run through addslashes() before being
inserted in your replacement expression. So if you have the string
He said: "You're here"
It would become:
He said: \"You\'re here\"
...and be inserted into the expression.
However, if you put this inside a set of single quotes, PHP will not strip away all the slashes
correctly! Try this:
print ' He said: \"You\'re here\" ';
Output: He said: \"You're here\"
This is because the sequence \" inside single quotes is not recognized as anything special, and
it is output literally.
Using double-quotes to surround the string/backreference will not help either, because inside
double-quotes, the sequence \' is not recognized and also output literally. And in fact, if you
have any dollar signs in your data, they would be interpreted as PHP variables. So double-quotes are
not an option.
The 'solution' is to manually fix it in your expression. It is easiest to use a separate
processing function, and do the replacing there (i.e. use
"my_processing_function('\\1')" or something similar as replacement expression,
and do the fixing in that function).
If you surrounded your backreference by single-quotes, the double-quotes are corrupt:
$text = str_replace('\"', '"', $text);
People using preg_replace with /e should at least be aware of this.
I'm not sure how it would be best fixed in preg_replace. Because double-quotes are a really bad
idea anyway (due to the variable expansion), I would suggest that preg_replace's auto-escaping
is modified to suit the placement of backreferences inside single-quotes (which seemed to be the
intention from the start, but was incorrectly applied).