M68000指令集深度解析:从数据移动到浮点运算的完整指南
2026/6/13 12:03:09
通过本章学习,您将能够:
filter_var,filter_input)进行数据清洗输入验证与数据过滤是 Web 应用安全的基石,是抵御攻击的第一道、也是最重要的一道防线.第 1 章帮助我们建立了安全威胁的宏观认知,本章将深入技术细节,聚焦于如何在实际代码中构建这第一道防线.它为后续章节(如防御 SQL 注入、XSS 等)提供了最基础的技术支撑——如果输入是干净的,许多高阶攻击将从根本上失去入口.
在第 1 章,我们通过 OWASP Top 10 了解了常见威胁.本章将直接针对其中多项威胁(如注入攻击、XSS)的根源——不可信的输入——提供具体的防御代码和实践方案.我们从"识别威胁"迈入了"主动防御"的阶段.
filter_var、filter_input、preg_match等核心函数.这是安全开发的黄金法则.它意味着开发者绝不应该信任任何来自外部的数据,包括但不限于:
$_GET,$_POST,$_REQUEST(用户表单提交)$_COOKIE(客户端 Cookie)$_SERVER中的部分信息(如HTTP_USER_AGENT,HTTP_REFERER)攻击案例:假设一个简单的搜索功能,后端直接使用$_GET[‘q’]构造 SQL 查询.攻击者输入‘ OR ‘1’=‘1,就可能造成 SQL 注入,窃取全部数据.根本原因就是相信了用户的输入.
客户端验证(通常用 JavaScript):
服务器端验证:
‘, ", <, >等字符.<script>,攻击者可能使用大小写混合<ScRiPt>或编码形式%3cscript%3e.<?php// 用户提交的原始输入(模拟)$rawEmail=‘user@example.com‘;// 使用 filter_var 进行白名单验证// FILTER_VALIDATE_EMAIL 是PHP内置的电子邮件验证过滤器if(filter_var($rawEmail,FILTER_VALIDATE_EMAIL)){echo‘邮箱地址格式有效.‘;$cleanEmail=$rawEmail;// 验证通过,可以认为是干净的}else{echo‘邮箱地址格式无效!‘;$cleanEmail=null;// 验证失败,应拒绝处理或使用默认值// 在实际应用中,这里应该终止业务流程或返回错误信息给用户}// 对比:不安全的做法(仅检查是否包含@符号)$unsafeCheck=strpos($rawEmail,‘@‘)!==false;// 这无法阻止像 ‘attacker@evil.com><script>alert(1)</script>‘ 这样的危险输入// 它只检查了结构,没有检查格式的纯洁性.?>邮箱地址格式有效.<?php// 场景:用户提交了一个可能包含多余空格或危险参数的URL$rawUrl=‘https:// example.com/path?query=<script>alert("xss")</script> ‘;// 1. 去除首尾空白字符$trimmedUrl=trim($rawUrl);// 2. 使用 filter_var 进行清洗和验证// FILTER_SANITIZE_URL 会移除所有非URL允许的字符// FILTER_VALIDATE_URL 会验证结果是否是一个合法的URL$sanitizedUrl=filter_var($trimmedUrl,FILTER_SANITIZE_URL);echo"原始URL: ‘".$rawUrl."‘\n";echo"清洗后URL: ‘".$sanitizedUrl."‘\n";// 进一步验证清洗后的URL是否有效if(filter_var($sanitizedUrl,FILTER_VALIDATE_URL)){echo"这是一个有效的URL,可以安全使用(例如进行重定向).\n";// 注意:即使URL格式有效,重定向到用户提供的URL也可能存在钓鱼风险,// 通常需要额外的白名单或域名检查.}else{echo"即使清洗后,这也不是一个有效的URL.\n";}?>原始URL: ‘ https:// example.com/path?query=<script>alert("xss")</script> ‘ 清洗后URL: ‘https:// example.com/path?query=alert%28%22xss%22%29‘ 这是一个有效的URL,可以安全使用(例如进行重定向).说明:FILTER_SANITIZE_URL将<,>,(,)等字符进行了百分比编码,从而消除了潜在的 XSS 风险,但保留了 URL 的完整功能.
filter_input直接从超全局变量获取并过滤数据<?php// 假设通过 GET 请求访问:?age=25&score=95.5// filter_input 直接从输入源读取并过滤,是更安全的做法// 验证并获取整数类型的年龄,范围 0-150$optionsAge=array(‘options‘=>array(‘min_range‘=>0,‘max_range‘=>150,‘default‘=>18// 如果验证失败或不存在,返回默认值));$cleanAge=filter_input(INPUT_GET,‘age‘,FILTER_VALIDATE_INT,$optionsAge);echo"年龄: ".($cleanAge!==null?$cleanAge:‘无效或未提供‘)."\n";// 验证并获取浮点数类型的分数,范围 0.0-100.0$optionsScore=array(‘options‘=>array(‘min_range‘=>0.0,‘max_range‘=>100.0,‘default‘=>0.0));$cleanScore=filter_input(INPUT_GET,‘score‘,FILTER_VALIDATE_FLOAT,$optionsScore);echo"分数: ".($cleanScore!==null?$cleanScore:‘无效或未提供‘)."\n";// 验证一个必需的布尔值标志$cleanFlag=filter_input(INPUT_GET,‘is_active‘,FILTER_VALIDATE_BOOLEAN,FILTER_NULL_ON_FAILURE);// FILTER_NULL_ON_FAILURE 使得非布尔值(如 ‘yes‘, ‘no‘, 1, 0)返回null,而不是falseif($cleanFlag===null){echo"激活标志格式无效.\n";}else{echo"激活标志: ".($cleanFlag?‘是‘:‘否‘)."\n";}?>年龄: 25 分数: 95.5 激活标志格式无效.<?php// 场景:验证用户名.规则:以字母开头,仅包含字母、数字和下划线,长度3-20字符.$username=‘Alice_123‘;$invalidUsername=‘123Alice‘;// 以数字开头$dangerousUsername=‘admin‘or‘1‘=‘1‘;// 包含SQL注入片段$pattern=‘/^[a-zA-Z][a-zA-Z0-9_]{2,19}$/‘;// 白名单正则表达式functionvalidateUsername($input,$pattern){// 先进行白名单正则匹配if(preg_match($pattern,$input)){return$input;// 验证通过}returnfalse;// 验证失败}echo"测试 ‘Alice_123‘: ".(validateUsername($username,$pattern)?‘有效‘:‘无效‘)."\n";echo"测试 ‘123Alice‘: ".(validateUsername($invalidUsername,$pattern)?‘有效‘:‘无效‘)."\n";echo"测试 ‘admin‘ or ‘1‘=‘1‘‘: ".(validateUsername($dangerousUsername,$pattern)?‘有效‘:‘无效‘)."\n";// 即使攻击者输入包含SQL注入,白名单正则也会直接拒绝,因为它包含了空格和单引号,不在允许的字符集内.?>测试 ‘Alice_123‘: 有效 测试 ‘123Alice‘: 无效 测试 ‘admin‘ or ‘1‘=‘1‘‘: 无效<?php// 一个更贴近实战的验证示例,包含多个字段和错误处理functionvalidateRegistrationInput($postData){$errors=[];$cleanData=[];// 1. 验证用户名 (白名单:字母开头,字母数字下划线,3-20位)if(empty($postData[‘username‘])){$errors[‘username‘]=‘用户名不能为空‘;}elseif(!preg_match(‘/^[a-zA-Z][a-zA-Z0-9_]{2,19}$/‘,$postData[‘username‘])){$errors[‘username‘]=‘用户名格式无效(字母开头,3-20位字母数字下划线)‘;}else{$cleanData[‘username‘]=$postData[‘username‘];// 验证通过}// 2. 验证并清洗电子邮件if(empty($postData[‘email‘])){$errors[‘email‘]=‘邮箱不能为空‘;}else{$sanitizedEmail=filter_var($postData[‘email‘],FILTER_SANITIZE_EMAIL);if(!filter_var($sanitizedEmail,FILTER_VALIDATE_EMAIL)){$errors[‘email‘]=‘邮箱地址格式无效‘;}else{$cleanData[‘email‘]=$sanitizedEmail;// 使用清洗后的版本}}// 3. 验证年龄(可选,但如果提供必须在0-150之间)if(!empty($postData[‘age‘])){$options=[‘options‘=>[‘min_range‘=>0,‘max_range‘=>150]];$cleanAge=filter_var($postData[‘age‘],FILTER_VALIDATE_INT,$options);if($cleanAge===false){$errors[‘age‘]=‘年龄必须是0到150之间的整数‘;}else{$cleanData[‘age‘]=$cleanAge;}}// 4. 验证网站URL(可选)if(!empty($postData[‘website‘])){$sanitizedUrl=filter_var($postData[‘website‘],FILTER_SANITIZE_URL);if(!filter_var($sanitizedUrl,FILTER_VALIDATE_URL)){$errors[‘website‘]=‘网站URL格式无效‘;}else{$cleanData[‘website‘]=$sanitizedUrl;}}return[‘isValid‘=>empty($errors),‘errors‘=>$errors,‘cleanData‘=>$cleanData];}// 模拟用户提交$testData=[‘username‘=>‘Bob‘,‘email‘=>‘bob@example.com‘,‘age‘=>‘25‘,‘website‘=>‘http:// bob.com‘];$result=validateRegistrationInput($testData);if($result[‘isValid‘]){echo"验证通过!\n";echo"清洁数据: ".print_r($result[‘cleanData‘],true);}else{echo"验证失败,错误如下:\n";print_r($result[‘errors‘]);}?>验证通过! 清洁数据: Array ( [username] => Bob [email] => bob@example.com [age] => 25 [website] => http:// bob.com )构建一个处理用户注册请求的 PHP 脚本.要求对所有输入字段进行严格的服务器端白名单验证和数据清洗,确保数据安全后方可进行后续处理(如存入数据库).
username: 必填,3-20 字符,字母开头,仅含字母、数字、下划线.email: 必填,有效的电子邮件格式.password: 必填,长度至少 8 位,需包含大小写字母和数字.age: 可选,必须是 18-120 之间的整数.bio: 可选,个人简介,允许有限 HTML(如<b>,<i>,<br>),需进行安全的 HTML 过滤.filter_var、正则表达式进行白名单验证.bio字段使用专门的 HTML 净化器(如strip_tags的允许标签模式).password_hash处理(详细在第 6 章讲解)./chapter2-project/ ├── register.php # 注册表单HTML页面 ├── process.php # 处理注册请求的后端脚本 └── README.md<!DOCTYPEhtml><html lang="zh-CN"><head><meta charset="UTF-8"><title>安全注册系统-第2章实战</title><style>body{font-family:sans-serif;max-width:500px;margin:40px auto;}.error{color:red;font-size:0.9em;margin-bottom:10px;}.field{margin-bottom:15px;}label{display:block;margin-bottom:5px;}input,textarea{width:100%;padding:8px;box-sizing:border-box;}</style></head><body><h1>用户注册</h1><?php// 从URL参数或Session中获取错误信息(实际项目可能用Session)$errors=$_GET[‘errors‘]??[];if(!empty($errors)&&is_string($errors)){// 简单解码演示,实际应更安全地传递错误$errors=json_decode(urldecode($errors),true);}?><form action="process.php"method="POST"><divclass="field"><labelfor="username">用户名*</label><input type="text"id="username"name="username"required value="<?php echo htmlspecialchars($_GET[‘old_username‘]?? ‘‘, ENT_QUOTES); ?>"><?phpif(!empty($errors[‘username‘])):?><divclass="error"><?phpechohtmlspecialchars($errors[‘username‘]);?></div><?phpendif;?></div><divclass="field"><labelfor="email">电子邮箱*</label><input type="email"id="email"name="email"required value="<?php echo htmlspecialchars($_GET[‘old_email‘]?? ‘‘, ENT_QUOTES); ?>"><?phpif(!empty($errors[‘email‘])):?><divclass="error"><?phpechohtmlspecialchars($errors[‘email‘]);?></div><?phpendif;?></div><divclass="field"><labelfor="password">密码*</label><input type="password"id="password"name="password"required><?phpif(!empty($errors[‘password‘])):?><divclass="error"><?phpechohtmlspecialchars($errors[‘password‘]);?></div><?phpendif;?><small>至少8位,需包含大小写字母和数字.</small></div><divclass="field"><labelfor="age">年龄</label><input type="number"id="age"name="age"min="18"max="120"value="<?php echo htmlspecialchars($_GET[‘old_age‘]?? ‘‘, ENT_QUOTES); ?>"><?phpif(!empty($errors[‘age‘])):?><divclass="error"><?phpechohtmlspecialchars($errors[‘age‘]);?></div><?phpendif;?></div><divclass="field"><labelfor="bio">个人简介</label><textarea id="bio"name="bio"rows="4"><?phpechohtmlspecialchars($_GET[‘old_bio‘]??‘‘,ENT_QUOTES);?></textarea><?phpif(!empty($errors[‘bio‘])):?><divclass="error"><?phpechohtmlspecialchars($errors[‘bio‘]);?></div><?phpendif;?><small>允许使用<b>,<i>,<br>标签.</small></div><button type="submit">注册</button></form></body></html><?php/** * 用户注册请求处理器 - 第2章实战项目 * 目标:演示严格的白名单输入验证与数据清洗. */// 1. 定义验证函数functionvalidateRegistration($postData){$errors=[];$cleanData=[];// --- 用户名验证 ---$username=trim($postData[‘username‘]??‘‘);if(empty($username)){$errors[‘username‘]=‘用户名不能为空‘;}elseif(!preg_match(‘/^[a-zA-Z][a-zA-Z0-9_]{2,19}$/‘,$username)){$errors[‘username‘]=‘用户名格式无效(字母开头,3-20位字母数字下划线)‘;}else{$cleanData[‘username‘]=$username;}// --- 邮箱验证与清洗 ---$email=trim($postData[‘email‘]??‘‘);if(empty($email)){$errors[‘email‘]=‘邮箱不能为空‘;}else{// 重要:先清洗,再验证!$sanitizedEmail=filter_var($email,FILTER_SANITIZE_EMAIL);if(!filter_var($sanitizedEmail,FILTER_VALIDATE_EMAIL)){$errors[‘email‘]=‘邮箱地址格式无效‘;}else{$cleanData[‘email‘]=$sanitizedEmail;}}// --- 密码验证 ---$password=$postData[‘password‘]??‘‘;if(empty($password)){$errors[‘password‘]=‘密码不能为空‘;}elseif(strlen($password)<8){$errors[‘password‘]=‘密码长度至少8位‘;}elseif(!preg_match(‘/[a-z]/‘,$password)||// 必须包含小写字母!preg_match(‘/[A-Z]/‘,$password)||// 必须包含大写字母!preg_match(‘/[0-9]/‘,$password)){// 必须包含数字$errors[‘password‘]=‘密码必须包含大小写字母和数字‘;}else{// 验证通过,密码将在后续步骤进行哈希处理,此处不保存明文$cleanData[‘password‘]=$password;// 临时存储,用于哈希}// --- 年龄验证(可选)---if(!empty($postData[‘age‘])){$age=trim($postData[‘age‘]);$options=[‘options‘=>[‘min_range‘=>18,‘max_range‘=>120]];$validatedAge=filter_var($age,FILTER_VALIDATE_INT,$options);if($validatedAge===false){$errors[‘age‘]=‘年龄必须是18到120之间的整数‘;}else{$cleanData[‘age‘]=$validatedAge;}}// --- 个人简介清洗(允许有限HTML)---if(!empty($postData[‘bio‘])){$bio=trim($postData[‘bio‘]);// 使用 strip_tags 的允许标签功能进行白名单过滤$allowedTags=‘<b><i><br>‘;// 只允许加粗、斜体和换行标签$cleanBio=strip_tags($bio,$allowedTags);// 可选:进一步清理标签属性(strip_tags不移除属性)$cleanBio=preg_replace(‘/<(b|i|br)[^>]*>/i‘,‘<$1>‘,$cleanBio);// 移除标签内所有属性$cleanData[‘bio‘]=$cleanBio;}else{$cleanData[‘bio‘]=‘‘;}return[‘errors‘=>$errors,‘cleanData‘=>$cleanData];}// 2. 处理请求if($_SERVER[‘REQUEST_METHOD‘]===‘POST‘){$validationResult=validateRegistration($_POST);if(empty($validationResult[‘errors‘])){// 验证成功!处理清洁数据.$data=$validationResult[‘cleanData‘];// 模拟安全存储(实际应存入数据库)// a. 密码哈希(第6章详解)$hashedPassword=password_hash($data[‘password‘],PASSWORD_DEFAULT);// 从清洁数据中移除明文密码unset($data[‘password‘]);$data[‘password_hash‘]=$hashedPassword;// 存储哈希值// b. 记录注册时间$data[‘registered_at‘]=date(‘Y-m-dH:i:s‘);echo"<h1>注册成功!</h1>\n";echo"<p>以下为经过验证和清洗的用户数据(模拟存储):</p>\n";echo"<pre>".htmlspecialchars(print_r($data,true),ENT_QUOTES)."</pre>\n";echo‘<p><a href="register.php">返回注册页</a></p>‘;// 在实际项目中,这里会进行数据库插入操作,然后重定向到成功页面.// $pdo->prepare(‘INSERT INTO users ...‘)->execute([...]);}else{// 验证失败,携带错误信息和旧数据重定向回表单页// 注意:这里为了简化演示,通过URL参数传递,实际项目应使用Session.$queryParams=http_build_query([‘errors‘=>json_encode($validationResult[‘errors‘]),‘old_username‘=>$_POST[‘username‘]??‘‘,‘old_email‘=>$_POST[‘email‘]??‘‘,‘old_age‘=>$_POST[‘age‘]??‘‘,‘old_bio‘=>$_POST[‘bio‘]??‘‘,]);header(‘Location:register.php?‘.$queryParams);exit();}}else{// 非POST请求直接访问处理页,重定向到表单header(‘Location:register.php‘);exit();}?>"Ab"(太短)、"123alice"(数字开头)、"alice!"(包含非法字符)应报错."invalid-email"、"user@.com"应报错."1234567"(短)、"abcdefgh"(无数字大写)、"ABCDEFGH"(无数字小写)、"12345678"(无字母)应报错."17"、"121"、"abc"应报错.bio字段输入<script>alert(‘xss‘)</script>,提交后查看处理结果.它应该被完全剥离,因为<script>不在允许标签白名单中.bio字段输入<b onclick="alert(1)">加粗</b>,提交后查看.onclick属性应该被preg_replace移除.‘ OR ‘1‘=‘1,它应该被白名单验证拒绝或无害化.$_SESSION来传递错误信息和旧数据,避免 URL 过长和潜在的信息泄露.respect/validation或illuminate/validation(Lavel 组件),它们提供更丰富、声明式的验证规则.filter_var和filter_input是经过充分测试、性能良好的工具,应作为首选.empty()或isset()做唯一验证// 错误示例if(!empty($_POST[‘username‘])){// 就认为用户名合法了}// 攻击者可以提交 username=<script>...</script>,empty() 返回 false,漏洞产生.preg_replace进行黑名单过滤// 危险的黑名单示例$input=preg_replace(‘/[<>]/‘,‘‘,$_POST[‘input‘]);// 攻击者可能使用 `<<script>>alert(1)<</script>/` 或编码字符进行绕过.// 错误顺序:先清洗可能改变长度,再验证长度$email=filter_var($_POST[‘email‘],FILTER_SANITIZE_EMAIL);if(strlen($email)>50){...}// 长度判断可能因清洗而失效// 正确顺序:先验证长度等业务规则,再清洗用于安全目的$rawEmail=$_POST[‘email‘];if(strlen($rawEmail)>50){...}$cleanEmail=filter_var($rawEmail,FILTER_SANITIZE_EMAIL);// strlen 和 preg_match 默认不识别多字节字符(如中文)$username=‘用户‘;// 两个字符,但占6个字节(UTF-8)if(strlen($username)<3){// 这里会判断为6>3,通过// 但用户可能期望的是字符数<3}// 应使用 mb_strlenif(mb_strlen($username,‘UTF-8‘)<3){echo‘用户名至少3个字符‘;}// 正则表达式应使用 /u 修饰符支持UTF-8preg_match(‘/^[a-z]+$/iu‘,$input);// i不区分大小写,u支持Unicode// 危险代码:用户控制文件名部分$userFile=$_GET[‘file‘];// 攻击者输入 ‘../../../etc/passwd‘include(‘./uploads/‘.$userFile.‘.php‘);// 防护:使用白名单或basename$allowedFiles=[‘page1.php‘,‘page2.php‘];$userFile=$_GET[‘file‘];if(!in_array($userFile,$allowedFiles)){die(‘非法文件请求‘);}// 或使用 basename 剥离目录部分(不完全可靠,因操作系统而异)$safeFile=basename($userFile);// 但攻击者仍可能请求 ‘passwd‘ 如果存在的话// 购买商品,验证库存$requestedQty=$_POST[‘quantity‘];if($requestedQty<=$stockQty){// 允许购买}// 如果攻击者传入负数,比如 -10,条件成立,可能导致库存增加或支付金额为负!// 防护:必须验证最小范围$options=[‘options‘=>[‘min_range‘=>1]];$validQty=filter_var($requestedQty,FILTER_VALIDATE_INT,$options);if($validQty!==false&&$validQty<=$stockQty){// ...}bio字段的 HTML 标签白名单过滤是防御存储型 XSS 的直接手段.对于其他字段,在第 4 章将使用htmlspecialchars进行输出转义.validateIntegerInRange($input, $min, $max),使用filter_var验证输入是否在指定范围内的整数.要求处理输入为空、非整数、超出范围的情况,并返回验证后的整数或false.FILTER_VALIDATE_INT和options参数.functionvalidateIntegerInRange($input,$min,$max){if($input===‘‘||$input===null){returnfalse;}$options=[‘options‘=>[‘min_range‘=>$min,‘max_range‘=>$max]];returnfilter_var($input,FILTER_VALIDATE_INT,$options);}$username=$_GET[‘name‘];echo"欢迎, ".$username;- **难度**:★☆☆☆☆// 1. 验证(白名单:允许中英文、数字、下划线,2-20字符)$rawName=$_GET[‘name‘]??‘‘;if(!preg_match(‘/^[\x{4e00}-\x{9fa5}a-zA-Z0-9_]{2,20}$/u‘,$rawName)){$username=‘游客‘;}else{$username=$rawName;}// 2. 输出转义(即使验证通过,转义是防御XSS的最后屏障)echo"欢迎, ".htmlspecialchars($username,ENT_QUOTES,‘UTF-8‘);‘Y-m-d H:i:s‘格式,并且日期是未来的时间(例如,用于验证会议开始时间).不使用DateTime::createFromFormat的异常捕获方式,而使用正则表达式和逻辑判断.strtotime或DateTime对象比较时间.functionvalidateFutureDateTime($input){// 1. 正则验证格式if(!preg_match(‘/^\d{4}-\d{2}-\d{2}\d{2}:\d{2}:\d{2}$/‘,$input)){returnfalse;}// 2. 检查各部分有效性(如月份1-12,日1-31,时0-23等)list($date,$time)=explode(‘ ‘,$input);list($year,$month,$day)=explode(‘-‘,$date);if(!checkdate($month,$day,$year)){returnfalse;}// 3. 检查是否为未来时间$inputTimestamp=strtotime($input);if($inputTimestamp===false||$inputTimestamp<=time()){returnfalse;}returntrue;}filter_var的FILTER_VALIDATE_URL过滤器默认不验证 URL 是否包含查询字符串中的危险片段(如javascript:协议).如何增强 URL 验证,确保 URL 的协议只能是http或https?parse_url函数分解 URL,检查scheme部分.functionvalidateSafeHttpUrl($url){// 基础URL格式验证if(filter_var($url,FILTER_VALIDATE_URL)===false){returnfalse;}// 解析URL组件$components=parse_url($url);if($components===false||!isset($components[‘scheme‘])){returnfalse;}// 白名单协议检查$allowedSchemes=[‘http‘,‘https‘];if(!in_array(strtolower($components[‘scheme‘]),$allowedSchemes)){returnfalse;}// 可选:检查主机名是否不为空(对于http/https,通常应有主机)if(empty($components[‘host‘])){returnfalse;}returntrue;}InputValidator.要求:$v->validate(‘email‘)->required()->email()).$_POST,$_GET等数据源进行批量验证.required,email,integer,min,max,regex.Rule类或使用闭包存储验证逻辑,在Validator类中管理字段与规则的映射.classInputValidator{private$data;private$rules=[];private$errors=[];publicfunction__construct(array$data){$this->data=$data;}publicfunctionvalidate($field,$ruleName,...$params){if(!isset($this->rules[$field])){$this->rules[$field]=[];}$this->rules[$field][]=[‘rule‘=>$ruleName,‘params‘=>$params];return$this;// 支持链式调用}publicfunctionfails(){foreach($this->rulesas$field=>$fieldRules){$value=$this->data[$field]??null;foreach($fieldRulesas$ruleDef){if(!$this->applyRule($value,$ruleDef[‘rule‘],$ruleDef[‘params‘])){$this->errors[$field][]=$this->getErrorMessage($field,$ruleDef[‘rule‘]);break;// 一个字段一个错误}}}return!empty($this->errors);}publicfunctionerrors(){return$this->errors;}privatefunctionapplyRule($value,$ruleName,$params){switch($ruleName){case‘required‘:return!(is_null($value)||$value===‘‘);case‘email‘:if($value===‘‘)returntrue;// 非required字段允许为空returnfilter_var($value,FILTER_VALIDATE_EMAIL)!==false;case‘integer‘:if($value===‘‘)returntrue;$options=[];if(isset($params[0],$params[1])){$options=[‘options‘=>[‘min_range‘=>$params[0],‘max_range‘=>$params[1]]];}returnfilter_var($value,FILTER_VALIDATE_INT,$options)!==false;case‘regex‘:if($value===‘‘)returntrue;returnpreg_match($params[0],$value)===1;default:returnfalse;}}privatefunctiongetErrorMessage($field,$ruleName){$messages=[‘required‘=>"{$field}字段是必填的",‘email‘=>"{$field}必须是有效的邮箱地址",‘integer‘=>"{$field}必须是整数",‘regex‘=>"{$field}格式无效",];return$messages[$ruleName]??"{$field}验证失败";}}// 使用示例$validator=newInputValidator($_POST);$validator->validate(‘username‘,‘required‘)->validate(‘username‘,‘regex‘,‘/^[a-z][a-z0-9_]{2,}$/i‘)->validate(‘email‘,‘required‘)->validate(‘email‘,‘email‘)->validate(‘age‘,‘integer‘,0,150);if($validator->fails()){print_r($validator->errors());}filter_var()和filter_input()函数进行常见数据类型(邮箱、URL、数字等)的验证与清洗.FILTER_SANITIZE_EMAIL)的作用,并知道在验证流程中何时进行清洗.完成本章学习与实践后,您应该能够: