0

****Update****

There seems to be nothing wrong with my code; since creating a new document with the exact same code totally worked. So the file could have become corrupt somehow. See my answer below.


I can not for the life of me find any related question or problem. Basically, I have a review form that gets sent via Ajax to a php process page. Once validated, inserts the data into a mySQL database. The Ajax sends info, mainly errors back to the user. I need a way to prevent multiple submissions on the server-side using php.

I have tried using form tokens which works without Ajax, but does not with it. The $_SESSION doesn't seem to be carrying over to the form process php page.

The problem... The $_SESSION['review_form_token'] doesn't hold any data at all. If I print the session data in an error, it doesn't print anything at all! However, I have a php captcha that uses sessions and it prints it out with no problems. When I set the session on page load, it will print the token as expected into the hidden input. I don't understand why the form token isn't getting passed to the form process. session_start() is on both documents. I've tried ob_start() to no avail. Please help me debug this.

Here is my simplified setup...

index.php (at the top):

<?php
session_start();
$reviewForm_token = md5(uniqid(rand(), true));
$_SESSION['review_form_token'] = $reviewForm_token;
?>

index.php - Form (somewhere)

<form id="reviewform" method="post" novalidate>
   <input type="text" class="form-control form-style name" name="firstname" size="15" maxlength="40" autocomplete="given-name">
   <input type="text" class="form-control form-style name" name="lastname" size="15" maxlength="40" autocomplete="family-name">                 
    <textarea class="form-control form-style" name="review" minlength="50" required></textarea>                 
    <input type="text" class="form-control form-style" name="captcha" autocomplete="off" maxlength="6" required>
    <img src="https://via.placeholder.com/200x60" id="captcha-review" alt="Review captcha image" width="200" height="60">

    <input type="hidden" name="form_token" value="<?php echo $_SESSION['review_form_token']; ?>">
    <button type="submit" name="submit" class="btn btn-primary submit float-right font">Send</button>
    <button type="reset" class="btn btn-primary reset font">Reset</button>
</form> <!-- End form -->

index.php - Ajax (at the bottom of the document)

$('#reviewform').submit(function(event) {
// Set some variables
var $this = this,
    firstnameInput = $('input[name=firstname]', $this),
    lastnameInput = $('input[name=lastname]', $this),
    nameInput = $('input.name', $this),
    ratingInput = $('input[name=StarRating]', $this),
    ratingInputChecked = $('input[name=StarRating]:checked', $this),
    stars = $('.star-rating', $this),
    reviewInput = $('textarea[name=review]', $this),
    captchaInput = $('input[name=captcha]', $this),
    form_tokenInput = $('input[name=form_token]', $this),
    submitButton = $("button.submit", $this);

// Get the form data
// Must relate to the name attribute...
var formData = {
    'firstname': firstnameInput.val(),
    'lastname': lastnameInput.val(),
    'StarRating': ratingInputChecked.val(),
    'review': reviewInput.val(),
    'captcha': captchaInput.val(),
    'form_token': form_tokenInput.val(),
};
// Process the form
$.ajax({
        type: 'POST', // Define the type of HTTP verb we want to use (POST for our form)
        url: 'formProcess-review.php', // The url where we want to POST
        data: formData, // Our data object
        dataType: 'json', // What type of data do we expect back from the server
        encode: true
    })
    .done(function(data) {
        // Here we will handle errors and validation messages
        if (!data.success) {

            // Handle errors for doublepost (form_token) ---------------
            if (data.errors.doublepost) {
                $('button', $this).parents('.form-row')
                    .append(label + data.errors.doublepost + '</label>')
                    .children('label.invalid').attr('id', 'doublepost-error');
            }
        } else {
            // SUCCESS!!
           // Thanks!
        }
    }); // End .done function
// Stop the form from submitting the normal way and refreshing the page
event.preventDefault();
}); // End .submit function

formProcess-review.php

<?php
session_start();
$errors     = array(); // array to hold validation errors
$data       = array(); // array to pass back data
$firstname  = $_POST['firstname'];
$lastname   = $_POST['lastname'];
$StarRating = $_POST['StarRating'];
$review     = $_POST['review'];
$captcha    = $_POST['captcha'];

// Form Validation...

