【问题标题】:How to validate form field in PHP using Object Oriented Technique如何使用面向对象技术在 PHP 中验证表单字段
【发布时间】:2017-09-08 11:38:31
【问题描述】:

我创建了一个“验证”类来验证两个字段,即“名字”和“姓氏”。它工作不正常,当字段为空时显示错误,但是当我提交带有非空字段的表单时,错误仍然存​​在。如何在表单提交时执行此操作?

 <?php

  class validation {

  public $firstName, $lastName, $errorFirstName = '', $errorLastName = '';

  function __constructor($fName, $lName){
    $this->firstName = $fName;
    $this->lastName = $lName;
  }

  function check(){

      if($_SERVER["REQUEST_METHOD"] == "POST"){
        if(empty($this->firstName)){
        $this->errorFirstName = 'First name is required';
       } else {
        $this->errorFirstName = 'Input is okay';
       }

     if(empty($this->lastName)){
         $this->errorLastName = 'Last name is required';
      }  else {
       $this->errorLastName = 'Input is okay';
      }
    }
   }
  }

 $obj = new validation($_POST['firstname'], $_POST['lastname']);
 $obj->check();
 $errorF = $obj->errorFirstName;
 $errorL = $obj->errorLastName;

 ?>

  <!DOCTYPE html>
  <html lang = "en-US" dir = "ltr">
   <head>
    <title>Home</title>
    <meta charset = "UTF-8"/>
   </head>
   <body>
   <form method = "POST" action="<?php echo $_SERVER["PHP_SELF"]?>">
    <label>First Name: </label>
    <input type = "text" name = "firstname" placeholder = "John"/>
    <p class = "error"><?php echo $errorF;?></p>
    <label>Last Name: </label>
    <input type = "text" name = "lastname" placeholder = "Doe"/>
    <p class = "error"><?php echo $errorL;?></p>
    <input type="submit">
   </form>
  </body>
 </html>

