1. 程式人生 > >使用PHP:Filter函式(過濾器)獲取引數並進行過濾

使用PHP:Filter函式(過濾器)獲取引數並進行過濾

通常,我們取得引數的方法為直接訪問超全域性變數:$_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 — 使用特定的過濾器過濾一個變數


1,檢測是否存在指定型別的變數:

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的值是'jo<br>ne',那麼在echo的時候會顯示錯誤,更嚴重的是如果對方使用了<script>標籤,就可以對網站進行注入攻擊,那麼有什麼辦法來解決這個問題呢?

2,通過名稱獲取特定的外部變數,並且可以通過過濾器處理它:
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 "<br>";
echo 'SANITIZE:';var_dump($email_2);


當我們使用localhost/test.php?email=1234578<br>qq.com訪問包含這段程式碼的指令碼時(顯然這是一個非法的email地址),輸出如下:
VALIDATE:bool(false) 
SANITIZE:string(15) "1234578brqq.com"

當使用localhost/[email protected]訪問時(合法url),輸出如下:
VALIDATE:string(14) "[email protected]" 
SANITIZE:string(14) "[email protected]"


很明顯,當引數的值合法時,兩個過濾器會返回相同的值,但是當引數非法時,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應該那來對給定的字串進行過濾(具體過濾規則請參考:http://php.net/manual/zh/filter.filters.sanitize.php)。


同時我們也發現了一個問題,雖然SANITIZE可以對字串進行過濾,但是這個過濾非常的簡單粗暴,直接把它看不順眼字元從字串中刪掉了,這在其他場景中或許大有用處,但在處理輸入上,通常我們應該返回給使用者一個‘你不能這麼做!’的提示,而不應該擅自替使用者做其他操作,或者想將那些字元轉義並保留下來,如何達到這個目的呢?


使用回撥函式:FILTER_CALLBACK

如果你看系統自帶的過濾器都不順眼,那你可以講第三個引數指定為FILTER_CALLBACK,並在第四個引數的位置指定一個回撥函式,來實現自己的過濾器,格式如下:
filter_input(INPUT_POST, 'email',FILTER_CALLBACK,array('options' => 'my_filter'));

回撥函式格式如下:
function my_filter($s){
	//需要一個形參來接受字串
	//拿到目標字串後就可以為所欲為了
	//最後記得將加工過的字串return
	return $s;
	}



擴充套件應用
相信你也發現了,這只是PHP的過濾器函式中的一部分,如果你的目標字串不是來源於前端輸入,而是後端自己加工(或是從資料庫直接取出)出來的,同樣也可以使用類似的過濾器函式,如filter_var(),該函式的語法為:
filter_var(variable, filter, options);
可以看到,和我們上面使用的函式大同小異,你只需要在傳入輸入型別的地方改為傳入一個要過濾的變數就可以了。