Skip to content

Assosiative Arrays via POST

World Wide Web Server edited this page Jul 4, 2012 · 14 revisions

This wiki page is about extending CI Input & Validation libraries to support assosiative arrays sent via post.

before this solution, validating a checkbox value inside a checkbox group wasn't available, you had to retrieve the value first as an array and then do manual validation.

this wasn't handy in anyway so I had to write this contribution.

read more about this topic into the original forum thread http://codeigniter.com/forums/viewthread/51260/ (any comments & bug reports should go there also, please )

[h2]Usage and Installation[/h2]

[h2]Usage[/h2]

I've wrote a small sample controller which illustrates everything for you, just check it out and check the source codes well :)

Don't be silly and try the sample controller before installing the modified libraries as it won't work :P

Create a new controller file and call it [b]test.php[/b] fill the following codes:

[code] <?php

class test extends controller{

function index(){ 

$this->load->library('validation');

$rules = array(
            'inputs[textbox]'    => 'trim|required',    
            'inputs[mycheckbox]' => 'trim|numeric',
 );
 
 $fields  =  array(
            'inputs[textbox]'    => 'TextBox',    
            'inputs[mycheckbox]' => 'MyCheckBox',
 );
 
 $this->validation->set_fields($fields);
 $this->validation->set_rules($rules); 
 $this->validation->run();



?&gt;
<h1>Testing Form:</h1>
&lt;form method="post"&gt;

<center>&lt;?=$this->validation->error_string?&gt;</center>

<b>TextBox Sample</b><br />
&lt;input type="text" name="inputs[textbox]"  value="&lt;?=$this-&gt;validation->value('inputs[textbox]')?&gt;" /> &lt;?=$this->validation->error('inputs[textbox]')?&gt;

<br /><br />

<b>Radio Sample</b><br />    
&lt;input type="radio" name="inputs[mycheckbox]"  value="1" &lt;? if($this-&gt;validation->value('inputs[mycheckbox]') == 1) echo "checked"; ?&gt;  /> 1
&lt;input type="radio" name="inputs[mycheckbox]"  value="2" &lt;? if($this-&gt;validation->value('inputs[mycheckbox]') == 2) echo "checked"; ?&gt;  /> 2
&lt;input type="radio" name="inputs[mycheckbox]"  value="abc" &lt;? if($this-&gt;validation->value('inputs[mycheckbox]') == 'abc') echo "checked"; ?&gt;  /> abc
&lt;?=$this->validation->error('inputs[mycheckbox]')?&gt;    

<br /><br />

&lt;input type="submit" value="Test!" /&gt;
&lt;/form&gt;
<hr />
<h1>Submitted post data:</h1>
<h3>dumping $_POST variable</h3>
<pre>&lt;? print_r($_POST) ?&gt;</pre>
<span style="font-size:smaller">You should find some extra keys into the post used by the class, just ignore them!</span>
<hr />
<h1>Testing submitted values:</h1>
$this->input->post('inputs[textbox']) <b>prints</b>  "&lt;?=$this->input->post('inputs[textbox]')?&gt;" <br />
$this->input->post('inputs[mycheckbox']) <b>prints</b>  "&lt;?=$this->input->post('inputs[mycheckbox]')?&gt;" <br />

<hr />

<h1>Redefining post values...</h1>
&lt;?
$this->input->set_post('inputs[textbox]' , 'textbox value changed, great it works!');
$this->input->set_post('inputs[mycheckbox]' , 'checkbox value changed!');
?&gt;

<h3>dumping $_POST variable</h3>    
<pre>&lt;? print_r($_POST) ?&gt;</pre>

<h1>Testing defined values:</h1>
$this->input->post('inputs[textbox']) <b>prints</b>  "&lt;?=$this->input->post('inputs[textbox]')?&gt;" <br />
$this->input->post('inputs[mycheckbox']) <b>prints</b>  "&lt;?=$this->input->post('inputs[mycheckbox]')?&gt;" <br />

    
   &lt;? 

}

}

