Creating a custom codeigniter validation rule - php

I have a function in my login form that checks if the email and password match the values in the database and if so it logs the user into the system.
I would like to display a validation error if this function returns false.
My problem is that I am unsure how to go about creating this. The message relates to both the password and email fields so I would not want a rule for each input field just display a single message.
I have tried using flashdata to achieve this but it only works when the page has been refreshed.
How can I created a new validation rule solely for the function $this->members_model->validate_member() ??
$this->form_validation->set_error_delimiters('<div class="error">', '</div>');
$this->form_validation->set_rules('email_address', '"Email address"', 'trim|required|valid_email');
$this->form_validation->set_rules('password', '"Password"', 'trim|required');
if ($this->form_validation->run() == FALSE)
{
$viewdata['main_content'] = 'members/login';
$this->load->view('includes/template', $viewdata);
}
else
{
if($this->members_model->validate_member())
{

You use the callback_ in your rules, see callbacks, for ex.
$this->form_validation->set_rules('email_address', '"Email address"', 'trim|required|valid_email|callback_validate_member');
and add the method in the controller. This method needs to return either TRUE or FALSE
function validate_member($str)
{
$field_value = $str; //this is redundant, but it's to show you how
//the content of the fields gets automatically passed to the method
if($this->members_model->validate_member($field_value))
{
return TRUE;
}
else
{
return FALSE;
}
}
You then need to create a corresponding error in case the validation fails
$this->form_validation->set_message('validate_member','Member is not valid!');

One best way to achieve this is extending CodeIgniter’s Form Validation library. Let say we want to create a custom validator named access_code_unique for the field access_code of the database table users.
All you have to do is creating a Class file named MY_Form_validation.php in application/libraries directory. The method should always return TRUE OR FALSE
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class MY_Form_validation extends CI_Form_validation {
protected $CI;
public function __construct() {
parent::__construct();
// reference to the CodeIgniter super object
$this->CI =& get_instance();
}
public function access_code_unique($access_code, $table_name) {
$this->CI->form_validation->set_message('access_code_unique', $this->CI->lang->line('access_code_invalid'));
$where = array (
'access_code' => $access_code
);
$query = $this->CI->db->limit(1)->get_where($table_name, $where);
return $query->num_rows() === 0;
}
}
Now you can easily add your new created rule
$this->form_validation->set_rules('access_code', $this->lang->line('access_code'), 'trim|xss_clean|access_code_unique[users]');

Related

Problems extending CI library Form_validation

I have tried to extend the Form_validation library from Codeigniter with no success.
I have two functions that I'd like in this extended class but when the validation is run i get these messages in the log:
DEBUG - 06-07-2016 11:20:33 --> Unable to find validation rule: checkAccountnameForUpdate
DEBUG - 06-07-2016 11:20:33 --> Unable to find validation rule: checkEmailForUpdate
Here is my extended class which is placed in
application/libraries
<?php defined('BASEPATH') OR exit('No direct script access allowed');
class MY_Form_validation extends CI_Form_validation
{
public function __construct($rules = array())
{
// Pass the $rules to the parent constructor.
parent::__construct($rules);
// $this->CI is assigned in the parent constructor, no need to do it here.
}
public function checkAccountnameForUpdate($accountname, $id)
{
return 1;
}
public function checkEmailForUpdate($email, $id)
{
return 1;
}
}
And here's my rules:
$this->form_validation->set_rules('editAccountname', 'Brugernavn', 'required|checkAccountnameForUpdate[hiddenField]');
$this->form_validation->set_rules('editEmail', 'Email', 'required|checkEmailForUpdate[hiddenField]');
$this->form_validation->set_message('checkAccountnameForUpdate', 'Test2');
$this->form_validation->set_message('checkEmailForUpdate', 'Test');
// hiddenField is the name of a hiddenField containing the users ID.
I've googled around and tired some different stuff. I have no idea why it doesn't work.
EDIT 1:
I've tried to replace
$this->form_validation->set_rules('editAccountname', 'Brugernavn', 'required|checkAccountnameForUpdate[hiddenField]');
$this->form_validation->set_rules('editEmail', 'Email', 'required|checkEmailForUpdate[hiddenField]');
to
$this->form_validation->set_rules('editAccountname', 'Brugernavn', 'required|checkAccountnameForUpdate');
$this->form_validation->set_rules('editEmail', 'Email', 'required|checkEmailForUpdate');
No changes.
Here is my extension to the validation library. I have left a few functions out as they are site specific but do not affect the demo here.
APPPATH/libraries/MY_Form_validation.php
class MY_Form_validation extends CI_Form_validation
{
public function __construct($rules = array())
{
parent :: __construct($rules);
}
/*
* reformats the input to ###-###-#### and returns formatted string,
* if it cannot accomplish the format (of a non-empty input) it returns FALSE.
*/
public function phone_format($phone)
{
if(empty($phone))
{
//assume an empty field is OK.
//There needs to be a required rule to check a required field and that rule should
//be before this one in the list of rules
return TRUE;
}
$phone = preg_replace('/[^0-9]/', '', $phone);
$newPhone = preg_replace("/([0-9]{3})([0-9]{3})([0-9]{4})/", "$1-$2-$3", $phone);
if(preg_match('/((\d){3})?(\-){1}(\d){3}(\-){1}(\d){4}/', $newPhone))
{
//preg_replace was able to reformat it to the correct pattern - must be good
return $newPhone;
}
return FALSE;
}
/**
* field validation for zipcode
*/
public function check_zipcode($zipcode)
{
$result = (bool) preg_match("/^([0-9]{5})(-[0-9]{4})?$/i", $zipcode);
return $result;
}
}
We can test this class with the simple controller and view shown below. The test uses the phone_format validator function.
A couple things to note about how I'm using form_validation->set_rules().
First, I pass an array of rules instead of the usually demonstrated pipe separated string. eg. "trim|required". Why? Because set_rules() turns the string into an array anyway so why make it do the extra work?
Second. Notice I am passing a fourth argument. The fourth argument is not well documented. Its use is shown in the Setting Error Messages section but it is not described in the Class Reference section of the documentation. The argument accepts an array of error messages in the form ['rule_name' => 'This is the error message'].
I'm also in the habit of using the short syntax to create arrays eg. $this->data = []; instead of $this->data = array(); mostly because it's less typing.
Here's the test controller Testcase.php
class Testcase extends CI_Controller
{
protected $data;
function __construct()
{
parent::__construct();
$this->data = [];
$this->load->library('form_validation');
}
public function test_validation()
{
$this->form_validation->set_rules('phone', 'Phone'
, ['trim', 'required', 'phone_format']
, [
'phone_format' => 'Not a valid phone number.',
'required' => '<em>{field}</em> required.'
]
);
if($this->form_validation->run() == FALSE)
{
$this->load->view('test_form_v', $this->data);
}
else
{
echo "Passed Validation<br>";
echo $_POST['phone'];
}
}
}
And here is the view file test_form_v.php
<?php
echo form_open('testcase/test_validation');
echo form_input('phone', set_value('phone'));
echo form_error('phone');
echo form_submit('Submit', 'Submit');
echo form_close();
Run it by entering this url in a browser your_doman.whatever/testcase/test_validation
Submit without entering any input and you get the required error. Submit "123456789" and you get the invalid phone number error message. Submit "1234567890" and you get
Passed Validation
123-456-7890
This demonstrates that the extend class and its new validator works. I hope this helps you figure out your problem.

Form Validation Won't Work if Load Two Models - CodeIgniter

I have one controller and try to load two models (Usermodel and Contentmodel) and also I need to load Form Validation Library. I use Usermodel to do everything with user such as login and register, and I need Contentmodel to do everything with my web content. At first I was able to login and register and I had no problem with Form Validation Library, but then when I add a line $this->load->model('contentmodel'); to load Contentmodel, I suddenly get this error:
If I remove the line $this->load->model('contentmodel'); everything goes back to normal again.
Controller (Controll.php):
defined('BASEPATH') OR exit('No direct script access allowed');
class Controll extends CI_Controller {
/**
* Index Page for this controller.
*
* Maps to the following URL
* http://example.com/index.php/welcome
* - or -
* http://example.com/index.php/welcome/index
* - or -
* Since this controller is set as the default controller in
* config/routes.php, it's displayed at http://example.com/
*
* So any other public methods not prefixed with an underscore will
* map to /index.php/welcome/<method_name>
* #see http://codeigniter.com/user_guide/general/urls.html
*/
public $lang;
public $logo;
public function __construct () {
parent::__construct();
$this->load->helper('url');
$this->load->helper('form');
$this->load->model('contentmodel');
$this->load->model('usermodel');
$this->load->library('session');
$this->load->library('form_validation');
/*get all user sessions data*/
$this->sesi = $this->session->all_userdata();
$config = $this->contentmodel->load_config();
$this->lang = $config['lang'];
$this->logo = $config['image_logo_path'];
$data['lang'] = $this->lang;
$this->load->view('/header/header');
}
public function panel(){
$this->form_validation->set_rules('email', 'Email', 'required');
$this->form_validation->set_rules('cred', 'Password', 'required');
if($this->form_validation->run() === false){
echo '<center style="position: relative;z-index:10000;font-family: \'Roboto\', sans-serif;color:white;top: 62%;">'.validation_errors().'</center>';
$this->load->view('login');
}else{
$user = $this->usermodel->login();
if($user == 0){
echo '<center class="logerror" style="position: relative;z-index:10000;font-family: \'Roboto\', sans-serif;color:white;top: 62%;">Username or Password incorect. Please try again</center>';
$this->load->view('login');
}else{
$data['data'] = 2;
$data['user'] = $user;
$this->load->view('/header/navbar',$data);
$this->load->view('panel');
$this->load->view('/footer/footer');
}
}
}
And also, if I remove/comment these lines:
$this->form_validation->set_rules('email', 'Email', 'required');
$this->form_validation->set_rules('cred', 'Password', 'required');
/* ... */
if($this->form_validation->run() === false){
/* ... */
}else{
/* ... */
}
Everything goes back to normal again as well.
Please help me. Thanks in advance.
The problem is your $lang variable. As you can see, the Form_validation Library is also using it ($this->CI->lang->load('form_validation');) . Change it to something else, and set it to private. As a rule, any variable inside your controller should be set to private, or else you will have such issues.
You produced a strange problem.Your question title Form Validation Won't Work if Load Two Models - CodeIgniter is wrong.
Form validation library does not stop working how many model you load. You need to find what mistake you do.
Your mistake
#CodeGodie already mentioned why you got that error.Little more addition
If you remove this code $this->lang = $config['lang']; from your controller construct function it will work
why?
Codeigniter's controller uses $lang as an object of CI_Lang class.Form validation class uses(look inside the file and the line number that your error message gave) that variable and it should be object of CI_Lang. But you replacing it as string at your controller construct function that's why you got that error.
On your form validation run part you use === try only with ==
`if($this->form_validation->run() === false){`
replace with.
`if($this->form_validation->run() == false){`
Also You have quite a bit in the construct area.
Auto load url and form helper
Don't load a view in __construct area bad practice I think
Controller With Callback
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class Controll extends CI_Controller {
public function __construct () {
parent::__construct();
$this->load->helper('url'); // Autoload it
$this->load->helper('form'); // Autoload it
$this->load->library('session'); // Autoload it
$this->load->model('contentmodel');
$this->load->model('usermodel');
$this->load->library('form_validation');
// Removed View From Construct not good idea to have in construct area.
}
// change panel to index.
public function index() {
$this->form_validation->set_rules('email', 'Email', 'required|callback_user_login');
$this->form_validation->set_rules('cred', 'Password', 'required');
if ($this->form_validation->run() == TRUE) {
// You could redirect to another controller once login
redirect('success_page');
}
// http://www.codeigniter.com/userguide2/general/views.html
// If not data pass through these views then you will need to use
// something like $this->load->view('header', null, true);
// or with data $this->load->view('header', $data, true);
$this->load->view('header', null, true);
//$this->load->view('header', $data, true);
$this->load->view('login'); // if you need to pass data through to login page then $this->load->view('login', $data);
$this->load->view('footer', null, true);
//$this->load->view('footer', $data, true);
}
public function user_login() {
$user = $this->usermodel->login();
if ($user == TRUE) {
return TRUE;
} else {
$this->form_validation->run('user_login', 'Incorrect Username Or Password');
return FALSE;
}
}
}
On your view then echo the validation messages
<?php echo validation_errors(); ?>
CI2 http://www.codeigniter.com/userguide2/libraries/form_validation.html
CI3 http://www.codeigniter.com/user_guide/libraries/form_validation.html

CodeIgniter: How to put custom validation function in model instead of controller?

In CI's documentation, it says that you could create your own custom validation for use in form submission check. It shows how this can be done in a controller:
http://ellislab.com/codeigniter%20/user-guide/libraries/form_validation.html
But what if I want to have my custom validation function in a model?
I've found that the following did not work...
BOTH FUNCTIONS BELOW ARE IN A MODEL:
public function validate_form(){
$this->form_validation->set_rules('username', 'Username', 'callback_illegal_username_check');
$this->form_validation->run();
}
And here's my custom validation function:
public function illegal_username_check($string){
if($string == 'fcuk'){
$this->form_validation->set_message('illegal_username_check', 'Looks like you are trying to use some swear words in the %s field');
return FALSE;
}
else{
return TRUE;
}
}
I found that because my custom validation function is in the model, it did not get called when I run my "validate_form()" function. How do I resolve this?
Many thanks in advance!
You should put custom validation rules in a MY_Form_validation.php in the application/libraries folder.
Then, when you assign your rules you can do something like this..
$this->form_validation->set_rules('field1', 'Field one name', 'trim|required|xss_clean|your_custom_validator');
Note the custom validator doesn't require the callback_ keyword in front.
Here's an example My_Form_valdation.php file.
class MY_Form_validation extends CI_Form_validation {
function __construct($rules = array()) {
parent::__construct($rules);
$this->ci = & get_instance();
$this->ci->load->database();
}
function your_custom_validator($val) {
$this->set_message('your_custom_validator', 'this isn\'t right!');
return (!$val) ? FALSE : TRUE;
}
Note in the construct I've got the Ci instance and loaded the database class.
To use it i'd do something like this..
$this->ci->db->where('id', 1)->get('user')->row();

codeigniter - pass messages to view

I am new to codeigniter. I have a controller users which loads a login view.
class user extends CI_Controller {
function __construct()
{
parent::__construct();
$this->load->helper(array('form'));
}
public function login()
{
$this->load->model('user_images');
$data = $this->load->model('login');
$this->load->view('login', $data);
}
}
In the login model I handle all the validation and processing. If there is a validation error or the like I return $data['msg'] = 'some error message'; I pass this data via $data = $this->load->model('login'); to $this->load->view('login', $data); and in view I echo $msg. However upon submission the form processes, if I enter the correct credentials I get logged in, however if I enter some wrong credentials the validation errors do not get passed to the view. I am moving this project over from an non-framework environment, so I am sure that the validation rules work .etc. I am just not sure why the messages are not getting parsed on the view.
It looks like you are getting this wrong
$data = $this->load->model('login');
The load->model() loads the login_model and makes it methods available via
$this->login->youMethodHere().
f there is a validation error or the like I return $data['msg'] = 'some error message'; I pass this data via $data = $this->load->model('login'); to $this->load->view('login', $data);
When you return something from a method/function you do not return the variable. You return the value of the variable.
You should add you method to the login_model (perhaps this should be user_model...) and return ex. an array or mysqli result set from the model. Depeanding on what the models returns you should set the data.
$this->load->model('user_model');
$login_succes = $this->user_model->login($username, $password);
if( $login_success )
{
$data['msg'] = 'hurrah you did it
...

Codeigniter HMVC MY_Form_validation from library

Whatever I do I cant seem to use the dob function in my MY_Form_validation... please note the _register_verify is inside my User library, and not a controller, so I'm using $CI and not $this...
<?php
/** application/libraries/MY_Form_validation **/
class MY_Form_validation extends CI_Form_validation
{
public $CI;
function __construct( $config = array() )
{
parent::__construct($config);
log_message('DEBUG', 'MY FORM VALIDATION Initialized!!');
}
// --------------------------------------------------------------------
public function dob($dob)
{
$CI =& get_instance();
$CI->form_validation->set_message('dob[]_check', 'Please enter a valid DOB');
show_error('I AM AN ERROR');
}
This is the function in my User Library...
public function _register_verify($testmode = FALSE)
{
if ($testmode) return TRUE;
$CI =& get_instance();
$CI->load->library('form_validation');
$CI->form_validation->CI =& $CI;
$CI->form_validation->set_rules('dob[]', 'DOB', 'trim|dob');
if ($CI->form_validation->run() == FALSE)
{
// What to do if user details are NOT correct?
$CI->session->set_flashdata('dob_error', form_error('dob[]'));
return FALSE;
} else {
return TRUE;
}
}
I'v tried extending the MY_Form_validation and nothing else and it still doesnt work. And most of the turotials i've found call the form_validation from a controller.
I have checked the log and the log message is not there and no error shows.
EDIT: Managed to get the class initialized, however the dob never gets called
Functions inside of MY_Form_Validation.php should return boolean values that give the outcome of the test.
public function dob($dob){
//not perfect, but, returns true if date matches 12/10/1999 for example.
return preg_match("/^[0-9]{2}\/[0-9]{2}\/[0-9]{4}$/", $dob);
}
Make sure you've set dob as a rule either in you controller, or in your config file, depending on how you've set things up:
$this->load->library('form_validation');
$this->form_validation->set_rules('dob', 'date of birth', 'required|dob');
Errors are handled in application/language/english/form_validation_lang.php. Add:
$lang['dob'] = "Oops, wrong DOB format.";
Lastly, please run your form validations inside your controller, not a library, or model. There is no need to call get_instance() and assign to $CI in this use-case.

Categories