Accepting and Displaying User Data Giving Warnings for Links

Saturday, March 28, 2009

There is one final manipulation of user submitted data that is regularly done. If the script allows users to include URLs in their data, the user could make the link say something completely different from where the URL actually goes. This ends up being a blemish on your website. The common solution is to display beside the actual link, the host name that the link refers to. This gives the browser a visual indication whether the link is going where they think it is.

This can be done whether you are allowing HTML to be entered or BBCode. If BBCode, just call the function defined in the following code after it has been converted into HTML. This technique can be useful for other purposes as well, such as scanning HTML data and placing "offsite" links for any external link versus ones to your own website.

<?php
// A function to create warnings on any links:
function warn_links($string) {
    // First, find all the links in the string:
    preg_match_all('|<a\s+href\s*=\s*([\'"])(.*?)\1>|i',
        $string, $results, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);

    // Now, loop over all results, BACKWARDS, to make replacements
    // Backwards so that our offsets don't start changing on us:
    foreach (array_reverse($results) as $r) {
        // [0][1] contains the offset position of the link & [2][0]
        //  contains the URL - So parse the URL to get it's host:
        $parsed = parse_url($r[2][0]);

        // Check the host - if it doesn't exist use this server's hostname:
        $host = isset($parsed['host']) ? $parsed['host'] :
            $_SERVER['HTTP_HOST'];

        // Now insert the 'host' warning:
        $string = substr_replace($string, " [{$host}] ", $r[0][1], 0);
    }

    return $string;
}

// If we had a POST, then output the data for reference:
if (count($_POST)) {
    echo "<p>The data, with link warnings:</p>\n";
    echo warn_links($_POST['data']);
}
?>
<form action="<?= $_SERVER['PHP_SELF'] ?>" method="post" name="f1">
<p>Enter some data:</p>
<p><textarea name="data" cols="80"
    rows="10"><?= @$_POST['data'] ?></textarea></p>
<p><input type="submit" /></p>
</form>


Hope it helps.

0 comments: