How to turn off magic quotes on shared hosting?

Viewed 129387

I want to turn off PHP's magic quotes. I don't have access to php.ini.

When I tried to add php_flag magic_quotes_gpc off to my .htaccess file, I get a 500 internal server error. This is what my .htaccess file looks like:

AddType x-mapp-php5 .php
php_flag magic_quotes_gpc off

Then I tried to use ini_set('magic_quotes_gpc', 'O'), but that had no effect.

How do I turn magic quotes off?

13 Answers

As per the manual you can often install a custom php.ini on shared hosting, where mod_php isn't used and the php_value directive thus leads to an error. For suexec/FastCGI setups it is quite common to have a per-webspace php.ini in any case.

--

I don't think O (uppercase letter o) is a valid value to set an ini flag. You need to use a true/false, 1/0, or "on"/"off" value.

ini_set( 'magic_quotes_gpc', 0 );   // doesn't work

EDIT

After checking the list of ini settings, I see that magic_quotes_gpc is a PHP_INI_PERDIR setting (after 4.2.3), which means you can't change it with ini_set() (only PHP_INI_ALL settings can be changed with ini_set())

What this means is you have to use an .htaccess file to do this - OR - implement a script to reverse the effects of magic quotes. Something like this

if ( in_array( strtolower( ini_get( 'magic_quotes_gpc' ) ), array( '1', 'on' ) ) )
{
    $_POST = array_map( 'stripslashes', $_POST );
    $_GET = array_map( 'stripslashes', $_GET );
    $_COOKIE = array_map( 'stripslashes', $_COOKIE );
}

While I can't say why php_flag is giving you 500 Internal Server Errors, I will point out that the PHP manual has an example of detecting if magic quotes is on and stripping it from the superglobals at runtime. Unlike the others posted, this one is recursive and will correctly strip quotes from arrays:

Update: I noticed today that there's a new version of the following code on the PHP manual that uses references to the super-globals instead.

Old version:

<?php
if (get_magic_quotes_gpc()) {
    function stripslashes_deep($value)
    {
        $value = is_array($value) ?
                    array_map('stripslashes_deep', $value) :
                    stripslashes($value);

        return $value;
    }

    $_POST = array_map('stripslashes_deep', $_POST);
    $_GET = array_map('stripslashes_deep', $_GET);
    $_COOKIE = array_map('stripslashes_deep', $_COOKIE);
    $_REQUEST = array_map('stripslashes_deep', $_REQUEST);
}
?>

New version:

<?php
if (get_magic_quotes_gpc()) {
    $process = array(&$_GET, &$_POST, &$_COOKIE, &$_REQUEST);
    while (list($key, $val) = each($process)) {
        foreach ($val as $k => $v) {
            unset($process[$key][$k]);
            if (is_array($v)) {
                $process[$key][stripslashes($k)] = $v;
                $process[] = &$process[$key][stripslashes($k)];
            } else {
                $process[$key][stripslashes($k)] = stripslashes($v);
            }
        }
    }
    unset($process);
}
?>

The php_flag and php_value inside a .htaccess file are technically correct - but for PHP installed as an Apache module only. On a shared host you'll almost never find such a setup; PHP is run as a CGI instead, for reasons related to security (keeping your server neighbours out of your files) and the way phpsuexec runs scripts as 'you' instead of the apache user.

Apache is thus correct giving you a server error: it doesn't know about the meaning of php_flag unless the PHP module is loaded. A CGI binary is to Apache an external program instead, and you can't configure it from within Apache.

Now for the good news: you can set up per-directory configuration putting there a file named 'php.ini' and setting there your instructions using the same syntax as in the system's main php.ini. The PHP manual lists all settable directives: you can set those marked with PHP_INI_PERDIR or PHP_INI_ALL, while only the system administrator can set those marked PHP_INI_SYSTEM in the server-wide php.ini.

Note that such php.ini directives are not inherited by subdirectories, you'll have to give them their own php.ini.

If you're running PHP 5.3+ this will do the trick, place it at the topmost of your page:

if (get_magic_quotes_gpc() === 1)
{
    $_GET = json_decode(stripslashes(json_encode($_GET, JSON_HEX_APOS)), true);
    $_POST = json_decode(stripslashes(json_encode($_POST, JSON_HEX_APOS)), true);
    $_COOKIE = json_decode(stripslashes(json_encode($_COOKIE, JSON_HEX_APOS)), true);
    $_REQUEST = json_decode(stripslashes(json_encode($_REQUEST, JSON_HEX_APOS)), true);
}

Handles keys, values and multi-dimensional arrays.

Different hosting providers have different procedures for doing this, so I would ask on their forums or file a support request.

If you can't turn them off, you could always using something like this which will escape input regardless of whether magic quotes are on or off:

//using mysqli

public function escapeString($stringToBeEscaped) {

    return $this->getConnection()->real_escape_string(stripslashes($stringToBeEscaped));
}
  1. Does it work if you remove the AddType line? I'm not quite sure why that's relevant to turning magic quotes off.

  2. If PHP isn't running under mod_php, htaccess won't work. Does it work as a CGI?

This is one for your hosting company really.

BaileyP's answer is already pretty good, but I would use this condition instead:

if(function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc() === 1){
  $_POST = array_map( 'stripslashes', $_POST );
  $_GET = array_map( 'stripslashes', $_GET );
  $_COOKIE = array_map( 'stripslashes', $_COOKIE );
}

It is more defensive.

If you can't turn it off, here is what I usually do:

get_magic_quotes_gpc() ? $_POST['username'] : mysql_real_escape_string($_POST['username']);

It will be placed in the database in its proper format.

Related