通常,我们获取请求参数的方法为直接访问超全局变量:$_GET,$_POST,$_SERVER,$_ENV,$_COOKIE,而在 php5.2 中,内置了 filter 模块,用于变量的验证和过滤等操作。过滤器函数简化了代码结构,相对于直接访问超全局变量来也更加的高效和安全。
过滤器函数列表:
- filter_has_var() — 检测是否存在指定类型的变量。
- filter_id() — 返回与某个特定名称的过滤器相关联的 id。
- filter_input_array() — 获取一系列外部变量,并且可以通过过滤器处理它们。
- filter_input() — 通过名称获取特定的外部变量,并且可以通过过滤器处理它。
- filter_list() — 返回所支持的过滤器列表。
- filter_var_array() — 获取多个变量并且过滤它们。
- filter_var() — 使用特定的过滤器过滤一个变量。
使用过滤器函数检测是否存在指定类型的变量:
bool filter_has_var(int $type ,string $variable_name);
其中,type 包含五个常量:
- INPUT_GET
- INPUT_POST
- INPUT_COOKIE
- INPUT_SERVER
- INPUT_ENV
分别对应
- $_GET
- $_POST
- $_COOKIE
- $_SERVER
- $_ENV
这些常量在其他过滤器函数中同样适用。
filter_has_var() 函数在成功时返回 TRUE,或者在失败时返回 FALSE。
使用该函数,可以把此段代码
if (isset($_GET['name'])){
echo htmlentities($_GET['name']);
} else {
echo '参数不存在';
}
复制代码
改写为:
echo filter_has_var(INPUT_GET, 'name') ? $_GET['name'] : '参数不存在';
复制代码
但是使用此函数,只解决了判断变量是否存在的问题,如果 $name 的值是
'jone'
那么在 echo 的时候会出现显示错误,更严重的是如果对方传过来的 name 中包含了 标签,就可以对网站进行注入攻击,那么有什么办法来解决这个问题呢?
通过名称获取特定的外部变量,并且可以通过过滤器处理它:
mixed filter_input ( int $type , string $variable_name [, int $filter = FILTER_DEFAULT [, mixed $options ]] )
这个函数可以说是 filter_has_var() 的加强版,它在检测输入是否存在的同时,还可以传入第三个参数(过滤器)来检测该输入是否符合规范,如果变量不存在返回NULL,不符合则返回 FALSE。 其中第三个参数需要填一个过滤器类型(默认为 FILTER_SANITIZE_STRING),PHP 有两种过滤器:
- Validating 过滤器:
- 用于验证用户输入
- 严格的格式规则(比如 URL 或 E-Mail 验证)
- 如果成功则返回预期的类型,如果失败则返回 FALSE
- Sanitizing 过滤器:
- 用于允许或禁止字符串中指定的字符
- 无数据格式规则
- 始终返回字符串
例:
$email_1 = filter_input(INPUT_GET,'email', FILTER_VALIDATE_EMAIL);
$email_2 = filter_input(INPUT_GET,'email', FILTER_SANITIZE_EMAIL);
echo 'VALIDATE:';
var_dump($email_1);
echo "";
echo 'SANITIZE:';
var_dump($email_2);
复制代码
当我们使用
localhost/test.php?email=1234578qq.com
访问包含这段代码的脚本时(显然这是一个非法的email地址),输出如下:
VALIDATE:bool(false) SANITIZE:string(15) "1234578brqq.com"
当使用
localhost/test.php?email=1234578@qq.com
访问时(合法url),输出如下:
VALIDATE:string(14) "1234578@qq.com" SANITIZE:string(14) "1234578@qq.com"
很明显,当参数的值合法时,两个过滤器会返回相同的值,但是当参数非法时,VALIDATE 会返回一个布尔值 FALSE,而 SANITIZE 返回了一个过滤掉特殊字符的字符串。
值得一提的是,可以传入 FILTER_VALIDATE_REGEXP 参数,从而根据 regexp,兼容 Perl 的正则表达式来验证值:
$options = ['options'=>['default'=>'', 'regexp'=>"/^\w*$/"]];
$xxx = filter_input(INPUT_GET,'xxx', FILTER_VALIDATE_REGEXP, $options);
复制代码
所以,VALIDATE 类型的过滤器适合用来判断格式是否正确,而 SANITIZE 能够对给定的字符串进行过滤(具体过滤规则请参考:php.net/manual/zh/f…)。
同时我们也发现了一个问题,虽然 SANITIZE 可以对字符串进行过滤,但是这个过滤非常的简单粗暴,直接把它看不顺眼字符从字符串中删掉了,这在其他场景中或许大有用处,但在处理输入上,通常我们应该返回给用户一个‘你不能这么做!’的提示,而不应该擅自替用户做其他操作,或者想将那些字符转义并保留下来,如何达到这个目的呢?
使用回调函数:FILTER_CALLBACK
如果你看系统自带的过滤器都不顺眼,那你可以将第三个参数指定为 FILTER_CALLBACK ,并在第四个参数的位置指定一个回调函数,来实现自己的过滤器,格式如下:
filter_input(INPUT_POST, 'email',FILTER_CALLBACK,array('options' => 'my_filter'));
复制代码
回调函数格式如下:
function my_filter($str)
{
// 需要一个形参(本例中为 $str)来接受字符串
// 拿到目标字符串后就可以对它为所欲为了
$str .= 'f*ck';
// 最后记得 return 加工后的字符串
return $str;
}
复制代码
扩展应用
相信你也发现了,这只是 PHP 的过滤器函数中的一部分,如果你的目标字符串不是来源于前端输入,而是后端自己加工(或是从数据库直接取出)出来的,同样也可以使用类似的过滤器函数,如 filter_var(),该函数的语法为:
filter_var(variable, filter, options); 可以看到,和我们上面使用的函数大同小异,你只需要在传入输入类型的地方改为传入一个要过滤的变量就可以了。