views:

638

answers:

6

When my PHP script receives data from an AJAX POST request, the $_POST variables are escaped. The really strange thing is that this only happens on my production server (running PHP 5.2.12 on Linux) and not on my local server (running PHP 5.3.1 on Windows).

Here is the AJAX code:

var pageRequest = false;
if(window.XMLHttpRequest)     pageRequest = new XMLHttpRequest();
else if(window.ActiveXObject) pageRequest = new ActiveXObject("Microsoft.XMLHTTP");

pageRequest.onreadystatechange = function() { }

var q_str = 'data=' + " ' ";

pageRequest.open('POST','unnamed_page.php',true);

pageRequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
pageRequest.setRequestHeader("Content-length", q_str.length);
pageRequest.setRequestHeader("Connection", "close");

pageRequest.send(q_str);

Is there any reason this is happening? And how should I fix this so that it works on both servers?

Edit: I have the following settings for magic_quotes:

                     Local   Master

magic_quotes_gpc     On      On
magic_quotes_runtime Off     Off
magic_quotes_sybase  Off     Off
+1  A: 

Maybe your Linux server's php.ini has magic quotes enabled.

http://php.net/manual/en/security.magicquotes.php

This is bad of course, as the functionality is deprecated and will be removed in the forthcoming PHP 6.

You can disable it in php.ini like so

magic_quotes_gpc = Off

You can test and disable it at runtime if you can not access your php.ini

<?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);
}
?>

From the PHP Manual

alex
How can I fix this? I can't edit php.ini on the production server.
George Edison
Check the code example, or click through to the manual link for more reading.
alex
+5  A: 

You probably have magic quotes enabled on the Linux server: magic_quotes

When magic_quotes are on, all ' (single-quote), " (double quote), \ (backslash) and NUL's are escaped with a backslash automatically.

They're a good thing to disable, as they are going to be removed from PHP 6 onwards anyway. You should also be able to disable them inside your script: set-magic-quotes-runtime You can't deactivate the part of magic_quotes responsible for escaping POST data during runtime. If you can, disable it in php.ini. If you can't do that, do a check whether the magic_quotes are enabled, and do a stripslashes() on any content you fetch from POST:

if (get_magic_quotes_gpc())  
 $my_post_var = stripslashes($_POST["my_post_var"]);
Pekka
And this won't break my local server? Just want to make sure I get this...
George Edison
@George if you do the check as described, it will work with your local server, because `get_magic_quotes_gpc()` will return false there, and no slashes will be stripped. Try it out, do a test output of the function. But the best thing would really be to disable magic quotes on the linux machine. You can do a `phpinfo()`, it will tell you what is enabled and what isn't.
Pekka
@George this was a security measure to prevent SQL injections by automatically escaping the relevant data with slashes. Not a bad idea basically, but it never caught on, and eventually became just a nuisance as well illustrated by your case.
Pekka
It's great, except I'm doing my own escaping for MySQL injections, so `Joe's head` becomes `Joe\'s head` in `$_POST` which becomes `Joe\\\'s head` in the query.
George Edison
@George yes, the check above is to make sure the data is in the same condition on the local and the remote server: Without slashes. (In theory, you could even do that on the POST variable directly, but I'm always uncomfortable with writing to $_POST.) After that, you can escape it again to your heart's content.
Pekka
@Pekka do you need to strip slashes in the key as well? I only ask because the example in the PHP manual does that. It is however unlikely you will have `$_POST` keys with characters that need escaping (at least in my experience).
alex
@alex I don't think it would make sense in the key. Can you post a link to that example?
Pekka
@Pekka http://www.php.net/manual/en/security.magicquotes.disabling.php (maybe I'm misread the code though, it's unlike anything I'd ever write).
alex
@alex as far as I can see, it strips only array keys *below* POST. Those seem to need the treatment (new to me as well). The POST keys themselves do not.
Pekka
Still, there could be a key with a slash if someone had particularly bad code. Like `$_POST['Groups\Categories']`
George Edison
@George or `$_POST["i wish I'd name keys better"]`
alex
I always preferred `$_POST = array_map('stripslashes', $_POST);`
Nick Presta
+3  A: 

This is a PHP "feature" known as Magic Quotes, which has now been deprecated in PHP 5 and will be removed in PHP 6.

It is easy to disable the silly nuisance in php.ini.

Matchu
A: 

Magic Quotes?

keithjgrant
A: 

You likely have magic quotes turned on in your production environment. Inspect phpinfo() output.

You can run all of your inputs through something like this to strip the quotes:

        /* strip slashes from the string if magic quotes are on */
    static function strip_magic_slashes($str)
    {
            return get_magic_quotes_gpc() ? stripslashes($str) : $str;
    }
BojanG
I checked phpinfo(): sure enough, it was enabled on the production server.
George Edison
A: 

I don't think this applies in your case, but I was just having a similar problem. I was loading a Wordpress install along with a site so I could show recent posts on all pages. It turns out Wordpress escapes all $_POST cars, no matter what magic_quotes are set to.

I mention it because it was frustrating to figure out, and googling for an answer brought me here.

Here's how I fixed it in my case:

$temp_POST = $_POST;
require '../www/wp_dir/wp-load.php'; // loading wordpress
$_POST = $temp_POST;
Syntax Error