I found myself wanting to validate an input field that will be used when inserting the POST values in a table. That input field would have to be a DATETIME type of value. That is to say that if someone will fill the value of an input field, let’s name the input field “published_at”, that value would have to have a DATETIME format: 2015-05-18 15:10:29.
So how would we go about doing this?
Firstly, we would create the input field (this tutorial is not about how to create a form. For this you can at any time study the manual):
<?php echo form_label('Published at','published_at'); echo form_error('published_at'); echo form_input('published_at',set_value('published_at'); ?>
After this we go to our form validation rules and create a rule for this input (let me mention that this tutorial is also not about how to do form validation in CodeIgniter…):
$this->form_validation->set_rules('published_at','Published at','trim|callback_published_at');
Now we will only have to create the callback function (actually a method inside our controller). For starters let’s create the basic setup. As the manual states, we will create a function named just like the rule, without the “callback_” part:
public function published_at($str) { if($str == 'test') { $this->form_validation->set_message('published_at', 'The {field} field must not be "test"'); return FALSE; } else { return TRUE; } }
Now, if we fill the input field with “test” value, it should throw us the error.
Cool. So we’re on the right track. Now, how would we go about validating the DATETIME:
public function published_at($str) { $date_time = explode(' ',$str); if(sizeof($date_time)==2) { $date = $date_time[0]; $time = $date_time[1]; } $this->form_validation->set_message('published_at', 'The {field} field must have a DATETIME format'); return FALSE; }
First we will validate the date:
$date_values = explode('-',$date); if((sizeof($date_values)!=3) || !checkdate( (int) $date_values[1], (int) $date_values[2], (int) $date_values[0])) { $this->form_validation->set_message('published_at', 'The date inside the {field} field is not valid.'); return FALSE; }
Now we will have to verify if the right time was inserted:
$time_values = explode(':',$time); if((int) $time_values[0]>23 || (int) $time_values[1]>59 || (int) $time_values[2]>59) { $this->form_validation->set_message('published_at', 'The time inside the {field} field is not valid.'); return FALSE; }
If no return was done until this point, we simply return TRUE:
return TRUE;
And that’s it. Now let’s see the function again:
public function published_at($str) { $date_time = explode(' ',$str); if(sizeof($date_time)==2) { $date = $date_time[0]; $date_values = explode('-',$date); if((sizeof($date_values)!=3) || !checkdate( (int) $date_values[1], (int) $date_values[2], (int) $date_values[0])) { $this->form_validation->set_message('published_at', 'The date inside the {field} field is not valid.'); return FALSE; } $time = $date_time[1]; $time_values = explode(':',$time); if((int) $time_values[0]>23 || (int) $time_values[1]>59 || (int) $time_values[2]>59) { $this->form_validation->set_message('published_at', 'The time inside the {field} field is not valid.'); return FALSE; } return TRUE; } $this->form_validation->set_message('published_at', 'The {field} field must have a DATETIME format.'); return FALSE; }
But…
But what if we know we will need this form validation rule in more than one controller? For this we can create a MY_Form_validation.php file in the application/libraries directory. We do this to extend the core functionality of the CodeIgniter framework without messing with the system files.
Now let’s just create a class named MY_Form_validation that will extend CI_Form_validation and then copy the method from our controller into our new library. We will rename the method datetime() as this name is actually more representative for the rule:
<?php defined('BASEPATH') OR exit('No direct script access allowed'); class MY_Form_validation extends CI_Form_validation { function __construct() { parent::__construct(); } public function datetime($str) { $date_time = explode(' ',$str); if(sizeof($date_time)==2) { $date = $date_time[0]; $date_values = explode('-',$date); if((sizeof($date_values)!=3) || !checkdate( (int) $date_values[1], (int) $date_values[2], (int) $date_values[0])) { $this->form_validation->set_message('published_at', 'The {field} field must have a DATETIME format.'); return FALSE; } $time = $date_time[1]; $time_values = explode(':',$time); if((int) $time_values[0]>23 || (int) $time_values[1]>59 || (int) $time_values[2]>59) { $this->form_validation->set_message('published_at', 'The {field} field must have a DATETIME format.'); return FALSE; } return TRUE; } $this->form_validation->set_message('published_at', 'The {field} field must have a DATETIME format.'); return FALSE; } }
After this we go to where we’ve set the form validation rules, and change the rule so that it will be using the new method:
$this->form_validation->set_rules('published_at','Published at','trim|datetime');
If we try to do a DATETIME validation we will get some slew of errors. That is because we try to call methods of a form_validation object that doesn’t exist ($this->form_validation->set_message()).
So let’s return to our MY_Form_validation and make the changes accordingly:
<?php defined('BASEPATH') OR exit('No direct script access allowed'); class MY_Form_validation extends CI_Form_validation { function __construct() { parent::__construct(); } public function datetime($str) { $date_time = explode(' ',$str); if(sizeof($date_time)==2) { $date = $date_time[0]; $date_values = explode('-',$date); if((sizeof($date_values)!=3) || !checkdate( (int) $date_values[1], (int) $date_values[2], (int) $date_values[0])) { $this->set_message('published_at', 'The {field} field must have a DATETIME format.'); return FALSE; } $time = $date_time[1]; $time_values = explode(':',$time); if((int) $time_values[0]>23 || (int) $time_values[1]>59 || (int) $time_values[2]>59) { $this->set_message('published_at', 'The {field} field must have a DATETIME format.'); return FALSE; } return TRUE; } $this->set_message('published_at', 'The {field} field must have a DATETIME format.'); return FALSE; } }
All looks OK, but what if we want to have fast access to the errors so that we can change what the messages say? Let’s just start by moving all the messages inside an array that we will define in the constructor, and call those messages inside our method:
<?php defined('BASEPATH') OR exit('No direct script access allowed'); class MY_Form_validation extends CI_Form_validation { private $my_error_messages = array(); function __construct() { parent::__construct(); $this->my_error_messages['form_validation_datetime'] = 'The {field} field must have a DATETIME format.'; } public function datetime($str) { $date_time = explode(' ',$str); if(sizeof($date_time)==2) { $date = $date_time[0]; $date_values = explode('-',$date); if((sizeof($date_values)!=3) || !checkdate( (int) $date_values[1], (int) $date_values[2], (int) $date_values[0])) { $this->set_message('datetime', $this->my_error_messages['form_validation_datetime']); return FALSE; } $time = $date_time[1]; $time_values = explode(':',$time); if((int) $time_values[0]>23 || (int) $time_values[1]>59 || (int) $time_values[2]>59) { $this->set_message('datetime', $this->my_error_messages['form_validation_datetime']); return FALSE; } return TRUE; } $this->set_message('datetime', $this->my_error_messages['form_validation_datetime']); return FALSE; } }
…And still…
…And still… it just doesn’t feel right? What about having messages for another language? You could of course make custom messages for the rule, but that would get burdensome on the long run.
Now, if we look at the Form_validation library inside the system/libraries directory, we can see that the messages are called automatically from the form_validation language file (form_validation_lang.php) if the result of the validation is false. So why not use this?
So why not have an easier life by creating ourselves a file like that inside the application/language/english directory. If we do this, CodeIgniter will append the values inside that file to the values inside the system’s file. Once we’ve created application/language/english/form_validation_lang.php we only have to write a line in it:
<?php defined('BASEPATH') OR exit('No direct script access allowed'); $lang['form_validation_datetime'] = 'The {field} field must have a DATETIME format.';
Now let’s go again to our MY_Form_validation class and change it to see if it takes the message from the language file:
<?php defined('BASEPATH') OR exit('No direct script access allowed'); class MY_Form_validation extends CI_Form_validation { function __construct() { parent::__construct(); } public function datetime($str) { $date_time = explode(' ',$str); if(sizeof($date_time)==2) { $date = $date_time[0]; $date_values = explode('-',$date); if((sizeof($date_values)!=3) || !checkdate( (int) $date_values[1], (int) $date_values[2], (int) $date_values[0])) { return FALSE; } $time = $date_time[1]; $time_values = explode(':',$time); if((int) $time_values[0]>23 || (int) $time_values[1]>59 || (int) $time_values[2]>59) { return FALSE; } return TRUE; } return FALSE; } }
Now, if in the input field we put something else than a DATETIME type of value, the form validation library will additionally “use” our MY_Form_validation and look for the validation error message inside the application/language/english/form_validation_lang.php which will be outputted in case of error.
Hope you’ve enjoyed it.
Really intresting tutorial…exactly what I need for my project.
In my app I need to store the date in the format of yyyy-mm-dd, with no time…and sometimes user could just add the year, whitout month and day…using checkdate function I cannot do that…any hint to tweak to script? Thanks
@federico:
In MY_Form_validation.php add this:
function valid_date($date, $format){
$d = DateTime::createFromFormat($format, $date);
if($d && $d->format($format) == $date) {
return true;
} else {
$this->set_message(‘valid_date’, ‘YOUR CUSTOM ERROR MESSAGE’);
return false;
}
}
And in controller use like this:
$this->form_validation->set_rules(‘dob’, ‘DOB’, ‘required|valid_date[d-m-Y]’);
You can change format paramer as you wish 🙂