CodeIgniter Form Validation Class - Handling errors - php

So I have made a form with CodeIgniter and it does uses CodeIgniter's form validation
class to validate input fields. I have a total of 6 input fields which all are
required fields.
I would like to show the same error of "This field is required" even
if there are multiple empty fields, but right now it will show the error message for each
of the fields. So if I leave every field empty, it will echo the same message 6 times.
I won't paste any code here since I know how to use the actual validation class, just
don't know how to implement it in a way as said above.
Thanks in advance!
E: Now comes another problem, it doesn't show any errors, in fact the whole method will fail right after it's checking if the "add_user" button is submitted. I'm 100% sure that the name of my submit button is "add_user".
Sorry about bad indenting, I'll never learn how to use StackOverflow's indenting.
Here's my controller for adding a user:
<?php
class Users extends CI_Controller {
public function add_user()
{
if($this->input->post('add_user'))
{
$this->load->model('subject');
$data['subjects'] = $this->subject->get_all_subjects();
$data['schools'] = $this->subject->get_all_schools();
$this->load->library('form_validation');
$this->form_validation->set_rules('f_name', 'Etunimi', 'required');
$this->form_validation->set_rules('l_name', 'Sukunimi', 'min_length[3]');
$this->form_validation->set_rules('email', 'Sähköpostiosoite', 'matches[email_confirm]|is_unique[users.email]|valid_email');
$this->form_validation->set_rules('email_confirm', 'Sähköpostiosoite', 'valid_email');
$this->form_validation->set_rules('phone_number', 'Puhelinnumero', 'min_length[7]|max_length[10]');
if($this->input->post('user_type') == "moderator")
{
$this->load->library('form_validation');
$this->form_validation->set_rules('school', 'Koulutalo', 'required');
$this->form_validation->set_rules('subject', 'Laji', 'required');
}
$this->form_validation->set_message('required', 'Täyttämättömiä kenttiä');
$this->form_validation->set_message('min_length', '%s - kentässä on liian vähän merkkejä');
$this->form_validation->set_message('matches', 'Sähköpostit eivät täsmää');
$this->form_validation->set_message('is_unique', '%s on jo rekisteröity');
if($this->form_validation->run() == FALSE)
{
$this->output->set_content_type('application_json');
$this->output->set_output(json_encode(array('result' => 0, 'error' => $this->form_validation->error_array() )));
return false;
}
$first_part_username = substr($this->input->post('f_name'), 0, 2);
$second_part_username = substr($this->input->post('l_name'), 0, 3);
$first_part_username = strtolower($first_part_username);
$second_part_username = strtolower($second_part_username);
$this->load->helper('string');
$random_number = random_string('numeric', 4);
$username = $first_part_username . $second_part_username .$random_number;
$password = random_string('alnum', 8);
$this->load->model('user');
$name = ucfirst($this->input->post('f_name')). " " .ucfirst($this->input->post('l_name'));
$data = array (
'name' => $name,
'email' => $this->input->post('email'),
'username' => $username,
'password' => $this->phpass->hash($password),
'user_type' => $this->input->post('user_type'),
'phone_number' => $this->input->post('phone_number'),
'subject_id' => !($this->input->post('subject')) ? null : $this->input->post('subject'),
'school_id' => !($this->input->post('school')) ? null : $this->input->post('school')
);
$this->user->add_user($data);
$this->load->library('email');
$config['mailtype'] = 'html';
$this->email->initialize($config);
$this->email->from('your#example.com', 'Your Name');
$this->email->to($this->input->post('email'));
$this->email->subject('test test');
$this->email->message('Test');
if($this->email->send()) {
$this->output->set_content_type('application_json');
$this->output->set_output(json_encode(array('result'=>1, 'msg' => 'Uusi käyttäjä lisätty')));
}
}
/* It will echo out this one which is viewable from developer tab right after the form is submitted */
$this->output->set_content_type('application_json');
$this->output->set_output(json_encode(array('result'=>1, 'msg' => 'Form not submitted')));
}
}
?>
And the javascript:
$(document).ready(function() {
$("#add_user_form").on('submit', function(e) {
e.preventDefault();
$("#loading_spinner").show();
var from = $(this);
$.ajax({
url: from.attr('action'),
type: from.attr('method'),
data: $(from).serialize(),
}).done(function(data) {
if(data.result == 0) {
$("#forgot-pass-success").hide();
$("#forgot-pass-error").show();
$("#forgot-pass-error").fadeIn(1000).html("<p>" + data.error + "</p>");
}
if(data.result == 1) {
$("#forgot-pass-error").hide();
$("#forgot-pass-success").show();
$("#forgot-pass-success").fadeIn(1000).html("<p>" + data.msg + "</p>");
}
$("#loading_spinner").hide();
}, 'json');
return false;
});
});

