14

I have an ajax call, that sends form data to a php function. Since I read a lot that using contentType: 'application/json' is best practice I wanted to give it a try as well. But unfortunately my script doesn't return anything when I use it. If I remove it, the script does what it is supposed to do.

Do you have any idea what the reason might be and why? Thank you!

$('#Form').submit(function(e) {
            e.preventDefault();

            var content = $(this).serialize() + "&ajax=1";

            $.ajax('app/class/controller/contactForm.php', {
              type: "POST",
              //contentType: 'application/json',
              dataType: 'json',
              data: content,
              success: function(result) {
                  console.log(result);
              }
            });
        })

and my PHP:

if(isset($_POST['ajax']) && $_POST['ajax'] === '1') {
    echo json_encode(validateForm($_POST));
}
Sebsemillia
  • 9,366
  • 2
  • 55
  • 70
  • If it's working without it, why do you feel a need to add it ? – adeneo Nov 30 '13 at 00:27
  • Kind of similiar http://stackoverflow.com/questions/17194251/no-response-from-generic-handler – Musa Nov 30 '13 at 00:27
  • 1
    contentType specifies the format of the data you are *sending* , not receiving. The format you send the data is the normal query string format. – Felix Kling Nov 30 '13 at 00:33

3 Answers3

24

When using contentType: 'application/json' you will not be able to rely on $_POST being populated. $_POST is only populated for form-encoded content types.

As such, you need to read your data from PHP raw input like this:

$input = file_get_contents('php://input');
$object = json_decode($input);

Of course if you want to send application/json you should actually send JSON, which you are not doing. You either need to build the object serialization to JSON directly, or you need to do something like this - Convert form data to JavaScript object with jQuery - to serialize the object from the form.

Honestly in your case, since you are dealing with form data, I don't quite think the use case for using application/json is there.

Community
  • 1
  • 1
Mike Brant
  • 70,514
  • 10
  • 99
  • 103
  • Thank you! I guess this is the root of the problem. I saw some examples were the form data was serialized and the contentType was set. This is why I thought it should be this way. – Sebsemillia Nov 30 '13 at 00:36
  • @Sebsemillia There is of course no reason that PHP can't respond with JSON if that is what you want to work with. It really probably comes down to how you have your available in javascript to determine how you want to POST to and work with the data in PHP. If for example, you had a nice javascript object that you wanted to POST to PHP. It would be trivial to serialize to JSON and send using `application/json` such that PHP could simple decode the object and work with it. – Mike Brant Nov 30 '13 at 00:40
  • Thanks for explaining the issue with $_POST not being populated. this was the information I was looking for. – Sarah Nov 23 '16 at 02:33
  • Your answer helped me greatly after hours looking although instead of json_encode I have json_decode as the data is already in json format so you need to decode it.. so this is what I have $rawPostData = file_get_contents('php://input'); $json = json_decode($rawPostData); – Sarah Nov 23 '16 at 02:46
3

The best practice you refer to is about the server script setting the Content-Type for JSON to "application/json":

Header('Content-Type: application/json; charset=UTF8');

This is because otherwise a default Content-Type will be sent, often a catch-all text/html, and this could lead to an incomprehension with the client.

If you do not specify yourself a Content-Type in the jQuery request, jQuery will determine the most appropriate one. The problem here is that you were sending a POST form, for which the default Content-Type set by jQuery is application/x-www-form-urlencoded, which tells PHP to decode the data as POST fields and populate $_POST. Your script would have then recovered its parameters from $_POST (or maybe $_REQUEST).

By changing it to application/json, $_POST will no longer be populated, the receiving script operation won't receive the parameters where it was expecting to, and the operation breaks.

So you either need to:

  • not specify the Content-Type yourself (better, IMHO)
  • set a Content-Type of application/x-www-form-urlencoded; charset=UTF-8
  • set a Content-Type of application/json; charset=UTF-8 and modify the script to parse the POST stream and decode the JSON data; see this answer.

The third option requires proper handling of php://input.

Community
  • 1
  • 1
LSerni
  • 55,617
  • 10
  • 65
  • 107
  • I see. This could be the problem. Thank you very much! – Sebsemillia Nov 30 '13 at 00:29
  • @Isemi the comment about the content type is correct. You infromation about not setting content-Type header is incorrect. Most all HTTP communications should have this setting set. This simply let's the receiving client know the format in whihc the data is being sent. IN the case of an AJAX call to a server, the server is the receiving client. The browser should absolutely set the Content-Type header so the server knows what to expect. In this case because that is happening, the server is expecting JSON and is not building `$_POST` as it would for form-encoded Content-Type. – Mike Brant Nov 30 '13 at 00:32
  • @Isemi Similarly when the server sends its response to the javascript client, it should set the Content-Type header as you have suggested. This tells the browser client what to expect format wise. So to summarize, Content-Type should be declared for BOTH the client-to-server call and in the server-to-client response. – Mike Brant Nov 30 '13 at 00:34
  • @MikeBrant, yes, I am aware of these issues; I phrased my answer poorly. Updating answer, even if I'm upvoting yours :-) – LSerni Nov 30 '13 at 15:02
  • Thank you so much. the link you provided for "proper handling of the php://input" has solved this for me after hours looking. :) – Sarah Nov 23 '16 at 02:32
2

The PHP script should be setting the Content-Type header.

if(isset($_POST['ajax']) && $_POST['ajax'] === '1') {
    header('Content-Type: application/json');
    echo json_encode(validateForm($_POST));
}
ceejayoz
  • 176,543
  • 40
  • 303
  • 368
  • Mhmm, unfortunately it is still not working. I just get an empty response. – Sebsemillia Nov 30 '13 at 00:26
  • You are correct that the PHP script SHOULD send such a header, but this has nothing to do with this problem, which is that, by setting `application/json` as content type for initial AJAX call to PHP, PHP is not building `$_POST`. There is also a problem in that he is not sending JSON at all, but rather a url-encoded query string as would be expecting with a typical form-encoded POST – Mike Brant Nov 30 '13 at 00:37