Nested foreach loop for array comparison driving me crazy.

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • gomako
    New Member
    • Jan 2010
    • 2

    Nested foreach loop for array comparison driving me crazy.

    Hi,

    I'm new, so please let me know if any of my forum etiquette is wrong! Apologies for the fairly nondescript subject line, but I am being driven insane by it.

    Anyhow, I have a form with multiple checkboxes that need to be sticky, so I check the checkbox $_POST array against the array of form elements using a nested foreach loop. The trouble is, that when the form is submitted, even though all the checked boxes are in the $_POST array, only the final matching checkbox is checked.

    Hopefully, this code will help:

    The data:

    Code:
    $areas = array("Brierley_Hill" => "Brierley Hill","Cradley_Heath" => "Cradley Heath",	"Dudley" => "Dudley" ,"Gornal" => "Gornal","Halesowen" => "Halesowen","Kingswinford" => "Kingswinford","Netherton" => "Netherton","Oldbury" => "Oldbury","Pensnett" => "Pensnett","Quarry_Bank" => "Quarry Bank","Rowley_Regis" => "Rowley Regis","Stourbridge" => "Stourbridge","Tipton" => "Tipton","Tividale" => "Tividale");
    The function to create the checkbox portion of the form:

    Code:
    function doTownCheckBoxes($areas){
    	
    	foreach($areas as $value => $area){
    		
    		foreach($_POST['Towns'] as $town){
    
                            $checked = ($town==$value) ? "checked" : "";
    
    		}
    	
    	$html.= '<li><input type="checkbox" name="Towns[]" value="'.$value.'" '.$checked.'> '.$area.'</li>';
    
    	}
    
    	return $html;
    	
    }
    Now, I imagine there's some coding horrors in there (like cleaning and escaping the POST data before use, which I promise I'll do!), and if you could point them out to me, I'd be most grateful.

    What it's supposed to do (in my mind) is loop thorough the whole of the $areas array, then for each entry, loop through the $_POST array, see if there's a match, write "checked" into the html and start again. However, it doesn't, and I don't understand why.

    Any help would be very much appreciated.
  • Atli
    Recognized Expert Expert
    • Nov 2006
    • 5062

    #2
    Hey.

    The problem there is that you set the $checked variable for every loop, so if the first element in the $_POST array matches the current town, $checked is set accordingly. However, when the next element is checked, it won't match and the $checked variable is reset to be empty.

    What you need to do is break out of the loop when a match is found, or otherwise prevent the iterations following a match from resetting the variable.

    Consider this:
    [code=php]<?php
    function doTownCheckBoxe s($areas)
    {
    foreach($areas as $value => $area)
    {
    // This is a basic security measure, to prevent
    // things like XSS. Most variables that are
    // to be printed into a HTML page should be
    // run through this function.
    $value = htmlspecialchar s($value, ENT_QUOTES, "UTF-8");
    $area = htmlspecialchar s($area, ENT_QUOTES, "UTF-8");

    // Reset $checked for each area. If you
    // do not do this, the results of the previous
    // iteration may "bleed" through.
    $checked = "";

    foreach($_POST['Towns'] as $town)
    {
    if($town==$valu e)
    {
    // Here the variable is only set if
    // there is a match. If there is not
    // a match, it is left unaltered.
    $checked = "checked";

    // This breaks out of the current loop,
    // ending the look for matches.
    // We have already establised there is
    // a match. No need to go though the rest
    // of them.
    break;
    }
    }
    $html.= '<li><input type="checkbox" name="Towns[]" value="'.$value .'" '.$checked.'> '.$area.'</li>';
    }
    return $html;
    }
    ?>[/code]

    You could also use the in_array function to replace the inner foreach loop.
    [code=php]if(in_array($va lue, $_POST['Towns']))
    {
    $checked = "checked";
    }
    else
    {
    $checked = "";
    }
    $html.= '<li><input type="checkbox" name="Towns[]" value="'.$value .'" '.$checked.'> '.$area.'</li>';[/code]

    So you could reduce the entire thing down to just a few lines:
    [code=php]<?php
    function doTownCheckBoxe s($areas)
    {
    foreach($areas as $value => $area)
    {
    $value = htmlspecialchar s($value, ENT_QUOTES, "UTF-8");
    $area = htmlspecialchar s($area, ENT_QUOTES, "UTF-8");

    $checked = (in_array($valu e, $_POST['Towns'])) ? "checked" : "";

    $html.= '<li><input type="checkbox" name="Towns[]" value="'.$value .'" '.$checked.'> '.$area.'</li>';
    }
    return $html;
    }
    ?>[/code]

    Hope that helps :)

    Comment

    • gomako
      New Member
      • Jan 2010
      • 2

      #3
      Thankyou very very much for your quick response, and taking the time to break it all down and comment it, I really appreciate it.

      The in_array() function is a nice new function for me! There are so many useful functions out there, it will take a while to figure them out I think! It'll also save another loop of loops. :-)

      I see now that the problem was in setting and resetting the $checked variable over and over. Thanks as well for the security pointers.

      Comment

      Working...