php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #64891 POST values in Google Chrome XHR.
Submitted: 2013-05-21 21:24 UTC Modified: 2015-09-05 13:33 UTC
Votes:9
Avg. Score:4.2 ± 0.8
Reproduced:6 of 6 (100.0%)
Same Version:4 (66.7%)
Same OS:4 (66.7%)
From: marc at kryn dot org Assigned: cmb (profile)
Status: Closed Package: Built-in web server
PHP Version: 5.4.15 OS: OS X 10.8.2
Private report: No CVE-ID: None
 [2013-05-21 21:24 UTC] marc at kryn dot org
Description:
------------
The PHP file servered through the built-int web server does not receive somehow 
the POST values from a AJAX/XHR POST call in Google Chrome. Only in Google Chrome.

Setup:

 - Create the file from the test script.
 - Open a built-in web server `php54 -S 127.0.0.1:8000 -t web/`
 - Open the file `http://127.0.0.1:8000/test.php`

This behaviour happens only for the built-in web server and Google Chrome. It 
works fine when running PHP behind fpm or as apache module. Any other browser 
works in all combinations (built-in server or not).

Tested on `5.4.15-1` installed through mac ports.

Test script:
---------------
<?php

if (isset($_GET['test'])) {
    echo 'received values: <br/>';
    var_dump($_POST);
    exit;
}
?>
<div id="response"></div>

<script>
var xhr = new XMLHttpRequest();
xhr.open('POST', '<?= $_SERVER['SCRIPT_NAME'] ?>?test=1', true);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.onload = function(){ document.getElementById('response').innerHTML = this.responseText; };
xhr.send('foo=bar');
</script>

Expected result:
----------------
received values:

array (size=1)
  'foo' => string 'bar' (length=3)


Actual result:
--------------
received values: 
array (size=0)
  empty

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2013-05-21 22:15 UTC] googleguy@php.net
-Status: Open +Status: Not a bug
 [2013-05-21 22:15 UTC] googleguy@php.net
Sorry, but your problem does not imply a bug in PHP itself.  For a
list of more appropriate places to ask for help using PHP, please
visit http://www.php.net/support.php as this bug system is not the
appropriate forum for asking support questions.  Due to the volume
of reports we can not explain in detail here why your report is not
a bug.  The support channels will be able to provide an explanation
for you.

Thank you for your interest in PHP.

This doesn't appear to be a bug in PHP. It looks to me like FireFox and some 
other UAs will modify the request headers resulting from that javascript code to 
comply with the spec.

Chrome seems to be sending a request, as a result of that javascript XHR, that 
is missing both the charset in the Content-type header as well as a Content-
length header. If I just let the UA do the encoding and formulate the request 
properly through javascript I get the expected result:

<?php
if (isset($_GET['test'])) {
    echo 'received values: <br/>';
    var_dump(file_get_contents("php://input"),$_POST,$_GET);
    exit;
}
?>
<div id="response"></div>
<form id="myform">
        <input name="foo" value="bar" type="text" />
</form>
 
<script>
var xhr = new XMLHttpRequest();
xhr.open('POST', '<?= $_SERVER['SCRIPT_NAME'] ?>?test=1', true);
xhr.onload = function(){ document.getElementById('response').innerHTML = 
this.responseText; };
var frm = new FormData(document.getElementById("myform"));
xhr.send(frm);
</script>

This works for me in all the latest versions of Chrome, FireFox, Opera, Safari, 
and IE.

Please feel free to reopen this bug report if you have additional evidence of a 
bug in PHP.
 [2013-05-21 22:35 UTC] marc at kryn dot org
Sorry, but you shouldn't modify the test script and then say 'it works with this 
modification'. I don't know what's the different in the header are to your 
example, but it's however not important, because mine produces a correct HTTP 
Request header.


Google Chrome sends with my script following header:

