lil_bugga
lil_bugga

Reputation: 91

Exiting a foreach loop and retrieve result

I'm working on a little project and I've gone brain dead, so I'm hoping someone here can help me defeat my coders block.

I'm trying to create a page using php that changes its content display depending on what (if any) value is passed to the page (Locations). I have created a safelist array which I've stored the different locations. First I check any value passed against the safe list, if its a match I display one set of content.

If it doesn't match I'm running a similarity test to check if theres maybe a simple typo and can still navigate people to the page I think they wanted but this is where I'm getting stuck.

I'm hoping that someone could type

www.example.co.uk/location.php <---- to load a generic location page

www.example.co.uk/location.php?loc=Bishops-Stortford <---- to load a targeted location page

www.example.co.uk/location.php?loc=Bishop-Stortford <---- to load a targeted location page despite mispelling providing its a 90% or more match

www.example.co.uk/location.php?loc=?php echo "I hacked your site"; ?> ---- hopefully my system will disarm nasty code injection

I'll post my code below so you can see what I've got.

<?php 
        $loc = "";
        $safelist = array("Bishops Stortford", "Braintree", "Chelmsford", "Dunmow", "Harlow", "Hertford", "Saffron Walden", "Sawbridgeworth", "Stansted", "Ware", 
                    "Essex", "Hertfordshire");

        if(isset($_GET["loc"])) {
            /* Gets the value of loc if set, replaces hyphens with spaces and capitalises first letters of words converting the rest to lowercase. */
            $loc = ucwords(strtolower(str_replace("-", " ", $_GET["loc"])));
        }

        /* Is word in safelist */
        if (in_array($loc, $safelist)) {
            /* Yes */
            if (($loc == "Essex") or ($loc == "Hertfordshire")) {
                $county = True;
            } else {
                $county = False;
            }

            if ($county == False) {
                echo "\"" . $loc . "\" is not a county";
            }else{
                echo "\"" . $loc . "\" is a county";
            }
        } else {
            /* No, Is string 90% similar to any entry within the safelist? */
            foreach ($safelist as $safeword) {      
                similar_text($safeword, $loc, $percent); 
                echo $safeword . " " . $loc . " " . $percent . "<br />";

                if ($percent >= 90) {

            }
        }


    ?>

I can't think what to do for the if ($percent >=90). I know I want to exit the loop and get the result from the first 90% or more match I find but am not 100% sure how to do this.

Also whats the best way to deal with code injection like www.example.co.uk/location.php?loc=?php echo "I hacked your site"; ?>

Upvotes: 0

Views: 187

Answers (3)

Barmar
Barmar

Reputation: 780879

I think this is what you want:

       foreach ($safelist as $safeword) {      
           similar_text($safeword, $loc, $percent); 
           echo $safeword . " " . $loc . " " . $percent . "<br />";
           if ($percent >= 90) {
               $loc = $safeword;
               $county = true;
               break;
           }
       }

As long as you don't call eval() on user input, you don't have to worry about them injecting PHP statements. When you echo something, it's sent to the browser, it's not executed again by PHP. However, you should still sanitize the output, because it might contain HTML markup, perhaps even Javascript, which could hijack the user's browser. When displaying output on the page, use htmlentities() to encode it:

echo "Greetings, " . htmlentities($first_name);

Upvotes: 1

Expedito
Expedito

Reputation: 7795

I think I would restructure it, something like this:

$loc = "";
$safelist = array("Bishops Stortford", "Braintree", "Chelmsford", "Dunmow", "Harlow", "Hertford", "Saffron Walden", "Sawbridgeworth", "Stansted", "Ware", 
                "Essex", "Hertfordshire");
if(isset($_GET["loc"])) {
    /* Gets the value of loc if set, replaces hyphens with spaces and capitalises first letters of words converting the rest to lowercase. */
    $loc = ucwords(strtolower(str_replace("-", " ", $_GET["loc"])));
}
$good = '';
if (in_array($loc, $safelist)) {
    $good = $loc;
} else {
    foreach ($safelist as $safeword) {      
        similar_text($safeword, $loc, $percent); 
        echo $safeword . " " . $loc . " " . $percent . "<br />";
        if ($percent >= 90) {
            $good = $safeword;
        }
    }
}
if ( ! empty($good)){
    /* Yes */
    if (($good == "Essex") or ($good == "Hertfordshire")) {
        $county = True;
    } else {
        $county = False;
    }

    if ($county == False) {
        echo "\"" . $good . "\" is not a county";
    }else{
        echo "\"" . $good . "\" is a county";
    }
    //And whatever else you want to do with the good location...
}

Like Barmar said, since you're not doing anything with the input value except for comparing it to an array, there's no risk of an attack in that way.

Upvotes: 0

Djave
Djave

Reputation: 9329

To answer the second part of your question, I use htmlentities to output data directly to the screen from input and something like this function on the data before a save to a database:

function escape_value($value)
{
    if($this->real_escape_string_exists)
    {
        if($this->magic_quotes_active){$value = stripslashes($value);}
        $value = mysql_real_escape_string($value);
    }
    else
    {
        if(!$this->magic_quotes_active){$value = addslashes($value);}
    }
    return $value;
}

Upvotes: 0

Related Questions