请注意,该函数不会验证“非拉丁”域名。
if (filter_var('уникум@из.рф', FILTER_VALIDATE_EMAIL)) {
echo 'VALID';
} else {
echo 'NOT VALID';
}
(PHP 5 >= 5.2.0, PHP 7, PHP 8)
filter_var — 使用指定的过滤器过滤变量
使用FILTER_VALIDATE_*
验证过滤器、FILTER_SANITIZE_*
清理过滤器或自定义过滤器来过滤变量。
value
标量值在内部被转换为字符串,然后再进行过滤。
filter
FILTER_VALIDATE_*
常量之一作为验证过滤器,使用FILTER_SANITIZE_*
或FILTER_UNSAFE_RAW
作为清理过滤器,或使用FILTER_CALLBACK
作为自定义过滤器。
注意: 默认值为
FILTER_DEFAULT
,它是FILTER_UNSAFE_RAW
的别名。默认情况下,这将导致不执行任何过滤。
options
FILTER_FLAG_*
的位掩码。 如果filter
接受选项,则可以通过使用数组的"flags"
字段来提供标志。 如果成功,则返回过滤后的数据。如果失败,则返回false
,除非使用了FILTER_NULL_ON_FAILURE
标志,在这种情况下,返回null
。
示例 #1 filter_var() 示例
<?php
var_dump(filter_var('[email protected]', FILTER_VALIDATE_EMAIL));
var_dump(filter_var('https://example.com', FILTER_VALIDATE_URL, FILTER_FLAG_PATH_REQUIRED));
?>
以上示例将输出
string(15) "[email protected]" bool(false)
示例 #2 验证数组条目的示例
<?php
$emails = [
"[email protected]",
"[email protected]",
"invalidemail"
];
var_dump(filter_var($emails, FILTER_VALIDATE_EMAIL, FILTER_REQUIRE_ARRAY));
?>
以上示例将输出
array(3) { [0]=> string(15) "[email protected]" [1]=> string(18) "[email protected]" [2]=> bool(false) }
示例 #3 为options
传递数组的示例
<?php
$options = [
'options' => [
'min_range' => 10,
],
'flags' => FILTER_FLAG_ALLOW_OCTAL,
];
var_dump(filter_var('0755', FILTER_VALIDATE_INT, $options));
var_dump(filter_var('011', FILTER_VALIDATE_INT, $options));
?>
以上示例将输出
int(493) bool(false)
示例 #4 直接或通过数组提供标志
$str = 'string'; var_dump(filter_var($str, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE)); var_dump(filter_var($str, FILTER_VALIDATE_BOOLEAN, ['flags' => FILTER_NULL_ON_FAILURE]));
以上示例将输出
NULL NULL
FILTER_VALIDATE_*
FILTER_SANITIZE_*
请注意,该函数不会验证“非拉丁”域名。
if (filter_var('уникум@из.рф', FILTER_VALIDATE_EMAIL)) {
echo 'VALID';
} else {
echo 'NOT VALID';
}
实际上,这对手册来说不是一个有帮助的评论(所以,不要点赞),但由于搜索引擎找不到很多关于错误消息的出现,尤其是没有有用的提示,所以它可能会为某些人节省一些时间。
如果您收到类似“filter_var(): Unknown filter with ID 2097152”或其他数字的错误消息,则您只是不小心弄混了参数。因此,而不是
<?php
filter_var($ip, FILTER_FLAG_IPV6)
?>
您应该尝试使用
<?php
filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)
?>
它就能工作了 ;) 我知道,这不是设计函数最直观的方式,而且很诱人地将所有内容都放到一个参数中,就像对常规检查所做的那样,但是,是的,就是这样。
我发现了一些FILTER_VALIDATE_EMAIL拒绝但RFC5321允许的地址
<?php
foreach (array(
'[email protected]',
'(comment)[email protected]',
'"this is v@lid!"@example.com',
'"much.more unusual"@example.com',
'postbox@com',
'admin@mailserver1',
'"()<>[]:,;@\\"\\\\!#$%&\'*+-/=?^_`{}| ~.a"@example.org',
'" "@example.org',
) as $address) {
echo "<p>$address is <b>".(filter_var($address, FILTER_VALIDATE_EMAIL) ? '' : 'not')." valid</b></p>";
}
?>
结果
[email protected] 无效
(comment)[email protected] 无效
"this is v@lid!"@example.com 无效
"much.more unusual"@example.com 无效
postbox@com 无效
admin@mailserver1 无效
"()<>[]:,;@\"\\!#$%&'*+-/=?^_`{}| ~.a"@example.org 无效
" "@example.org 无效
文档中没有说明FILTER_VALIDATE_EMAIL应该通过RFC5321,但是您可以参考这些示例(特别是第一个示例)。所以这是一个说明,而不是错误报告。
请注意,FILTER_VALIDATE_BOOLEAN试图变得智能,识别诸如Yes、No、Off、On之类的单词,以及true和false的字符串和原生类型,并且在验证字符串时不区分大小写。
<?php
$vals=array('on','On','ON','off','Off','OFF','yes','Yes','YES',
'no','No','NO',0,1,'0','1','true',
'True','TRUE','false','False','FALSE',true,false,'foo','bar');
foreach($vals as $val){
echo var_export($val,true).': '; var_dump(filter_var($val,FILTER_VALIDATE_BOOLEAN,FILTER_NULL_ON_FAILURE));
}
?>
输出
'on': bool(true)
'On': bool(true)
'ON': bool(true)
'off': bool(false)
'Off': bool(false)
'OFF': bool(false)
'yes': bool(true)
'Yes': bool(true)
'YES': bool(true)
'no': bool(false)
'No': bool(false)
'NO': bool(false)
0: bool(false)
1: bool(true)
'0': bool(false)
'1': bool(true)
'true': bool(true)
'True': bool(true)
'TRUE': bool(true)
'false': bool(false)
'False': bool(false)
'FALSE': bool(false)
true: bool(true)
false: bool(false)
'foo': NULL
'bar': NULL
"hek"关于HTML5具有模式从而减少在PHP中过滤需求的说明完全错误:您仍然必须在服务器端过滤输入。HTML5表单输入是客户端的,这意味着它们完全在用户的控制之下。只有当您在PHP中接收数据时,它才是服务器端的,并且在您的控制之下。一旦数据在您的控制之下,您就必须对其进行正确过滤/清理。
无论服务器端语言如何,这都是正确的。我鼓励版主删除“hek”的说明,因为它会误导人们并造成可怕的后果。
Steve
这也是一个有效的URL
http://example.com/"><script>alert(document.cookie)</script>
请注意
URL中的问号也是有效的
<?php
echo filter_var("http://test???test.com", FILTER_VALIDATE_URL)?"valid":"not valid"; #valid
?>
FILTER_VALIDATE_URL允许
filter_var('javascript://comment%0Aalert(1)', FILTER_VALIDATE_URL);
其中%0A(URL编码的新行)在某些情况下会将注释与JS代码分开。
这可能导致XSS漏洞。
我编写了一个与PHP的filter_var()实现完全兼容的JavaScript电子邮件验证器。
mpyw/FILTER_VALIDATE_EMAIL.js:与PHP的filter_var($value, FILTER_VALIDATE_EMAIL)兼容的电子邮件验证
https://github.com/mpyw/FILTER_VALIDATE_EMAIL.js
请注意,使用FILTER_VALIDATE_URL的filter_var()使用已过时的RFC2396。这意味着它将某些当前有效字符(例如“_”)视为无效。
在许多情况下,使用php parse_url()可能更有益,它使用当前有效的RFC3986。
使用FILTER_CALLBACK需要将数组作为选项传递
<?php
function toDash($x){
return str_replace("_","-",$x);
}
echo filter_var("asdf_123",FILTER_CALLBACK,array("options"=>"toDash"));
// 返回 'asdf-123'
?>
您很可能实际上想要检测所有保留范围,而不仅仅是私有IP,并且还有另一个常量应该与之进行按位或运算。
<?php
function is_private_ip($ip) {
return !filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE);
}
?>
以下是如何使用多个标志(对于那些通过示例学习更好的人,比如我)
<?php
echo "|asdf".chr(9).chr(128)."_123|";
echo "\n";
// "按位合取"表示逻辑或/按位|
echo filter_var("|asdf".chr(9).chr(128)."_123\n|" ,FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH);
/*
结果:
|asdf �_123|
|asdf_123|
*/
?>
请注意,仅使用FILTER_VALIDATE_URL来验证URL输入可能会导致XSS
$url = 'javascript://%0Aalert(document.cookie)';
if (filter_var($url, FILTER_VALIDATE_URL, FILTER_FLAG_SCHEME_REQUIRED)) {
echo '<a href="' . $url . '">click</a>';
}
您至少应该另外检查实际使用的方案。
这是一个带有标志的过滤器语法的实际示例,因为任何地方似乎都没有单行代码可以做到这一点
'hours' => array('filter'=>FILTER_SANITIZE_NUMBER_FLOAT, 'flags' => FILTER_FLAG_ALLOW_FRACTION, 'options'=> '.')
请注意,即使URL不正确,以下内容也将返回true。因为它只验证域名、子域名、路径和查询,而不验证协议。
<?php
filter_var( 'http://https://example.com', FILTER_VALIDATE_URL );
?>
请阅读更多内容 https://php.net/manual/en/filter.filters.validate.php
您可以使用多个标志来验证IP地址
//验证输入是否为IPv4地址
$_FILTERS = array('flags' => FILTER_FLAG_IPV4);
//验证输入是否为IPv4地址且不是私有IP。
$_FILTERS = array('flags' => FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE);
//验证输入是否为IPv4且不是保留IP。
$_FILTERS = array('flags' => FILTER_FLAG_IPV4 | FILTER_FLAG_NO_RES_RANGE);
//验证输入是否为IPv4,且不是私有IP或保留IP。
$_FILTERS = array('flags' => FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE);
filter_var($_input, FILTER_VALIDATE_IP, $_FILTERS);
我看到了一些关于FILTER_VALIDATE_URL的报告,我也想添加我的,因为在像这样的愚蠢代码中
<?php
$ckOrigin = 'https://forum.myw3host.comhttps://forum.myw3host.comhttps://forum.myw3host.com/viewtopic.php?p=45#p45';
if(filter_var($ckOrigin, FILTER_VALIDATE_URL)){
echo 'ok the URL is valid';
}
?>
因为我确信如果URL错误,它会返回false,所以我花了很长时间才意识到它反而失败为上面这样的字符串,并且返回true。
作为对https://php.net/manual/en/function.filter-var.php#128235的回复
如果你使用FILTER_FLAG_PATH_REQUIRED,它可以正常工作。
var_dump( filter_var('http://test???test.com/path/?t=1', FILTER_VALIDATE_URL) ); // true
var_dump( filter_var('http://test???test.com/path/?t=1', FILTER_VALIDATE_URL, FILTER_FLAG_PATH_REQUIRED) ); // false
请注意,FILTER_FLAG_PATH_REQUIRED 对单个斜杠(/)很满意,因此
<?php
$options = array('flags' => FILTER_FLAG_PATH_REQUIRED);
filter_var('http://example.com', FILTER_VALIDATE_URL, $options); // 返回 false
filter_var('http://example.com/', FILTER_VALIDATE_URL, $options); // 返回 'http://example.com/'
?>
我不建议在普通网站上使用此函数验证电子邮件地址。问题在于,根据 RFC 3696(名称检查和转换的应用程序技术),以下电子邮件地址将被视为有效
customer/[email protected]
[email protected]
!def!xyz%[email protected]
[email protected]
"Abc@def"@example.com
在 2020 年的实时 Web 应用程序中,我几乎不会接受这些 :-/
"(comment)[email protected]"
根据 RFC5322(附录 A.6.3),这是一个无效的电子邮件地址。
"此外,地址、日期和消息标识符中的注释和空格都是过时语法的组成部分。"
请注意,当将 FILTER_VALIDATE_INT 与 FILTER_FLAG_ALLOW_HEX 标志一起使用时,例如字符串“2f”不会成功验证,因为您必须使用“0x”前缀,否则它会将数据视为十进制。
范围选项也足够智能,可以识别不同基数下边界超出时的状况。
这是一个例子
<?php
$foo = '256';
$bar = '0x100';
var_dump(validate_int($foo)); // false,太大
var_dump(validate_int($bar)); // false,太大
function validate_int($input)
{
return filter_var(
$input,
FILTER_VALIDATE_INT,
// 我们必须传递一个关联数组
// 以包含范围检查选项。
array(
'flags' => FILTER_FLAG_ALLOW_HEX,
'options' => array('min_range' => 1, 'max_range' => 0xff)
)
);
}
?>
FILTER_VALIDATE_URL 不支持国际化域名 (IDN)。无论有效与否,任何包含 Unicode 字符的域名都无法通过验证。
我们可以使用自制解决方案来规避此问题,但 C 代码就是 C 代码,因此我选择了以下代码,它建立在 filter_var() 的基础上。
<?php
$res = filter_var ($uri, FILTER_VALIDATE_URL);
if ($res) return $res;
// 检查它是否包含 Unicode 字符。
$l = mb_strlen ($uri);
if ($l !== strlen ($uri)) {
// 用“X”替换宽字符。
$s = str_repeat (' ', $l);
for ($i = 0; $i < $l; ++$i) {
$ch = mb_substr ($uri, $i, 1);
$s [$i] = strlen ($ch) > 1 ? 'X' : $ch;
}
// 现在重新检查。
$res = filter_var ($s, FILTER_VALIDATE_URL);
if ($res) { $uri = $res; return 1; }
}
?>
逻辑很简单。非 ASCII 字符的长度超过一个字节。我们将这些字符中的每一个替换为“X”,然后再次检查。
另一种方法是在调用 filter_var() 之前对 URI 进行 Punycode 编码,但 PHP 缺乏对 Punycode 的原生支持。我认为我的方法很有效。如果您认为有其他意见或有改进的空间,请发邮件给我。
一些布尔转换
<?php
var_dump(filter_var('oops', FILTER_VALIDATE_BOOLEAN, array('flags' => FILTER_NULL_ON_FAILURE)));
// NULL
var_dump(filter_var('false', FILTER_VALIDATE_BOOLEAN, array('flags' => FILTER_NULL_ON_FAILURE)));
// bool(false)
var_dump(filter_var('true', FILTER_VALIDATE_BOOLEAN, array('flags' => FILTER_NULL_ON_FAILURE)));
// bool(true)
var_dump(filter_var(0, FILTER_VALIDATE_BOOLEAN, array('flags' => FILTER_NULL_ON_FAILURE)));
// bool(false)
var_dump(filter_var(1, FILTER_VALIDATE_BOOLEAN, array('flags' => FILTER_NULL_ON_FAILURE)));
// bool(true)
var_dump(filter_var('TRUE', FILTER_VALIDATE_BOOLEAN, array('flags' => FILTER_NULL_ON_FAILURE)));
// bool(true)
var_dump(filter_var('', FILTER_VALIDATE_BOOLEAN, array('flags' => FILTER_NULL_ON_FAILURE)));
// bool(false)
var_dump(filter_var('FALSE', FILTER_VALIDATE_BOOLEAN, array('flags' => FILTER_NULL_ON_FAILURE)));
// bool(false)
关于整数过滤,需要记住的一点是,选项 `max_range` 的值必须小于或等于 `PHP_INT_MAX` 的值。
filter_var($someVariable, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => SOME_VALUE_GREATER_THAN_PHP_INT_MAX)));
即使 `$someVariable` 是预期范围内的有效整数,这也会失败。
当您尝试在 32 位系统上验证无符号 MySQL INT 类型(其最大值为 4294967295)的潜在键时,可能会出现此问题,其中 `PHP_INT_MAX` 的值为 2147483647。
需要注意的是,尽管函数第一个参数的数据类型被声明为“混合”,但这只是事实的一半。
虽然它接受任何数据类型,但在验证或清理之前,第一个参数始终会被转换为字符串。
该函数似乎严格设计用于用户输入字符串。例如:来自在线表单。在将其用于其他用途时,您可能会遇到问题。因此请仔细阅读文档!
尤其要注意,在使用 `FILTER_NULL_ON_FAILURE` 标志时,存在一个(至今)未解决的问题(#49510),涉及布尔过滤器。请注意,(string) FALSE 和 FALSE 都不被识别为布尔值,并将返回 NULL(而不是您可能期望的 FALSE)。
因此,我个人建议(迄今为止),将 `filter_var()` 函数扩展到其原始用途之外(并允许未来的扩展和自定义)的最佳方法是将其包装在您自己的类中。这将允许您解决非字符串输入上的意外行为,并添加自定义检查,或移植 PHP 后续版本中可能添加的过滤器或清理程序。
(尤其是在 PHP 目前仍然缺乏某些更奇特的 HTML5 输入类型的过滤器和清理程序,例如“color”。因此,我们确实有可能在将来的某个时间需要自定义过滤器或移植。)
回复 Andi
这不是一个有效的 URL,因为字符没有编码。
http://example.com/"><script>alert(document.cookie)</script>
这是一个有效的 URL
http://example.com/%22%3E%3Cscript%3Ealert%28document.cookie%29%3C%2Fscript%3E