Here is an example that returns the errors in a JSON string to process with jQuery, you have to load the form validation helper.
Load the library:
$this->load->library('form_validation');
/* Outputto Json Format */
$this->output->set_content_type('application_json');
/* Validate Form Data */
$this->form_validation->set_rules('login', 'Username', 'required|min_length[4]|max_length[16]|is_unique[user.login]');
$this->form_validation->set_rules('email', 'Email', 'required|valid_email|is_unique[user.email]');
$this->form_validation->set_rules('password', 'Password', 'required|min_lenght[6]|max_length[16]|matches[confirm_password]');
/* Custom Messages */
$this->form_validation->set_message('required', 'You must enter a %s.');
$this->form_validation->set_message('is_unique', 'That %s is already in use, please try again.');
$this->form_validation->set_message('valid_email', 'You must enter a vaild email address.');
if($this->form_validation->run() == false)
{
$this->output->set_output(json_encode(['result' => 0, 'error' => $this->form_validation->error_array()]));
return false;
}
$login = $this->input->post('login');
$email = $this->input->post('email');
$password = $this->input->post('password');
$confirm_password = $this->input->post('comfirm_password');
$user_id = // DO YOUR QUERY HERE
if($user_id)
{
$this->session->set_userdata(['user_id' => $user_id]);
$this->output->set_output(json_encode(['result' => 1]));
return false;
}
$this->output->set_output(json_encode(['result' => 0, 'error' => 'User not created.']));
EDIT:
Sorry I'm using a custom library to extend the form_validation so I can create arrays to return. Just make sure you save this in your library files as my_form_validation.php
class MY_Form_validation extends CI_Form_validation
{
// ------------------------------------------------------------------------
public function __construct($config = array())
{
parent::__construct($config);
}
// ------------------------------------------------------------------------
public function error_array()
{
if(count($this->_error_array > 0))
{
return $this->_error_array;
}
}
// ------------------------------------------------------------------------
}
EDIT: Example of dealing with this data in jQuery
<!-- Javascript POST -->
<script type="text/javascript">
$(function() {
// You need to create a div called #register_form_error
$("#register_form_error").hide();
// Your register form would go here in place of #regiser_form
$("#register_form").submit(function(evt) {
evt.preventDefault();
var url = $(this).attr('action');
var postData = $(this).serialize();
$.post(url, postData, function(o) {
if (o.result == 1) {
// If the registration was successful where to go.
window.location.href = '<?=site_url('where to go')?>';
} else {
// This is where all of the form errors will be displayed
$("#register_form_error").show();
var output = '<ul>';
for (var key in o.error) {
var value = o.error[key];
output += '<li>' + value + '</li>';
}
output += '</ul>';
$("#register_form_error").html(output);
}
}, 'json');
});
});
</script>
Lastly:
if($this->input->post('add_user'))
Shoud be:
if($this->input->post('$_POST'))
That way you get the entire post array.