?> [/code]

[h2]Attention![/h2]

[b]after applying this contribution you have to note some changes:[/b]

1- due to the fact that we can't use brackets [ ] into a class variable, we can't access $this->validation->mycheckbox[element1]_error anymore to print the field error, so use $this->validation->error('mycheckbox[element1]') instead.

2- same to echo a value, instead of $this->validation->mycheckbox[element1], use $this->validation->value('mycheckbox[element1]')

3- to redefine a variable inside the $_POST, use $this->validation->set_post('mycheckbox[element1]' , 'new value here')

[h2]Installation[/h2] all you need is to create two files under your "application/libraries" folder, and name them:

[b]MY_Input.php[/b] [b]MY_Validation.php[/b]

fill the following codes:

[b]MY_Input.php Codes[/b] [code] <?php

class MY_Input extends CI_Input{

function MY_Input()
{
    parent::CI_Input();
}


/**
 * Fetch an item from the POST array
 *
 * @access    public
 * @param    string
 * @param    bool
 * @return    string
 */
function post($index = '', $xss_clean = FALSE)
{        
    $value  = $this->brackets_to_index($index , "post");

    if ( ! isset($value))
    {
        return FALSE;
    }

    if ($xss_clean === TRUE)
    {
        if (is_array($value))
        {
            foreach($value as $key => $val)
            {                    
                $value[$key] = $this->xss_clean($val);
            }
        }
        else
        {
            return $this->xss_clean($value);
        }
    }

    return $value;
}

// --------------------------------------------------------------------

/**
 * Set an item from the POST array
 *
 * @access    public
 * @param    string
 * @param    bool
 * @return    string
 */
function set_post($index = '', $value)
{
    return $this->set_brackets_to_index($index , $value ,  'post');
}

// --------------------------------------------------------------------

/**
 * Fetch an item from the COOKIE array
 *
 * @access    public
 * @param    string
 * @param    bool
 * @return    string
 */
function cookie($index = '', $xss_clean = FALSE)
{
    $value  = $this->brackets_to_index($index , "cookie");

    if ( ! isset($value))
    {
        return FALSE;
    }

    if ($xss_clean === TRUE)
    {
        if (is_array($value))
        {
            $cookie = array();
            foreach($value as $key => $val)
            {
                $cookie[$key] = $this->xss_clean($val);
            }
    
            return $cookie;
        }
        else
        {
            return $this->xss_clean($value);
        }
    }
    else
    {
        return $value;
    }
}    

/*
 * This function gets the value of an "array item" passed via post, get or cookie which is written on the form
 * array[array1][array2][item]
 * @access    public
 * @param    string the form of the array
 * @param    string the method used to send the variable possible values are: "post" , "get" and "cookie" .. default is "post"
 * @return    string
 */

function brackets_to_index($str , $method="post"){

    // first we remove the closing bracket ]
    $str2 = str_replace("]" , "" , $str);
    // next , we explode the str by opening bracket [
    $array = explode("[", $str2);

    switch($method){
    default:
        $value = $_POST;
    break;
    case "cookie":
        $value = $_COOKIE;
    break;
    case "get":
        $value = $_GET;
    break;
    }
    // finally we get the index value from the specified array
    foreach($array as $key=>$index){
        $value = $value[$index];
    }
    $value = isset($value) ? $value : NULL;
    $value = ($value === false) ? "" : $value;
    switch($method){
    default:
        $_POST[$str]   = $value;
    break;
    case "cookie":
        $_COOKIE[$str] = $value;
    break;
    case "get":
        $_GET[$str]    = value;
    break;
    }

    return $value;

}



function set_brackets_to_index($str , $value, $method = 'post'){

    // first we remove the closing bracket ]
    $str2 = $str;
    if(strpos($str2 , '[') != 0){
    $str2  = substr($str2 , 0 ,strpos($str2 , '[')) . ']' . strstr($str2 , '['); // add ] after the first index
    $str2  = "[" . $str2;
    }
    $str2 = str_replace("]" , "']" , $str2);
    $str2 = str_replace("[" , "['" , $str2);

    switch($method){
    default:
        eval&#40; '$_POST'.$str2.' = $value; '&#41;;
    break;
    case "get":
        eval&#40; '$_GET'.$str2.' = $value; '&#41;;
    break;
    case "file":
        eval&#40; '$_FILES[\'userfile\'][\'name\']'.$str2.' = $value; '&#41;;
    break;
    }
}



function file&#40;$str , $key = "name"&#41;{
    // first we remove the closing bracket ]
    $str2 = str_replace("]" , "" , $str);
    // next , we explode the str by opening bracket [
    $array = explode("[", $str2);

