PHP Conference Japan 2024

filter_var

(PHP 5 >= 5.2.0, PHP 7, PHP 8)

filter_var使用指定的過濾器過濾變數

說明

filter_var(混合 $value, 整數 $filter = FILTER_DEFAULT, 陣列|整數 $options = 0): 混合

使用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('bob@example.com', FILTER_VALIDATE_EMAIL));
var_dump(filter_var('https://example.com', FILTER_VALIDATE_URL, FILTER_FLAG_PATH_REQUIRED));
?>

上述範例將輸出

string(15) "bob@example.com"
bool(false)

範例 #2 驗證陣列項目的範例

<?php
$emails
= [
"bob@example.com",
"test@example.local",
"invalidemail"
];

var_dump(filter_var($emails, FILTER_VALIDATE_EMAIL, FILTER_REQUIRE_ARRAY));
?>

上述範例將輸出

array(3) {
  [0]=>
  string(15) "bob@example.com"
  [1]=>
  string(18) "test@example.local"
  [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

另請參閱

新增註釋

使用者貢獻的註釋 30 則註釋

cabrinosimone at gmail dot com
11 年前
請注意,此函式不會驗證「非拉丁」網域。

if (filter_var('уникум@из.рф', FILTER_VALIDATE_EMAIL)) {
echo '有效';
} else {
echo '無效';
}
隨機使用者
11 個月前
實際上,這對手冊來說並不是很有幫助的註釋(所以不要按讚),但由於搜尋引擎找不到很多關於此錯誤訊息的資訊,尤其沒有任何有用的提示,它可能會為某些人節省一些時間。

如果您收到類似「filter_var(): 含有 ID 2097152 的未知過濾器」或其他數字的錯誤訊息,您只是不小心混淆了參數。因此,不要使用

<?php
filter_var
($ip, FILTER_FLAG_IPV6)
?>

您應該嘗試使用

<?php
filter_var
($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)
?>

它會起作用 ;) 我知道,這不是設計函數最直觀的形式,而且很容易像在一般檢查中那樣把所有東西都丟到一個參數中,但是,是的,它就是這樣。
gt at kani dot hu
11 年前
我發現了一些 FILTER_VALIDATE_EMAIL 拒絕,但 RFC5321 允許的地址
<?php
foreach (array(
'localpart.ending.with.dot.@example.com',
'(comment)localpart@example.com',
'"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>";
}
?>
結果

localpart.ending.with.dot.@example.com 不合法
(comment)localpart@example.com 不合法
"this is v@lid!"@example.com 不合法
"much.more unusual"@example.com 不合法
postbox@com 不合法
admin@mailserver1 不合法
"()<>[]:,;@\"\\!#$%&'*+-/=?^_`{}| ~.a"@example.org 不合法
" "@example.org 不合法

文件並沒有說明 FILTER_VALIDATE_EMAIL 應該要通過 RFC5321,然而你可能會遇到這些例子(尤其是第一個)。所以這是一個注意事項,而不是錯誤報告。
divinity76 at gmail dot com
7 年前
請注意,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': 布林值(真)
'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': 空值
Steve
6 年前
「hek」關於 HTML5 擁有模式因此減輕 PHP 過濾需求的說明完全錯誤:您仍然必須在伺服器端過濾輸入。 HTML5 表單輸入是客戶端,意味著它們完全在用戶的控制之下。只有當您在 PHP 中收到數據時,它才是伺服器端並在您的控制之下。一旦數據在您的控制之下,您就必須正確地過濾/清理它。

無論伺服器端語言為何,這都是事實。我會建議版主刪除「hek」的說明,因為它會誤導人們,造成可怕的後果。

Steve
Andi, info at pragmamx dot org
12 年前
這也是一個有效的網址

http://example.com/"><script>alert(document.cookie)</script>
匿名
1 年前
請注意
網址中的問號也是有效的

<?php
echo filter_var("http://test???test.com", FILTER_VALIDATE_URL)?"有效":"無效"; #有效
?>
匿名
9 年前
FILTER_VALIDATE_URL 允許

filter_var('javascript://comment%0Aalert(1)', FILTER_VALIDATE_URL);

其中 %0A(URL 編碼的換行符),在某些情況下,會將註釋從 JS 代碼中分割出來。

這可能導致 XSS 漏洞。
mpyw628 at gmail dot com
6 年前
我寫了一個與 PHP 的 filter_var() 實作完全相容的 JavaScript 電子郵件驗證器。

mpyw/FILTER_VALIDATE_EMAIL.js:與 PHP 的 filter_var($value, FILTER_VALIDATE_EMAIL) 相容的電子郵件驗證
https://github.com/mpyw/FILTER_VALIDATE_EMAIL.js
Guy Sartorelli
1 年前
請注意,帶有 FILTER_VALIDATE_URL 的 filter_var() 使用已過時的 RFC2396。這表示它將一些目前有效的字元(例如「_」)視為無效。

在許多情況下,使用 php parse_url() 可能更有益,它使用目前有效的 RFC3986。
dale dot liszka at gmail dot com
16 年前
使用 FILTER_CALLBACK 需要傳遞一個陣列作為選項

<?php
function toDash($x){
return
str_replace("_","-",$x);
}

echo
filter_var("asdf_123",FILTER_CALLBACK,array("options"=>"toDash"));
// 返回 'asdf-123'
?>
marcus at synchromedia dot co dot uk
12 年前
您很可能實際上想要偵測所有保留範圍,而不僅僅是私有 IP,並且還有另一個常數可以用於它們,應該與它進行位元或運算。
<?php
function is_private_ip($ip) {
return !
filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE);
}
?>
dale dot liszka at gmail dot com
16 年前
以下是使用多個旗標的方法(對於像我一樣透過範例學習效果更好的人)

<?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|
*/
?>
keevitaja at gmail dot com
12 年前
請注意 FILTER_VALIDATE_URL 會通過以下網址

http://example.ee/sdsf"f
crisp at tweakers dot net
6 年前
請注意,僅使用 FILTER_VALIDATE_URL 來驗證網址輸入可能會導致 XSS 漏洞

$url = 'javascript://%0Aalert(document.cookie)';

if (filter_var($url, FILTER_VALIDATE_URL, FILTER_FLAG_SCHEME_REQUIRED)) {
echo '<a href="' . $url . '">點擊</a>';
}

您至少應該另外檢查實際使用的通訊協定。
jon dot bertsch at ucop dot edu
15 年前
這是一個帶有旗標的 filter 語法實際範例,因為似乎沒有任何地方有單行程式碼可以做到這一點

'hours' => array('filter'=>FILTER_SANITIZE_NUMBER_FLOAT, 'flags' => FILTER_FLAG_ALLOW_FRACTION, 'options'=> '.')
remindfwd
1 年前
請注意,即使網址不正確,以下內容也會返回 true。因為它只驗證網域、子網域、路徑和查詢,而不驗證通訊協定。

<?php
filter_var
( 'http://https://example.com', FILTER_VALIDATE_URL );
?>

詳情請參閱 https://php.dev.org.tw/manual/en/filter.filters.validate.php
ajcorrea at gmail dot com
1 年前
您可以使用多個 FLAGS 來驗證 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);
axew3 at me dot you
4 個月前
我看過一些關於 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
'網址有效';
}
?>

