Part of the EllisLab Network
   
1 of 2
1
Validation of listbox, checkbox groups and reselect multiple values using set_select, set_checkbox / Sol: Array to string conversion error (line 709)
Posted: 01 March 2008 12:52 AM   [ Ignore ]  
Summer Student
Avatar
Total Posts:  14
Joined  02-27-2008

Overview:
CI is not dealing with user submitted array values properly.

Impacts:
* You cannot validate listbox (select with multiple enabled), checkbox groups and reselect the user selected values using set_select, set_checkbox for multiple values

* You cannot use trim, htmlspecialchars or any other native php function in rules

* When you enable XSS_Clean in config.php error will pop-up when user select multiple values in list box or check checkbox groups ( ie: checking multiple checkboxes for hobbies in html form )

* You cannot use any other validation rules that CI provides like numeric, integer, xss_clean


What this post address:
This post address the following:

* Allowing to use trim, required, htmlspecialchars or any other native php function call in the rules.

* Allowing to use set_select, set_checkbox for listboxes and checkbox groups, checkboxgroupname_error, listboxname_error

Note:
Still you cannot use CI’s validation rules like integer, numeric, xss_clean for arrays. But I don’t think these validation will be needed for listboxes and checkbox groups as you are not going to store these values in db / re-display in html. Mostly, you will make use of the values from db / array to populate, validate against user submitted values.

But if you still need to validate for any purpose, you can call those functions in a loop for all the user selected values in a listbox / checkbox.


Solution:
Enabling CI’s - Validation library to support list box and check box group is involve replacing the system’s Validation.php with our version. To enable this copy system/library/validation.php to application/library/ and do the necessary modification listed below.

This file contains the following modifications:

1. set_select method has been modified to support arrays: (line 617 in original validation.php )

 

function set_select($field = '', $value = '')
    
{
        
if ($field == '' OR $value == '' OR  ! isset($_POST[$field]))
        
{
            
return '';
        
}
        
        
if(is_array($_POST[$field])) {
            
if(in_array($value,$_POST[$field])) {
                
return ' selected="selected"';
            
}
        }
elseif ($_POST[$field] == $value) {
            
return ' selected="selected"';
        
}
        
    }

2. set_checkbox has been modified to support arrays: (line 669 in original validation.php )

function set_checkbox($field = '', $value = '')
    
{
        
if ($field == '' OR $value == '' OR  ! isset($_POST[$field]))
        
{
            
return '';
        
}
        
        
if(is_array($_POST[$field])) {
            
if(in_array($value,$_POST[$field])) {
                
return ' checked="checked"';
            
}
        }
elseif ($_POST[$field] == $value) {
            
return ' checked="checked"';
        
}
    }


3. Prep_for_form function has been updated: (line 694 in original validation.php )

function prep_for_form($data = '')
    
{
        
if (is_array($data))
        
{
            
foreach ($data as $key => $val)
            
{
                $data[$key]
= $this->prep_for_form($val);
            
}
        }
        
        
if ($this->_safe_form_data == FALSE OR $data == '')
        
{
            
return $data;
        
}
        
        
if(is_array($data)) {
            
return $data;
        
} else {
            
return str_replace(array("'", '"', '<', '>'), array("&#39;", "&quot;", '<', '>'), stripslashes($data));    
        
}
    }

4. Method php_func_caller has been added. This enables setting rules like trim, htmlspecial chars and other native php function calls that take single parameter and return the same.

/**
     * native php function caller
     *
     * This function calls native php functions for each values submitted from the form
     *
     * @access    public
     * @param    string
     * @return    string
     * @author r.vadivelan / hivelan [.at.] gmail [.dot.] com
     */
    
function php_func_caller($rule, $data = '')
    
{
        
if (is_array($data))
        
{
            
foreach ($data as $key => $val)
            
{
                $data[$key]
= $this->php_func_caller($rule,$val);
            
}
        }
        
        
if ($data == '')
        
{
            
return $data;
        
}
        
        
if(is_array($data)) {
            
return $data;
        
} else {
            
return $rule($data);
        
}
    }

5. Call the php_func_caller when processing rules ( Line no 302 in original validation.php )

if (function_exists($rule))
                        
{
                            $_POST[$field]
= $this->php_func_caller($rule,$_POST[$field]);
                            
$this->$field = $_POST[$field];
                        
}


