-
Notifications
You must be signed in to change notification settings - Fork 26
ClientServer Validation
Implementing client-side and server-side validation usually requires a significant duplication of effort. Despite following the same logic rules, the code usually must be developed in two different environments - e.g. javascript and php.[br]
For those who are too lazy to do the same work twice (like I am), here is a crude prototype of a validation library (subclass of built-in Validation class) that would do this work for you. [br]
The usage is simple:
- Add a method to your controller, where you set up your validation rules.
- Call this method twice per form life-cycle: once before rendering the form (html), and again after it has been submitted.
For example:
-
Set up validation: [code] function _setup_validation() { $this->load->library('validation');
$fields = array( 'email'=>'Email', 'password'=>'Password', 'password2'=>'Confirm Password', 'firstname' => 'First Name', 'lastname' => 'Last Name', 'address1'=>'Address 1', 'city'=>'City', 'zipcode'=>'Zip' ); $rules = array( 'email'=>'required|valid_email', 'password'=>'min_length[5]', 'password2'=>'required|matches[password]', 'firstname' => 'required', 'lastname' => 'required', 'address1'=>'required', 'city'=>'min_length[2]', 'zipcode'=>'exact_length[5]' ); $this->validation->set_fields($fields); $this->validation->set_rules($rules);
} [/code]
-
When rendering the form, define your validation rules and then call special function from our Validation (sub)class to generate a corresponding [removed]
[code] function index() { $this->_setup_validation();
$data['javascript'] = $this->validation->javascript();
$this->load->view('register', $data);
}
[/code]
- In your view, use 'javascript' variable to inject the contents of our validation (js) script:
[code] <html> <head> <title>Account Registration</title> <?= @$javascript ?> </head> ... [/code]
- Once the form has been submitted, process it as usual:
[code] function submit() { $this->_setup_validation();
if ($this->validation->run() == false)
return $this->index();
$this->load->view('sucess');
}
[/code]
Here's [b]MY_Validation.php[/b] in its entirety:
[code] <?php if (!defined('BASEPATH')) exit('No direct script access allowed');
// ------------------------------------------------------------------------
/**
-
Validation Class extension
-
@package CodeIgniter
-
@subpackage Libraries
-
@category Validation
-
@author AK
-
@link http://codeigniter.com/user_guide/libraries/validation.html */
/**
- Set Fields
- This function takes an array of field names as input
- and generates class variables with the same name, which will
- either be blank or contain the $_POST value corresponding to it
- @access public
- @param string
- @param string
- @return void */ class MY_Validation extends CI_Validation {
function MY_Validation() { parent::CI_Validation(); }
/**
- JavaScript
- This function provides default implementation of the built-in CI validation rules in javascript.
- The function generates a client-side js script, complete with ... html tags,
- suitable for inclusion in the document header. Additionally, custom rules can be added by
- defining global js functions, or extending Validation js object.
- @access public
- @param string
- @param string
- @return void */
function javascript($alert_msg='', $alert_func='null') { if(!$this->_fields || !$this->_rules) return 'function validation_run(f) {}';
// client-side javascript implementation of CI built-in validation rules. $script = '
String.prototype.trim = function() { return this.replace(/^\s\s*/, "").replace(/\s\s*$/, ""); } var Validator = function(f) { this.form = f; } Validator.prototype.required = function(str) { return str.search(/\S/) > -1; } Validator.prototype.matches = function(str, field) { return (str == this.form.elements[field].value); } // FIX! change "field" from input name to input ref?
Validator.prototype.max_length = function(str, val) { return (str.length <= val); }
Validator.prototype.min_length = function(str, val) { return (str.length >= val); }
Validator.prototype.exact_length = function(str, val) { return (str.length == val); }
Validator.prototype.valid_email = function(str) { return str.search(/^([\w+-]+)(.[\w+-]+)*@([a-z\d-]+.)+[a-z]{2,6}$/i) > -1; }
Validator.prototype.valid_ip = function(ip) { var segments = ip.split("."); for (var i in segs) if(segs[i].length>3 || segs[i]>255 || segs[i].search(/\D/)>-1) return false; return true; }
Validator.prototype.alpha = function(str) { return str.search(/[^a-z]/i) == -1; }
Validator.prototype.alpha_numeric = function(str) { return str.search(/[^a-z0-9]/i) == -1; }
Validator.prototype.alpha_dash = function(str) { return str.search(/[^\w-]/i) == -1; }
Validator.prototype.numeric = function(str) { return ! isNaN(str); }
Validator.prototype.integer = function(str) { return ! (isNaN(str) || str.indexOf(".") > -1); }
Validator.prototype.valid_base64 = function(str) { return str.search(/[^a-zA-Z0-9/+=]/) == -1; }
Validator.prototype.validate = function (rules, callback) { try {
if (!rules.length) return true;
var res, errors=[];
for (var i in rules) {
var item = rules[i];
var field = this.form.elements[item.input];
var rule_list = item.rule.split("|");
for (var r in rule_list) {
var re = /(callback_|validate_)?(\w+)(?:\[(.+)\])?/i.exec(rule_list[r]);
var func = re[2];
//if (!re[1]) re[1] = "";
if (!this[func]) {
try { func = eval(func); } catch (e2) { }
res = (typeof(func) == "function") ? func(field.value, re[3]) : false;
} else {
res = this[func](field.value, re[3]);
}
}
if (!res && item.msg) {
errors.push([item.msg, item.input]);
}
} } catch (e) { alert(e); }
if (errors.length) {
// show errors
return callback ? callback(errors) : display_alert(errors);
}
return true;
} '; // default alert message if ($alert_msg == '') $alert_msg = 'Please fix the following errors:';
// default implementation of the validation action
$script .= '
function display_alert(errors) { var str = ""; for (var i in errors) str += "\n- " + errors[i][0]; alert("'. addslashes($alert_msg) .'" + str); return false; } '; // Load the language file containing error messages $this->CI->lang->load('validation');
$params = null;
foreach ($this->_rules as $field => $rules)
{
//Explode out the rules!
$ex = explode('|', $rules);
$messages = array();
foreach ($ex as $rule)
{
$param = FALSE;
if (preg_match("/(.*?)\[(.*?)\]/", $rule, $match))
{
$rule = $match[1];
$param = $match[2];
}
if ( ! isset($this->_error_messages[$rule]))
{
if (FALSE === ($line = $this->CI->lang->line($rule)))
{
$line = 'Unable to access an error message corresponding to your field name.';
}
}
else
{
$line = $this->_error_messages[$rule];
}
// Build the error message
$mfield = ( ! isset($this->_fields[$field])) ? $field : $this->_fields[$field];
$mparam = ( ! isset($this->_fields[$param])) ? $param : $this->_fields[$param];
$messages[] = sprintf($line, $mfield, $mparam);
}
$params[] = '{input:"'.$field.'",rule:"'.$rules.'",name:"'
.( isset($this->_fields[$field]) ? addslashes($this->_fields[$field]) : $field ).'",msg:"'.join(' ', $messages).'"}';
}
$script .= "\nfunction validation_run(f) {\n\tvar rules = [\n\t\t" . join(",\n\t\t", $params) . "\n\t];\n\treturn new Validator(f).validate(rules,". $alert_func .");\n}\n";
return $script;
}
}
?> [/code]