    $value = $_FILES['userfile'];

    for($i = 0 ; $i < count($array) ; $i++){
    if($i == 0) $value = $value[$key];
    else        $value = $value[$array[$i]];
    }

    return $value;
}

// --------------------------------------------------------------------

/**
 * Set an item from the POST array
 *
 * @access    public
 * @param    string
 * @param    bool
 * @return    string
 */
function set_file&#40;$index = '', $value&#41;
{
    return $this->set_brackets_to_index($index , $value , 'file');
}

} ?> [/code]

[b]MY_Validation.php[/b] [code] <?php

class MY_Validation extends CI_Validation{

var $_value = array();

function MY_Validation()
{
    parent::CI_Validation();
}
// --------------------------------------------------------------------

/**
 * 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
 */
function set_fields($data = '', $field = '')
{    
    if ($data == '')
    {
        if (count($this->_fields) == 0)
        {
            return FALSE;
        }
    }
    else
    {
        if ( ! is_array($data))
        {
            $data = array($data => $field);
        }
        
        if (count($data) > 0)
        {
            $this->_fields = $data;
        }
    }        
        
    foreach($this->_fields as $key => $val)
    {        

// $this->_value[$key] = ( ! isset($_POST[$key]) OR is_array($_POST[$key])) ? '' : $this->prep_for_form($_POST[$key]); $this->_value[$key] = $_POST[$key];

        /*
        $error = $key.'_error';
        if ( ! isset($this->$error))
        {
            $this->$error = '';
        }
        */
        // USE INSTEAD: $this->error('username');
    }        
}
    
// --------------------------------------------------------------------

/**
 * Run the Validator
 *
 * This function does all the work.
 *
 * @access    public
 * @return    bool
 */        
function run()
{
    // Do we even have any data to process?  Mm?
    if (count($_POST) == 0 OR count($this->_rules) == 0)
    {
        return TRUE;
    }

    // Load the language file containing error messages
    $this->CI->lang->load('validation');
                        
    // Cycle through the rules and test for errors
    foreach ($this->_rules as $field => $rules)
    {
        $fieldO = $field; // save the original field name;
        $this->CI->input->brackets_to_index($field);
        //Explode out the rules!
        $ex = explode('|', $rules);

        // Is the field required?  If not, if the field is blank  we'll move on to the next text
        if ( ! in_array('required', $ex, TRUE) AND strpos($rules, 'callback_') === FALSE)
        {
            if ( ! isset($_POST[$field]) OR $_POST[$field] == '')
            {
                continue;
            }
        }
        
        /*
         * Are we dealing with an "isset" rule?
         *
         * Before going further, we'll see if one of the rules
         * is to check whether the item is set (typically this
         * applies only to checkboxes).  If so, we'll
         * test for it here since there's not reason to go
         * further
         */
        if ( ! isset($_POST[$field]))
        {            
            if (in_array('isset', $ex, TRUE) OR in_array('required', $ex))
            {
                if ( ! isset($this->_error_messages['isset']))
                {
                    if (FALSE === ($line = $this->CI->lang->line('isset')))
                    {
                        $line = 'The field was not set';
                    }                            
                }
                else
                {
                    $line = $this->_error_messages['isset'];
                }
                
                $field = ( ! isset($this->_fields[$field])) ? $field : $this->_fields[$field];
                $this->_error_array[$fieldO] = sprintf($line, $field);    
            }
                    
            continue;
        }

        /*
         * Set the current field
         *
         * The various prepping functions need to know the
         * current field name so they can do this:
         *
         * $_POST[$this->_current_field] == 'bla bla';
         */
        $this->_current_field = $field;

        // Cycle through the rules!
        foreach ($ex As $rule)
        {
            // Is the rule a callback?            
            $callback = FALSE;
            if (substr($rule, 0, 9) == 'callback_')
            {
                $rule = substr($rule, 9);
                $callback = TRUE;
            }
            
            // Strip the parameter (if exists) from the rule
            // Rules can contain a parameter: max_length[5]
            $param = FALSE;
            if (preg_match("/(.*?)\[(.*?)\]/", $rule, $match))
            {
                $rule    = $match[1];
                $param    = $match[2];
            }
            
            // Call the function that corresponds to the rule
            if ($callback === TRUE)
            {
                if ( ! method_exists($this->CI, $rule))
                {         
                    continue;
                }
                
                $result = $this->CI->$rule($_POST[$field], $param);    
                
                // If the field isn't required and we just processed a callback we'll move on...
                if ( ! in_array('required', $ex, TRUE) AND $result !== FALSE)
                {
                    continue 2;
                }
                
            }
            else
            {                
                if ( ! method_exists($this, $rule))
                {
                    /*
                     * Run the native PHP function if called for
                     *
                     * If our own wrapper function doesn't exist we see
                     * if a native PHP function does. Users can use
                     * any native PHP function call that has one param.
                     */
                    if (function_exists($rule))
                    {
                        $_POST[$field] = $rule($_POST[$field]);
                        // $this->$field = $_POST[$field];
                        // USE INSTEAD: $this->value('username');
                        $this->_value[$field] = $_POST[$field];
                    }
                                        
                    continue;
                }
                
                $result = $this->$rule($_POST[$field], $param);
            }
                            
            // Did the rule test negatively?  If so, grab the error.
            if ($result === FALSE)
            {
                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];
                $message = sprintf($line, $mfield, $mparam);
                
                // Set the error variable.  Example: $this->username_error
                // $error = $field.'_error';
                // $this->$error = $this->_error_prefix.$message.$this->_error_suffix;
                // USE INSTEAD:
                // $this->error('username');

                // Add the error to the error array
                $this->_error_array[$fieldO] = $message;                
                continue 2;
            }                
        }
        
    }
    
