php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #10666 preg_replace 'e' modifier
Submitted: 2001-05-04 11:27 UTC Modified: 2001-08-03 12:01 UTC
From: smoonen at andstuff dot org Assigned:
Status: Closed Package: PCRE related
PHP Version: 4.0.5 OS: Linux
Private report: No CVE-ID: None
View Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
If you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: smoonen at andstuff dot org
New email:
PHP Version: OS:

 

 [2001-05-04 11:27 UTC] smoonen at andstuff dot org
Formerly, preg_replace's "e" modifier inserted extraneous backslashes in backreferences of "\\1" or '\\1' form.

Ostensibly, the $1 backreference form was added to fix this.  However, the following code fails:

  function f($x) { return 'yo'; }
  $s = "xyzabc def123";
  $s = preg_replace('/(abc def)/e', 'f($1)', $s, -1);

It seems to be trying to evaluate $1 as code, rather than as a variable containing the contents "abc def".

This is borne out by the fact that the following succeeds:

  $s = preg_replace('/(abc def)/e', 'f("$1")', $s, -1);

But "$1" and '$1' are no better than "\\1" and '\\1', since it still inserts extraneous backslashes before single quotes or double quotes (respectively)!!!

I was sincerely hoping that PHP 4.04 and 4.05 would fix this oversight, since my web application depends on it.  I'm keeping my fingers crossed that it's just me doing something wrong, though I doubt it...

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2001-05-04 13:02 UTC] andrei@php.net
$n notation was introduced to be similar to Perl. It is exactly equivalent to \\n.

You can't simply use f($1) in the evaluation string because $1 is replaced with the matched contents and after replacement it becomes, in your example, f(abc def), which is not valid PHP code. So you have to use f("$1") or f('$1').

The fact that it backslash-escapes single and double quotes in matches before substituting $1 is a feature, not a bug, otherwise you'd have a really hard time figuring out which quotes go where when using evaluation strings.
 [2001-05-04 13:55 UTC] smoonen at andstuff dot org
Okay.  Then I have a problem with how backslash escaping is inconsistently applied when using \\1 and $1.

Specifically, consider the following:

  function f($x) { print $x; }
  $s = "a' \\ \"b";
  $s = preg_replace('/a(.*)b/e', 'f("$1")', $s, -1);

The single quote is escaped; I'd rather it weren't but that's okay.  But the backslash itself isn't escaped!  This prevents me from running stripslashes() on the match, since I can't guarantee that every backslash has been properly escaped.

Worse, the following will actually fail:

  function f($x) { print $x; }
  $s = "a' \" \\b";
  $s = preg_replace('/a(.*)b/e', 'f("$1")', $s, -1);

Since the final backslash hasn't been escaped, it actually slurps up the second double-quote in 'f("$1")'!

I'd like to see either of the following:

  1. $1 treated as a "real" variable, rather than a string
     substitution.  This is convenient, since it saves me
     having to call stripslashes().

  2. Backslash escapes consistently applied in backrefs.
     Specifically, escape existing backslashes in the match.
     Presently, I can't perform a stripslashes() -- and in
     some cases, as indicated above, it fails altogether!

 [2001-05-04 14:36 UTC] smoonen at andstuff dot org
Also, as a merely informational aside, PHP's use of $1 is in this instance actually incompatible with Perl.  Perl, in a s///e expression, treats $n as a variable rather than expanding it in-place.

Hence my preference. :-)

 [2001-08-03 12:01 UTC] smoonen at andstuff dot org
Strangely, while the bug referenced in my update at [2001-05-04 13:55:39] was very repeatable across several PHP installations, I can no longer duplicate it.

Am closing the bug, though in my dreams I still wish for $n pseudovariables. ;-)
 [2004-08-23 16:49 UTC] info at webprog dot de
3 Years ago its allready a feature? :-)
I build something like this:

$r = "<span lang=\"en\" xml:lang=\"en\">".$words."</span>";

$this->template = preg_replace ("/((<[^>]*)|(^| |>)($words)([^a-zA-Z]|$))/e", '"\\2"=="\\1"? "\\1":"\\3<span lang=\"en\" xml:lang=\"en\">\\4</span>\\5"', $this->template);

...and it works fine with Perl and bad with PHP, because it sets in front of every single quote a backslash.
 [2011-07-21 11:07 UTC] raincious at gmail dot com
NO, this just IS A BUG. Please fix it or add a switch to shutdown the bug, i don't 
need it done any other thing for me without replace then call the function.

I know someone want to be perfect, but it's overplayed. If you want to do 
everything for user, why don't just pay time for create a function php, named 
give_me_my_wanted_website();?
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sun Dec 22 16:01:31 2024 UTC