2

I have a registration script (called "script.php") divided in 3 steps; this is the basic structure (i have stripped things out like sanitizing user input and preventing direct access to other steps than 1):

<?php
$step = $_GET['step'];

switch($step) {
    case 1:
        //show form - action="script.php?step=2" method="post"
        break;
    case 2:
        //if user data is good show an overview of the data and show a button to go to step 3 (the button is enclosed in a form - action="script.php?step=3" and method="post")
        //if not, show again form - action="script.php?step=2" method="post" - and display errors
        break;
    case 3:
        //add user data into db
        break;
}
?>

Real code:

<?php
switch ($step) {
case 1:
    //display form
    $html = <<<FORM
        <form action="/install?step=2" method="post">

            <input type="text" name="username">
            <input type="email" name="email">
            <input type="password" name="password">
            <input type="password" name="password_repeat">
            <button class="next" type="submit">Next</button>
        </form>
FORM;
    break;
case 2:
    $errors = array();
    if (empty($_POST['username'])||!preg_match_all('/^([A-Za-z0-9]+){1,16}$/', $_POST['username'])) {
        $errors[] = 'bad/empty username';
    }
    if (empty($_POST['email'])||!filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)) {
        $errors[] = 'bad/empty email';
    }
    if (empty($_POST['password'])) {
        $errors[] = 'empty password';
    }
    if (empty($_POST['password_repeat'])) {
        $errors[] = 'empty password confirm';
    }
    if ((!empty($_POST['password'])&&!empty($_POST['password_repeat']))&&$_POST['password']!==$_POST['password_repeat']) {
        $errors[] = 'passwords do not match';
    }

    if(count($errors)>0) {
        $error_html = 'some errors occurred';
        foreach ($errors as $err) {
            $error_html .= 'error: '.$err;
        }
        $form_html = <<<FORM
            <form action="/install?step=2" method="post">

                <input type="text" name="username" value="{$_POST['username']}">
                <input type="email" name="email" id="email" value="{$_POST['email']}">
                <input type="password" name="password">
                <input type="password" name="password_repeat">
                <button class="next" type="submit">Next</button>
            </form>
FORM;
        $html = $error_html.$form_html;
    }
    else {
        $ent = 'htmlentities';
        $html = <<<DATA_OK
            <h3>Data overview</h3>
            <table>
                <tr>
                    <th>Username:</th>
                    <td>{$ent($_POST['username'])}</td>
                </tr>
                <tr>
                    <th>email:</th>
                    <td>{$ent($_POST['email'])}</td>
                </tr>
                <tr>
                    <th>Password:</th>
                    <td>{$ent($_POST['password'])}</td>
                </tr>
            </table>

            <form action="/install?step=3" method="post">
                <button class="next" type="submit">Avanti</button>
            </form>
DATA_OK;
    }
    break;
case 3:
    //connect to db and insert data
    break;
}
?>
<!doctype HTML>
<html>
<head>
    <title>Script</title>
    <meta charset="utf-8">
</head>
<body>
    <?php echo $html; ?>
</body>
</html>

The problem is that when i go to step 3 $_POST is always empty. Is the button shown in step 2 (if user data is good) overwriting $_POST? Or is it emptied because that form has no input but only a submit? How can i pass the $_POST data to step 3 without using hidden fields (as they would contain passwords/pw hashes)?

I have searched on google and here on SO but i couldn't find anything related to my problem.

plumbe0
  • 97
  • 1
  • 1
  • 9
  • why are you pulling your value from `$_GET`? – celeriko May 19 '14 at 14:15
  • Please post the form HTML. Does your form have method="post" ? – Thomas May 19 '14 at 14:19
  • 1
    @Joe yes i am using breaks. I'll add them into the code, i thought they were irrelevant. – plumbe0 May 19 '14 at 14:23
  • Does the form with `action="script.php?step=3"` have all form fields enclosed in the form? An overview of the data is not the same as the actual (hidden...) fields. – jeroen May 19 '14 at 14:25
  • 1
    @pinetreesarecool better add the whole real switch statement with real html output etc, there's no such known issue with mixing get and post, so maybe it's somethng concrete in the rest of your code – Royal Bg May 19 '14 at 14:25
  • you should post whatever php code pulls the `$_POST` variables – celeriko May 19 '14 at 14:32
  • @jeroen step 3 doesn't have any form, it just enters data into the DB and show a success/error message. If you refer to the first form in step 2 (if user data is good) then data is displayed in a table. – plumbe0 May 19 '14 at 14:35
  • @pinetreesarecool why don't you give us the rest of your code, an explanation is not enough, the mistake might be syntactic or typo, you never know – Royal Bg May 19 '14 at 14:36
  • @pinetreesarecool If you are just submitting an empty form as the first form of step 2, `$_POST` will be empty. You need to add all form fields again (as hidden fields for example) or store the information in a session to have it persist. A table is not the same as a form. – jeroen May 19 '14 at 14:37
  • You should save data at all steps in database. – Knase May 19 '14 at 14:38
  • `"I have stripped things out like sanitizing user input"` - Don't do that... [Do this](http://stackoverflow.com/questions/60174/how-can-i-prevent-sql-injection-in-php) – Jack May 19 '14 at 14:40
  • @JackWilliams i mean i have not included sanitizing user input in my example code to make it more readable - security is my first concern. – plumbe0 May 19 '14 at 14:49

1 Answers1

0
<form action="/install?step=3" method="post">
   <button class="next" type="submit">Avanti</button>
</form>

What values do you expect to be posted in Step 3 ? There is none in your form. Even the button does not have a name attribute. No fields inside a form with name attribute will sent an EMPTY post.

POST data can be disposed the same way as the hidden fields. The one who posts can see what he posts, so there is no reason to hide it from him. If he has posted password from step 1, he knows what he has posted. You can hash it, and set it into a session/hidden fields, even thought it's bad practice.

I, really, don't understand why do you have 2 steps. If step 2 is only having a button, why do you have it? You can make the validation in step 1, and if it is OK, go to step 3, if not - stay.

Royal Bg
  • 6,988
  • 1
  • 18
  • 24
  • So this form is overwriting my $_POST as i thought. How can i pass the array after data check in step 2 is passed? It shouldn't be empty at that stage, no? – plumbe0 May 19 '14 at 14:58
  • @pinetreesarecool serialization, sessions or hidden fields. The data will not stay in memory. This is not like a desktop application which uses your memory all the time while it is opened. Each request to new or the same page clears the memory the same way as if you close an application and open it again. I expanded my answer. – Royal Bg May 19 '14 at 15:01
  • thank you for your answer. I have two (actually three) steps because the flow should be: step1: user input --> step 2: input is good, show an overview. if user wants to proceed --> step 3: add data into db – plumbe0 May 19 '14 at 15:06