if ($_POST['form_token'] !== $_SESSION['review_form_token']) {
   $errors['doublepost'] = 'You have already submitted your review, you can not resubmit. If you need to send another review, please reload the page.';
}
// return a response ===========================================================
// if there are any errors in our errors array, return a success boolean of false
if (!empty($errors)) {
   // if there are items in our errors array, return those errors
   $data['success'] = false;
   $data['errors']  = $errors;
} else {
   // if there are no errors process our form, then return a message

   unset($_SESSION['review_form_token']);

   // mySQL inserting data...

   // show a message of success and provide a true success variable
   $data['success'] = true;
   $data['message'] = 'Success!';
}
// return all our data to an AJAX call
echo json_encode($data);
?>
Studocwho
  • 2,290
  • 3
  • 20
  • 27
  • Have you tried using a debugger or dumping $_SESSION right after session_start in formProcess-review? – Devon Jul 17 '18 at 01:40
  • what happens when you add an `else{}` to `if ($_POST['form_token'] !== $_SESSION['review_form_token']) {...}`? Or do you have one already? Use php's error reporting, look at the source and the developer console. – Funk Forty Niner Jul 17 '18 at 01:48
  • @Devon using a foreach loop I can dump the available sessions, of which the token is not apart of. Only the captcha session is dumped. – Studocwho Jul 17 '18 at 02:32
  • @FunkFortyNiner Not a right lot to be honest, still doesn't work. And the error reporting doesn't show anything either. Whether I have done it correctly is another matter, I was using this answer as a guide: https://stackoverflow.com/a/21429652/2358222 – Studocwho Jul 17 '18 at 02:35
  • What do you mean by all available sessions and why a foreach loop? Can't you just `var_dump($_SESSION)`? – Devon Jul 17 '18 at 03:34
  • You sure this isn't mysql related and that something's failing due to a possible already existing key in db, preventing anything to budge up until the session was destroyed? That could be a possibility here, that and/or you need to destroy the session key. – Funk Forty Niner Jul 17 '18 at 07:28
  • @Devon there are several $_sessions on the go to do with the captchas, thus it prints all these too. Yes, I tried that, but it breaks the ajax and the javascript for some reason and nothing is printed out, not even the form errors. But doing a foreach loop works. – Studocwho Jul 17 '18 at 10:33
  • @FunkFortyNiner I am 100% sure this isn't mysql related. Because if there is even one form error (which a multiple submission would be classed as an error), it fails the validation and never gets as far as the database stuff. I've tried unsetting the session, but for some reason it doesn't seem to work. – Studocwho Jul 17 '18 at 10:36
  • could be caching then. Don't unset the session, try destroying it instead. – Funk Forty Niner Jul 17 '18 at 11:04
  • @FunkFortyNiner I've tried emptying the cache. I've tried unsetting and destroying and the combination of the 2, to no avail. It's like it's not adhering to anything. – Studocwho Jul 17 '18 at 11:20
  • Is it possible a file can become corrupt but still update the page?? Because I've just copied all my index.php code to a new document and it all works fine! What's going on? – Studocwho Jul 17 '18 at 14:40

3 Answers3

1

I just tried your code and both the Form Token and Session token are being captured correctly on your formProcess-review.php. You're code must have other problems that causes it.

Simplified Ajax submit.

$.ajax({
        type: 'POST', 
        url: 'formProcess-review.php', 
        data: formData, 
        dataType: 'json', 
        encode: true
    })
    .done(function(data) {
    alert(data.message);
      
    });

Simplified formProcess-review.php

<?php
session_start();
$data['message'] = "Form token = ".$_POST['form_token']."   Session value = ".$_SESSION['review_form_token'];
echo json_encode($data);
die();
?>
jun drie
  • 800
  • 6
  • 12
0

Try to add this option 'withCredentials' to the ajax call:

$.ajax({
    type: 'POST', 
    url: 'formProcess-review.php', 
    data: formData, 
    dataType: 'json', 
    encode: true,
    xhrFields: {
      withCredentials: true
    }
}

It's probably that the ajax call not send the session cookie to the server.

Clemen
  • 334
  • 1
  • 8
0

jun drie's anwser has given me the incentive to create a whole new index.php with the same code; which seemed to work. I don't know why or how but the original file must have become corrupt, forcing it not work properly, but still make it show up on the web (weird, eh?!)

I've edited my code to make more simplistic and hopefully better.

I was having trouble with unsetting the session, so I am now calling session_unset(); straight after session_start(); in the index.php to unset any previous sessions from 1 reload ago.

Though I've made this change, it's very strange that it used to work without it.

Studocwho
  • 2,290
  • 3
  • 20
  • 27