Saam4
Saam4

Reputation: 27

I can't send my data from JavaScript to my PHP code so I can save it in databse(Wordpress website)

IN SUMMARY: My online website has a stopwatch, that stopwatch is run on my header.php using Javascript. When user finishes the quiz and clicks the "submit" button, the data of the stopwatch(total seconds the user took to finish the quiz), should be saved on my PhpMyAdmin database.

So, In my header.php I have the following code inside my <head> ... </head> tag. This code will start a stopwatch as soon as the user is transferred to the page https://mathspeedtest.com/questions/ . The stopwatch will stop when the user clicks the submit button, and then the data of the stopwatch (totalSeconds) should be transferred to my php code snippet. My php code snippet is supposed to save the totalSeconds in my PhpMyAdmin database. but that's not what's happening. My stopwatch data is not being saved in my database.

In my header.php:

<head>
<script>
//STOPWATCH JAVASCRIPT CODE
  var stopwatchInterval; // Variable to store the interval ID
  var startTime; // Variable to store the start time
  var totalSeconds = 0; // Variable to store the total number of seconds

  window.onload = function() {
    if (window.location.href.indexOf('/questions/') > -1) {
      startTime = new Date().getTime();
      var stopwatchDiv = document.createElement('div');
      stopwatchDiv.id = 'stopwatch';
      stopwatchDiv.style.position = 'fixed';
      stopwatchDiv.style.top = '40px';
      stopwatchDiv.style.right = '20px';
      stopwatchDiv.style.background = '#ffffff';
      stopwatchDiv.style.padding = '20px';
      stopwatchDiv.style.borderRadius = '10px';
      stopwatchDiv.style.zIndex = '9999';
      stopwatchDiv.style.fontSize = '24px'; // Increase font size for better visibility
      stopwatchDiv.innerText = '00:00:00';
      document.body.appendChild(stopwatchDiv);

    stopwatchInterval = setInterval(function() {
          var currentTime = new Date().getTime();
          var timeDifference = currentTime - startTime;
          var totalMilliseconds = Math.floor(timeDifference); // Calculate the total number of milliseconds
          totalSeconds = timeDifference / 1000; // Calculate the total number of seconds
          var hours = Math.floor((timeDifference % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
          var minutes = Math.floor((timeDifference % (1000 * 60 * 60)) / (1000 * 60));
          var seconds = Math.floor((timeDifference % (1000 * 60)) / 1000);
          var milliseconds = totalMilliseconds % 1000; // Extract milliseconds from the total milliseconds
          var formattedMilliseconds = milliseconds.toString().padStart(3, '0').slice(0, 2); // Format milliseconds to 2 significant digits

          var formattedTime = (hours < 10 ? "0" + hours : hours) + ":" +
                              (minutes < 10 ? "0" + minutes : minutes) + ":" +
                              (seconds < 10 ? "0" + seconds : seconds) + "." +
                              formattedMilliseconds; // Include formatted milliseconds in the time string
          document.getElementById('stopwatch').innerText = formattedTime;
        }, 1); // Change the interval to 1 millisecond
    }

      // Save the totalSeconds in the database
  var submitButton = document.querySelector('input[name="submit_answer"]');
  if (submitButton) {
    submitButton.addEventListener('click', function() {
      clearInterval(stopwatchInterval); // Stop the stopwatch interval when the submit button is clicked
      console.log("Total seconds: " + totalSeconds); // Log the total number of seconds in the console

      // send the total seconds to my php code snippet
      var ajaxurl = '<?php echo admin_url('admin-ajax.php'); ?>'; // Get the correct URL path to admin-ajax.php
      var xhr = new XMLHttpRequest();
      xhr.open('POST', ajaxurl, true);
      xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
      xhr.send('action=save_total_seconds&total_seconds=' + totalSeconds);
    });
  };
  
  };
</script>
</head>

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

MY SHORTCODE PHP CODE SNIPPET I HAVE IN MY https://mathspeedtest.com/questions/ page:

Only focus on the BOLD part of the code. everything else works fine.

$total_seconds = $_POST['total_seconds']; // Make sure to sanitize the input

$data = array('time_taken' => $total_seconds);

$where = array('user_name' => $user_name);

$wpdb->update($table_name, $data, $where);


<?php

get_header();

// Check if the form has been submitted
if (isset($_POST['submit_answer'])) {
    $totalScore = 0; // Initialize total score
    $userAnswers = $_POST['answerIn']; // Get the user's answers from the submitted form

    $user_name = $_SESSION['user_name']; // Retrieve the username from the session

    for ($i = 1; $i <= 20; $i++) {
        $answerKey = 'answer' . $i;
        if ($userAnswers[$i] == $_SESSION[$answerKey]) {
            $totalScore++;
        }
    }

    global $wpdb; // Access the global $wpdb object
    $table_name = $wpdb->prefix . 'users_test_info'; // Prefix the table name with the WordPress prefix

    // Check if the user already exists in the database
    $user_exists = $wpdb->get_var($wpdb->prepare("SELECT user_name FROM $table_name WHERE user_name = %s", $user_name));

    if ($user_exists) {
        // If the user exists, update their test score
        $data = array('test_score' => $totalScore);
        $where = array('user_name' => $user_name);
        $wpdb->update($table_name, $data, $where);
    } else {
        // If the user doesn't exist, insert a new record
        $data = array(
            'user_name' => $user_name,
            'test_score' => $totalScore
        );
        $wpdb->insert($table_name, $data);
    }

// Retrieve the current user_id
$current_user_id = $wpdb->get_var($wpdb->prepare("SELECT user_id FROM $table_name WHERE user_name = %s", $user_name));
$_SESSION['current_user_id'] = $current_user_id;
$questions_table = $wpdb->prefix . 'users_questions_info'; // Prefix the table name with the WordPress prefix

// Check if the user exists in the questions table
$user_exists = $wpdb->get_var($wpdb->prepare("SELECT COUNT(*) FROM $questions_table WHERE user_id = %d", $current_user_id));

$questions_data = array();

for ($i = 1; $i <= 20; $i++) {
    $question_key = 'Q' . $i;
    $user_answer_key = 'Q' . $i . 'UserAns';
    $correct_answer_key = 'Q' . $i . 'CorrectAns';

    $TestingNum1 = strval($_SESSION['questions'][$i - 1]['number1']);
    $TestingNum2 = strval($_SESSION['questions'][$i - 1]['number2']);

    $questions_data[$question_key] = "What is  $TestingNum1 + $TestingNum2 ?";

    $questions_data[$user_answer_key] = $userAnswers[$i];
    $questions_data[$correct_answer_key] = $_SESSION['answer' . $i];
}

if ($user_exists) {
    // User exists, update the existing row, including questions
    $where = array('user_id' => $current_user_id);
    $wpdb->update($questions_table, $questions_data, $where);
} else {
    // User doesn't exist, insert a new row
    $questions_data['user_id'] = $current_user_id;
    $wpdb->insert($questions_table, $questions_data);
}
sleep(3);// wait 3 seconds incase the database is slow or to allow time for data to transfer
$total_seconds = $_POST['total_seconds']; // Make sure to sanitize the input
$data = array('time_taken' => $total_seconds);
$where = array('user_name' => $user_name);
  $wpdb->update($table_name, $data, $where);
 
    // Direct the user to a different webpage
    wp_redirect(admin_url('/results-page/'));
    exit;
} else {
    // Generating 20 random numbers and calculating answers
    $_SESSION['questions'] = array();
    $userAnswers = array();

    for ($i = 1; $i <= 20; $i++) {
        $number1 = rand(1, 10); // Generate a random number between 1 and 10
        $number2 = rand(1, 10); // Generate another random number between 1 and 10
        $answer = $number1 + $number2;

        $_SESSION['questions'][] = array(
            'number1' => $number1,
            'number2' => $number2
        );

        $answerKey = 'answer' . $i;
        $_SESSION[$answerKey] = $answer;
        $userAnswers[$i] = '';
    }
}

?>

<form method="POST">
    <?php for ($i = 1; $i <= 20; $i++) : ?>
        <p>Question <?php echo $i; ?>: What is <?php echo $_SESSION['questions'][$i - 1]['number1']; ?> + <?php echo $_SESSION['questions'][$i - 1]['number2']; ?>?</p>
        <input type="text" name="answerIn[<?php echo $i; ?>]" placeholder="Enter your answer" required><br>
    <?php endfor; ?>

    <div class="centered-container-ForSubmitBtn">
        <input type="submit" name="submit_answer" value="Submit" style="border: 1px solid;">
    </div>
</form>

<?php
get_footer();
?>


I tried to debug by printing out the value for the total seconds from stopwatch:

<?php 
$total_seconds = $_POST['total_seconds']; // Make sure to sanitize the input
var_dump($total_seconds); 
?>

and this is the result that I'm getting: Output: Error message

If it was working properly, I should be getting the value of the $total_seconds (i.e. 49.425), just as an example.

Note: Line 35 is $total_seconds = $_POST['total_seconds'];

Upvotes: 0

Views: 77

Answers (1)

TUPKAP
TUPKAP

Reputation: 5294

It seems that you are trying to manage two different request (XMLHttpRequest and a form submit from the browser) as if they were a single request. In fact, XMLHttpRequest will generate a first request and immediately after the form submit will generate another.

From your code I assume that the endpoint of the XMLHttpRequest is the same of the form submit. So the second call (form submit) will probably cancel the first one (XMLHttpRequest). Even if that doesn't happen, the request invoked by XMLHttpRequest will send only the action and total_seconds variables, so when the PHP script is executed it can't find any submit_answer variable and the if (isset($_POST['submit_answer'])) { will skip to the else branch and the code:

sleep(3);// wait 3 seconds incase the database is slow or to allow time for data to transfer
$total_seconds = $_POST['total_seconds']; // Make sure to sanitize the input
$data = array('time_taken' => $total_seconds);
$where = array('user_name' => $user_name);
$wpdb->update($table_name, $data, $where);

will not be executed (the sleep(3) is anyway unnecessary).

Instead, when the form is submitted, the request does not contains any total_seconds field and thus the error is displayed.


Bearing in mind that anyone could tamper with the data whether sent via XMLHttpRequest or via form submit, I suggest you this approach:

  • remove the XMLHttpRequest
  • create on the fly a hidden field that will contain the elapsed time

The section of JS code that manage this functionality will result as:

// Save the totalSeconds in the database

const submitButton = document.querySelector('input[name="submit_answer"]');

if (submitButton) {

    submitButton.addEventListener('click', function() {
    
        clearInterval(stopwatchInterval); // Stop the stopwatch interval when the submit button is clicked
        console.log("Total seconds: " + totalSeconds); // Log the total number of seconds in the console

        // ADDED CODE
        const input = document.createElement("input");
        input.setAttribute("type", "hidden");
        input.setAttribute("name", "total_seconds");
        input.setAttribute("value", totalSeconds);
        this.form.appendChild(input);

        /* REMOVED CODE
          // send the total seconds to my php code snippet
          var ajaxurl = '<?php echo admin_url('admin-ajax.php'); ?>'; // Get the correct URL path to admin-ajax.php
          var xhr = new XMLHttpRequest();
          xhr.open('POST', ajaxurl, true);
          xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
          xhr.send('action=save_total_seconds&total_seconds=' + totalSeconds);
        */  
    });
}

In any case remove the sleep(3) from the PHP

Upvotes: 2

Related Questions