Part of the EllisLab Network
x
 
Create New Page
 View Previous Changes    ( Last updated by George Petsagourakis )

ClientServer Validation

Category:Core | Category:Core -> Community | Category:Core -> Validation

Information

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.

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.

Usage

The usage is simple:
1. Add a method to your controller, where you set up your validation rules.
2. Call this method twice per form life-cycle: once before rendering the form (html), and again after it has been submitted.

Example

1. Set up validation:

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

2. When rendering the form, define your validation rules and then call special function from our Validation (sub)class to generate a corresponding js script:

function index()
    
{
        $this
->_setup_validation();
                
        
$data['javascript'$this->validation->javascript();
        
$this->load->view('register'$data);
    

3. In your view, use ‘javascript’ variable to inject the contents of our validation (js) script:

<html>
    <
head>
        <
title>Account Registration</title>
        
<?= @$javascript ?>
    
</head>
    ... 


4. Once the form has been submitted, process it as usual:

function submit()
    
{
        $this
->_setup_validation();
        
        if (
$this->validation->run() == false)
            return 
$this->index();

        
$this->load->view('sucess');
    


Here’s MY_Validation.php in its entirety:

<?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 <script>...</script> 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 - custom error message (optional)
     * @param    string - name of a js error callback function (optional) 
     * @return    string - js
     */
     
    
function javascript($alert_msg=''$alert_func='null')
    
{
        
if(!$this->_fields || !$this->_rules)
            return 
'<script type="text/javascript">function validation_run(f) {}</script>';
    
    
        
// client-side javascript implementation of CI built-in validation rules.
        
$script '
<script type="text/javascript">
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</script>";

        return 
$script;
    
}
}

?> 

Categories: