I am trying to add a captcha for my login form in codeigniter.
The captcha is displaying fine. and problem is in verifying it.
When validate_captcha is being called the value from input post is correct but session value is new page value.(For example , if on the 1st page load captcha was 12345 (let's assume in second load it will be 54321) . then when in first load user inputs 12345 it will be checked with 54321.
What can I do?
Here is what I have tried
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Login extends CI_Controller
{
public function index()
{
$capCode = rand(10000, 99999);
$this->session->set_userdata(array('captcha'=>$capCode));
echo $this->session->userdata['captcha'];//for debug only
$this->load->helper('captcha');
$vals = array(
'word' => $capCode ,
'img_path' => CAPTCHA_PATH,
'img_url' => base_url().CAPTCHA_PATH,
'img_width' => '150',
'img_height' => 30,
'expiration' => 1200
);
$cap = create_captcha($vals);
$data = array('un' => $un,'defTab'=>'','captcha'=>$cap);
$this->load->library('form_validation');
//I need to load different data if form is result of a post($data['defTab'])
if($this->input->post('submit'))
{
$this->form_validation->set_rules('email', 'Email', 'required|valid_email');
$this->form_validation->set_rules('captcha', 'Captcha', 'required|callback_validate_captcha');
if ($this->form_validation->run() == FALSE)
{
$data['defTab'] = 'what i need';
$this->load->view('login',$data);
}
else
{
print_r($this->input->post());
}
}
else
{
$this->load->view('login',$data);
}
}
public function validate_captcha()
{
$sss=$this->input->post('captcha');
//I Use this line to find problem
$this->form_validation->set_message('validate_captcha', 'session:'.$this->session->userdata['captcha'].'\nPosted val:'.$sss);
if($sss!= $this->session->userdata['captcha'])
{
return false;
}
else
{
return true;
}
}
}
You have to set the session during creation of your form:
.
.
.
} else {
if (isset($cap["word"])) {
$this->session->set_userdata("word", $cap["word"]);
}
$this->load->view('login',$data);
}
And during the validation check it with:
if($this->input->post("word", TRUE) == $this->session->userdata("word")){
// do something
}
Before calling the create_captcha method use the below code to set the previous captcha
$this->session->set_userdata('prev_captcha',$this->session->userdata('captcha_word'));
provided captcha_word contains current captcha
and check like below
function checkCaptcha($str){
$word = $this->session->get('prev_captcha');
if(strcmp(strtoupper($str),strtoupper($word)) == 0){
return true;
}else{
return false;
}
}
Related
I am unable to get the callable form validation feature of CodeIgniter 3 to work when the validation rules are placed in a separate config file.
I am getting the following error message:
A PHP Error was encountered
Severity: Notice
Message: Undefined property: CI_Config::$form_validation_callback_library
The config file with the form validation rules are as follows (config/fvalidation.php):
$config['client_details'] = array(
array(
'field' => 'client_abn',
'label' => 'Client ABN',
'rules' => array('trim', 'required', array('abn_callable', array($this->form_validation_callback_library, 'abn_check'))),
'errors' => array('abn_callable' => 'Invalid ABN has been entered %s.')
)
);
The form validation class attempting to be called is (i.e. $this->form_validation_callback_library):
class Form_validation_callback_library
{
public function abn_check()
{
$this->load->library('abn_validator');
$abn = $this->input->post_get('abn', TRUE);
if (!$this->abn_validator->isValidAbn($abn)) {
return FALSE;
}
return TRUE;
}
}
The controller is:
$this->config->load('fvalidation');
$validation_rules = $this->config->item('client_details');
$this->form_validation->set_rules($validation_rules);
if ($this->form_validation->run() == FALSE) {
// show form
} else {
// process form data
}
Any help would be greatly appreciated.
Cheers,
VeeDee
I would use codeigniter callback example below callback
http://www.codeigniter.com/user_guide/libraries/form_validation.html#callbacks-your-own-validation-methods
<?php
class Example extends CI_Controller {
public function index() {
$this->load->library('form_validation');
$this->form_validation->set_rules('client_abn', 'ABN Number', 'required|callback_checkabn');
if ($this->form_validation->run() == FALSE) {
$this->load->view('something');
} else {
// Redirect to success page i.e login or dashboard or what ever
redirect('/'); // Currently would redirect to home '/'
}
}
public function checkabn() {
$this->load->library('abn_validator');
$abn = $this->input->post('abn');
if (!$this->abn_validator->isValidAbn($abn)) {
$this->form_validation->set_message('checkabn', 'Invalid ABN has been entered %s.');
return FALSE;
} else {
return TRUE;
}
}
}
And on your view in or above form add
<?php echo validation_errors('<div class="error">', '</div>'); ?>
<form action="<?php echo base_url('example');?>" method="post">
<input type="text" name="client_abn" placeholder="" value="" />
</form>
This is a most common problem we face when we run custom form validation in CI. Whether the callback function is in the same controller or it is in the a library of callback function we need to pass the accessible object of the class containing the callback function.
So when your run the
$callable_validations = new Form_validation_callback_library();
$this->form_validation->run($callable_validations)
Looks like this is not possible currently on CodeIgniter 3.
I have created a crude workaround.. so please go ahead an improve it because it doesn't look pretty :)
Update the config file like so (/config/fvalidation.php):
$config['client_details'] = = array(
array(
'field' => 'client_abn',
'label' => 'Client ABN',
'rules' => array('trim', 'required', array('abn_callable', array("library:form_validation_callback_library", 'abn_check'))),
'errors' => array('abn_callable' => 'Invalid %s has been entered .')
)
);
Note the following line in the config file above as we will be using them as flags in the controller code:
array('abn_callable', array("library:form_validation_callback_library", 'abn_check'))
The Library is pretty much the same except we load the instance (/libraries/Form_validation_callback_library.php):
class Form_validation_callback_library
{
private $_CI;
function Form_validation_callback_library() {
$this->_CI =& get_instance();
log_message('info', "Form_validation_callback_library Library Initialized");
}
public function abn_check($abn)
{
$this->_CI->load->library('abn_validator');
if (!$this->_CI->abn_validator->isValidAbn($abn)) {
return FALSE;
}
return TRUE;
}
}
In the controller we load the library (/controllers/Foo.php):
// load the config file and store
$this->config->load('fvalidation', TRUE);
$rule_dataset = $this->config->item('client_details', 'fvalidation');
// search and load the 'callable' library
foreach ($rule_dataset as $i => $rules) {
if (isset($rules['rules'])) {
foreach ($rules['rules'] as $k => $rule) {
if (is_array($rule) && preg_match("/_callable/",$rule[0]) && isset($rule[1][0])) {
list ($load_type, $load_name) = explode(":", $rule[1][0]);
// load the library
$this->load->$load_type($load_name);
$rule_dataset[$i]['rules'][$k][1][0] = $this->$load_name;
}
}
}
}
// set the rules
$this->form_validation->set_rules($rule_dataset);
// load the form
if ($this->form_validation->run() == FALSE) {
// show form
} else {
// process form data
}
I did something similar to Vidura, but extended the Form Validation library by adding MY_Form_validation.php with the following code
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class GS_Form_validation extends CI_Form_validation {
public function set_rules($field, $label = '', $rules = array(), $errors = array())
{
if (is_array($rules))
{
foreach ($rules as &$rule)
{
if (is_array($rule))
{
if (is_array($rule[1]) and is_string($rule[1][0]))
{
// handles rule like ['password_check', ['library:passwords', 'check_valid_password']]
// You would set_message like $this->form_validation->set_message('password_check', 'Incorrect password');
// The advantage of defining the rule like this is you can override the callback functions error message
list ($load_type, $load_name) = explode(":", $rule[1][0]);
$CI =& get_instance();
$CI->load->$load_type($load_name);
$rule[1][0] = $CI->$load_name;
}
else if (is_string($rule[0]))
{
// handles rule like ['library:password', 'check_valid_password']
// You would set_message like $this->form_validation->set_message('check_valid_password', 'Incorrect password');
list ($load_type, $load_name) = explode(":", $rule[0]);
$CI =& get_instance();
$CI->load->$load_type($load_name);
$rule[0] = $rule[1];
$rule[1] = [$CI->$load_name, $rule[1]];
}
}
}
}
return parent::set_rules($field, $label, $rules, $errors);
}
}
Then you can define callbacks to library functions like:
$this->form_validation->set_rules(['library:passwords', 'check_valid_password']);
Where passwords is the library and check_valid_password is the method.
I've simply do (config/form_validation.php):
$CI =& get_instance();
$CI->load->model('form_validation_callback_library');
$config['client_details'] = array(
array(
'field' => 'client_abn',
'label' => 'Client ABN',
'rules' => array('trim', 'required', array('abn_callable', array($CI->form_validation_callback_library, 'abn_check'))),
'errors' => array('abn_callable' => 'Invalid ABN has been entered %s.')
)
And it works to me...
I'm running on Codeigniter 3.0.4
note : everything going well when I try in Localhost.
So I have a problem when I want to call my do_login controller in my login form.
this is my controller :
<?php
if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Do_login extends CI_Controller {
public function __construct()
{
parent::__construct();
$this->load->model('login_model', '', TRUE);
}
public function index()
{
$this->load->library('form_validation');
$this->form_validation->set_rules('email', 'email', 'trim|required');
$this->form_validation->set_rules('password', 'password', 'trim|required|callback_check_database');
if($this->form_validation->run() == FALSE)
{
$this->load->view('admin/login_view');
}
else
{
redirect('home', 'refresh');
}
}
public function check_database($password)
{
$email = $this->input->post('email', TRUE);
$result = $this->login_model->check_login($email, $password);
if($result)
{
$sess_array = array();
foreach($result as $row)
{
$sess_array = array(
'user_id' => $row->user_id,
'email' => $row->email
);
$this->session->set_userdata('logged_in', $sess_array);
}
return TRUE;
}
else
{
$this->form_validation->set_message('check_database', 'Email / Password salah');
return FALSE;
}
}
}
?>
this is my view :
<?php
$attributes = array('class' => 'form-signin', 'id' => 'myform');
echo form_open('do_login', $attributes);
?>
When I try it in Localhost, everything going well and smooth.
But when I try in my web server, everytime I submit the login form, I directed into 404.
Thanks for your help :)
Check your file names Because it happens with me that different case file name was worked on localhost but not on server.
So check it once.
I am working with Codeigniter. I have a controller with the method named login which takes the form data and checks if user exists?, upon success it loads another view. But when I click the refresh button in my browser the method in my controller re-executes, I want to prevent the re-submission of form data. Kindly Help me. Also please suggest me how it should behave normally,whether it should just prevent the re-submission of form and stay insane or should it redirect to login screen.
here is the code :
Login Controller
<?php
class Login extends CI_Controller {
/**
*
* load the Models
*/
function __construct() {
parent::__construct();
$this->load->library('form_validation');
$this->load->model('User');
// $this->session->set_flashdata('success','data posted');
$this->load->library('session');
$this->load->helper('url');
}
public function index() {
$this->load->view('login');
}
/**
*
* Log in a user
*/
public function login() {
$this->form_validation->set_rules(array(
array(
'field' => 'username',
'label' => 'username',
'rules' => 'required|is_numeric|max_length[1]|min_length[1]',
),
array(
'field' => 'password',
'label' => 'password',
'rules' => 'required|is_numeric|max_length[1]|min_length[1]',
),
));
$this->form_validation->set_error_delimiters('<div class="alert alert-error">', '</div>');
//GETTING ID AND PASSWORD FROM THE FORM
$id = $this->input->post('username') . "<br>";
$password = $this->input->post('password') . "<br>";
//check if user exists
$user = new User();
$user_exists = $user->user_exists($id, $password);
//validate the user input
$validated = $this->form_validation->run();
if (!$validated) {
$this->load->view('login');
} else {
if ($user_exists) {
//use php function to pickup the current year from the pc
//set your min to 01-01-current year and your max to 31-12-current year
$min = strtotime(date('Y') . "-01-01");
$max = strtotime(date('Y') . "-12-31");
$date = rand($min, $max);
$dec2 = strtotime('2014-12-02');
$randomDate = date('Y-m-d', $date);
echo "random date:" . $randomDate . "<br>";
$date_timestamp = strtotime($randomDate);
if ($date_timestamp >= $dec2) {
$is_updated = $user->is_holiday_updated();
if (!$is_updated) {
// $user->update_national_holidays();
echo "holiday table updated";
} else {
echo "already updated the table";
}
} else {
echo "no update required";
}
$this->load->view('national_holiday_screen');
} else {
$this->load->view('login');
}
}
}
}
here is the View:
<h2> National Holiday Screen </h2>
You have to do like the following steps
in your model You have to create Method to check the username and password and in my example i will call that method Valid($username,$password);
this method will return true if matching db and false if not .
in your controller .
public function login()
{
// check if button is clicked by
if(isset($_POST['loginButton'])){
// check if username and password is correct
if($model->valid($this->input>post('username'),$this->input>post('password')){
//redirect to admin page
}else{
//load login form template
}
}else{
// load your login form template here
}
}
well , the main point here is that , to remove the post submitting from browser you have to redirect the user to another page as above example .
Note : your issue is with if statement you are displaying the template at end of the controller , you have to display the template base on if statement .
I want to limit my registration to emails with #mywork.com I made the following in My_Form_validation.
public function email_check($email)
{
$findme='mywork.com';
$pos = strpos($email,$findme);
if ($pos===FALSE)
{
$this->CI->form_validation->set_message('email_check', "The %s field does not have our email.");
return FALSE;
}
else
{
return TRUE;
}
}
I use it as follows. I use CI rules for username and password and it works, for email it accepts any email address. Any I appreciate any help.
function register_form($container)
{
....
....
/ Set Rules
$config = array(
...//for username
// for email
array(
'field'=>'email',
'label'=>$this->CI->lang->line('userlib_email'),
'rules'=>"trim|required|max_length[254]|valid_email|callback_email_check|callback_spare_email"
),
...// for password
);
$this->CI->form_validation->set_rules($config);
The problem with creating a callback directly in the controller is that it is now accessible in the url by calling http://localhost/yourapp/yourcontroller/yourcallback which isn't desirable. There is a more modular approach that tucks your validation rules away into configuration files. I recommend:
Your controller:
<?php
class Your_Controller extends CI_Controller{
function submit_signup(){
$this->load->library('form_validation');
if(!$this->form_validation->run('submit_signup')){
//error
}
else{
$p = $this->input->post();
//insert $p into database....
}
}
}
application/config/form_validation.php:
<?php
$config = array
(
//this array key matches what you passed into run()
'submit_signup' => array
(
array(
'field' => 'email',
'label' => 'Email',
'rules' => 'required|max_length[255]|valid_email|belongstowork'
)
/*
,
array(
...
)
*/
)
//you would add more run() routines here, for separate form submissions.
);
application/libraries/MY_Form_validation.php:
<?php
class MY_Form_validation extends CI_Form_validation{
function __construct($config = array()){
parent::__construct($config);
}
function belongstowork($email){
$endsWith = "#mywork.com";
//see: http://stackoverflow.com/a/619725/568884
return substr_compare($endsWith, $email, -strlen($email), strlen($email)) === 0;
}
}
application/language/english/form_validation_lang.php:
Add: $lang['belongstowork'] = "Sorry, the email must belong to work.";
Are you need validation something like this in a Codeigniter callback function?
$this->form_validation->set_rules('email', 'email', 'trim|required|max_length[254]|valid_email|xss_clean|callback_spare_email[' . $this->input->post('email') . ']');
if ($this->form_validation->run() == FALSE)
{
// failed
echo 'FAIL';
}
else
{
// success
echo 'GOOD';
}
function spare_email($str)
{
// if first_item and second_item are equal
if(stristr($str, '#mywork.com') !== FALSE)
{
// success
return $str;
}
else
{
// set error message
$this->form_validation->set_message('spare_email', 'No match');
// return fail
return FALSE;
}
}
A correction to Jordan's answer, the language file that you need to edit should be located in
system/language/english/form_validation_lang.php
not application/.../form_validation_lang.php. If you create the new file under the application path with the same name, it will overwrite the original in the system path. Thus you will lose all the usage of the original filters.
What I want to implement is a simple login page, if user login successfully, then redirect to main page, else remain login page.
I have 1 controller named login, and 1 model named main.
When user click the login button, the login/login_send will be called.
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Login extends CI_Controller{
function __construct() {
parent::__construct();
$this->load->model('model_login');
}
function index()
{
if ($this->model_login->is_logged_in())
{
redirect('main');
}
else
{
// load login page
$data['main'] = 'view_login';
$data['style'] = 'style_login';
$this->load->view('template', $data);
}
}
function login_send()
{
$this->form_validation->set_rules('username', 'Username', 'trim|required');
$this->form_validation->set_rules('password', 'Password', 'trim|required');
if ($this->form_validation->run() == FALSE)
{
$this->index();
}
else
{
if ( $this->model_login->validate_user() )
{
$user_session_data = array(
'username' => $this->input->post('username'),
'is_logged_in' => 1
);
$this->session->set_userdata($user_session_data);
redirect('main');
}
else
{
redirect('login');
}
}
}// end function login_send
function logout()
{
if ($this->model_login->is_logged_in())
{
$this->session->sess_destroy();
$this->session->set_userdata(array('username' => '', 'is_logged_in' => 0));
log_message('debug', 'Some variable was correctly set');
}
redirect('login','refresh');
}
}// end class Login
?>
Model_login here is just to help to verify if user is logged in, by check the session data.
<?php
class Model_login extends CI_MOdel{
function _isUserExist($username, $password)
{
$options = array(
'UserName' => $username,
'Password' => $password
);
$query = $this->db->get_where('userinfo', $options);
return $query->num_rows() > 0;
}
function validate_user()
{
$username = $this->input->post('username');
$password = $this->input->post('password');
return ($this->_isUserExist($username, $password));
}
function is_logged_in()
{
$is_logged_in = $this->session->userdata('is_logged_in');
if ( !isset($is_logged_in) || $is_logged_in != 1 ) return FALSE;
else return TRUE;
}
}// end class model_login
?>
When first time login, and then logout, there is no problem. However, if I login second time, I can not log out. Even the login/logout was called correctly, I also refreshed the page, but the session['is_logged_in'] == 1. Something wrong with my code?
In your application/config/config.php try changing
$config['sess_time_to_update'] = 300; //This is the default setting in ver 2.1.1
to
$config['sess_time_to_update'] = 0;
This gave me some problems a few years back