Off the top of my head, you could try using individual errors.
In your view:
<?php
$form_errors = array(
form_error('field_1'),
form_error('field_2'),
form_error('field_3'),
form_error('field_4'),
form_error('field_5'),
form_error('field_6')
);
$error = FALSE;
foreach ($form_errors as $form_error)
{
if ( ! empty($form_error))
$error = TRUE;
}
if ($error)
echo "All fields are required".
?>
So basically what you are doing here, is filling an array of individual form errors. form_error() returns an empty string if the field is filled in correctly according to the validation rule, otherwise it will be an error message.
To confirm that everything is filled in correctly, you are looking for an array of empty strings. If a field isn't filled in correctly, your array will contain an element which has an error message.

Related

Captcha in Codeigniter can't verify text

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;
}
}

CodeIgniter TankAuth ajax forms

I am using the lastest version of CodeIgniter and TankAuth and all functions work properly such as login, logout, email and register. Currently when a user needs to login, you are redirected to a separate page, which is, /auth/login.
What I am experimenting with is loading the login page in a modal(using fancybox) instead of requiring the user to leave the current page and having to login.
The problem I am running into is how can I alter the standard TankAuth setup to use ajax to submit the form rather than submitting the form and then redirecting the user.
Here is the code from the auth/login controller:
function login()
{
if ($this->tank_auth->is_logged_in()) { // logged in
redirect('');
} elseif ($this->tank_auth->is_logged_in(FALSE)) { // logged in, not activated
redirect('/auth/send_again/');
} else {
$data['login_by_username'] = ($this->config->item('login_by_username', 'tank_auth') AND
$this->config->item('use_username', 'tank_auth'));
$data['login_by_email'] = $this->config->item('login_by_email', 'tank_auth');
$this->form_validation->set_rules('login', 'Login', 'trim|required|xss_clean');
$this->form_validation->set_rules('password', 'Password', 'trim|required|xss_clean');
$this->form_validation->set_rules('remember', 'Remember me', 'integer');
// Get login for counting attempts to login
if ($this->config->item('login_count_attempts', 'tank_auth') AND
($login = $this->input->post('login'))) {
$login = $this->security->xss_clean($login);
} else {
$login = '';
}
$data['use_recaptcha'] = $this->config->item('use_recaptcha', 'tank_auth');
if ($this->tank_auth->is_max_login_attempts_exceeded($login)) {
if ($data['use_recaptcha'])
$this->form_validation->set_rules('recaptcha_response_field', 'Confirmation Code', 'trim|xss_clean|required|callback__check_recaptcha');
else
$this->form_validation->set_rules('captcha', 'Confirmation Code', 'trim|xss_clean|required|callback__check_captcha');
}
$data['errors'] = array();
if ($this->form_validation->run()) { // validation ok
if ($this->tank_auth->login(
$this->form_validation->set_value('login'),
$this->form_validation->set_value('password'),
$this->form_validation->set_value('remember'),
$data['login_by_username'],
$data['login_by_email'])) { // success
redirect('');
} else {
$errors = $this->tank_auth->get_error_message();
if (isset($errors['banned'])) { // banned user
$this->_show_message($this->lang->line('auth_message_banned').' '.$errors['banned']);
} elseif (isset($errors['not_activated'])) { // not activated user
redirect('/auth/send_again/');
} else { // fail
foreach ($errors as $k => $v) $data['errors'][$k] = $this->lang->line($v);
}
}
}
$data['show_captcha'] = FALSE;
if ($this->tank_auth->is_max_login_attempts_exceeded($login)) {
$data['show_captcha'] = TRUE;
if ($data['use_recaptcha']) {
$data['recaptcha_html'] = $this->_create_recaptcha();
} else {
$data['captcha_html'] = $this->_create_captcha();
}
}
$this->load->view('auth/login_form', $data);
}
}
The code in the view is using php to open and submit the form as such:
<?php
$login = array(
'name' => 'login',
'id' => 'login',
'value' => set_value('login'),
'maxlength' => 80,
'size' => 30,
);
if ($login_by_username AND $login_by_email) {
$login_label = 'Email or login';
} else if ($login_by_username) {
$login_label = 'Login';
} else {
$login_label = 'Email';
}
$password = array(
'name' => 'password',
'id' => 'password',
'size' => 30,
);
$remember = array(
'name' => 'remember',
'id' => 'remember',
'value' => 1,
'checked' => set_value('remember'),
'style' => 'margin:0;padding:0',
);
$captcha = array(
'name' => 'captcha',
'id' => 'captcha',
'maxlength' => 8,
);
?>
<?php echo form_open($this->uri->uri_string()); ?>
<?php echo form_submit('submit', 'Let me in'); ?>
<?php echo form_close(); ?>
Would it be as simple as using a $.ajax request and setting the url to the /auth/login controller?
If that's the case then I assume i would also need to add a return ajax data of (true / false) to the auth/login controller.
Any help would be greatly appreciated.
Ok well I'm totally sure how the codeIgniter works but I will run you through the process of it so you can try and apply it.
Then to send the form you will have to target when the form is submitted. Say this is your form
<form id="target" action="destination.html">
<input type="text" value="Hello there" />
<input type="submit" value="Go" />
</form>
$('#target').submit(function() {
alert('Handler for .submit() called.');
return false;
});
This code will be run when you press the submit button. Caution: make sure return false; to stop the page refreshing.
Inside the submit function you will need to send the POST variables off to the php file that login processes.
$.post('doLogin.php', function(data) {
$('.result').html(data);
});
So it should end up something like this
$('#target').submit(function() {
$.post('doLogin.php', function(data) {
$('.result').html(data);
});
return false;
});
Please take a look at the jQuery API to better learn the jQuery functions.
get function to get the form
see when the form is submitted
jQuery post
That should help you get going

