Stefan
Stefan

Reputation: 93

POST/REDIRECT/GET not working in PHP contact form

I am trying to configure a basic contact POST form with one checkbox input and server-side validation. This means the form must submit to itself, so a self-serving contact form. The problem I'm having is when refreshing the page, the form is submitted again.

I am using session data to store form validation as this form is an initial popup to which the user must tick and confirm to enter the page. The page has two contact forms on it but I am showing one and I think the implementation should be the same for both (correct me if I'm wrong). Once the user ticks the box and submits the form, the popup form will hide allowing the user to see the page.

To solve this, I believe the POST/REDIRECT/GET design pattern should prevent this, however, I don't think my implementation is correct and I don't know what is wrong in my code.

index.php code below:

<!DOCTYPE html>
<html lang="en">
<?php
session_start();
include('form_process.php');
?>
<head>
    <meta charset="UTF-8" />
    <link rel="stylesheet" href="assets/css/main.min.css" />
</head>
<body>
    <section id="selfCertOverlay" <?=$_SESSION['closeSelfCert']?>>
        <div class="blurOverlay">
            <form id="selfCert" method="post">
                <label for="self_cert">I have read and confirm the statement.
                    <input type="checkbox" name="self_cert" id="self_cert">
                    <span id="checkmark" class="<?= ($_SESSION['self_cert_checkbox_error']) ? 'inputError' : ''; ?>"></span>
                    <span class="error"><?= (isset($_SESSION["self_cert_error"])) ? $_SESSION["self_cert_error"] : ''; ?></span>
                </label>
                <input type="submit" name="submit_self_cert" value="Confirm & Proceed">
            </form>
        </div>
    </section>
</body>
</html>

form_process.php code below:

<?php
$_SESSION["self_cert_error"] = "";
$_SESSION["self_cert_checkbox_error"] = false;

if (!isset($_POST["self_cert"])) {
    $_SESSION["self_cert_error"] = "Please read and accept the statement to proceed";
    $_SESSION["self_cert_checkbox_error"] = true;
} else {
    unset($_SESSION["self_cert_error"]);
    $message_body = '';
    unset($_POST['submit']);
    foreach ($_POST as $key => $value) {
        $keyOutput = str_replace('_', ' ', $key);
        $keyOutput = ucwords($keyOutput);
        $message_body .= "$keyOutput: $value\n";
    }
    $to = '[email protected]';
    $subject = 'Email Subject';
    if (mail($to, $subject, $message_body)){
        $_SESSION["closeSelfCert"] = 'style="display: none;"';
        // Redirect to itself.
        header( "Location: {$_SERVER['REQUEST_URI']}", true, 303 );
        return;
    }
}
?>

Upvotes: 1

Views: 207

Answers (1)

Kevin Ife
Kevin Ife

Reputation: 53

The refresh button on the browser resends the last HTTP request that was sent by the client. This is why when you refresh the page, it re-submits the form.

The only way to get around this is to use the POST/REDIRECT method.

To setup a POST/REDIRECT method, use an intermediate page to do the operations and then redirect to the original form afterwards.

For example: index.php --> the page with the form on - make sure the form has action="form_process.php" declared, so it will POST the data to the form_process.php script

form_process.php --> receives the form data and carries out your operations, then redirects back to the index.php page at the end.

So your final code should look something like the below;

index.php

I have removed the include('form_process.php'); at the top

I have added action="form_process.php" to the <form> tag

<!DOCTYPE html>
<html lang="en">
<?php
session_start();
?>
<head>
    <meta charset="UTF-8" />
    <link rel="stylesheet" href="assets/css/main.min.css" />
</head>
<body>
    <section id="selfCertOverlay" <?=$_SESSION['closeSelfCert']?>>
        <div class="blurOverlay">
            <form id="selfCert" method="post" action="form_process.php">
                <label for="self_cert">I have read and confirm the statement.
                    <input type="checkbox" name="self_cert" id="self_cert">
                    <span id="checkmark" class="<?= ($_SESSION['self_cert_checkbox_error']) ? 'inputError' : ''; ?>"></span>
                    <span class="error"><?= (isset($_SESSION["self_cert_error"])) ? $_SESSION["self_cert_error"] : ''; ?></span>
                </label>
                <input type="submit" name="submit_self_cert" value="Confirm & Proceed">
            </form>
        </div>
    </section>
</body>
</html>

form_process.php

I have added session_start(); at the top so you can access the $_SESSION data

I have added header( "Location: index.php", true, 303 ); within your first IF statement

I have altered your header() routing which takes place after you send your email, so this redirects back to index.php

<?php
session_start();
$_SESSION["self_cert_error"] = "";
$_SESSION["self_cert_checkbox_error"] = false;

if (!isset($_POST["self_cert"])) {
    $_SESSION["self_cert_error"] = "Please read and accept the statement to proceed";
    $_SESSION["self_cert_checkbox_error"] = true;
    header( "Location: index.php", true, 303 );
    exit;
} else {
    unset($_SESSION["self_cert_error"]);
    $message_body = '';
    unset($_POST['submit']);
    foreach ($_POST as $key => $value) {
        $keyOutput = str_replace('_', ' ', $key);
        $keyOutput = ucwords($keyOutput);
        $message_body .= "$keyOutput: $value\n";
    }
    $to = '[email protected]';
    $subject = 'Email Subject';
    if (mail($to, $subject, $message_body)){
        $_SESSION["closeSelfCert"] = 'style="display: none;"';
        // Redirect back to the form page.
        header( "Location: index.php", true, 303 );
        exit;
    }
}
?>

Upvotes: 1

Related Questions