3
\$\begingroup\$

My goal is to create a really seamless multi step form for onboarding with only PHP. It stores in sessions and cookies, and retrieves the session data from the cookie if it is stored.

This is what I came up with but I feel it is pretty messy, and the more steps I have the messier it gets. I'm sure there are cleaner ways to do this.

//Sets session & cookie to post

if (isset($_POST['name'])){
    $_SESSION['name'] = $_POST['name']; 
    setcookie("name", $_POST['name']);
}

if (isset($_POST['address'])){
    $_SESSION['address'] = $_POST['address']; 
    setcookie("address", $_POST['address']);
}

if (isset($_POST['city'])){
    $_SESSION['city'] = $_POST['city']; 
    setcookie("city", $_POST['city']);
}


// Sets session to cookie

if (isset($_COOKIE['name'])){
    $_SESSION['name'] = $_COOKIE['name'];
}

if (isset($_COOKIE['address'])){
    $_SESSION['address'] = $_COOKIE['address'];
}

if (isset($_COOKIE['city'])){
    $_SESSION['city'] = $_COOKIE['city'];
}


//Sets post to session

if (isset($_SESSION['name'])){
    $_POST['name'] = $_SESSION['name'];
}

if (isset($_SESSION['address'])){
    $_POST['address'] = $_SESSION['address'];
}

if (isset($_SESSION['city'])){
    $_POST['city'] = $_SESSION['city'];
}


if(!isset($_POST['name']) || !isset($_SESSION['name']) ): ?>

<h2>name</h2>
<form method="post" autocomplete="off">
    <input type="text" name="name" autocomplete="off" placeholder="name"><br>
    <input value="submit" type="submit">
</form>

<?php elseif (!isset($_POST['address']) || !isset($_SESSION['address']) ): ?>

<h2>address</h2>
<form method="post" autocomplete="off">
    <input type="text" name="address" autocomplete="off" placeholder="address"><br>
    <input value="submit" type="submit">
</form>

<?php elseif (!isset($_POST['city']) || !isset($_SESSION['city']) ): ?>
    
<h2>city</h2>
<form method="post" autocomplete="off">
    <input type="text" name="city" autocomplete="off" placeholder="city"><br>
    <input value="submit" type="submit">
</form>

<?php endif ?>


<form method="post" autocomplete="off">
    <input type="text" name="clear_session" value="1" hidden><br>
    <input value="clear_session" type="submit">
</form>

<form method="post" autocomplete="off">
    <input type="text" name="clear_cookies" value="1" hidden><br>
    <input value="clear_cookies" type="submit">
</form>
\$\endgroup\$

1 Answer 1

3
\$\begingroup\$
  1. The most obvious and simple fix is to D.R.Y. your code. You can easily see structures where only the string name changes occur but the process stays the same.

  2. To separate your HTML markup from your processing code, it will look very tidy to declare HTML template strings. These can be declared as variables, but I'll use constants since they have no reason to change during processing. I'm using 'HEREDOC' syntax so that the numbered placeholders are not rendered as an undeclared variable $s.

  3. My opinion is that $_POST should have one-way population in that its contents should always represent the pure, unadulterated version of the user's submission payload. In my script below, I've removed the process where $_POST is populated by cached data.

  4. Although a departure from your original script (and I hope it is an acceptable alteration), I recommend that you not make successive if statements which may overwrite previous processes. You should determine which data points take priority over other and order your if-elseif-else logic accordingly.

Suggested Code: (Demo)

define('FIELDS', ['name', 'address', 'city']);
define(
    'HTML_FIELD_FORM',
    <<<'HTML'
    <h2>%1$s</h2>
    <form method="post" autocomplete="off">
        <input type="text" name="%1$s" autocomplete="off" placeholder="%1$s"><br>
        <input value="submit" type="submit">
    </form>
    HTML
);
define(
    'HTML_CLEAR_FORM',
    <<<'HTML'
    <form method="post" autocomplete="off">
        <input type="text" name="%1$s" value="1" hidden><br>
        <input value="%1$s" type="submit">
    </form>
    HTML
);

foreach (FIELDS as $field) {
    if (isset($_POST[$field])) {
        // Set session & cookie from post 
        $_SESSION[$field] = $_POST[$field]; 
        setcookie($field, $_POST[$field]);
    } elseif (isset($_COOKIE[$field])) {
        // Set session from cookie
        $_SESSION[$field] = $_COOKIE[$field];
    } elseif (!isset($_SESSION[$field])) {
        // Present individual field form
        printf(HTML_FIELD_FORM, $field);
    }
}

// Present nuking forms
foreach (['clear_session', 'clear_cookies'] as $action) {
    printf(HTML_CLEAR_FORM, $action);
}
\$\endgroup\$
2
  • \$\begingroup\$ Excellent reply. Exactly what I was looking for. Question for you though: the reason I repeated the code in the HTML portion was because in the future I am going to need to make every input field look and act a bit differently. For example some input boxed will be numeric only and others would be date pickers. What would your advice for that be? \$\endgroup\$
    – tony
    Jan 6 at 20:14
  • 1
    \$\begingroup\$ Distinguish which precise parts are variable. Extend the lookup array's fields to indicate what their special attributes are. When you call printf(), you keep the static html in the first argument and all of the variable html/content as subsequent arguments. Just keep extending. \$\endgroup\$ Jan 6 at 22:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.