过滤掉input_get变量中的任何类型的URL,这是最好的方法吗?


Filter out any type of URL in input_get variable, is this the best way?

我想出了这个潜在的解决方案,但想仔细检查是否有更好/更有效的方法。

如果 ?uri 包含 $filter 数组中的任何内容,则应退出。注意:我想检查它是否不包含诸如 ?url=http://google.com 之类的 URL,因此例如FILTER_VALIDATE_URL不起作用。

使用我的 uri,我只想接受以下参数:"示例"或"示例示例",因为 uri 已经附加到具有域的变量上。因此,示例输出将是 domain.com/pdf.php?uri=example-example

    $uri = filter_input(INPUT_GET, 'uri', FILTER_SANITIZE_STRING);
    $filter = array('http://', 'https://' ,'www.', '.', '@', '/');
    foreach ($filter as $k) {
        if (strpos($uri, $k) === false) {
            // No matches, carry on
        } else {
            // Match is found, exit
            exit("Error in url parameter: $k is not allowed!");
        }
    }

您可以定义自己的自定义过滤器:

$uri = filter_input(INPUT_GET, 'uri', FILTER_CALLBACK, [
    'options' => function($value) {
        return !preg_match('~https?://|[.@/]~', $value);
    }
]);

有几种方法可以做到这一点。

据我了解,您不希望它包含任何 URI 方案或字符,例如 @ 或/或 www。

您可以使用正则表达式仅允许所需的字符:

// not valid
$uri = 'http://google.com';
// Is only valid if contains A-Z, a-z, 0-9, -, _
$isValidUri = preg_match('/^['-A-Za-z0-9_]+$/', $uri);
if ($isValidUri) {
    // Do something here with the valid uri . . .
} else throw new Exception('Not a valid uri');

您还可以使用 PHP filter_input或filter_var函数来清理输入,就像您所做的那样。但要非常小心地清理用户输入,并确保彻底测试防止滥用。

无论挑战如何,PHP 通常都为同一解决方案提供不同的路径。关键是决定哪个最适合您的特定目的。有时,任何有效的代码都是最好的解决方案。例如,其他时候,您可能需要测试各种解决方案,以查看哪个解决方案执行速度最快。

所以,你问是否有"更好或更有效的方法"。"更好"是主观的;效率更高可以通过测试来确定。例如,针对现有代码测试下面的代码,看看哪个版本的执行速度更快。 通过这样做,而不是依赖他人的意见,您将学习如何做出自己的"哪个是最好的"决定。这样做将大大有助于你成为一个受过更好教育的程序员。

$start = microtime(true);
$myarray = array("http://google.com","ftp://google.com","https://google.com","Nothing to see here");
foreach ($myarray as $uri)
{
if (!preg_match("/'b(?:(?:https?|ftp):'/'/|www'.)[-a-z0-9+&@#'/%?=~_|!:,.;]*[-a-z0-9+&@#'/%=~_|]/i",$uri)) 
{
  echo "$uri contains no matches - carry on<br>";
} else {
          echo "Match is found in $uri, <br>";
       }
}
$elapsed_time = (microtime(true) - $start);
echo "Routine took $elapsed_time seconds to run";