I am confused about PHP Post/Redirect/Get
In an article on preventing PHP form resubmissions, I read the following:
(Not quoting) This could be the page that receives the form data, for example called "form.php":
<form action="submit.php">
<input type="text" name="user" required />
<input type="password" name="pass" required />
<input type="submit" value="Log in" />
</form>
The page that would process the POST data would therefore be called "submit.php". I开发者_StackOverflow中文版f the login went correctly, this code would run:
header('Location: /login/form.php?success=true');
However, couldn't a user just navigate to the URL above? Also, what is the purpose of the GET variable? Couldn't I just have a script at form.php that checks if the user is logged in?
At submit.php, should I save the logged in username as $_SESSION['username'], and then check if isset() at form.php? Also, since a URL with "success" in it isn't really pretty, is it economical to redirect the user once again? Should I use PHP header() or Javascript window.location.href? As you see, I'm sort of confused.
Thanks for any help.
However, couldn't a user just navigate to the URL above?
Yes, he can. This will not cause anything bad though.
Also, what is the purpose of the GET variable?
To have some flag that represents the fact that the form has been processed successfully and you need to congratulate user.
Couldn't I just have a script at form.php that checks if the user is logged in?
Uhm, you can keep your code in the way you like. There is no any strong requirements
At submit.php, should I save the logged in username as $_SESSION['username'], and then check if isset() at form.php?
If you need to persist it across the current session - yes, do so.
Also, since a URL with "success" in it isn't really pretty, is it economical to redirect the user once again?
Redirect where. Redirection is pretty cheap thing.
Should I use PHP header() or Javascript window.location.href?
You definitely should do that in php, otherwise you'll get the troubles you're trying to avoid following PRG-way.
PRG or Post/Redirect/Get is just a pattern you can use to prevent the message boxes. How you use it in detail (and the article does only a generic suggestion) depends on your needs.
If you want to flag the success flash message inside a cookie or a session or a get variable, that's totally up to you. A second redirect won't help btw, you'll learn that if you play around with it.
The only important part is, that after you have received the POST request, you do the redirect. The user then can still move back and forward in history w/o being asked to re-submit POST data.
The pattern works and is a fine thing. Just two days ago I did it again and a step-by-step weppapp installer was much nicer to navigate with the browser interface.
About your redirect
This code is wrong:
header('Location:/login/form.php?success=true');
First of all, you need to have a space after the colon:
header('Location: /login/form.php?success=true');
Then the address must be an absolute URI, it must contain the full URL:
header('Location: http://example.com/login/form.php?success=true');
Next to the header()
, you should provide a message body as per RFC, many so called "web-developers" don't even know:
$url = 'http://example.com/login/form.php?success=true';
header(sprintf('Location: %s', $url));
printf('<a href="%s">Moved</a>.', $url);
exit;
Don't forget the exit. Sure, that's pretty much re-enventing the wheel, instead install the http extension of PHP and just do this line:
http_redirect('/login/form.php?success=true');
You find that nifty helper here.
To recap: Important is that you do the redirect after post. Everything else, like passing a variable is totally up to you how you would like to do it.
Yes, you should never rely on a GET variable (or even a hidden POST variable) to say, "sure, let me in, I'm a valid user!".
Personally, I would strip the GET information from the link and rely solely on session variables. Remember to place a 'session_start();' as the first line of code if you are using PHP to activate the session.
For submit.php:
<?php
session_start();
if ($_POST['user'] && $_POST['pass']) { // Make sure both variable are set
if (your_method) {
// Code to check if the user and pass are valid however you plan
$_SESSION['user'] = $_POST['user'];
$_SESSION['loggedin'] = time();
}
}
header('Location: form.php'); // Either way, pass or fail, return to form.php
exit();
?>
Then in form.php:
<?php
session_start();
$activeuser = false;
if ($_SESSION['user'] && $_SESSION['loggedin'] < (time()+600)) {
// Check if the user exists and the last access was with in 10 minutes.
$_SESSION['loggedin'] = time(); // If so, keep them up to date!
$activeuser = true;
}
if ($activeuser) {
// whatever should show to someone logged in
} else {
// Show log in form
}
?>
Also, you may already know this, but the default method of transferring is GET, so be sure to specify method="post" in the form tag.
It's normally best to use header() to redirect if needed as Javascript is client-side and can be avoided which can break your intent for the functioning of your site.
The main idea behind POST/REDIRECT/GET, as the article you linked to points out, is to avoid users resubmitting data (most of the time). Generally, you don't want the same POST (with the exact same data) to happen twice -- indeed, in some situations, it could end up performing some action (like charging a credit card) a second time, which would be bad.
Most of what you ask about in your question are implementation details (like sending the ?success request parameter in the redirect).
In practice, what usually happens is that your redirect on success. If, for example, the user's input fails validation, you don't redirect, and instead, redisplay the form, along with relevant error messages.
Here's a basic example, all in one script. I've tried to include only what's important, with as little extraneous stuff as possible.
login.php
<?php
/**
* ensure user supplied both username & password
* @return mixed true or an array of error messages
*/
function validate_login_values($vars){
$errors = array();
if (empty($vars['username'])) $errors[] = 'You must supply a username, genius.';
if (empty($vars['password'])) $errors[] = 'You must supply a password, dummy.';
if (empty($errors)) return true;
return $errors; // $errors must be an array.
}
if (! empty($_POST)){
$validationResults = validate_login_values($_POST);
if ($validationResults === true){
// assume here that authenticate properly escapes it's arguments before sending them
// to the database.
if (authenticate($_POST['username'],$_POST['password'])){
//GREAT SUCCESS! The user is now logged in. Redirect to home page
header("Location: /");
die();
}
$errors[] = 'Invalid username/password. Try again, slim";
}else{
$errors = $validationResults; // validate_login_values created errors.
}
}
?>
<h1>Log In, Friend!</h1>]
<?php
//display errors, if there were any
if (! empty($errors)): ?>
<div class="errors">Something went horribly wrong:
<ul><?php foreach($errors as $e) echo "<li>$e</li>"; ?></ul>
<div>
<?php endif; ?>
<form method="POST">
<!-- //username, password, and submit -->
</form>
精彩评论