SamC Posted March 23, 2017 Share Posted March 23, 2017 So I've got my search form working ok now. I haven't run any of this through sanitizer yet though and could do with help choosing which functions are required. I'm over here having a read through them: https://processwire.com/api/variables/sanitizer/ The items I GET are: // search.php // GET towns array $towns = $input->get->town; // array - maybe $sanitizer->array($value) // GET building type $buildingType = $input->get->type; // dropdown select. Is a string? $sanitizer->text($value) perhaps or $sanitizer->string($value) // GET min area $minArea = $input->get->minArea; // integer - maybe $sanitizer->int($value) // GET max area $maxArea = $input->get->maxArea; // integer - maybe $sanitizer->int($value) Not entirely sure which to choose. The checkboxes and dropdowns are created from values entered in the admin area so I guess they could be entered incorrectly. Does that mean I should run sanitizer on the select list options too on my actual form before they are populated? Thanks for any advice. I can post the entire code of search-form.php and search.php if necessary, I thought that might distract a bit in this post. search-form.php: search.php: Link to comment Share on other sites More sharing options...
Zeka Posted March 23, 2017 Share Posted March 23, 2017 I think you should use $sanitizer->selectorValue($value) as you use values in selector. 1 Link to comment Share on other sites More sharing options...
LostKobrakai Posted March 23, 2017 Share Posted March 23, 2017 You form looks like $sanitizer->option() and ->options() should be enough. There's no input where a user is supposed to supply other values than the ones you supply. 1 Link to comment Share on other sites More sharing options...
SamC Posted March 23, 2017 Author Share Posted March 23, 2017 Thanks guys. Not sure I get how to use this though: // Return $value if it exists in the $allowed array of values, or null if it doesn't. $sanitizer->option($value, $allowed) // Return array of given $values that that also exist in $allowed array whitelist of values. $sanitizer->options($values, $allowed) Do I make a whitelist? The code for the search.php is: <?php // catchall selector for empty fields $theSelector = "template=building-entry"; // start building selectors $sorting = "sort=addressBuildingTown"; $townSelector = "addressBuildingTown"; $buildingTypeSelector = "buildingType"; $areaSelector = "buildingArea"; // used to output 'filtered by' above results $summary = [ "towns" => "", "type" => "", "min" => "", "max" => "", ]; // GET towns array $towns = $input->get->town; // GET building type $buildingType = $input->get->type; // GET min area $minArea = $input->get->minArea; // GET max area $maxArea = $input->get->maxArea; // if a town has been selected if (count($towns)) { foreach ($towns as $town) { $townSelectorPart .= $town . '|'; } $townSelectorPart = rtrim($townSelectorPart, '|'); $summary["towns"] = $townSelectorPart; $theSelector .= "," . $townSelector . "=" . $townSelectorPart; } // if a building type has been selected if ($buildingType) { $summary["type"] = $buildingType; $theSelector .= "," . $buildingTypeSelector . "=" . $buildingType; } // if min or max area has been selected if ($minArea || $maxArea) { // if min area selected if ($minArea) { $summary["min"] = $minArea; $minAreaSelectorPart = $areaSelector . ">={$minArea}"; $theSelector .= "," . $minAreaSelectorPart; } // if max area selected if ($maxArea) { $summary["max"] = $maxArea; $maxAreaSelectorPart = $areaSelector . "<={$maxArea}"; $theSelector .= "," . $maxAreaSelectorPart; } } echo "<h1>Summary array: "; print_r($summary); echo "</h1>"; ?> <?php echo "Selector used for this page: " . $theSelector; ?> <h1>Filtered by: <br> <?php $str = ""; if ($summary["towns"]) { $str .= "Towns: " . str_replace("|", ", ", $summary["towns"]) . "<br>"; } if($summary["type"]) { $str .= "Type: " . $summary["type"] . "<br>"; } if ($summary["min"]) { $str .= "Min area: " . $summary["min"] . "<br>"; } if($summary["max"]) { $str .= "Max area: " . $summary["max"] . "<br>"; } echo $str; ?> </h1> <?php $buildings = $pages->find($theSelector . "," . $sorting); foreach ($buildings as $building): ?> <h2><?php echo $building->title; ?></h2> <?php if ($building->addressBuildingName): ?> <p>BUILDING NAME: <?php echo $building->addressBuildingName; ?></p> <?php endif; ?> <p>ADDRESS: <?php echo $building->addressBuildingNumber . ' ' . $building->addressBuildingStreet . ', '; ?> <a href='#'><?php echo $building->addressBuildingTown; ?></a> </p> <p>TYPE: <a href='#'><?php echo $building->buildingType->title; ?></a></p> <p>AREA: <?php echo $building->buildingArea; ?></p> <?php echo $building->buidingDescription; ?> <?php endforeach; ?> Link to comment Share on other sites More sharing options...
LostKobrakai Posted March 23, 2017 Share Posted March 23, 2017 $allowed is a simple array, where you put the values, which the form does present, e.g. <?php $values = [500 => "500 sq ft.", 1000 => "1000 sq ft."]; ?> <select> <?php foreach($values as $value => $label) : ?> <option value="<?=$value?>"><?=$label?></option> </select> <?php // With the same $values array $allowed = array_keys($values); // [500, 1000] $minArea = $input->get->options("minArea", $allowed); Link to comment Share on other sites More sharing options...
SamC Posted March 23, 2017 Author Share Posted March 23, 2017 My selects are populated with this data in search-form.php <?php // get all buildings $buildings = $pages->find("template=building-entry"); // set up variables $towns = []; $buildingTypes = []; $minAreas = [ '500', '1000', '2000', '3000', '4000', '5000', '6000', '7000', '8000', '9000', '10000', '50000' ]; $maxAreas = [ '500', '1000', '2000', '3000', '4000', '5000', '6000', '7000', '8000', '9000', '10000', '60000', '100000' ]; //get unique towns into array foreach ($buildings as $building) { if(!in_array($building->addressBuildingTown, $towns)) { $towns[] = $building->addressBuildingTown; } $uniqueTowns = $towns; sort($uniqueTowns); //get unique building types into array if(!in_array($building->buildingType->title, $buildingTypes)) { $buildingTypes[] = $building->buildingType->title; } $uniqueBuildingTypes = $buildingTypes; sort($uniqueBuildingTypes); } ?> <form id='building_search' method='get' action='<?php echo $config->urls->root?>search/'> <h3>Building search</h3> <p> <label for='search_town'>Filter by town</label><br> <?php foreach ($uniqueTowns as $town) { echo "<input type='checkbox' name='town[]' value='{$town}'>{$town}<br>"; } ?> </p> <p> <label for='search_type'>Building type</label> <select id='search_type' name='type'> <option value=''>Any</option> <?php foreach ($uniqueBuildingTypes as $type) { echo "<option value='{$type}'>{$type}</option>"; } ?> </select> </p> <p> <label for='search_min_area'>Min area</label> <select id='search_min_area' name='minArea'> <option value=''>No min</option> <?php foreach($minAreas as $minArea) { $formatMinArea = number_format($minArea); echo "<option value='{$minArea}'>{$formatMinArea} sq ft.</option>"; } ?> </select> </p> <p> <label for='search_max_area'>Max area</label> <select id='search_max_area' name='maxArea'> <option value=''>No max</option> <?php foreach($maxAreas as $maxArea) { $formatMaxArea = number_format($maxArea); echo "<option value='{$maxArea}'>{$formatMaxArea} sq ft.</option>"; } ?> </select> </p> <p><button type='submit' id='search_submit' name='submit' value='1'>Search</button></</p> </form> Looks like I'm missing something in my $minAreas and $maxAreas arrays. So are we saying I should change the key/values to: // FROM $minAreas = [ '500', '1000', '2000', '3000', '4000', '5000', '6000', '7000', '8000', '9000', '10000', '50000' ]; // TO $minAreas = [ 500 => '500 sq ft', 1000 => '1000 sq ft', 2000 => '2000 sq ft', 3000 => '3000 sq ft', 4000 => '4000 sq ft', 5000 => '5000 sq ft', 6000 => '6000 sq ft', 7000 => '7000 sq ft', 8000 => '8000 sq ft', 9000 => '9000 sq ft', 10000 => '10000 sq ft', 50000 => '50000 sq ft' ]; // use keys to make whitelist $allowed = array_keys($minAreas); // [500, 1000] // on search.php $minArea = $input->get->options("minArea", $allowed); Where does sanitizer come in here? Maybe I'm just being slow but still not fully getting this. Link to comment Share on other sites More sharing options...
LostKobrakai Posted March 23, 2017 Share Posted March 23, 2017 array_keys() will just revert your array back to the form of just the sq ft "[500, 1000, …]" so no need to change that one. Just make sure you have all the possible keys of your form inputs accessable when sanitizing. It doesn't matter where those keys come from or how the arrays are created. 6 minutes ago, SamC said: Where does sanitizer come in here? Maybe I'm just being slow but still not fully getting this. It's just a shortcut. Both versions below do the same. $minArea = $input->get->options("minArea", $allowed); $minArea = $sanitizer->options($input->get->minArea, $allowed); Edit: Also there's no magic whitelist anywhere. This is all plain php and using arrays. 1 Link to comment Share on other sites More sharing options...
SamC Posted March 23, 2017 Author Share Posted March 23, 2017 Thanks @LostKobrakai, I'll give it a try. Link to comment Share on other sites More sharing options...
SamC Posted March 23, 2017 Author Share Posted March 23, 2017 Ok, so I did this (parts from two different files but run in the following order): $minAreas = [ 500 => '500 sq ft', 1000 => '1,000 sq ft', 2000 => '2,000 sq ft', 3000 => '3,000 sq ft', 4000 => '4,000 sq ft', 5000 => '5,000 sq ft', 6000 => '6,000 sq ft', 7000 => '7,000 sq ft', 8000 => '8,000 sq ft', 9000 => '9,000 sq ft', 10000 => '10,000 sq ft', 50000 => '50,000 sq ft' ]; <label for='search_min_area'>Min area</label> <select id='search_min_area' name='minArea'> <option value=''>No min</option> <?php foreach($minAreas as $value => $label) { echo "<option value='{$value}'>{$label}</option>"; } ?> </select> // GET (sanitized) min area $allowedMinAreas = array_keys($minAreas); // Return $input->get->minArea if it exists in the $allowedMinAreas array of values, or null if it doesn't. $minArea = $sanitizer->option($input->get->minArea, $allowedMinAreas); Now, I get the following results after submitting the form, and secondly after changing the value in the URL itself: search/?type=&minArea=4000 // Selector used for this page: template=building-entry,buildingArea>=4000 // after changing URL manually to a number NOT in the 'Min area' select list // a user can't change the values in the list, but they can modify the URL search/?type=&minArea=4200 // Selector used for this page: template=building-entry So I think it's working correctly Two things I still don't understand. What am I sanitizing? There's no input from a user on a select list. Am I correct in assuming it's to stop someone from changing the value in the URL (like I did above in my second result). Secondly, in the case of my checkboxes, those town names are obtained from text fields within the CMS. If a building-entry exists, and has a unique town name, it ends up as a new checkbox (the building-entry becomes searchable). So in this case, when do I sanitize? BEFORE the checkboxes are even rendered on the screen to a user? Or only when obtaining the values via $input->get? Or both even? Quote from $sanitizer api page: https://processwire.com/api/variables/sanitizer/#options-that-may-be-provided-to-the-text-and-textarea-functions Quote Always sanitize/filter any data you get from $input->get, $input->post, $input->cookie (and PHP's $_GET, $_POST, $_COOKIE if you use them). I think these are the only issues I have with sanitizer so far, otherwise, pleased to have learned something new! Getting there, slowly but surely. Link to comment Share on other sites More sharing options...
LostKobrakai Posted March 23, 2017 Share Posted March 23, 2017 45 minutes ago, SamC said: So in this case, when do I sanitize? You only sanitize the user input. So anything coming in via GET/POST/… data. Anything else comes from your system and your system should never have data in it, which aren't "save", so no need to sanitize anything there. 48 minutes ago, SamC said: Am I correct in assuming it's to stop someone from changing the value in the URL (like I did above in my second result). It's not only about plainly changing the number to another one. People try to inject all manner of things into websites, like sql statements or else. So it's for security as well as for preventing errors in your system because of values you didn't expect. 2 Link to comment Share on other sites More sharing options...
SamC Posted March 23, 2017 Author Share Posted March 23, 2017 @LostKobrakai thanks you're a gent. I applied similar functions to my other GET values: // GET towns array // // this one freaks if no towns are selected // Fatal error: Uncaught TypeError: Argument 1 passed to ProcessWire\Sanitizer::options() must // be of the type array, null given // $allowedTowns = array_values($uniqueTowns); $towns = $sanitizer->options($input->get->town, $allowedTowns); // GET building type $allowedTypes = array_values($uniqueBuildingTypes); $buildingType = $sanitizer->option($input->get->type, $allowedTypes); // GET (sanitized) min area $allowedMinAreas = array_keys($minAreas); $minArea = $sanitizer->option($input->get->minArea, $allowedMinAreas); // GET max area $allowedMaxAreas = array_keys($maxAreas); $maxArea = $sanitizer->option($input->get->maxArea, $allowedMaxAreas); So, nearly works. --EDIT-- I was thinking: // GET towns array if($input->get->town) { $allowedTowns = array_values($uniqueTowns); $towns = $sanitizer->options($input->get->town, $allowedTowns); } ...but the the code inside the if() statement isn't sanitized. Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now