有效的数据验证

时间:2010-05-17 11:48:03

标签: php validation

例如,从表单提交处理数据验证的有效方法是什么?

最初我有一堆if语句检查每个值并在数组中收集无效值以供以后检索(和列表)。

// Store errors here
$errors = array();

// Hypothetical check if a string is alphanumeric
if (!preg_match('/^[a-z\d]+$/i', $fieldvalue))
{
    $errors[$fieldname] = 'Please only use letters and numbers for your street address';
}

// etc...

我接下来要做的是创建一个处理各种数据验证方案的类,并将结果存储在内部数组中。数据验证完成后,我会检查是否发生了任何错误并进行相应处理:

class Validation
{
    private $errorList = array();

    public function isAlphaNumeric($string, $field, $msg = '')
    {
        if (!preg_match('/^[a-z\d]+$/i', $string))
        {
            $this->errorList[$field] = $msg;
        }
    }

    // more methods here

    public function creditCard($cardNumber, $field, $msg = '')
    {
        // Validate credit card number
    }

    // more methods here

    public function hasErrors()
    {
        return count($this->errorList);
    }
}

/* Client code */

$validate = new Validation();
$validate->isAlphaNumeric($fieldvalue1, $fieldname1, 'Please only use letters and numbers for your street address');
$validate->creditCard($fieldvalue2, $fieldname2, 'Please enter a valid credit card number');

if ($validate->hasErrors())
{
    // Handle as appropriate
}

当然,不久之后,这个课程变得臃肿,几乎无限类型的数据需要验证。我现在正在做的是使用装饰器将不同类型的数据分成它们自己的类,只在需要时在基类中留下通用验证(即isAlphaNumeric())来调用它们:

class Validation
{
    private $errorList = array();

    public function isAlphaNumeric($string, $field, $msg = '')
    {
        if (!preg_match('/^[a-z\d]+$/i', $string))
        {
            $this->errorList[$field] = $msg;
        }
    }

    // more generic methods here

    public function setError($field, $msg = '')
    {
        $this->errorList[$field] = $msg;
    }

    public function hasErrors()
    {
        return count($this->errorList);
    }
}

class ValidationCreditCard
{
    protected $validate;

    public function __construct(Validation $validate)
    {
        $this->validate = $validate;
    }

    public function creditCard($cardNumber, $field, $msg = '')
    {
        // Do validation
        // ...
        // if there is an error
        $this->validate->setError($field, $msg);
    }

    // more methods here
}

/* Client code */

$validate = new Validation();
$validate->isAlphaNumeric($fieldvalue, $fieldname, 'Please only use letters and numbers for your street address');

$validateCC = new ValidationCreditCard($validate);
$validateCC->creditCard($fieldvalue2, $fieldname2, 'Please enter a valid credit card number');

if ($validate->hasErrors())
{
    // Handle as appropriate
}

我是否在正确的轨道上?或者我只是将数据验证复杂化,然后才需要?

4 个答案:

答案 0 :(得分:2)

如果有的话,你没有足够的验证。要读取$ _POST和$ _GET中的数据,至少需要:

  • 检查是否存在(array_key_exists)
  • 检查是否为数组
  • 如果期望UTF-8,请检查它是否有效UTF-8(带有'u'修饰符的preg_match是一个选项)
  • 然后执行特定于字段类型的验证

顺便说一句,目前在PHP中进行验证和清理的方法是使用filters。在您的具体情况下,这是一个例子:

<?php
$data = array(
    "arg1good" => "sdgdf790",
    "arg1bad"  => "sdgdf7/90",
    "arg1bad2" => array("sdgdf90", "sfdssf"),
    "arg2good" => "4567576456",
    "arg2bad"  => "45675764561",
);

$validateCredCard = function ($cc) {
    if (preg_match('/^\\d{10}$/', $cc))
        return $cc;
    else
        return false;
};

$arg1filt = array('filter'  => FILTER_VALIDATE_REGEXP,
                  'flags'   => FILTER_REQUIRE_SCALAR,
                  'options' => array('regexp' => '/^[a-z\d]+$/i'),
                  );
$arg2filt = array('filter'  => FILTER_CALLBACK,
                  'flags'   => FILTER_REQUIRE_SCALAR,
                  'options' => $validateCredCard,
                  );
$args = array(
    "arg1good" => $arg1filt,
    "arg1bad"  => $arg1filt,
    "arg1bad2" => $arg1filt,
    "arg2good" => $arg2filt,
    "arg2bad"  => $arg2filt,
);

var_dump(filter_var_array($data, $args));

给出:

array(5) {
  ["arg1good"]=>
  string(8) "sdgdf790"
  ["arg1bad"]=>
  bool(false)
  ["arg1bad2"]=>
  bool(false)
  ["arg2good"]=>
  string(10) "4567576456"
  ["arg2bad"]=>
  bool(false)
}

答案 1 :(得分:1)

您似乎并不十分清楚自己的目标是什么 - 表现?简单的新代码?总体可维护性?

当然,出于性能原因,我建议将验证保留为代码,而不是将正则表达式(以及阈值和......)存储为数据。问题似乎是如何将您拥有的数据项映射到适当的验证。虽然您可以将静态映射设置为数组,但由于您还需要了解数据结构以呈现表单并映射到数据库列,因此您可能应考虑在代码中实现更正式的元数据管理方法

℃。

答案 2 :(得分:0)

这对我来说似乎过于复杂。

数字数据:只需转换$ _POST值

$val=(int)$_POST["val"];

电子邮件:有预制功能可以做到这一点(希望找到一个正确的功能)。

$email=check_email($_POST["email"]) or die("Ha!");

姓名和地址:什么都不做,因为它会在陌生人进入你没想过的unicode角色的那一天到来,并被你的功能过滤掉。

电话号码:什么都不做,如果他想给出一个错误的号码,无论如何都会这样做。

特殊代码,例如邮政编码和类似的东西:你通常会有一个非常严格的标准,创建一个使用那个过滤的功能,你就完成了。

答案 3 :(得分:0)

@ Lo'oris 关于投射值的答案并不完全。请考虑以下示例:

$val_1 = (int)null;    // $val_1 equals 0
$val_2 = (int)false;   // $val_2 equals 0
$val_3 = (int)'';      // $val_3 equals 0
$val_4 = (int)array(); // $val_4 equals 0

正如此示例所示,此策略仅在您希望变量为 大于0的整数时才有效。

就“check_email”功能而言 - 你说在互联网上有许多实现是正确的,但大多数都是不完整或不正确。

大多数实现都使用像这样的正则表达式:

"^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$"

或者这个:

"^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+.[a-zA-Z0-9-.]+$"

这两个正则表达式拒绝这样的电子邮件地址:

Abc\@def@example.com
customer/department=shipping@example.com
!def!xyz%abc@example.com 

全部有效(根据http://www.linuxjournal.com/article/9585?page=0,0)。

还请看看: http://www.regular-expressions.info/email.html