41

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
Nathan Osman
  • 71,149
  • 71
  • 256
  • 361
  • Related: *[With “magic quotes” disabled, why does PHP/WordPress continue to auto-escape my POST data?](https://stackoverflow.com/questions/8949768)* – Peter Mortensen Dec 01 '19 at 02:48

6 Answers6

71

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
  • 442,112
  • 142
  • 972
  • 1,088
  • @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 Mar 22 '10 at 23:31
  • 1
    @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 Mar 22 '10 at 23:32
  • 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. – Nathan Osman Mar 22 '10 at 23:37
  • @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 Mar 22 '10 at 23:43
  • @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 Mar 22 '10 at 23:44
  • @alex I don't think it would make sense in the key. Can you post a link to that example? – Pekka Mar 22 '10 at 23:47
  • @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 Mar 22 '10 at 23:49
  • @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 Mar 22 '10 at 23:51
  • Still, there could be a key with a slash if someone had particularly bad code. Like `$_POST['Groups\Categories']` – Nathan Osman Mar 22 '10 at 23:56
  • @George or `$_POST["i wish I'd name keys better"]` – alex Mar 23 '10 at 00:14
  • 8
    I always preferred `$_POST = array_map('stripslashes', $_POST);` – Nick Presta Mar 25 '10 at 04:03
29

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 vars, 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;
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Syntax Error
  • 4,475
  • 2
  • 22
  • 33
  • After 3 years, it's still unfixed in WP 3.7. – biziclop Oct 28 '13 at 06:48
  • 1
    Maybe it's a feature and not a bug. In wp-settings.php the method wp_magic_quotes() is invoked which is defined in wp-includes/load.php. This method makes sure that inside WordPress all parameters are quoted regardless of Magic Quotes. – Björn Weinbrenner Jun 10 '14 at 17:33
  • 2
    I think a more accurate description is "someone intended it as a feature but didn't think of the consequences so now it's a bug for other people" Could be easily avoided by wordpress copying the POST vars for it's own use and then escaping them there, rather than changing what's actually in POST where anything outside wordpress has to deal with the changes. – Syntax Error Mar 27 '15 at 18:48
  • 1
    holy mother of jesus christ may you be blessed @SyntaxError You shall have a prosperous and healthy long life. STILL NOT FIXED IN WORDPRESS 4.7 in 2017 – Toskan Apr 18 '17 at 22:46
  • ticket created under: https://core.trac.wordpress.org/ticket/40476#ticket – Toskan Apr 18 '17 at 22:53
  • 2
    talking to a wp dev: `$myvar = wp_unslash( $_POST['variable'] ); or $my_POST = wp_unslash( $_POST ); both of which wouldnt work in my case I fear – Toskan May 31 '17 at 17:40
  • 1
    @biziclop: It is still not fixed in 2019, 6 more years later. – Peter Mortensen Dec 01 '19 at 02:49
  • See also *[With “magic quotes” disabled, why does PHP/WordPress continue to auto-escape my POST data?](https://stackoverflow.com/questions/8949768)* – Peter Mortensen Dec 01 '19 at 02:50
9

This is a PHP "feature" known as Magic Quotes, which has now been deprecated in PHP 5.3 and removed in PHP 5.4.

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

HamZa
  • 14,671
  • 11
  • 54
  • 75
Matchu
  • 83,922
  • 18
  • 153
  • 160
4

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;
    }
alex
  • 479,566
  • 201
  • 878
  • 984
BojanG
  • 1,872
  • 1
  • 15
  • 23
4

So I did talk to a WordPress developer (#40476. $_POST values ' and \ for sure are getting escaped with a slash) and he said:

Back in the day, many many moons ago, WordPress blindly followed PHP in accepting that all of the superglobal values should be slashed. PHP later did a reversal on the idea to something more sane which you see today, but the damage was done.

WordPress as an application had existed for long enough, and there were enough existing plugins and themes relying upon WordPress creating a sane single environment that WordPress also changing would cause irreparable damage to those sites - introduce security vulnerabilities, mangle content, and a bunch of other fun things.

https://core.trac.wordpress.org/ticket/18322 is our ticket for tracking this and getting to something more sane - in the shortterm (and longer term) we'd request that if you're accessing $_POST variables you do it as such: $myvar = wp_unslash( $_POST['variable'] ); so that one day, we'll be able to have $_POST as an unslashed array.

Concerning the answer given here:

$temp_POST = $_POST;
require '../www/wp_dir/wp-load.php';
$_POST = $temp_POST;

Please don't do that. You're just opening yourself to security issues, and unexpected things happening to your content where WordPress does expect the values to be slashed. Instead, simply use wp_unslash(), and if you really need a copy of $_POST to operate on yourself, do it as such: $my_POST = wp_unslash( $_POST );.

I should also add - I expect you're doing this because you're trying to use an API endpoint for something, I'd highly suggest switching to using the REST API introduced with WordPress 4.7 instead, as it allows us to offer much more consistent experience to developers.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Toskan
  • 13,911
  • 14
  • 95
  • 185
2

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
  • 479,566
  • 201
  • 878
  • 984