Validating Forms

I have a form that I submit with jQuery ajax and have it being sent to a controller function called submit to validate and do any other tasks I need to with the form data. I'm trying to find out why my form validation library isn't showing an error when the username doesn't contain only lowercase letters and numbers.
$this->form_validation->set_rules('username', 'Username', 'trim|required|xss_clean|strtolower');
POST Value after form submission:
username TestingUSER
EDIT:
As far as I know it gets to the php server side properly.
PHP:
public function submit()
{
$output_status = 'Notice';
$output_title = 'Not Processed';
$output_message = 'The request was unprocessed!';
$this->form_validation->set_rules('username', 'Username', 'trim|required|xss_clean|strtolower');
$this->form_validation->set_rules('password', 'Password', 'trim|required|xss_clean');
$this->form_validation->set_rules('remember', 'Remember Me', 'trim|xss_clean|integer');
if ($this->form_validation->run() == TRUE)
{
}
else
{
$output_status = 'Error';
$output_title = 'Form Not Validated';
$output_message = validation_errors();
}
echo json_encode(array('output_status' => $output_status, 'output_title' => $output_title, 'output_message' => $output_message));
}
EDIT 2:
Based off of Sheikh answer. I am getting a response back that says "Unable to access an error message corresponding to your field name." It does say Form Not Validated for the title so the message isn't working.
public function check_username($str)
{
if (preg_match('#[0-9]#', $str) && preg_match('#[a-z]#', $str))
{
return TRUE;
}
$this->form_validation->set_message('username', 'This is not have an accepted value!');
return FALSE;
}
EDIT 3:
What I'm wanting to do is have it report back that there there are validation errors but not the specific errors in the pnotify response. However I do want it to display the specific errors under the form elements.
jQuery Code:
http://pastebin.com/1KehMJkh
Login Form:
http://pastebin.com/EfpBfbfN
I think you can use a callback function in your controller
public function check_username($str)
{
if (preg_match('#[a-z0-9]#', $str)) {
return TRUE;
}
$this->form_validation->set_message('check_username', 'This is not have an accepted value!');
return FALSE;
}
Validation rules for username
$this->form_validation->set_rules('username', 'Username', 'trim|required|xss_clean|callback_check_username');
You may like this too.

Adding custom callback to Codeigniter Form Validation

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.

Codeigniter form validation error message

