I'm working in PHP to build a form. I know how to display the form and then take submitted values from the $_POST variable, and I know how to validate those variables and display a "Thank You" or an "Error" page depending on the input.
What I don't know how to do, though, is create a client-side-like system wherein despite having my users hit a "back" button a separate screen I can then take the information I gathered from the first submission and display dynamic error messages like "Please provide a valid email address" or "First name is a required field" next to the fields that were entered incorrectly. I'd also like to retrieve any previously submitted data that was valid and have it populate in the form so users don't get frustrated by losing everything they entered.
What is the right approach to accomplishing something like this in PHP? I originally thought if I could pass back an array of error m开发者_如何学运维essages with an input type="hidden" tag I could then pull my values and display messages dynamically with PHP, but I keep getting stuck in that approach.
You could add the errors a php session, but this creates issues for users who have multiple browser tabs open.
My preferred method is to have the form submit to the same page and put the errors directly on that page so the user does not have to click the back button. That way you can highlight the fields directly in the form (make the background or outline red or something similar.)
<input type="text"
<?php (empty($_POST['field']?'style="backgroung-color: red;"':''))?>
name="field" value="<?php echo $_POST['field']?>" />
You can put <input type="text" name="field" value="<?php echo $_POST['field']?>" />
to get the old value.
Because the web is, by definition, stateless, there is no really good way to track what the user does when they hit the back button. There are hacks that work using a hidden iframe, but that is way more trouble that what you are looking for.
Don't mix client logic with server logic. The exact same script can output the form and take it's input. In case input successfully validates, it goes on. If not, it will display the form again, this time with error messages and the already-entered data.
Next time the user submits the form, validation starts again until it passes successfully.
So you extend the form with input values and error messages in the first place, but you only display them if flagged/set.
This can be done just with additional variables next to $_POST
- or if you like it - by using a complete form abstraction from a framework, like zend framework (which might be overhead for what you like to do) or just with a library/component like the popular HTML_QuickForm2.
Edit:
This is some very bare code to demonstrate the overall methodology, if you use a library it is much nicer (and you don't have to code it instead you can concentrate on the actual form like the definition on top). This code is more for reading and understanding the flow than for using, I quickly typed it so it (most certainly has) syntax errors and it's not feature complete for a full blown form. This one has only one email field and is even missing the submit button:
/* setup the request */
$request->isSubmit = isset($_POST['submit']);
/* define the form */
$form->fields = array
(
'email' => array
(
'validate' => function($value) {return filter_var($value, FILTER_VALIDATE_EMAIL);},
'output' => function($value, $name) {return sprintf('<input type="text" value="%s" id="%s">', htmlspecialchars($value), htmlspecialchars($name)},
'default' => 'info@example.com',
),
);
/**
* Import form data from post request
*
* @return array data with keys as field names and values as the input strings
* or default form values.
*/
function get_form_post_data($form, $request)
{
$data = array();
foreach($form->fields as $name => $field)
{
$data[$name] = $field->default;
if ($request->isSubmit && isset($_POST[$name]))
{
$data[$name] = $_POST[$name];
}
}
return $data;
}
/**
* Validate form data
*/
function validate_form_data($form, $data)
{
foreach($form->fields as $name => $field)
{
$value = $data[$name];
$valid = $field['validate']($value);
if (!$valid)
{
$form->errors[$name] = true;
}
}
}
function display_form($form, $data)
{
foreach($form->fields as $name => $field)
{
$value = isset($data[$name]) ? $data[$name] : '';
$hasError = isset($form->errors[$name]);
$input = $field['output']($name, $value);
$mask = '%s';
if ($hasError)
{
$mask = '<div class="error"><div class="message">Please Check:</div>%s</div>';
}
printf($mask, $input);
}
}
// give it a run:
# populate form with default values -or- with submitted values:
$form->data = get_form_post_data($form, $request);
# validate form if there is actually a submit:
if ($request->isSubmit)
{
validate_form_data($form, $form->data);
}
# finally display the form (that can be within your HTML/template part), works like echo:
display_form($form, $form->data)
Use the form to submit to the same page, and if the form validates, use a header to redirect the user into the thank you page.
header("Location: thank-you.php");
If the form fails validation, you could easily display all the errors on the same page.
精彩评论