PHP 业务实体验证
PHP 业务实体验证
PHP 验证功能
如果我说所有应用程序都使用验证功能,我不会泄露任何秘密。其中一些应用程序的验证功能非常简单,只是使用 if
-else
条件来确保传入的数据是正确的,但有些应用程序需要高级功能,尤其是处理传入用户数据的业务应用程序。如果您开发一些基于 Web 的业务应用程序,并且您确信应用程序用户将设置正确的数据,您仍然需要一些验证,因为 HTTP 网络流量很容易被黑客攻击(当然如果不是 HTTPS),并且有人可能会发送不正确的数据到 ... 甚至只是为了开玩笑。
在这里,我将解释一个非常好的验证功能,我们现在在不同的 PHP 和 .NET 项目中使用它。 为什么我认为它很好? 因为它易于扩展和移动。 我们最后的 .NET 项目将验证作为解决方案的外部项目包含在内,不幸的是,PHP 没有像 .NET 这样的命名空间,我们将所有验证保存在项目中的单独文件夹中,然后将此文件夹复制到新项目中。
让我们开始...
例如,您开发了一些具有不同业务实例的业务应用程序。 假设您有 Employee
业务实例和相应的 DEmployee
数据实例。 它们具有不同的属性和函数,并实现一些 IBusiness
和 IDataEnity
接口。 在将 Employee
实例保存到数据库之前,我必须验证它。 我只是将 Validate
函数添加到我们的接口,添加到 IBusiness
以根据业务规则验证实例,例如员工姓名应以 Department
编号开头,添加到 IDataEnity
以根据数据库规则验证实例,例如员工姓名长度应大于 5 个符号。 为什么我们不能只进行一次员工验证? 以 Department
编号开头 employee
姓名是业务规则,我们要求员工姓名应以另一个业务属性的属性开头,我们应该在业务级别验证它。 员工长度应在 5 到 25 个符号之间是数据规则,因为字段长度是数据库限制,业务级别不考虑姓名符号,它使用姓名属性作为对象。 也许 Employee
姓名是一个复杂的实例,它根本没有符号,它是引用,但是字符串 Employee
表示应该从 Department
编号开始。
正如我们在 IBusiness
接口中声明了 Validation 函数,我们需要在 Employee
类中实现它,如下所示
public function Validate(Action $action) {
$v = new Validator ( $action );
$v
->Validate ( new BusinessNamePattern ( ),
array ('Employee Name' => $this->getActualName () ) );
if ($v->hasError ())
return $v;
return parent::Validate ( $action );
}
看起来很简单,我们创建 Validator 实例并运行带有模式实例和数据数组的函数进行验证。 如果数据错误,则返回 Validator
实例。
同样简单的 Validation 实现也在 DEmployee
类中。
public function Validate(BaseBusinessAction $action)
{
$v = new Validator($action);
$v->Validate(new DOBPatternYYYYMMDD(), array('dob' => $this->get_dob()));
$v->Validate(new NamePattern(), array('Last Name'=>$this->get_last_name()));
$v->Validate(new NamePattern(), array('First Name'=>$this->get_first_name()));
if ($v->hasError())
return $v;
return parent::Validate($action);
}
在这里,我们验证出生日期以及名字、姓氏。 完全一样,但看起来太复杂了,让我们更优雅地重写它,如下所示
public function Validate(BaseBusinessAction $action)
{
$v = new Validator($action);
$v
->Validate(new DOBPatternYYYYMMDD(), array('dob' => $this->get_dob()))
->Validate(new NamePattern(), array(
'First Name'=>$this->get_first_name()
, 'Last Name'=>$this->get_last_name()
));
if ($v->hasError())
return $v;
return parent::Validate($action);
}
这是一样的。
验证已准备就绪,如果您有 Validator 和模式,那么一切就完成了。 在我们的项目中,一切都完成了。 简单吗? 是的。
快吗? 是的。
开发和支持成本低廉吗? 是的。
您没有验证器,让我们继续。 没什么困难的。 所有模式都扩展了 IPattern
接口并实现 isApproved
函数,如果数据良好,则返回 TRUE
或 ValidationError
实例。
class Validator
{
private $_errors = array();
/**
*
* @var BaseBusinessAction
*/
private $_action;
public function __construct($action)
{
$this->_action = $action;
}
/**
* Validate $data
* @param BasePattern $pattern
* @param $data it is key=>value array to validate
* @return Validator
* @uses
* $v = new Validator();
* $v->Validate(new NotEmptyPattern(BasePattern::ACTION_INSERT),
* array('name'=>$name, 'city'=>$city, 'address'=>$address))
* $v->Validate(new NamePattern(BasePattern::ACTION_INSERT),
* array('name'=>$name))
* if ($v->hasError)
* throw new ValidationException($v);
*/
public function Validate(BasePattern $pattern, $data)
{
if (is_array($data))
{
$pattern->set_action($this->_action);
foreach ($data as $key => $value)
if (!(($error = $pattern->isApproved($key, $value))
=== TRUE))
$this->_errors[] = $error;
}
else
throw new ApplicationException
('Wrong argument parameters:'.print_r($data, true));
return $this;
}
/**
*
* @return true if there is some error
*/
public function hasError()
{
return (count($this->_errors) > 0);
}
/**
* @return the $_action
*/
public function get_action() {
return $this->_action;
}
/**
* @return the $_errors
*/
public function get_errors() {
return $this->_errors;
}
/**
* Return validation errors as string
* @return string
*/
public function toString()
{
$result = array();
foreach ($this->_errors as $error)
$result[] = $error->toString();
return implode("\n", $result);
}
public function __toString()
{
return $this->toString();
}
}
您可以根据需要拥有任何模式,一些棘手的或困难的或容易的,您需要的一切。 下面我展示了 NamePattern
类
class NamePattern extends BasePattern
{
/**
* Satisfy data with coded requirements
* Name can not have any numbers or any special symbols
* @param $field
* @param $value
* @return ValidationError or TRUE
*/
public function isApproved($field, $value)
{
$not_empty = new NotEmptyPattern($this->get_action());
if (($res = $not_empty->isApproved($field, $value)) !== TRUE)
return $res;
//if (preg_match('/[\d~!@#$%^&\*\(\)\+={}\[\]|\\:;"<>\?\/]/', $value))
if (preg_match('/[~!@#$%^&\*\(\)\+={}\[\]|\\:;"<>\?\/]/', $value))
return new ValidationError($field, $value,
"$field has unavailable symbols: $value");
$clear_value = preg_replace('/\s/', "", $value);
$len = strlen($clear_value);
if ($len<5)
return new ValidationError($field, $value,
"$field is too short.");
if ($len>25)
return new ValidationError($field, $value,
"$field is too long.");
return TRUE;
}
}
它使用另一个模式 NotEmptyPattern
来确保姓名不为空,查找未经批准的符号并检查姓名长度。 此模式不依赖于操作。 例如,实例 Id 验证模式可能依赖于操作,因为通常 INSERT
操作可以具有 id = 0
,但更新不能。
class ValidationError
{
private $_field;
private $_value;
private $_message;
/**
* Create instance
* @param $field
* @param $value
* @param $message it is format of error string for sprintf.
*/
public function __construct($field, $value, $message='')
{
$this->_field = $field;
$this->_value = $value;
$this->_message = $message;
}
/**
* @return the $_message
*/
public function get_message() {
return $this->_message;
}
/**
* @return the $_value
*/
public function get_value() {
return $this->_value;
}
/**
* @return the $_field
*/
public function get_field() {
return $this->_field;
}
public function __toString()
{
return $this->toString();
}
public function toString()
{
if (empty($this->_message))
return "Field ".$this->_field."
has incorrect value '".$this->_value."'.";
else
return sprintf($this->_message, $this->_value);
}
}
我想您明白了使用它是多么简单。 获取已填充的实例,验证它,检查结果,如果数据不正确则回滚,如果数据正确则保存。 看起来像这样
//......................................
$employee = new Employee ( );
//...... populate employee instance......
$v = $employee->Validate(BasePattern::ACTION_UPDATE);
if ($v->hasError())
{
$transaction->rollback();
HTTPFactory::sendJSONResponse ( array
('code'=>1, 'processStatus' => "Form is not saved
(Employee data validation error:\n".$v.')' ) );
}
$employee->save ();
//......................................
HTTPFactory::sendJSONResponse
将 json 响应发送到用户浏览器并退出。
就是这样。
历史
- 2010 年 9 月 29 日:初始帖子