Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CodeIgniter: validating form array not working

I have an array of profile data I need to validate:

$user_group_profiles = $this->input->post('user_group_profiles', TRUE);
foreach ($user_group_profiles as $key => $user_group_profile)
{
    $this->form_validation->set_rules("user_group_profiles[$key][profile_name]", 'Profile Name', 'trim|required');
    $this->form_validation->set_rules("user_group_profiles[$key][birthdate]", 'Birthdate', 'trim|required');

    // TODO: heigth/weight not required, but the validation somehow makes it required
    $this->form_validation->set_rules("user_group_profiles[$key][height]", 'Height', 'trim|greater_than[0]');
    $this->form_validation->set_rules("user_group_profiles[$key][weight]", 'Weight', 'trim|greater_than[0]');
}

Height and weight are option, but when no value is set for those fields, CI validation complains. A var_dump($user_group_profiles); shows this:

array
  'ugp_b33333338' => 
    array
      'profile_name' => string '' (length=0)
      'birthdate' => string '' (length=0)
      'height' => string '' (length=0)
      'weight' => string '' (length=0)

Any ideas what might be wrong?

EDIT 1:

I went into CI's Form_validation library and made $_field_data and public member. When I var_export it after, I got this:

  'user_group_profiles[ugp_833333338][height]' => 
    array
      'field' => string 'user_group_profiles[ugp_833333338][height]' (length=42)
      'label' => string 'Height' (length=6)
      'rules' => string 'greater_than[1]' (length=15)
      'is_array' => boolean true
      'keys' => 
        array
          0 => string 'user_group_profiles' (length=19)
          1 => string 'ugp_833333338' (length=13)
          2 => string 'height' (length=6)
      'postdata' => string '' (length=0)
      'error' => string 'The Height field must contain a number greater than 1.' (length=54)
like image 620
StackOverflowNewbie Avatar asked May 18 '12 02:05

StackOverflowNewbie


2 Answers

Ok - I've just spent an hour on this - and I've worked out the problem + solution

The issue is that when the variable you are testing is part of an array, CI interprets the field as being set, and thus "contains" a value (even when it is empty). Because that "value" is NOT a number greater than 0 - it fails.

Therefore you'll need to unset the $_POST (NOT $user_group_profiles) variable when it is "empty" so that it passes validation. Note - validation is run on $_POST - that is why you are unsetting $_POST and not $user_group_profiles

So the workaround is this:

$user_group_profiles = $this->input->post('user_group_profiles', TRUE);
foreach ($user_group_profiles as $key => $user_group_profile)
{
     // Set the rules
     $this->form_validation->set_rules($key."[profile_name]", "Profile Name", "trim|required");
     $this->form_validation->set_rules($key."[birthdate]", "Birthdate", "trim|required");
     $this->form_validation->set_rules($key."[height]", "Height", "trim|greater_than[0]");
     $this->form_validation->set_rules($key."[weight]", "Weight", "trim|greater_than[0]");

     // Now check if the field is actually empty
     if (empty($user_group_profile['height']))
     {
         // If empty, remove from array so CI validation doesnt get tricked and fail
         unset($_POST[$key]['height']);
     }
     if (empty($user_group_profile['weight']))
     {
         unset($_POST[$key]['weight']);
     }
}

I've tested this - and it fixes your problem.

You could also program it this way if you dont want to touch the $_POST data:

foreach ($user_group_profiles as $key => $user_group_profile)
    {
         // Set the rules
         $this->form_validation->set_rules($key."[profile_name]", "Profile Name", "trim|required");
         $this->form_validation->set_rules($key."[birthdate]", "Birthdate", "trim|required");


         // Now check if the field is actually empty
         if ( ! empty($user_group_profile['height']))
         {
             $this->form_validation->set_rules($key."[height]", "Height", "trim|greater_than[0]");
         }
         if ( ! empty($user_group_profile['weight']))
         {
             $this->form_validation->set_rules($key."[weight]", "Weight", "trim|greater_than[0]");
         }
    }
like image 158
Laurence Avatar answered Sep 28 '22 03:09

Laurence


Let's try and break this down into parts. I hope I can help you out here.

I'm assuming you're doing the following for the XSS Filtering with the second "TRUE" argument:

$user_group_profiles = $this->input->post('user_group_profiles', TRUE);

You can actually do the XSS filtering with the form validation rules, or if you prefer filter the post after the rules. See here for my preference:

$this->form_validation->set_rules('profile_name', 'Profile Name', 'xss_clean|trim|required');

So with knowing that now, we can follow the CI convention for their Form Validation Library. It's not necessary to grab the post before using the Form Validation Library because it auto-detects I believe the POST data anyway by the field name. For example:

$this->form_validation->set_rules('profile_name', 'Profile Name', 'trim|required|xss_clean');
$this->form_validation->set_rules('birthdate', 'Birthdate', 'trim|required|xss_clean');
$this->form_validation->set_rules('height', 'Height', 'trim|greater_than[0]|numeric');
$this->form_validation->set_rules('weight', 'Weight', 'trim|greater_than[0]|numeric');

if ($this->form_validation->run() == FALSE) {
    $this->load->view('my_view_where_this_post_came_from');
} else {
    $profile_name = $this->input->post('profile_name');

    //or if you prefer the XSS check here, this:
    //$profile_name = $this->input->post('profile_name', TRUE);

    $birthdate= $this->input->post('birthdate');
    $height= $this->input->post('height');
    $weight= $this->input->post('weight');

    //$user_group_profiles = $this->input->post();

}

I hope this helps!

EDIT: I also just noticed this. If you're trying to grab the entire post array the code is:

$user_group_profiles = $this->input->post(NULL, TRUE); // returns all POST items with XSS filter 
$user_group_profiles = $this->input->post(); // returns all POST items without XSS filter

Not:

 $user_group_profiles = $this->input->post('user_group_profiles');

A good help if you don't know your $_POST names or are confused, you can do this to see if that data is even there! Like this as your first line:

var_dump($_POST);
exit();
like image 30
envysea Avatar answered Sep 28 '22 02:09

envysea