Let's say I enter a registration form with this ending URL: registration.php?accountType=a
The form is parsed on the same page (registration.php). If the user doesn't pass form validation they are taken to registration.php with error messages. So you see I lost my variable accountType=a. My question:
Can I submit a form for validation and retain the accountType variable? I'm aware that this could easily be done using a cookie. I just want a further understanding.
Solution: Although all of the answers below were valid, I went with a Session variable and <form action="registration.php?<?php print 'accountType=' . $_SESSION['accountType']; ?>" etc. Thanks for the help.
You should use this in your form:
<form action="registration.php?accountType=a">
You should use this in your php:
if ($validation_success) {
header('sucess.php')
} else {
// don't do anything. The page(registration.php?accountType=a) loads
}
I'm just giving you the idea.
You can easily to it in 3 ways...
Using PHP Sessions. Simply do something like
session_start();
$_SESSION['namespace'] = array('post' => $_POST, 'get' => $_GET);
Using Cookie (Session seems for me to be more elegant).
Use Ajax request; it will make your tasks easier.
I think you should add the "accountType=$accountType" at the url's end, when you make a http forward, so the user will taken back to the correct page.
I dont see your code, but maybe like this:
if(auth())
{
//do something...
}
else
{
header("Location: /registration.php?somerror=true&accountType=" . $accountType);
}
Related
Okay. I have yet another easy problem which I can't solve. I am working with PHP and I am working on a form to be validated by PHP. I have validated the form in another page containing the same elements. That's the
<form name = "Order Form" action = "<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>" method = "post">
but now the problem arises is that, when we have validated the form and there are no more errors, how to send the data for further registration in other pages. Assuming that Javascript is off I have to use this method. Help is very much appreciated.
You can use session to store some data for a short time such as registration process example:
<?php session_start();
if(noerror){
$_SESSION['username']=$username;
//similarly do for more
header("Location:next_page.php");
}
else{
//show error
}
Note: Alternatively You can also use hidden input but I will discourage that as for security purpose you need to re-validate that.
Update:
To check if an error has occurred or not no need to count them simply use an variable called $noerror and initialize it with TRUE and as soon as an error occurs set it to false then simply put it in if($noerror) at last.
If you want to display error message store them in an array like $error_log
example:
if(error_in_username){
$noerror=false;
$error_log['username']="Invalid Username";
}
Please refer to below link.
http://www.w3schools.com/php/php_form_url_email.asp
Hope this will solve your problem.
On your validation 'page' which should be a controller of sorts, if validation is successful, load the step2 page with the previous form data in hidden inputs.
OR
After successful validation of step1, save the data already into database (could be a temp table), and then proceed to step2 with the id of the entry you just saved. On submission of step2, you can merge the step2 data with the data of the entry that was saved in the database, and proceed to step3 if necessary. etc.
If you simply want to get to another page, the basic logic is:
if(validation_success)
{
header("Location: step2.php");
} else {
show_errors();
}
Possibly stupid question time:
On many websites, when a user submits a form, the information is checked, and if it is incorrect they are redirected back to the form, with all/most of the information still intact and entered into the form. E.g. they type in the wrong password, but after the redirect, their username is still intact in the form. I want to know the best method in which this can be done.
I did some testing:
post1.php:
<?php
$_POST['user']='name';
header('Location: post2.php');
?>
post2.php:
<?php
if(!empty($_POST['user'])){
header('Location: post3.php');
//echo 'post: '.$_POST['user'];
}
else{
echo 'nope post2.';
}
?>
post3.php:
<?php
if(!empty($_POST['user'])){
echo 'post: '.$_POST['user'];
}
else{
echo 'nope post3.';
}
?>
When using a form on post1.php, I could get post3.php to echo 'nope post3.' which shows that post values don't stick around after a redirect. However, when using the current version of post1.php, I could only get post2.php to echo 'nope post2.', meaning that setting $_POST variables manually doesn't work, or I could on the validation page enter $_POST['var']=$_POST['var'] and it would save the post variable through one more redirect.
I know this could be done using SESSION variables, but I feel like that could get messy quickly.
and before you comment about security risks, I obviously wouldn't do this with any sensitive information.
tl:dr; How do I best send variables back to the page the form is on after form validation fails?
I think as you mention using $_SESSION is more appropriate in this case. When You put something like:
$_SESSION['formVariables'] = $_POST;
then You can refer to these variables when you will be back on form1.php page.
The best solution would be to do validation on same page as the form by including validation script before the form and then if all is correct redirect to relevant page.
Is there any particular reson why you want to do validation on different page than form?
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". If 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('Moved.', $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>
Once some data are submitted through POST, is it possible to make them available as $_POST through different pages, same like how $_SESSION allows us to do?
You'll need to parse the data in $_POST and recreate it in your form. You can do it with hidden fields.
Or, you can save the $_POST data in a user session and refer to it when you need it. You'll have to manage the lifecycle of the data to make sure it doesn't stay around too long.
Digging up an old question today. But i forgot to post the working solution I dug....
Place this snippet in top of your every page
if(isset($_POST) & count($_POST)) { $_SESSION['post'] = $_POST; }
if(isset($_SESSION['post']) && count($_SESSION['post'])) { $_POST = $_SESSION['post']; }
The problem is that you are sending the data in via the URL which is stored in the $_GET variable, not in $_POST. If you want the ability to submit the data in either format, use $_REQUEST instead.
There is a bit of a debate on whether it is a good idea to use $_REQUEST, but if you are doing a simple site, there is little wrong with it.
If you would rather not use $_REQUEST, then you can use the following code on each variable you are expecting:
if (!empty($_GET['foo'])) {
$foo = $_GET['foo'];
} elseif (!empty($_POST['foo'])) {
$foo = $_POST['foo'];
} else {
die("Foo not submitted");
}
I might not have known what to search for to get this answer so please point me to the correct post if this has been dealt with already.
Now then, I have a little custom CMS and I want to ensure users don't re-submit their $_POST data by refreshing the page. So I've done something like this:
<?
//Start a session to hold variables I want after my redirect
session_start();
if($_POST){
//Do some php stuff and if I'm happy with the results...
$_SESSION['some_vars'] = $whatever;
//Bring me back here but without the $_POST data
header('Location: '.THIS_PAGE);
exit;
}
?>
When the script reloads I use my session variables and trash the session.
I'm wondering if anybody has a better way to handle this. It's fairly non cumbersome but I'm always looking for more efficiency.
Thanks.
EDIT: By the way, stackoverflow.com does this somehow when you post a question if what I'm doing seems unclear, but they also make a permalink while they're at it.
You have actually implemented what is called the Post-Redirect-Get pattern, and it is absolutely a correct way to do this. I do this myself. I use it so often, I usually implement some minor helper functions into my base controller classes to help me use it:
public function prgRedirect($url = null, $sessionData = null)
{
if ($sessionData !== null) {
if (! isset($_SESSION)) session_start();
$_SESSION['_PRG'] = $sessionData;
}
if ($url === null) $url = $_SERVER['HTTP_REFERER'];
header("Location: ".$url);
}
public function getPrgData()
{
if (! isset($_SESSION)) session_start();
if (isset($_SESSION['_PRG'])) {
$data = $_SESSION['_PRG'];
unset($_SESSION['_PRG']);
}
else {
$data = null;
}
return $data;
}
I usually use it with REST-style URLs, so a POST request will do whatever it has to do, save some data to session using prgRedirect(), which then redirects back to the GET url for the same resource/page. The handler for the GET method will call getPrgData() at the top of the execution and see if there's anything in the session data.
if its important that user dont insert the same data I'm sure there must be some unique column in your database (like headline maybe?). so just check if this headline already exists. you wont need to use any sessions that way
What about:
1. Generate random string (uniqid or md5)
2. Store it in session and put in into hidden input at the form
3. Check form value and session value - if it matches - process the form. Clear the session value.
There are actually two problems here:
users hitting the refresh button in their browser when the data is already saved and you are in a page which saves the data
user hits the "back" button in the browser and clicks "submit" button once again.
In the first scenario, the best scheme is to follow the GET-after-POST pattern where you use the header("location:somewhere_else.php") call to redirect the user. This way you do not have to worry about being called two times consecutively, since the page where you posted the data, is not in the browser's history list (because the server had returned 302 header).
The second scenario hurts a bit more, because the GET-after-POST does not help. If the user submits the form twice, the you may save the data twice. In this case, there may be several solutions:
put a "form identifier" (a random string) in every form you send to the client. When client submits the form, check if you already have such identifier in session data. If you don't have it, save form data and remember the identifier in user's session as "already used". If you find the identifier in session data, don't save anything - it's a duplicate.
check the database for exactly the same values that are submitted. If they match, do not save a duplicate. However, the user may have clicked "back" button, changed some piece of data and then re-submitted the form.