【问题讨论】:

  • 如果我要创建一个验证类,我不会把所有的检查都放在一个方法中。相反,我会使用不同的规则为不同的验证制定不同的方法。我会像 CodeIgniter 一样编写自己的 validation.php 库(基于我自己的偏好),或者我会使用 CI 的库(这也很棒)。它使验证变得更加容易和可重用。
  • 您应该删除 if($_SERVER["REQUEST_METHOD"] == "POST"){ 签入您的类并将其包裹在您实例化对象的位置。
  • 感谢 alistaircol。我是 PHP 和 OOP 的新手。我删除了构造函数并写了一个 set 函数。它有效。

标签: php forms validation oop


【解决方案1】:

每个人总是做“数据库类”和“验证类”。呃……哇哇?

不要创建验证类。它永远不会起作用。最.. emm ... 验证用户输入的可持续选项是:

使用实体进行验证非常简单。在您的情况下,您将拥有 Profile 类,其中您拥有方法 setFirstName(string $name)。然后在此方法中进行验证,并在出错时抛出自定义的exception,如InvalidFirstName .. 或类似的东西。

使用 值对象 有点棘手,但它可以防止代码重复。例如,您需要验证电子邮件地址。因此,您希望使用它的方式如下所示:

try {
    $profile = new Profile;
    $profile->setEmail(new EmailAddress($_POST['email']));
} catch (InvalidArgumentException $e){
    // validation failed
}

因此,要获得这种行为,您需要像这样定义类:

class EmailAddress
{
    private $email;


    public function __construct(int $emailId = null, string $email = null)
    {
        if (!$this->isValid($email)) {
            throw new InvalidArgumentException('Not valid email address');
        }
        $this->email = $email;
    }


    private function isValid($email)
    {
        return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
    }


    public function __toString()
    {
        return $this->email;
    }
}

这种方法更具表现力,但在与持久层交互时往往会变得很棘手。

在实践中,最好的选择是结合使用这两种解决方案:

  • 将验证保留在实体中,以获取唯一的规则
  • 为经常重复的约束使用值对象

【讨论】:

  • 为什么构造函数收到$emailId却从不使用?
  • 因为这是从真实代码中复制的,删除了额外的位......显然没有删除所有这些。老实说,我不知道为什么甚至$emailId 存在于那个类中。
【解决方案2】:

做一个验证器类。

表单通常由多个字段组成,这意味着在建议的方法中,您在设置对象时尝试/捕获错误将在单个字段上失败,当您可能有多个无效字段并且在表单提交时您希望所有字段都验证并返回所有错误,以便它们可以同时显示。

<?php

class MyValidator
{
    /**
     * Is form valid;
     *
     * @var bool
     */
    private $isValid = true;
    /**
     * List of errors, assoc array with error messages one per fieldName
     *
     * @var array
     */
    private $errors = [];

    /**
     * Check if form is valid
     *
     * @return bool
     */
    public function isValid(): bool
    {
        return $this->isValid;
    }

    /**
     * Get error message
     *
     * @param $fieldName
     * @return mixed|string
     */
    public function getError($fieldName)
    {
        return isset($this->errors[$fieldName]) ? $this->errors['fieldName'] : '';
    }

    /**
     * @param array $rules list of rules
     * @param array $payload list of form parameters
     * @return bool Return validation result, same as isValid
     */
    public function validate(array $rules, array $payload)
    {
        foreach ($rules as $rule) {
            if (!$this->validateRequired($rule, $payload)) {
                continue;
            }
            switch ($rule['type']) {
                case 'string':
                    $this->validateString($rule, $payload);
                    break;
                case 'email':
                    $this->validateEmail($rule, $payload);
                    break;
                    //extend with other validation rules as needed
            }
        }

        return $this->isValid();
    }

    public function validateRequired(array $rule, array $payload)
    {
        if (true === $rule['required'] && !isset($payload[$rule['fieldName']])) {
            $this->isValid = false;
            $this->errors[$rule['fieldName']] = 'This field is required';

            return false;
        }

        return true;
    }

    public function validateString($rule, $payload)
    {
        // Checkup logic, set $this->isValid to false if not valid, add
        // See add $this->errors[$rule['fieldname']] = 'your message';
    }

    public function validateEmail($rule, $payload)
    {
        // Checkup logic, set $this->isValid to false if not valid, add
        // See add $this->errors[$rule['fieldname']] = 'your message';
    }

}

// Call validator by giving validator ruleset in the format

$rules = [
    [
        'fieldName' => 'firstName',
        'type' => 'string',
        'minLength' => 10,
        'maxLength' => 20,
        'required' => true,
    ],
    [
        'fieldName' => 'email',
        'type' => 'email',
        'required' => true,
    ]
];

$validator = new MyValidator();
$isValid = $validator->validate($rules, $_POST);

// if false do repeat form with error messages shown
// use $validator->getError('firstName'); to get error message for a field.

【讨论】:

    【解决方案3】:

    在提到的代码中,它的编写方式是在创建类时将表单值传递给类,并且在构造函数中,类变量将使用提供的值进行初始化。

    之后 check() 方法会检查字段是否为空。

    但这并没有按预期工作,因为从表单传递的值无法初始化为 $firstName 和 $lastName。

    原因是,

    function __constructor() 
    

    不是类的构造函数,应该是

    function __construct()
    

    这就是为什么没有为类变量分配表单中给出的值并且出现错误的原因。

    修改后问题就解决了。

    【讨论】:

    • 感谢您的回答,Rajen。不幸的是,我打开赏金只是为了奖励 tereško 的答案。但我感谢您为写下答案所做的努力。 P.S:一般来说,某人打开赏金的动机在其描述文本中呈现。
    猜你喜欢
    • 2012-08-31
    • 1970-01-01
    • 1970-01-01
    • 2010-09-15
    • 1970-01-01
    • 2011-08-09
    • 2023-03-15
    • 1970-01-01
    • 2018-08-21
    相关资源
    最近更新 更多