    $total_errors = count($this->_error_array);

    /*
     * Recompile the class variables
     *
     * If any prepping functions were called the $_POST data
     * might now be different then the corresponding class
     * variables so we'll set them anew.
     */    
    if ($total_errors > 0)
    {
        $this->_safe_form_data = TRUE;
    }
    
    $this->set_fields();

    // Did we end up with any errors?
    if ($total_errors == 0)
    {
        return TRUE;
    }
    
    // Generate the error string
    foreach ($this->_error_array as $val)
    {
        $this->error_string .= $this->_error_prefix.$val.$this->_error_suffix."\n";
    }

    return FALSE;
}

// --------------------------------------------------------------------

/**
 * Return error message of given field name
 *
 * @access    public
 * @param    string
 * @return    string
 */    
function error($field){
    return $this->_error_array[$field];
}

// --------------------------------------------------------------------

/**
 * Return passed value of given field name
 *
 * @access    public
 * @param    string
 * @return    string
 */
 
function value($field){
    return $this->_value[$field];
}

// --------------------------------------------------------------------            

/**
 * Overwrite object values with validation output.
 *
 * @access    public
 * @param    obj
 * @return    obj
 */
 
 function error_set($field , $error){
     $this->_error_array[$field] .= $error;
 }

} ?>
[/code]

[b]Congratulations, now you are able to access and validation and redefine assosiative arrays elements with no limits![/b]

Clone this wiki locally