使用 PHP 过滤器(Filter)进行严格表单验证
PHP 过滤器(Filter)用于验证和过滤来自非安全来源的数据,比如用户的输入,使用过滤器扩展可以使数据过滤更轻松快捷。要求的 PHP 版本是 PHP 5 >= 5.2.0,PHP 7
和 Filter 有关的函数包括
filter_has_var — 检测接收指定类型的变量是否存在,例如通过post传递的username变量是否存在 filter_id — 返回与某个特定名称的过滤器相关联的id filter_input_array — 获取一系列外部变量,并且可以通过过滤器处理它们 filter_input — 通过名称获取特定的外部变量,并且可以通过过滤器处理它 filter_list — 返回所支持的过滤器列表 filter_var_array — 获取多个变量并且过滤它们 filter_var — 使用特定的过滤器过滤一个变量
其中
filter_input(int $type, string $variable_name [, int $filter = FILTER_DEFAULT] [, mixed $options])
参数 $type 可以是 INPUT_GET,INPUT_POST,INPUT_COOKIE,INPUT_SERVER 或 INPUT_ENV
参数 $filter 的类型可以参见 php 手册:http://php.net/manual/zh/filter.filters.php
使用 Filter 可以对表单必填域验证、数字验证、email 验证、下拉菜单验证、单选按钮验证、复选框验证等。
使用 Filter 可以节省很多正则,例如验证 email、INT、bool ,并且 filter_has_var 函数比 isset 函数要更快。
一、验证必填域
//检查$_POST['username']长度之前首先确保它存在 if(! (filter_has_var(INPUT_POST, 'username') && (strlen(filter_input(INPUT_POST, 'username')) > 0) )) { echo '请输入用户名'; exit; }
说明:filter_has_var 函数在接收到了变量时对变量的值进行验证,在该例中,如果接受到了 $_POST['username'] ,即对 $_POST['username'] 的值进行验证,如果没有接收到变量 $_POST['username'],例如该字段在表单中是单个的复选框,不勾选的话,处理的页面是接收不到该字段的信息的。
二、验证长度
//FILTER_SANITIZE_STRING过滤器会去除HTML标记、删除二进制非ASCII字符、并对与字符编码(&) if(filter_has_var(INPUT_POST, 'country') && strlen(filter_input(INPUT_POST, 'country', FILTER_SANITIZE_STRING)) <=2) { echo 'country长度不小于2个字符'; exit; }
说明:
参数 FILTER_SANITIZE_STRING 用于去除 HTML 标记、删除二进制非 ASCII 字符、并且对与字符编码(&)
三、验证邮箱
//验证邮箱 $email = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL); if($email === false) { echo '请输入正确的邮箱'; exit; }
说明:使用参数 FILTER_VALIDATE_EMAIL 验证 email
四、验证整数
//验证整数,如果填写了年龄则进行验证 if(strlen(filter_input(INPUT_POST, 'age')) > 0) { $age = filter_input(INPUT_POST, 'age', FILTER_VALIDATE_INT); if($age === false) { echo '请输入正确的年龄'; exit; } }
说明:使用参数FILTER_VALIDATE_INT 验证整数
五、验证小数
//验证小数,如果填写了salary则进行验证 if(strlen(filter_input(INPUT_POST, 'salary')) > 0) { $salary = filter_input(INPUT_POST, 'salary', FILTER_VALIDATE_FLOAT); if($salary === false) { echo '请输入正确的薪资'; exit; } }
说明:使用参数 FILTER_VALIDATE_FLOAT 验证浮点数
六、验证数组,复选框验证组
//确保$_POST['sports']存在且是一个数组 if(! (filter_has_var(INPUT_POST, 'sports') && filter_input(INPUT_POST, 'sports', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY))) { echo '请选择一项运动'; exit; } //验证复选框组 //array_intersect 计算数组的交集 if(array_intersect($_POST['sports'], array_values($sports)) != $_POST['sports']) { echo '请选择正确的运动'; exit; }
说明:使用参数 FILTER_DEFAULT 进行占位,使用参数 FILTER_REQUIRE_ARRAY 验证是否是数组
使用 array_intersect 函数计算数组的交集
七、验证单个复选框
//验证单个复选框 if(filter_has_var(INPUT_POST, 'single')) { if($_POST['single'] == $value) { $single = true; } else { $single = false; echo '错误的提交'; exit; } }
八、验证下拉菜单
//验证下拉菜单 if(! (filter_has_var(INPUT_POST, 'food') && array_key_exists($_POST['food'], $choices))) { echo '请选择喜欢的食物'; exit; }
九、验证单选按钮
//验证性别 if(! (filter_has_var(INPUT_POST, 'sex') && in_array($_POST['sex'], $sex))) { echo '请选择性别'; exit; }
十、验证时间
//验证时间 if(filter_has_var(INPUT_POST, 'time')) { foreach($_POST['time'] as $time) { @list($year, $month, $day) = explode('-', $time); if(! @checkdate($month, $day, $year)) { echo '时间错误'; exit; } //时间段验证(略) } }
说明:使用 checkdate 函数验证是否是正确的时间
完整代码:
<?php header('Content-type:text/html;charset=utf-8'); //下拉菜单 value=>choice $choices = ['Eggs'=>'Eggs Benedict', 'toast'=>'Buttered Toast with jam', 'coffee'=>'piping hot coffee']; //单选按钮 choice=>value $sex = ['male'=>1, 'femail'=>2]; $defaults['sex'] = 'male'; //单个复选框 $value = 'yes'; //复选框组 choice=>value $sports = ['足球'=>'football', '跑步'=>'run', '壁球'=>'wall_ball']; if($_SERVER['REQUEST_METHOD'] == 'GET') { ?> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script language="javascript" type="text/javascript" src="My97DatePicker/WdatePicker.js"></script> </head> <body> <form action="<?php echo htmlentities($_SERVER['SCRIPT_NAME']);?>" method="post"> <table> <tr> <td>name:</td> <td><input type="text" name="username"></td> </tr> <tr> <td>country:</td> <td><input type="text" name="country"></td> </tr> <tr> <td>email:</td> <td><input type="text" name="email"></td> </tr> <tr> <td>age:</td> <td> <input type="text" name="age"> </td> </tr> <tr> <td>salary:</td> <td> <input type="text" name="salary"> </td> </tr> <tr> <td>food:</td> <td> <?php echo "<select name='food'>\n"; echo "<option value='0'>请选择喜欢的食物:</option>\n"; foreach($choices as $key=>$choice) { echo "<option value='".$key."'>".$choice."</option>\n"; } echo "</select>"; ?> </td> </tr> <tr> <td>sex:</td> <td> <?php foreach($sex as $key=>$choice) { echo "<input type='radio' name='sex' value='".$choice."'"; if($defaults['sex'] == $key) { echo "checked='checked'"; } echo ">".$key."\n"; } ?> </td> </tr> <tr> <td colspan="2"> <?php foreach($sports as $key=>$choice) { echo "<input type='checkbox' name='sports[]' value='".$choice."'>".$key."\n"; } ?> </td> </tr> <tr> <td> 是否单身: </td> <td> <?php echo "<input type='checkbox' name='single' value='yes'>"; ?> </td> </tr> <tr> <td> 工作起始时间: </td> <td> <input class="Wdate" type="text" name="time[]" onClick="WdatePicker()"> 至 <input class="Wdate" type="text" name="time[]" onClick="WdatePicker()"> </td> </tr> <tr> <td colspan="2"> <input type="submit" value="提交"> </td> </tr> </table> </form> </body> </html> <?php } else { //严格表单认证 //检查$_POST['username']长度之前首先确保它存在 if(! (filter_has_var(INPUT_POST, 'username') && (strlen(filter_input(INPUT_POST, 'username')) > 0) )) { echo '请输入用户名'; exit; } //$_POST['country']是可选的,不过如果提供了country字段,则保证在处理后要多于5个字符 //FILTER_SANITIZE_STRING过滤器会去除HTML标记、删除二进制非ASCII字符、并对与字符编码(&) if(filter_has_var(INPUT_POST, 'country') && strlen(filter_input(INPUT_POST, 'country', FILTER_SANITIZE_STRING)) <=2) { echo 'country长度不小于2个字符'; exit; } //验证邮箱 $email = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL); if($email === false) { echo '请输入正确的邮箱'; exit; } //确保$_POST['sports']存在且是一个数组 if(! (filter_has_var(INPUT_POST, 'sports') && filter_input(INPUT_POST, 'sports', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY))) { echo '请选择一项运动'; exit; } //验证复选框组 //array_intersect 计算数组的交集 if(array_intersect($_POST['sports'], array_values($sports)) != $_POST['sports']) { echo '请选择正确的运动'; exit; } //验证单个复选框 if(filter_has_var(INPUT_POST, 'single')) { if($_POST['single'] == $value) { $single = true; } else { $single = false; echo '错误的提交'; exit; } } //验证整数,如果填写了年龄则进行验证 if(strlen(filter_input(INPUT_POST, 'age')) > 0) { $age = filter_input(INPUT_POST, 'age', FILTER_VALIDATE_INT); if($age === false) { echo '请输入正确的年龄'; exit; } } //验证小数,如果填写了salary则进行验证 if(strlen(filter_input(INPUT_POST, 'salary')) > 0) { $salary = filter_input(INPUT_POST, 'salary', FILTER_VALIDATE_FLOAT); if($salary === false) { echo '请输入正确的薪资'; exit; } } //验证下拉菜单 if(! (filter_has_var(INPUT_POST, 'food') && array_key_exists($_POST['food'], $choices))) { echo '请选择喜欢的食物'; exit; } //验证性别 if(! (filter_has_var(INPUT_POST, 'sex') && in_array($_POST['sex'], $sex))) { echo '请选择性别'; exit; } //验证时间 if(filter_has_var(INPUT_POST, 'time')) { foreach($_POST['time'] as $time) { @list($year, $month, $day) = explode('-', $time); if(! @checkdate($month, $day, $year)) { echo '时间错误'; exit; } //时间段验证(略) } } echo 'Hello, ',$_POST['username']; var_dump($_POST); } ?>
参考:
<PHP Cookbook>,3rd