Skip to content

Assosiative Arrays via POST

Liam Anderson edited this page Oct 17, 2015 · 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 )

Usage and Installation

Usage

I've written 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 test.php fill the following codes:

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



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

    }


}

?&gt;

Attention!

after applying this contribution you have to note some changes:

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

Installation

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

MY_Input.php MY_Validation.php

fill the following codes:

MY_Input.php Codes

&lt;?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');
    }
}
?&gt;

MY_Validation.php

&lt;?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;
     }

}
?&gt;

Congratulations, now you are able to access, validate and redefine associative arrays elements with no limits!

Category:Contributions::Libraries::Miscallenous

Clone this wiki locally