Fix to Replicate “Magic Quotes” and “Register Globals” in PHP 5.4+

It pains me to write this post in 2013, but after doing some client work recently, I’ve found that these issues still actually exist in the wild, so these “fixes” may potentially help people.

A little history… Back in the day, PHP had a feature called “Magic Quotes” (magic_quotes_gpc). When it was on, all ‘ (single-quote), ” (double quote), \ (backslash) and NULL characters in the $_POST, $_GET and $_COOKIE arrays would be escaped with a backslash automatically. Like many things in PHP, it was a bad idea. But it was often turned on by default, so people became dependent on it. Specifically, they would do things like this:

mysql_query("INSERT INTO records SET name = '{$_POST['name']}'");

That statement has a number of things wrong with it (using a deprecated MySQL API is among them), but the biggest issue is that it assumes $_POST['name'] has been properly escaped to prevent SQL injection. That assumption is (dangerously) based on PHP’s “Magic Quotes” being enabled. Unfortunately, there’s still lots of terrible legacy code like this out there. This type of thing fell out of practice 8+ years ago, but you’d be surprised how long sites will stick around, untouched.

“Magic Quotes” was depreciated in PHP 5.3.0 (2009) and was dropped completely in PHP 5.4.0 (2012). I recently had to move a client’s (very old) PHP site to a new server running PHP 5.4. The code depended on “Magic Quotes” being enabled. Since that was now impossible, lots of things broke. Refactoring the code was, unfortunately, not an option. Instead, I had to implement the quick hack below. As long as this is placed in a globally included file before any processing is done (e.g. – the database connection file), it’ll replicate the magic_quotes_gpc functionality and add slashes to the $_POST and $_GET arrays (you could also do this with $_COOKIE, if you’d like).

// This replicates magic_quotes_gpc in PHP 5.4+
foreach($_POST as $key => $val){
  $_POST[$key] = addslashes($val);
}
foreach($_GET as $key => $val){
  $_GET[$key] = addslashes($val);
}

Believe me, I’m not proud of this solution — or even the fact that I’m dealing with sites this old. But if you run into the same problem, you now have a possible fix.

While I’m at it, if you need to replicate register_globals (I hope you don’t), here’s a snippet for doing that. This will take the values in your $_POST and $_GET arrays and make them available as independent global variables (e.g. – $_POST['name'] will be accessible as $name).

// This replicates register_globals in PHP 5.4+
foreach (array_merge($_GET, $_POST) as $key => $val) {
  global $$key;
  $$key = addslashes($val);
}

Disclaimer: I’d strongly suggest refactoring your code over using any of these hacks. Only use them if you must.