因為我確信如果網址錯誤它會返回 false,所以我花了很多時間才意識到它反而會失敗在像上面這樣的字串中,並且它返回 true。
dakaenev at gmail dot com
11 個月前
回覆 https://php.dev.org.tw/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
mmerlone at gmail dot com
3 年前
請注意,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/'
?>
Robert Vlach
4 年前
我不建議在一般的網站上使用這個函式來驗證電子郵件地址。問題在於,根據 RFC 3696(名稱檢查和轉換的應用技術),以下電子郵件地址將被視為有效:

customer/department=shipping@example.com
$A12345@example.com
!def!xyz%abc@example.com
_somename@example.com
"Abc@def"@example.com

在 2020 年的線上網路應用程式中,這些我幾乎都不會接受 :-/
joe at bloe dot com
10 年前
"(comment)localpart@example.com"
根據 RFC5322(附錄 A.6.3),這是一個無效的電子郵件地址。
「此外,地址、日期和訊息識別碼中的註釋和空格都是過時語法的一部分。」
dyer85 at gmail dot com
16 年前
請注意,當 FILTER_VALIDATE_INT 與 FILTER_FLAG_ALLOW_HEX 旗標一起使用時,例如字串「2f」將無法成功驗證,因為您必須使用「0x」前綴,否則它會將資料視為 10 進位。

範圍選項也夠聰明,可以識別不同進位制中超出邊界的情況。

以下是一個範例:

<?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)
)
);
}

?>
php at maisqi dot com
13 年前
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 的原生支援。我認為我的方法很有效。如果您有其他想法或認為有改進空間,請發送電子郵件給我。
yoanlin93 at gmail dot com
9 年前
一些布林值轉換

<?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)
drew_mirage at hotmail dot com
11 年前
過濾整數時,有一件很重要的事情需要記住,`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。
buttflattery at gmail dot com
8 年前
`FILTER_VALIDATE_URL` 會驗證像 http://www. 這樣的網址。
Tom
11 年前
需要注意的是,雖然函數的第一個參數的資料類型被聲明為「mixed」,但这只是事实的一半。

雖然它接受任何資料類型,但在驗證或清理之前,第一個參數始終會被轉換為字串。

看來這個函數的設計嚴格來說是用於使用者輸入的字串。例如:來自線上表單。當用於其他用途時,您可能會看到問題。因此,請仔細閱讀文件!

特別要注意的是,目前有一個尚未解決的問題 (#49510),關於在使用 FILTER_NULL_ON_FAILURE 旗標時,布林值過濾器的問題。要注意的是,(字串) FALSE 和 FALSE 都無法被識別為布林值,而且會回傳 NULL(而不是您可能預期的 FALSE)。

因此我個人建議,目前為止,要讓 filter_var() 函式超越其原始用途(並允許未來的擴充和客製化)的最佳方法,是將它們封裝在您自己的類別中。這將允許您處理非字串輸入的非預期行為,並新增您的自訂檢查,或者回溯移植可能在未來 PHP 版本中新增的過濾器或清理器。
(尤其是因為 PHP 目前仍然缺少一些較特殊的 HTML5 輸入類型(例如「color」)的過濾器和清理器。因此,我們確實有可能在未來的某個時間點需要自訂過濾器或回溯移植。)
匿名
6 年前
回覆 Andi

這不是有效的網址,因為字元沒有經過編碼

http://example.com/"><script>alert(document.cookie)</script>

這是有效的網址

http://example.com/%22%3E%3Cscript%3Ealert%28document.cookie%29%3C%2Fscript%3E
To Top