1
votes

I am trying to send form data to a PHP script by using an AJAX call. I'm serializing the form data and sending it as a JSON variable, by a POST method, to a PHP script. Ajax data variable seems correct, but for some reason the PHP $_POST array is empty and I'm having a hard time understanding what I am doing wrong here.

This is my ajax call

// AJAX
        var input_data = $('#contact-form').serialize(); 

        event.preventDefault();

        $.ajax({
            url: 'contact.php',
            type:'POST',
            dataType:'json',//return type from server side function [return it as JSON object]
            contentType: "application/json",
            data: input_data, //Pass the data to the function on server side
            success: function (data) { //Array of data returned from server side function

                $.each(data,function(index){
                    alert(data[index]); // used for debugging, returns 1
                });
            }

        });

        alert("called");
        if(input_data.length < 1)
        {
            alert("empty");
            alert(input_data);
        }
        else
        {
            alert("not empty");
            alert(input_data);
        }
        return false; 

Form

<form class="text-center" id="contact-form" method="POST" action="contact.php">
                    <div class="form-group">
                        <input type="text" class="form-control" id="name" name="name" placeholder="Name">
                    </div>
                    <div class="form-group">
                        <input type="email" class="form-control" id="email" name="email" placeholder="Email">
                    </div>
                    <div class="form-group">
                        <textarea class="form-control" rows="5" id="msg" name="msg" placeholder="Type your message"></textarea>
                    </div>
                    <div class="form-group">
                        <div class="g-recaptcha buffer" data-sitekey="some_key" data-callback="recaptcha_callback"></div>
                        <input type="hidden" class="hiddenRecaptcha required" name="hiddenRecaptcha" id="hiddenRecaptcha">
                    </div>


                    <button type="submit" class="btn btn-lg btn-primary text-uppercase buffer">Send message</button>
                </form>

And finally my contact.php script

<?php
    header('Content-Type: application/json');

    $name;
    $email;
    $msg;

    $nameErr = $emailErr = $msgErr = 0;

    if ($_SERVER["REQUEST_METHOD"] == "POST") {
        if (empty($_POST["name"])) {
            $nameErr = 1;
        }
        else {
            $name = $_POST["name"];
            $nameErr = 0;
        }

        if (empty($_POST["email"])) {
            $emailErr = 1;
        }
        else {
            $email = $_POST["email"];
            if (!filter_var($email, FILTER_VALIDATE_EMAIL) === false) {
                $emailErr = 0;
            } else {
                $emailErr = 1;
            }
        }

        if (empty($_POST["msg"]))  {
            $msgErr = 1;
        }
        else {
            $msg = $_POST["msg"];
            $msgErr = 0;
        }

        if($nameErr == 0 && $emailErr == 0 && $msgErr == 0)
        {
            $to = "[email protected]";
            $subject = 'Contact request - site';
            $txt = $_POST['msg'];
            $headers = "From: " . $_POST['email'] . "\r\n";
            mail($to,$subject,$txt,$headers);
            echo json_encode(array("sent"));
        }
        else
        {
            echo json_encode(array($nameErr, $emailErr, $msgErr));
        }
    }
    else
    {
        echo json_encode(array("post_error"));
    }

?>

By running PHP code, the email gets send correctly. When using an Ajax call, $_POST array is empty and it sends back three error codes from the last if statement in PHP code. Also, if there is a better way to acomplish this, I would be more than happy to see an alternative. I appreciate any help, thank you.

EDIT: JSON data

json_data

1
First off, if you're using jQuery, why not just use $.post() instead of $.ajax()? Second, the $_POST-variables should show up in the PHP-file - do a var_dump($_POST) at the start of the PHP-file? - junkfoodjunkie
@junkfoodjunkie $.post is an alias for $.ajax with the type POST, there is no need to change something. - Charlotte Dunois
It's not needed, it just is a cleaner method when you already do POST anyway, and you don't need to do any X-HTTP requests. $.post('contact.php',{ $('#formID').serialize()},function(data) {}} - junkfoodjunkie
I tried it and it returned an empty array. Calling the PHP script from form action works as expected. I think I'll just rewrite it from scratch tomorrow, it's probably something simple and I just can see it. I'll use jQuery $.post() this time to see how it works. - Petar-Krešimir
You told the webserver you are sending JSON, but in fact you were sending a regular HTTP query string - since it was JSON, PHP didn't parse the POST variables into $_POST. With the removal of contentType: "application/json", jQuery tells the webserver "I send application/x-www-form-urlencoded data" and makes PHP parse the POST parameters into $_POST. - Charlotte Dunois

1 Answers

1
votes

By using $('#contact-form').serialize() you make jQuery convert the data from regular fields to a HTTP query string key=val&key2=val2&... - but now you set in $.ajax that the contentType is application/json, which makes jQuery set a HTTP header Content-Type: application/json to the request. jQuery will not complain that it might be the wrong Content-Type - you should know it the best.

Since the POST-Request has the Content-Type application/json, PHP will not parse the HTTP POST data into the superglobal $_POST. Instead you have to read the raw POST data from php://input.

Your problem is now, that you tell the HTTP POST data is JSON, but it's really not JSON what you send - it's a HTTP query string. Since it's a HTTP query string, you can remove contentType: "application/json", from your $.ajax call, which will make jQuery set the correct Content-Type header.

jQuery will set the Content-Type header to application/x-www-form-urlencoded - which is the correct Content-Type header for you. Since that is one of the Content-Type PHP parses, the HTTP POST data is now available in the superglobal $_POST.

$_POST will only be filled on specific Content-Types, namely multipart/form-data and application/x-www-form-urlencoded. If the HTTP Content-Type is neither of them, $_POST will not be filled and you have to read the RAW POST data from php://input.

http://php.net/manual/en/reserved.variables.post.php