Nathan Osman
Nathan Osman

Reputation: 73175

Why are $_POST variables getting escaped in PHP?

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

Upvotes: 42

Views: 36434

Answers (6)

Pekka
Pekka

Reputation: 449415

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 5.4 onwards anyway. 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"]);

Upvotes: 71

Toskan
Toskan

Reputation: 14931

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.

Upvotes: 5

Syntax Error
Syntax Error

Reputation: 4527

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;

Upvotes: 31

Matchu
Matchu

Reputation: 85794

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.

Upvotes: 9

BojanG
BojanG

Reputation: 1922

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

Upvotes: 4

alex
alex

Reputation: 490193

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

Upvotes: 2

Related Questions