I have a login page using method POST (no ajax), it works properly. But when I press back button after login it says "Confirm form re submission"
How can I fix this in CodeIgniter??
I have a login page using method POST (no ajax), it works properly. But when I press back button after login it says "Confirm form re submission"
How can I fix this in CodeIgniter??
You can do this by using the Post/Redirect/Get Pattern.
The simple explanation of this pattern is that you Post to a controller/method that processes the inputs and which then Redirects to another controller/method. Redirects always produce a Get request.
For your needs, the login form (at user/login) could use an action like `user/process_login'
// in the "user" controller
public function process_login
{
// get inputs and validate them
$valid = //validated inputs and username + password all are good - or not
if($valid){
redirect('user/home_page', 'refresh', 303);
}
redirect('user/login', 'refresh', 303);
}
The complicating factor is if you want to repopulate the form inputs and/or show validation error messages. CodeIgniter makes that a bit more complicated because you will need to use a session in order to retrieve those things after being redirected back to 'user/login'.
My solution is a custom class that extends CI_Form_validation. I use it for all form processing in my projects. The file has a lot of comments that I hope provide an explanation of what's happening.
file: /application/libraries/MY_Form_validation.php
<?php
/**
* Extends CI_Form_validation to allow using the Post/Redirect/Get form processing pattern.
* https://en.wikipedia.org/wiki/Post/Redirect/Get
* provides a basic overview of the pattern.
*
* A more comprehensive examination is found at
* http://www.theserverside.com/news/1365146/Redirect-After-Post
*
* IMPORTANT: To use this class CodeIgniter's Session class must be setup and working.
*
* HOW THIS WORKS
*
* The base class (CI_Form_validation) has the protected property $_field_data.
* That property holds all the information supplied by CI_Form_validation::set_rules()
* and all the results gathered by CI_Form_validation::run().
*
* $_field_data is the key to re-populating a <form> and showing validation error messages.
* This class stores $_field_data in session flash data.
*
* MY_Form_validation::has_failed_validation() is used in the redirect target
* to restore $_field_data thereby making it possible to re-populate a <form> and
* to display error messages after a redirect.
*
* This class is also a handy place for defining application specific (custom)
* validation methods. These methods will NOT require the "callback_" prefix and
* can be used just like "standard" CodeIgniter validation methods.
* Simply define custom validation methods in this file as needed.
*
* There are two examples of custom methods below - valid_user() and valid_password().
*
*/
defined('BASEPATH') OR exit('No direct script access allowed');
class MY_Form_validation extends CI_Form_validation
{
public function __construct($rules = array())
{
parent::__construct($rules);
$this->CI->load->library('session');
}
/**
* run($group = '')
*
* Overrides CI_Form_validation::run()
* Sets a $_SESSION item with the contents of $this->_field_data
* if CI_Form_validation::run() returns FALSE.
*
* @param string $group The name of the validation group to run
* @return boolean TRUE on success and FALSE on failure
*/
public function run($group = '')
{
if(parent::run($group))
{
return TRUE;
}
$_SESSION['validation_field_data'] = $this->_field_data;
$this->CI->session->mark_as_flash('validation_field_data');
return FALSE;
}
/**
* has_failed_validation()
*
* Determine if CI_Form_validation::run() returned false.
* This method should be used in the controller/method that is the
* failed validation redirect target. In other words,
* used in the method that displays the form.
*
* A return of FALSE should be taken as an indication that no attempt has been
* made to validate fields yet.
*
* This method also restores the $_field_data property using session data,
*
* @return boolean TRUE if CI_Form_validation::run() returned false,
* otherwise it returns FALSE.
*/
public function has_failed_validation()
{
if(isset($_SESSION['validation_field_data']))
{
// Validation->run() has failed (returned false).
// Restore the $_field_data property stored in session data.
$this->_field_data = $_SESSION['validation_field_data'];
return TRUE;
}
return FALSE;
}
/**
* capture()
*
* The CI_Form_validation class does not save $_POST data for an <input> unless
* it has a rule. This validation method forces the "capture" of a field's
* $_POST data by giving the field a rule that always returns true.
*
* Use the "capture" rule on fields that don't otherwise need validation
* but you would still like to be able to use set_value('field_name') to
* re-populate the field on a <form>.
*
*/
public function capture()
{
return TRUE;
}
/*
* The next two methods have been added to demonstrate how custom validation
* methods are easily defined for application specific needs.
*
* These two are not to be taken as anything but super-trivial, demo-only code.
* They provide a no-fuss, hard-coded way to validate the user_name and
* password fields for the Pgr_example.
*
* These should be removed in your implementation.
*
*/
/**
* A "custom" validation method for the example app
*/
public function valid_user($str)
{
if($str === 'Foo')
{
return TRUE;
}
//Don't really want to tell them the User Name is wrong, so use an empty string
$this->set_message('valid_user', '');
return FALSE;
}
/**
* Another "custom" validation method for the Example app
*/
public function valid_password($str)
{
if($str === "Bar")
{
return TRUE;
}
//Don't really want to tell them the pasword is wrong, so we use an empty string
$this->set_message('valid_password', '');
return FALSE;
}
}
Prg_example.php is a controller to demonstrate using MY_Form_validation to implement the Post/Redirect/Get pattern
<?php
/**
* A controller to demonstrate usage of MY_Form_validation
* The index() method shows a typical "Sign In" screen and
* uses two custom rule validation methods
* defined in the version of MY_Form_validation shown above.
*
* index() also makes an additional "message" available to the
* "view" when sign in fails.
*
*/
defined('BASEPATH') OR exit('No direct script access allowed');
class Prg_example extends CI_Controller
{
public function __construct()
{
parent::__construct();
$this->load
->library('form_validation') //Do you know that 'form_validation' loads the Form helper? It's true.
->helper('url');
$this->form_validation->set_error_delimiters('<span class="error">', '</span>');
}
/**
* Presents a typical Sign In screen.
* I have put the HTML for the page here instead of using a "view" file.
* Yes, that breaks the MVC pattern, but this IS only an example.
*/
public function index()
{
//Here we use the return to set the extra "message" for the view
if($this->form_validation->has_failed_validation())
{
$message = $this->session->message;
}
$usernameField = array(
'name' => 'username',
'label' => 'User Name',
'placeholder' => "Foo is correct",
'value' => $this->form_validation->set_value('username'),
);
$passwordField = array(
'name' => 'password',
'label' => 'Password',
'placeholder' => "Bar is correct",
'value' => $this->form_validation->set_value('password'),
);
?>
<!DOCTYPE html>
<html>
<head>
<title>Login Example</title>
<style>
div{ padding-top: .5em; }
.error {color: red; }
</style>
</head>
<body>
<h4>Sign In</h4>
<span class="error">*</span>Required
<?= form_open('prg_example/login_process'); ?>
<div>
<label>User Name:<span class="error">*</span></label>
<div>
<?php
echo form_input($usernameField);
echo form_error($usernameField['name']);
?>
</div>
</div>
<div>
<label>Password:<span class="error">*</span></label>
<div>
<?php
echo form_password($passwordField);
echo form_error($passwordField['name']);
?>
</div>
</div>
<div>
<?= form_submit('submit', 'Submit'); ?>
<span class="error"><?= isset($message) ? $message : ""; ?></span>
</div>
<?= form_close(); ?>
</body>
</html>
<?php
}
/**
* The "action" for the Sign In form is the POST part of PRG
*/
public function login_process()
{
//A custom error message for required fields
$required_err = ['required' => '<em>{field}</em> required.'];
$validation_rules = [
[
'field' => 'username',
'label' => 'User Name',
// Cascading multiple rules 'piped' together in a string
'rules' => 'trim|required|valid_user',
// An error message is needed for the valid_user() method,
// but we don't actually want to display anything.
'errors' => $required_err
],
[
'field' => 'password',
'label' => 'Password',
//Cascading multiple rules using an array
'rules' => ['trim', 'required', 'valid_password'],
'errors' => $required_err
]
];
$this->form_validation->set_rules($validation_rules);
if($this->form_validation->run())
{
// Hurray! Valid fields.
// Do other processing here as required
// GET the success page via REDIRECT
redirect('prg_example/login_success', 'refresh', 303);
}
//Oops, failed. Setup an additional message for the login screen
$_SESSION['message'] = "Log in Failed";
$this->session->mark_as_flash('message');
// GET the sign in page
redirect('prg_example', 'refresh', 303);
}
/**
* A place to go when login() succeeds
*/
public function login_success()
{
echo "In a real app you would be logged in now";
}
}