How to test

* Create a html file containing a select box with multiple enabled, and a checkbox group like hobbies. Make use of set_select, set_checkbox, error_string, checkboxgroupname_error, listboxname_error so that we can verify everything work properly.

* Create a controller, initialize validation libarary, set the rules and fields. Make sure you set trim, required and any other native php functions as rules. Rules like xss_clean, interger ( those given by CI ) will not work ( as CI’s validation function’s don’t support arrays).

Now it would be possible to validate listbox and checkboxes without any problem.

Summary:
Even though I have explained in detail, the entire process is very simple:
1. Just copy system/library/Validation.php to application/library and do the modifications.

2. Validate the listbox and checkbox group as you will normally do for other fields.

Hope this will be useful to you. Please let me know your comments.

Image Attachments
Validation_Failure.JPGValidation_Success.JPG
Click thumbnail to see full-size image
 Signature 

Validation: Enable CI to validate forms with multiple select (listboxes), checkbox groups, re-select listbox and multiple checkboxes

Profile
 
 
Posted: 02 March 2008 11:46 AM   [ Ignore ]   [ # 1 ]  
Research Assistant
Avatar
RankRankRank
Total Posts:  825
Joined  04-20-2006

Very nice addition !
I have bookmarked it and will test it in a next project.

 Signature 

All CodeIgniter resources into one place?
http://www.codeigniterdirectory.com

Buildon.net - The PHP Frameworks Showcase - Add your links!
http://www.buildon.net

My website: Création de sites Genève, Too Pixel

Profile
 
 
Posted: 03 March 2008 03:53 AM   [ Ignore ]   [ # 2 ]  
Summer Student
Avatar
Total Posts:  14
Joined  02-27-2008

Welcome. Email me if you need the modified validation.php file.

 Signature 

Validation: Enable CI to validate forms with multiple select (listboxes), checkbox groups, re-select listbox and multiple checkboxes

Profile
 
 
Posted: 03 March 2008 04:08 AM   [ Ignore ]   [ # 3 ]  
Sr. Research Associate
RankRankRankRankRank
Total Posts:  4839
Joined  07-14-2006

I’ve responded in another thread to set the form elements in the form helper instead of the validation library.

But i don’t understand the use of the php_func_caller method. The validation library does process native php functions added as rules. Check the Validation user guide page under the title Prepping Data.

Profile
 
 
Posted: 03 March 2008 06:20 AM   [ Ignore ]   [ # 4 ]  
Summer Student
Avatar
Total Posts:  14
Joined  02-27-2008

CI will not call native function calls for array values submitted by end user. For eg: select multiple, check box groups selected by users, CI will try to call the native php function with array and that will result in error / will not work. This function takes every element and will run the php function for it.

Please have a look at the attached image in the end of the post. That show you the user can select multiple values and this code will still apply all the trim, htmlspecialchars etc

 Signature 

Validation: Enable CI to validate forms with multiple select (listboxes), checkbox groups, re-select listbox and multiple checkboxes

Profile
 
 
Posted: 12 May 2008 09:56 AM   [ Ignore ]   [ # 5 ]  
Administrator
Avatar
RankRankRankRankRankRankRank
Total Posts:  19199
Joined  06-03-2002

I can agree to part of this being a bug, but some of it is feature request, albeit the line is a bit blurry.  Would you mind zipping and attaching the controller and view files you are using to this thread?

 Signature 
Profile
MSG
 
 
Posted: 16 May 2008 12:27 PM   [ Ignore ]   [ # 6 ]  
Summer Student
Avatar
Total Posts:  14
Joined  02-27-2008

Hi Derek
Apologize. Just seen your last post. Sending the file right away.

 Signature 

Validation: Enable CI to validate forms with multiple select (listboxes), checkbox groups, re-select listbox and multiple checkboxes

Profile
 
 
Posted: 18 May 2008 04:09 PM   [ Ignore ]   [ # 7 ]  
Summer Student
Total Posts:  5
Joined  05-17-2008

Derek Jones, could this become the patch you’re looking for in bug?: http://codeigniter.com/bug_tracker/bug/4530/

I would like to help get a solution to this array problem into CI.

Profile
 
 
Posted: 28 May 2008 02:22 PM   [ Ignore ]   [ # 8 ]  
Summer Student
Total Posts:  3
Joined  04-21-2008

If you are trying to use above hack to preserve group of checkboxes and it dosen’t work at all,
just make sure you call set_checkbox() in right way, i.e.

(sorry if someone pointed that earlier)

<input name="id_box[]" type="checkbox" value="1" <?=$this->validation->set_checkbox('id_box', '1' ); ?>  />
<
input name="id_box[]" type="checkbox" value="2" <?=$this->validation->set_checkbox('id_box', '2' ); ?>  />

notice id_box instead id_box[]

Profile
 
 
Posted: 22 June 2008 05:04 AM   [ Ignore ]   [ # 9 ]  
Grad Student
Avatar
Rank
Total Posts:  40
Joined  03-07-2007

Hi vadivelan,

thanks a lot for your contribution.

I took the liberty to put your code into the followin MY_Validation class, which is working well as far as I can tell.

<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');

// include native CI_Validation class file
include_once(BASEPATH.'libraries/Validation.php');

/**
* MY_Validation Class, extends CI_Validation
*
* @package     CodeIgniter
* @subpackage  Libraries
* @category    Validation
*/
class MY_Validation extends CI_Validation {

    
/**
     * Constructor
     *
     * @access    public
     */
    
public function MY_Validation()
    
{
        parent
::CI_Validation();
        
log_message('debug', "MY_Validation Class Initialized");
    
}

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


    /**
    * Overwrites CI's native validation set_select method to work
    * with arrays.
    *
    * @access   public
    * @param    string
    * @param    string
    * @return   string
    * @author   r.vadivelan / hivelan [.at.] gmail [.dot.] com
    * @link     http://codeigniter.com/forums/viewthread/73012/
    */
    
public function set_select($field = '', $value = '')
    
{
        
if ($field == '' OR $value == '' OR  ! isset($_POST[$field]))
        
{
            
return '';
        
}

        
if(is_array($_POST[$field])) {
            
if(in_array($value,$_POST[$field])) {
                
return ' selected="selected"';
            
}
        }
elseif ($_POST[$field] == $value) {
            
return ' selected="selected"';
        
}

    }

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


    /**
    * Overwrites CI's native validation set_checkbox method to work
    * with arrays.
    *
    * @access   public
    * @param    string
    * @param    string
    * @return   string
    * @author   r.vadivelan / hivelan [.at.] gmail [.dot.] com
    * @link     http://codeigniter.com/forums/viewthread/73012/
    */
    
public function set_checkbox($field = '', $value = '')
    
{
        
if ($field == '' OR $value == '' OR  ! isset($_POST[$field]))
        
{
            
return '';
        
}

        
if(is_array($_POST[$field])) {
            
if(in_array($value,$_POST[$field])) {
                
return ' checked="checked"';
            
}
        }
elseif ($_POST[$field] == $value) {
            
return ' checked="checked"';
        
}
    }

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


    /**
    * Overwrites CI's native validation prep_for_form method to work
    * with arrays. Takes a string or an array and returns the same.
    *
    * @access   public
    * @param    mixed
    * @return   mixed
    * @author   r.vadivelan / hivelan [.at.] gmail [.dot.] com
    * @link     http://codeigniter.com/forums/viewthread/73012/
    */
    
public function prep_for_form($data = '')
    
{
        
if (is_array($data))
        
{
            
foreach ($data as $key => $val)
            
{
                $data[$key]
= $this->prep_for_form($val);
            
}
        }

        
if ($this->_safe_form_data == FALSE OR $data == '')
        
{
            
return $data;
        
}

        
if(is_array($data)) {
            
return $data;
        
} else {
            
return str_replace(array("'", '"', '<', '>'), array("&#39;", "&quot;", '<', '>'), stripslashes($data));
        
}
    }

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


    /**
     * native php function caller
     *
     * This function calls native php functions for each values submitted from the form
     *
     * @access  public
     * @param   string
     * @return  string
     * @author  r.vadivelan / hivelan [.at.] gmail [.dot.] com
     * @link    http://codeigniter.com/forums/viewthread/73012/
     */
    
public function php_func_caller($rule, $data = '')
    
{
        
if (is_array($data))
        
{
            
foreach ($data as $key => $val)
            
{
                $data[$key]
= $this->php_func_caller($rule,$val);
            
}
        }

        
if ($data == '')
        
{
            
return $data;
        
}

        
if(is_array($data)) {
            
return $data;
        
} else {
            
return $rule($data);
        
}
    }

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

}
// END MY_Validation Class

?>

cheers,
Thomas

Profile
 
 
Posted: 29 June 2008 01:50 PM   [ Ignore ]   [ # 10 ]  
Summer Student
Avatar
Total Posts:  14
Joined  02-27-2008

Welcome Thomas!
Best Wishes
Velan

 Signature 

Validation: Enable CI to validate forms with multiple select (listboxes), checkbox groups, re-select listbox and multiple checkboxes

Profile
 
 
Posted: 14 August 2008 09:28 AM   [ Ignore ]   [ # 11 ]  
Summer Student
Avatar
Total Posts:  15
Joined  07-07-2008

Thanks for posting this. I’ve found that the default value works well, the only problem I’m having now is with the error message. If you set the rule for the (say) multiple checkbox field to ‘required’ then the default error message needs changing. So, I did this with:

$this->validation->set_message('required', 'Please check %s');

This can then be adapted by entering the information in the fields array. However, this seems to change the message for all other fields apart from the checkboxes. I then tried setting a callback to validate checkboxes instead of using the ‘required’ rule (so I could set the error message from within the callback function), however, the callback function only seems to run when at least one of the checkboxes is checked. Does anyone have a work around for this?

Many thanks

Profile
 
 
Posted: 15 August 2008 01:46 AM   [ Ignore ]   [ # 12 ]  
Summer Student
Avatar
Total Posts:  15
Joined  07-07-2008

Looking closer, the error message returned for the checkbox array with the ‘required’ rule was coming from $lang[‘isset’] rather than $lang[‘required’] (which the other fields with ‘required’ were) (see http://codeigniter.com/wiki/Validation/). This means that to change the error message for the checkbox array with the validation fix and ‘required’ rule you need to use something like:

$this->validation->set_message('isset', 'Please select at least one %s');
Profile
 
 
Posted: 18 August 2008 01:07 PM   [ Ignore ]   [ # 13 ]  
Lab Assistant
Avatar
RankRank
Total Posts:  279
Joined  05-08-2008

Hello Friends,

how does it look like when we generate dropdowns with the form helper?

are we able to add validation to them?

 Signature 

mit freundlichen Grüßen, Herr Kaleun

iScaffold - Check this out, it saves time smile

Profile
 
 
Posted: 20 August 2008 06:48 PM   [ Ignore ]   [ # 14 ]  
Research Assistant
Avatar
RankRankRank
Total Posts:  548
Joined  07-28-2008

I personally vote this going in as a bug. I find (at least myself) every 2 to 3 forms i build out of say 5, require the use of an array data being passed. I was really surprised this wasn’t standard functionality. Thanks for the extension. I look forward to this being standard functionality smile

This also works with the ‘set default values’ hack that has been going around for CI’s Validation library. I know, it probably doesn’t belong there. I just couldn’t justify a hole new helper just for one function.

 Signature 

~ 4 All the Right Reasons ~

Profile
 
 
Posted: 21 August 2008 02:53 AM   [ Ignore ]   [ # 15 ]  
Lab Assistant
Avatar
RankRank
Total Posts:  279
Joined  05-08-2008

yeah i think it should be standart behavior too:)

 Signature 

mit freundlichen Grüßen, Herr Kaleun

iScaffold - Check this out, it saves time smile

Profile
 
 
   
1 of 2
1
 
Post Marker Legend
New Topic New posts Hot Topic Hot Topic with new posts New Poll New Poll Moved Topic Moved Topic Sticky Topic Sticky topic
Old Topic No new posts Hot Old Topic Hot Topic with no new posts Old Poll Old Poll Closed Topic Closed Topic Announcement Announcements
Theme
Change Theme
Visitor Statistics
The most visitors ever was 721, on January 06, 2010 09:38 AM
Total Registered Members: 115004 Total Logged-in Users: 59
Total Topics: 122436 Total Anonymous Users: 4
Total Replies: 647302 Total Guests: 516
Total Posts: 769738    
Members ( View Memberlist )