Coding Horrors: PHP - Magic Quotes

September 28, 2010 by PHP   Coding Horrors  

Ah, magic quotes, one of those terrible not thought through PHP anti-features, not to mention overly blogged about (but hey, hopefully this post can provide some additional insights on this evil, this abomination to the Lord) - but at least its deprecated as of PHP 5.3 and will apparently be removed with the fabled coming of PHP 6 (and there will be no pain and suffering no illness...)

For those of you who came in late - Magic Quotes (like Anakin Skywalker), was initially intended for good and on a lot of websites it still provides some protection (unknowingly to some) against the mediocre "SQL Injection" issue - basically it escapes all values within the GET/POST & COOKIE globals, which automatically makes these strings safer (not completely safe) to use.

But what is so evil about all of this?

  • Its unnecessary to escape everything, which means an unnecessary performance sacrifice - its not like everything will always be inserted into/selected from a database.
  • It also becomes rather annoying since we won't even (on the values that actually require escaping) always do a direct insert into the database either, chances are that we will display or do some validation on values before inserting it, which means we need to unescape values an re-escape values - defeating the whole purpose.
The biggest issue, which makes it truly evil (in my opinion), is the fact that it potentially screws with portability of scripts, since we can turn the feature on/off.

Let me explain this issue using three scenarios.

Scenario 1:

You're in the process of "building" or rather (in your case) downloading pieces of code/scripts that will eventually be your website/ web application.

You download the source code for forum A (which requires magic quotes), and the sources for blog B (which doesn't use magic quotes).

Disabling magic quotes will leave forum A vulnerable, enabling magic quotes will potentially screw the input/output to blog B.

In this scenario you might at least have the choice to simply download other scripts that don't require magic quotes, or vice-versa.

Scenario 2:

You start at a new company and inherit the most horrible source code ever conceived and constructed by mankind.

The developer(s) that developed (more like mangled) the code either firmly believed in magic quotes or didn't know any better.

Forcing you to either continue the downwards spiral (dev using the same style), or do things following certain/better standards - forcing you to code around the "cest pool" they like to call code.

In this scenario you are forced to work with what you've got.

Scenario 3:

You become senior developer at a web dev company with 1000's of custom built sites, 90% of these sites require magic quotes - you warn the managers and tell them that with the coming of PHP 6 all scripts that use magic quotes will go to hell.

Unfortunately they pretty much ignore you and the next day some clever system administrator decides to disable magic quotes on all servers - while he/she neglected to make any backups for the last 10 months.

All of a sudden the phones start to ring wildly and out of control, customers demanding answers to why you lost all their data.

In this scenario you're screwed...

How do we solve these scenarios?

All over the web you can find tons of "solutions", like the following dangerous snippet (and invert versions of the script):
function stripslashes_deep(&$value) 
{ 
    $value = is_array($value) 
		? array_map('stripslashes_deep', $value) 
		: stripslashes($value); 

    return $value; 
}

if((function_exists("get_magic_quotes_gpc") && get_magic_quotes_gpc()) || 
	(ini_get('magic_quotes_sybase') && (strtolower(ini_get('magic_quotes_sybase'))!="off")) )
{ 
    stripslashes_deep($_GET); 
    stripslashes_deep($_POST); 
    stripslashes_deep($_COOKIE); 
}

The preceding snippet basically unescapes values, returning values in a "magic quotes off" manner - I believe(hope) that the true reason the author wrote this script is for scenarios where you can't for some dodgy reason disable magic quotes.

The danger of scripts like this is when you implement them without considering the codebase you're using - like seen in scenario 1 - 3.

So how (in my opinion) do we actually solve this issue?

When confronted with legacy code, over which you have no control or have no time to fix millions of lines of code, the safest bet is to unfortunately keep magic quotes enabled, data integrity is paramount.

Always write your code to function with & without magic quotes, don't ever rely on magic quotes but cater for its unfortunate existence, for example:
define('MQ_ENABLED', ((function_exists("get_magic_quotes_gpc") && get_magic_quotes_gpc()) || (ini_get('magic_quotes_sybase') && (strtolower(ini_get('magic_quotes_sybase'))!="off"))));

function value($name)
{
	if (isset($_POST[$name]))
	{
		return (MQ_ENABLED) ? stripslashes($_POST[$name]) : $_POST[$name];
	}
	return null;
}

Thinking back about the brainwave behind this anti-feature, why stop at Magic Quotes? What about Magic numbers? (Prevent our integers from being turned into malicious queries) or all kinds of "Magic" XSS attack protection - why not just for the hell of it html encode everything while we think we're being helpful?

The horror!


Leave a Comment


September 29, 2010 by Christoff Truter

Rasmus Lerdorf on Magic Quotes: "It escapes me"