I have a form on my website header where i allow the user to log in with his username/password... then i POST to /signin page and check if the username exists to allow the user to log in.. if there is a problem upon login i output these errors...
i tried using the following code to show a custom error but with no luck
if ($this->form_validation->run() == false){
$this->load->view("login/index", $data);
}else{
$return = $this->_submitLogin();
if ($return == true){
//success
}else{
$this->form_validation->set_message('new_error', 'error goes here');
//error
}
$this->load->view("login/index", $data);
}
how does set_message work and if this is the wrong method, which one allow me to show a custom error in this case?
EDIT :
validation rules:
private $validation_rules = array(
array(
'field' => 'username',
'label' => 'Username',
'rules' => 'trim|required|callback__check_valid_username|min_length[6]|max_length[20]|xss_clean'
),
array(
'field' => 'password',
'label' => 'Password',
'rules' => 'trim|required|min_length[6]|max_length[32]'
),
);
The set_message method allows you to set your own error messages on the fly. But one thing you should notice is that the key name has to match the function name that it corresponds to.
If you need to modify your custom rule, which is _check_valid_username, you can do so by perform set_message within this function:
function _check_valid_username($str)
{
// Your validation code
// ...
// Put this in condition where you want to return FALSE
$this->form_validation->set_message('_check_valid_username', 'Error Message');
//
}
If you want to change the default error message for a specific rule, you can do so by invoking set_message with the first parameter as the rule name and the second parameter as your custom error. E.g., if you want to change the required error :
$this->form_validation->set_message('required', 'Oops this %s is required');
If by any chance you need to change the language instead of the error statement itself, create your own form_validation_lang.php and put it into the proper language folder inside your system language directory.
As you can see here, you can display the custom error in your view in the following way:
<?php echo form_error('new_error'); ?>
PS: If this isn't your problem, post your corresponding view code and any other error message that you're getting.
The problem is that your form is already validated in your IF part! You can fix the problem by this way:
if ($this->form_validation->run() == false){
$this->load->view("login/index", $data);
}else{
$return = $this->_submitLogin();
if ($return == true){
//success
}else{
$data['error'] = 'Your error message here';
//error
}
$this->load->view("login/index", $data);
}
In the view:
echo $error;
The CI way to check user credentials is to use callbacks:
$this->form_validation->set_rules('username', 'Username', 'callback_username_check');
...
public function username_check($str) {
// your code here
}
I recommend you to read CI documentation: http://codeigniter.com/user_guide/libraries/form_validation.html
The way I did this was to add another validation rule and run the validation again. That way, I could keep the validation error display in the view consistent.
The following code is an edited excerpt from my working code.
public function login() {
$this->form_validation->set_rules('email', 'Email', 'required');
$this->form_validation->set_rules('password', 'Password', 'required');
$data['content'] = 'login';
if($this->form_validation->run()) {
$sql = "select * from users where email = ? and password = ?";
$query = $this->db->query($sql, array($this->input->post('email'), $this->input->post('password')));
if($query->num_rows()==0) {
// user not found
$this->form_validation->set_rules('account', 'Account', 'callback__noaccount');
$this->form_validation->run();
$this->load->view('template', $data);
} else {
$this->session->set_userdata('userid', $query->id);
redirect('/home');
}
} else {
$this->load->view('template', $data);
}
}
public function _noaccount() {
$this->form_validation->set_message('_noaccount', 'Account must exist');
return FALSE;
}
Require Codeigniter 3.0
Using callback_ method;
class My_controller extends CI_Controller {
function __construct() {
parent::__construct();
$this->form_validation->set_message('date_control', '%s Date Special Error');
}
public function date_control($val, $field) { // for special validate
if (preg_match("/^[0-9]{2}.[0-9]{2}.[0-9]{4}$/", $val)) {
return true;
} else {
return false;
}
}
public function my_controller_test() {
if ($this->input->post()) {
$this->form_validation->set_rules('date_field', 'Date Field', 'trim|callback_date_control[date_field]|xss_clean');
if ($this->form_validation->run() == FALSE) {
$data['errors']=validation_errors();
$this->load->view('my_view',$data);
}
}
}
}
Result:
if date = '14.07.2017' no error
if date = '14-7-2017' Date Field Date Special Error

Categories