POST /test3.php?test=1 HTTP/1.1
Host: 127.0.0.1:8000
Connection: keep-alive
Content-Length: 7
Cache-Control: max-age=0
Origin: http://127.0.0.1:8000
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.36 
(KHTML, like Gecko) 
Chrome/27.0.1453.93 Safari/537.36
Content-type: application/x-www-form-urlencoded
Accept: */*
Referer: http://127.0.0.1:8000/test3.php
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8

So it's a valid request header and should thus be handled correctly in PHP.
You've mentioned a missing Content-Length: it's not missing.
You've mentioned a missing charset in the Content-Type: This is not 
mandatory as you can read in http://tools.ietf.org/html/rfc2616#section-3.7.

Please re-open this ticket, since it's still a bug on php's side and not a 
support question.
 [2013-05-21 22:59 UTC] googleguy@php.net
Well, first of all you're linking to the wrong part of the RFC when you're referring 
to the character encoding of the HTTP request header. There is undefined behavior 
according to the spec and you can see that here 
http://tools.ietf.org/html/rfc2616#section-3.4.1

where it clearly says:

   Some HTTP/1.0 software has interpreted a Content-Type header without
   charset parameter incorrectly to mean "recipient should guess."
   Senders wishing to defeat this behavior MAY include a charset
   parameter even when the charset is ISO-8859-1 and SHOULD do so when
   it is known that it will not confuse the recipient.

   Unfortunately, some older HTTP/1.0 clients did not deal properly with
   an explicit charset parameter. HTTP/1.1 recipients MUST respect the
   charset label provided by the sender; and those user agents that have
   a provision to "guess" a charset MUST use the charset from the
   Content coding values indicate an encoding transformation that has
   been or can be applied to an entity. Content codings are primarily
   used to allow a document to be compressed or otherwise usefully
   transformed without losing the identity of its underlying media type
   and without loss of information. Frequently, the entity is stored in
   coded form, transmitted directly, and only decoded by the recipient.

So with that said if I go ahead and add the charset to the request header in your 
script I get the expected result.

<?php

if (isset($_GET['test'])) {
    echo 'received values: <br/>';
    var_dump($_POST);
    exit;
}
?>
<div id="response"></div>

<script>
var xhr = new XMLHttpRequest();
xhr.open('POST', '<?= $_SERVER['SCRIPT_NAME'] ?>?test=1', true);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=UTF-
8");
xhr.onload = function(){ document.getElementById('response').innerHTML = 
this.responseText; };
xhr.send("foo=bar");
</script>


You can see that by reviewing the Request Headers from both FireFox and Chrome with 
your developer tools that FireFox appends the charset=UTF-8 to the Content-type 
header for you, whereas Chrome does not (you can see that from your supplied request 
header).
 [2013-05-21 23:56 UTC] marc at kryn dot org
First of all: You've copy&pasted a not existing paragraph/mixed sentences
to a complete new paragraph. Your quote does not exist in that RFC!

The correct one is:

   Some HTTP/1.0 software has interpreted a Content-Type header without
   charset parameter incorrectly to mean "recipient should guess."
   Senders wishing to defeat this behavior MAY include a charset
   parameter even when the charset is ISO-8859-1 and SHOULD do so when
   it is known that it will not confuse the recipient.

   Unfortunately, some older HTTP/1.0 clients did not deal properly with
   an explicit charset parameter. HTTP/1.1 recipients MUST respect the
   charset label provided by the sender; and those user agents that have
   a provision to "guess" a charset MUST use the charset from the
   content-type field if they support that charset, rather than the
   recipient's preference, when initially displaying a document. See
   section 3.7.1.

And here again: it says 'MAY' and 'SHOULD', and not 'MUST',
thus the charset is optional (MAY) and max recommended (SHOULD)
IF we know the charset. All as already mentioned in
   
   http://tools.ietf.org/html/rfc2616#section-3.7.

The only sentence with a MUST ...

                                         and those user agents that have
   a provision to "guess" a charset MUST use the charset from the
   content-type field if they support that charset, rather than the
   recipient's preference, when initially displaying a document.

... is not important here, since it's about the Response header.
We're talking about the opposite.


And here is what PHP should probably do:

http://tools.ietf.org/html/rfc2616#section-3.7.1

                                            When no explicit charset
   parameter is provided by the sender, media subtypes of the "text"
   type are defined to have a default charset value of "ISO-8859-1" when
   received via HTTP.


I know now that other browsers add the Charset part to the Content-Type,
but that's however not important, since it's not a MUST regarding the RFC.
The PHP built-in web server should handle also requests without a charset
and assume that the text body of request without a defined charset is a
"ISO-8859-1".

The strange behaviour is that PHP _does_ parse the Request infrequently
correct, but mostly not.
 [2013-05-23 19:01 UTC] aharvey@php.net
-Status: Not a bug +Status: Re-Opened
 [2013-05-23 19:01 UTC] aharvey@php.net
Really, whatever the spec says, Apache and lighttpd both deal OK with this, so it would be nice if the CLI server did too.
 [2015-09-05 13:33 UTC] cmb@php.net
-Status: Re-Opened +Status: Closed -Assigned To: +Assigned To: cmb
 [2015-09-05 13:33 UTC] cmb@php.net
I can reprodue this issue with PHP 5.4.19 and 5.0.0, but not with
PHP 5.4.42, 5.5.9, 5.6.10 and latest master. Obviously, it has
been resolved in the meantime.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri Apr 19 05:01:29 2024 UTC