- 1 认识 zentaoPHP 框架
- 2 入口文件
- 3 配置管理
- 4 模块管理
- 4.1 控制器(control)
- 4.2 业务逻辑(model)
- 4.2.1 定义 model
- 4.2.2 跨模块调用
- 4.2.3 获取模块名
- 4.2.4 删除记录
- 4.2.5 数据处理对象 dao
- 4.3 模版视图(view)
- 4.4 从 hello world 开始
- 4.5 模块的配置
- 4.6 模块的语言
- 4.7 模块的 CSS 和 JS 管理
- 5 类库
- 6 扩展机制
- 6.1 扩展机制简介
- 6.2 新增独立模块
- 6.3 对控制层(control)扩展
- 6.4 对模型层(model)扩展
- 6.5 对视图层(view)扩展
- 6.6 对样式表和js进行扩展
- 6.7 对语言配置进行扩展
数据过滤类
- 2021-09-27 11:01:49
- admin
- 2460
- 最后编辑:admin 于 2022-10-14 08:11:06
数据过滤在 Web 应用中尤为重要,本节讲解 zentaoPHP 框架的数据过滤机制。
一、在哪进行数据过滤?
MVC 框架中,每一层都可以过滤数据。比如表单验证,会自动根据用户的输入进行验证,然后给予提示。那么数据过滤该放在哪一层呢?这个问题网络上大家有很多的争议,有的人主张放在 view 层,有的则主张放在 control 层。zentaoPHP 选择了 model 层。
因为 model 层是底层,所有的数据操作都要经过 model 来进行处理。那么只要在这一关把数据过滤做好,就可以保证数据的准确和安全。当然,用户也可以同时在前端加上 js 的验证,和 model 层的验证不会冲突。
二、zentaoPHP 数据过滤机制说明
受 PHP 的 filter 机制启发,zentaoPHP 的数据过滤分为两个部分,一个是数据修正,一个是数据验证。首先是要对从客户端传递过来的数据进行修正,然后再对数据进行校验。
数据修正类和验证类是在 lib/base/filter/filter.class.php 里面定义的。
三、数据修正
首先来看示例:
$bug = fixer::input('post') ->add('openedBy', $this->app->user->account) ->add('openedDate', $now) ->setDefault('project,story,task', 0) ->setDefault('openedBuild', '') ->setIF($this->post->assignedTo != '', 'assignedDate', $now) ->setIF($this->post->story != false, 'storyVersion', $this->loadModel('story')->getVersion($this->post->story)) ->specialChars('title,steps,keyword') ->cleanInt('product, module, severity') ->join('openedBuild', ',') ->remove('files, labels') ->get();
首先,是调用 fixer 这个类的 input 方法,实例化 fixer 对象,它的参数 post 表示是从 $_POST 这个变量中获取数据。创建对象时,超级变量的数据被转化为对象的形式存储。
紧接着的两行 add(),是向数据中增加两个变量;
后面的两行 setDefault 则是表示,当这个变量没有传值的时候设置成默认值;
接下来是两行setIF。setIF 共有三个参数,第一个是判断条件,后面两个分别是 key 和 value。也就是当条件为 true 的时候,设置 $key = $value;
spechialchars 则表示对这三个字段进行 htmlspecialchars 处理;
cleanInt 则将变量处理成 int 类型;
join 则将 openedBuild 使用 , 连接起来;
最后,使用 remove 把两个不需要的变量删掉。
通过 get 方法就可以得到一个已经经过修正的完整的数据集合。这个集合已经可以准备入库了,接下来是进行数据验证操作。
数据修正方法:
方法 | 参数 | 说明 |
setDefault | $fields:待处理的字段,多个以逗号分隔; $value:这些字段的默认值 | 设置指定字段的默认值。 |
specialChars | $fieldName:待处理的字段,多个以逗号分隔 | 对字段进行 htmlspecialchars 处理,转换为可以在浏览器查看的编码。 |
cleanEmail | $fieldName:待处理的字段,多个以逗号分隔 | 清理 Email 中的字符。删除除字母、数字和 !#$%&'*+-=?^_`{|}~@.[] 之外的所有字符。 |
cleanFloat | $fieldName:待处理的字段,多个以逗号分隔 | 清理 Float 类型,删除除数字、+- 和可选的 .,eE 之外的所有字符。 |
cleanInt | $fieldName:待处理的字段,多个以逗号分隔 | 清理 Int 类型,删除除数字、加号和减号之外的所有字符。 |
cleanURL | $fieldName:待处理的字段,多个以逗号分隔 | 清理 URL,删除除字母、数字和 $-_.+!*'(),{}|\\^~[]`<>#%";/?:@&= 之外的所有字符。 |
encodeurl | $fieldName:待处理的字段,多个以逗号分隔 | URL 编码字符串,可选择剥离或编码特殊字符。 |
stripTags | $fieldName:待处理的字段,多个以逗号分隔; $allowedTags :允许使用的标签 ,默认为空 | 去除目标字段中的标签。 |
skipSpecial | $fieldName:待处理的字段,多个以逗号分隔 | 忽略处理给定的字段。 |
quote | $fieldName:待处理的字段,多个以逗号分隔 | 给字段添加引用,防止字符与关键字冲突。(注:<php7.3 可用) |
setIF | $condition:条件判断 $fieldName:字段名 $value:字段值 | 如果条件为真,则为字段赋值。 |
setForce | $fieldName:字段名 $value:字段值 | 强制给字段赋值(覆盖)。 |
remove | $fieldName:待删除的字段名,多个以逗号分隔 | 移除字段。 |
removeIF | $condition:条件判断 $fields:待删除的字段名,多个以逗号分隔 | 如果条件为真,移除该字段。 |
add | $fieldName:新增数据字段名; $value:新增数据值 | 向数据对象中新增一个数据字段。 |
addIF | $condition:条件判断 $fieldName:字段名 $value:字段值 | 如果条件为真,则为数据添加新的项。 |
join | $fieldName:字段名 $value:字段值 | 为指定字段增加值,使用逗号连接起来。 |
callFunc | $fieldName:待处理的字段,多个以逗号分隔; $func:自定义方法名 | 调用一个自定义方法来处理数据。 |
get | $fields:待返回的字段,多个以逗号分隔 | 处理完成后返回数据。参数为空,则表示返回所有字段数据。 |
注:quote 方法使用的 FILTER_SANITIZE_MAGIC_QUOTES 自 PHP 7.3.0 起已弃用,自 PHP 8.0.0 起已删除,可改用 FILTER_SANITIZE_ADD_SLASHES(>php7.3有效)。
四、数据验证
验证器
框架的 validater 验证类中包含了一系列验证方法,这里所谓的验证器,是指向其对应验证方法的标识符,验证器和验证方法是一一对应的。
我们通过在配置文件或某些方法中指定验证器,来告诉框架应该使用哪个验证方法进行验证操作。
验证器的应用场景主要有两处:
在参数过滤配置文件(config/filter.php)中设置验证器,用于验证页面传递的参数(传送门:参数过滤配置);
在某些方法中作为参数传入,常用于数据入库前的验证。
本节我们主要讲解验证器作为 dao 类方法的参数传入,用于数据入库前的验证操作。
验证器列表:
验证器 | 对应验证方法 | 方法说明 |
bool | checkBool | 验证一个变量是否能过滤为 bool 值。 过滤规则:当变量值为“1”、“true”、“on”和“yes”时返回 true,否则返回 false。 |
int | checkInt | 验证一个变量是否能过滤为整数。 可选择从指定的范围内,如果成功则返回该整数,否则返回 false。 该方法会去掉参数值左侧的0。例如:'0000123'会返回123。 |
notint | checkNotInt | 检查不是 int 类型,取的是上面方法的反值。 |
float | checkFloat | 验证一个变量是否能过滤为浮点数。 可选择指定的范围内,如果成功则返回过滤后的值,否则返回 false。 |
checkEmail | 验证一个变量是否是有效的电子邮件地址。 如果是则返回该邮箱地址,否则返回 false。 | |
tel | checkTel | 验证是否是有效电话号码,是则返回1,否则返回0。 |
mobile | checkMobile | 验证是否是有效手机号码,是则返回1,否则返回0。 |
phone | checkPhone | 基于上面两个方法,验证是否是有效电话号码或手机号码。 |
url | checkURL | 验证是否是有效 URL,注意变量值须要带上协议。该方法只会查找有效的 ASCII URL,不支持中文。 如果成功则返回有效的 URL 地址,否则返回 false。 |
domain | checkDomain | 验证是否有效域名,不支持中文。是则返回1,否则返回0。 |
ip | checkIP | 验证是否是有效IP地址,支持IPv4、IPv6。是则返回 IP 地址,否则返回 false。 |
idcard | checkIdcard | 验证是否是有效身份证号,返回值为 true 或false。 |
date | checkDate | 验证是否是有效日期。返回值为 true 或 false。 注意:2022-09-31是一个合法日期,系统会将它转换为2022-10-01。 |
reg | checkREG | 根据 regexp(一种 Perl 兼容的正则表达式)验证字符串匹配正则表达式。如果匹配成功,返回该字符串,否则返回 false。 |
length | checkLength | 验证字符串长度是否符合要求,成功则返回其长度值,否则返回 false。 |
notempty | checkNotEmpty | 验证是否不为空。返回值为 true 或 false。 |
empty | checkEmpty | 验证是否为空。返回值为 true 或 false。 |
account | checkAccount | 验证用户名是否有效。有效则返回用户名,否则返回 false。 用户名的组成规则可以在配置文件中设置 $config->accountRule。 |
code | checkCode | 验证 code,匹配正则 |^[A-Za-z0-9]+$|,如果匹配成功,则返回该字符串,否则返回 false。 |
captcha | checkCaptcha | 验证验证码是否正确。返回值为 true 或 false。 |
equal | checkEqual | 验证是否等于给定的值,返回值为 true 或 false。 |
notequal | checkNotEqual | 验证是否不等于给定的值,返回值为 true 或 false。 |
gt | checkGT | 验证是否大于给定的值,返回值为 true 或 false。 |
lt | checkLT | 验证是否小于给定的值,返回值为 true 或 false。 |
ge | checkGE | 验证是否大于等于给定的值,返回值为 true 或 false。 |
le | checkLE | 验证是否小于等于给定的值,返回值为 true 或 false。 |
in | checkIn | 验证变量值是否在给定的列表里。返回值为 true 或 false。 |
filename | checkFileName | 验证文件名是否有效。返回值为 true 或 false。 |
sensitive | checkSensitive | 验证变量中是否包含敏感词。 $vars 为待校验的词(对象),$dicts 为敏感词集合(数组)。 包含则返回 false,否则返回 true。 |
model 层的验证操作
在 model 层,使用 dao 对象操作数据,完成对数据入库前的最后验证。在 dao 类中定义了对数据字段的验证方法,主要有以下5个:
方法 | 参数 | 说明 |
autoCheck | $skipFields:忽略验证的字段,默认为空 | 根据数据库结构(字段的类型、长度)验证字段。 |
check | $fieldName:要验证的字段; $funcName:验证器; $condition:验证唯一性时的附加查询条件,默认为空 | 通过一个指定的验证器,验证字段是否满足条件。(可参见验证器列表) |
checkIF | $condition:条件; $fieldName:要验证的字段; $funcName:验证器 | 当指定条件成立时,才进行 check 操作。 |
batchCheck | $fields:要验证的字段集合,多个以逗号分隔; $funcName:验证器 | 批量检查字段。即对集合里的每个字段进行 check 操作。 |
batchCheckIF | $condition:条件; $fields:要验证的字段集合,多个以逗号分隔; $funcName:验证器 | 当指定条件成立时,才进行 batchCheck 操作。 |
注:对于这几个方法的参数 $funcName,除了已给的验证器外,还可以使用 'unique' 来验证字段值在数据库中的唯一性。 |
例如:
接着前面的示例,完成数据修正后,对返回的数据集合 $bug 进行入库前的验证操作:
$this->dao->insert(TABLE_BUG)->data($bug) ->autoCheck() ->batchCheck('id, name', 'notempty') ->exec();
这句 sql 插入语句通过 data 方法,将修正过的数据传递给 dao 对象,然后通过 autoCheck() 对其进行自动检查。autoCheck() 会根据数据库里面字段的类型,长度进行判断。如果类型不对,或者长度不对,会自动记录错误。
然后调用的 batchCheck() 方法,对一批字段进行非空的验证。
当然也可以通过 check() 方法对单个字段进行验证。
checkIF() 方法是当指定条件成立时,才进行 check 操作。batchCheckIF() 方法同理。
例如:
->checkIF($this->post->email != '', 'email', 'email')
其他地方的验证操作
除了数据入库前的验证,我们平时在 control、modle 层时常也会遇到数据验证操作。此时我们可以直接通过静态调用的方式进行验证。
例如:
if(!empty($paramName) and !validater::checkREG($paramName, '/^[A-Za-z_0-9]+$/')) { dao::$errors[] = $this->lang->job->invalidName; return false; }
call($val, $func)方法
validater 验证类还提供了一个 call 方法,通过调用一个用户自定义函数来过滤数据。该方法为我们提供了对数据过滤的完全控制。 参数 $func 为自定义函数名,或是已有的 PHP 函数。
示例:
$str="Peter is a great guy!"; echo validater::call($str, "strtoupper"); // 输出结果:PETER IS A GREAT GUY!
五、获取验证错误
如果数据验证过程中没有错误,则执行了exec()方法,将数据插入数据库。
如果有错,exec()方法什么都不会执行,但会记录到错误日志中。可以在 control 层中判断是否有错误。
if(dao::isError()) die(js::error(dao::getError()));
如果有错误,用 js 警告框的方式弹出,然后重置错误日志。
框架在 module/common/lang 中定义了对应验证器的错误提示信息:
/** * Error message. * $lang->error->验证器 = "提示信息" */ $lang->error = new stdclass(); $lang->error->reg = "『%s』不符合格式,应当为:『%s』。"; $lang->error->unique = "『%s』已经有『%s』这条记录了。"; $lang->error->notempty = "『%s』不能为空。"; $lang->error->empty = "『%s』必须为空。"; $lang->error->equal = "『%s』必须为『%s』。"; $lang->error->int = array("『%s』应当是数字。", "『%s』应当介于『%s-%s』之间。"); $lang->error->float = "『%s』应当是数字,可以是小数。"; $lang->error->email = "『%s』应当为合法的EMAIL。"; $lang->error->date = "『%s』应当为合法的日期。"; $lang->error->account = "『%s』应当为合法的用户名。";