Today we are going to look at something incredibly dangerous which has been deprecated. Note that “deprecated” means it still works. It’s only been a little more than a year since deprecation was proposed, which in PHP years is, like, a week.

For comparison, the oldest checkin the git history shows that this functionality was present in the year 1999 and goodness only knows how long before that. I’m not sure how old PHP actually is. The 90s is the Beforetime.

What are we talking about? We’re talking about PREG_REPLACE_EVAL, which is for evaluating freaking strings at runtime as PHP code to use for messing with data in regular expressions which is a totally necessary and reasonable thing to do and can’t possibly go wrong.

The red warning box and no less than three yellow caution boxes make this possibly the best-documented regret on the entire manual.

Let’s take it blow-by-blow.

“If this deprecated modifier is set, preg_replace() does normal substitution of backreferences in the replacement string, evaluates it as PHP code, and uses the result for replacing the search string. Single quotes, double quotes, backslashes () and NULL chars will be escaped by backslashes in substituted backreferences.”

Gee whittaker, I love it when I get to dynamically alter my code arbitrarily at runtime! From a string! Because strings can come from anywhere and contain anything! It’s so FLEXIBLE! It saves me from having to architect anything!

Caution “The addslashes() function is run on each matched backreference before the substitution takes place. As such, when the backreference is used as a quoted string, escaped characters will be converted to literals. However, characters which are escaped, which would normally not be converted, will retain their slashes. This makes use of this modifier very complicated.”

Sufficiently complicated that I have no idea what was just said. No example? Which escaped characters will become literal and which will retain slashes?

Caution “Make sure that replacement constitutes a valid PHP code string, otherwise PHP will complain about a parse error at the line containing preg_replace().”

If that doesn’t warn you off, what will? Don’t forget, you can pass dynamically generated strings to this. The power is in your hands to cause nondeterministic parse errors with a freakin’ regex. Note that you CANNOT do this with eval()! Eval returns false if there is a parse error and execution continues. It even says “It is not possible to catch a parse error in eval()”. What the heeeeeeeeeee-ey.

It then goes on to point out the blatantly obvious dangerous security hole the size of the moon if you use user-controlled data in this string, and meekly points out the correct way to do this that should have been the only way in the first place. I’m sure there are Exciting Historical Reasons it wasn’t possible to implement it back in the Beforetime.

After some snooping I tracked down the RFC where deprecating this was formally proposed and accepted. Remember that note about the weird escaping? Looks like it might be responsible for some of those \ ‘literal slashes around quotes\ ’ you occasionally see on PHP forum posts. (Tumblr is good enough at avoiding them that I had to insert that space.)

It was deprecated and now emits a little notification to that effect. There is no scheduled date for its removal at this time.

I’m not even going to bother speculating why anyone thought this was a good idea in the first place. The reason is PHP. But why did four people vote against deprecating it?!