2009-04-10 38 views
30

Tôi cần một thư viện php đơn giản có thể được sử dụng để dễ dàng chuyển các quy tắc và tên trường đến, và sau đó xác thực có thể dễ dàng thực hiện. Cũng nên có cách dễ dàng để truy xuất lỗi.Thư viện xác thực Mẫu dễ nhất cho PHP?

Mọi đề xuất?

Trả lời

61

Tôi đã viết một lớp đơn giản của riêng mình, kết hợp một số regexes tôi thu thập qua nhiều năm với các chức năng lọc và lọc của PHP.

<? 
/** 
* Pork Formvalidator. validates fields by regexes and can sanatize them. Uses PHP filter_var built-in functions and extra regexes 
* @package pork 
*/ 


/** 
* Pork.FormValidator 
* Validates arrays or properties by setting up simple arrays 
* 
* @package pork 
* @author SchizoDuckie 
* @copyright SchizoDuckie 2009 
* @version 1.0 
* @access public 
*/ 
class FormValidator 
{ 
    public static $regexes = Array(
      'date' => "^[0-9]{4}[-/][0-9]{1,2}[-/][0-9]{1,2}\$", 
      'amount' => "^[-]?[0-9]+\$", 
      'number' => "^[-]?[0-9,]+\$", 
      'alfanum' => "^[0-9a-zA-Z ,.-_\\s\?\!]+\$", 
      'not_empty' => "[a-z0-9A-Z]+", 
      'words' => "^[A-Za-z]+[A-Za-z \\s]*\$", 
      'phone' => "^[0-9]{10,11}\$", 
      'zipcode' => "^[1-9][0-9]{3}[a-zA-Z]{2}\$", 
      'plate' => "^([0-9a-zA-Z]{2}[-]){2}[0-9a-zA-Z]{2}\$", 
      'price' => "^[0-9.,]*(([.,][-])|([.,][0-9]{2}))?\$", 
      '2digitopt' => "^\d+(\,\d{2})?\$", 
      '2digitforce' => "^\d+\,\d\d\$", 
      'anything' => "^[\d\D]{1,}\$" 
    ); 
    private $validations, $sanatations, $mandatories, $errors, $corrects, $fields; 


    public function __construct($validations=array(), $mandatories = array(), $sanatations = array()) 
    { 
     $this->validations = $validations; 
     $this->sanatations = $sanatations; 
     $this->mandatories = $mandatories; 
     $this->errors = array(); 
     $this->corrects = array(); 
    } 

    /** 
    * Validates an array of items (if needed) and returns true or false 
    * 
    */ 
    public function validate($items) 
    { 
     $this->fields = $items; 
     $havefailures = false; 
     foreach($items as $key=>$val) 
     { 
      if((strlen($val) == 0 || array_search($key, $this->validations) === false) && array_search($key, $this->mandatories) === false) 
      { 
       $this->corrects[] = $key; 
       continue; 
      } 
      $result = self::validateItem($val, $this->validations[$key]); 
      if($result === false) { 
       $havefailures = true; 
       $this->addError($key, $this->validations[$key]); 
      } 
      else 
      { 
       $this->corrects[] = $key; 
      } 
     } 

     return(!$havefailures); 
    } 

    /** 
    * 
    * Adds unvalidated class to thos elements that are not validated. Removes them from classes that are. 
    */ 
    public function getScript() { 
     if(!empty($this->errors)) 
     { 
      $errors = array(); 
      foreach($this->errors as $key=>$val) { $errors[] = "'INPUT[name={$key}]'"; } 

      $output = '$$('.implode(',', $errors).').addClass("unvalidated");'; 
      $output .= "alert('there are errors in the form');"; // or your nice validation here 
     } 
     if(!empty($this->corrects)) 
     { 
      $corrects = array(); 
      foreach($this->corrects as $key) { $corrects[] = "'INPUT[name={$key}]'"; } 
      $output .= '$$('.implode(',', $corrects).').removeClass("unvalidated");'; 
     } 
     $output = "<script type='text/javascript'>{$output} </script>"; 
     return($output); 
    } 


    /** 
    * 
    * Sanatizes an array of items according to the $this->sanatations 
    * sanatations will be standard of type string, but can also be specified. 
    * For ease of use, this syntax is accepted: 
    * $sanatations = array('fieldname', 'otherfieldname'=>'float'); 
    */ 
    public function sanatize($items) 
    { 
     foreach($items as $key=>$val) 
     { 
      if(array_search($key, $this->sanatations) === false && !array_key_exists($key, $this->sanatations)) continue; 
      $items[$key] = self::sanatizeItem($val, $this->validations[$key]); 
     } 
     return($items); 
    } 


    /** 
    * 
    * Adds an error to the errors array. 
    */ 
    private function addError($field, $type='string') 
    { 
     $this->errors[$field] = $type; 
    } 

    /** 
    * 
    * Sanatize a single var according to $type. 
    * Allows for static calling to allow simple sanatization 
    */ 
    public static function sanatizeItem($var, $type) 
    { 
     $flags = NULL; 
     switch($type) 
     { 
      case 'url': 
       $filter = FILTER_SANITIZE_URL; 
      break; 
      case 'int': 
       $filter = FILTER_SANITIZE_NUMBER_INT; 
      break; 
      case 'float': 
       $filter = FILTER_SANITIZE_NUMBER_FLOAT; 
       $flags = FILTER_FLAG_ALLOW_FRACTION | FILTER_FLAG_ALLOW_THOUSAND; 
      break; 
      case 'email': 
       $var = substr($var, 0, 254); 
       $filter = FILTER_SANITIZE_EMAIL; 
      break; 
      case 'string': 
      default: 
       $filter = FILTER_SANITIZE_STRING; 
       $flags = FILTER_FLAG_NO_ENCODE_QUOTES; 
      break; 

     } 
     $output = filter_var($var, $filter, $flags);   
     return($output); 
    } 

    /** 
    * 
    * Validates a single var according to $type. 
    * Allows for static calling to allow simple validation. 
    * 
    */ 
    public static function validateItem($var, $type) 
    { 
     if(array_key_exists($type, self::$regexes)) 
     { 
      $returnval = filter_var($var, FILTER_VALIDATE_REGEXP, array("options"=> array("regexp"=>'!'.self::$regexes[$type].'!i'))) !== false; 
      return($returnval); 
     } 
     $filter = false; 
     switch($type) 
     { 
      case 'email': 
       $var = substr($var, 0, 254); 
       $filter = FILTER_VALIDATE_EMAIL;  
      break; 
      case 'int': 
       $filter = FILTER_VALIDATE_INT; 
      break; 
      case 'boolean': 
       $filter = FILTER_VALIDATE_BOOLEAN; 
      break; 
      case 'ip': 
       $filter = FILTER_VALIDATE_IP; 
      break; 
      case 'url': 
       $filter = FILTER_VALIDATE_URL; 
      break; 
     } 
     return ($filter === false) ? false : filter_var($var, $filter) !== false ? true : false; 
    }  



} 

Điều này đòi hỏi mootools đối với một số javascript bạn thấy ở đây, nhưng bạn có thể dễ dàng thay đổi điều đó thành khung javascript yêu thích của mình. Tất cả những gì nó làm là tìm kiếm phần tử và thêm lớp CSS 'unvalidated' vào nó.

Cách sử dụng cũng đơn giản như tôi luôn luôn bao giờ muốn:

Ví dụ:

$validations = array(
    'name' => 'anything', 
    'email' => 'email', 
    'alias' => 'anything', 
    'pwd'=>'anything', 
    'gsm' => 'phone', 
    'birthdate' => 'date'); 
$required = array('name', 'email', 'alias', 'pwd'); 
$sanatize = array('alias'); 

$validator = new FormValidator($validations, $required, $sanatize); 

if($validator->validate($_POST)) 
{ 
    $_POST = $validator->sanatize($_POST); 
    // now do your saving, $_POST has been sanatized. 
    die($validator->getScript()."<script type='text/javascript'>alert('saved changes');</script>"); 
} 
else 
{ 
    die($validator->getScript()); 
} 

Để xác nhận chỉ là một phần tử:

$validated = new FormValidator()->validate('[email protected]', 'email'); 

Để sanatize chỉ là một phần tử:

$sanatized = new FormValidator()->sanatize('<b>blah</b>', 'string'); 

T điều tuyệt vời nhất về lớp này là bạn có thể gửi biểu mẫu của mình với mục tiêu ajax hoặc khung nội tuyến và thực thi tập lệnh kết quả. Không cần phải làm mới trang hoặc gửi lại cùng một dữ liệu biểu mẫu trở lại trình duyệt :) Ngoài ra, nếu tập lệnh cần thay đổi, không có khung khổ quá khó để phân tích, chỉ cần thay đổi theo bất kỳ cách nào bạn muốn :)

Oh vâng, cảm thấy tự do để sử dụng điều này bất cứ nơi nào bạn muốn. Không có giấy phép

+3

lưu ý rằng điều này sẽ không hoạt động trên các phiên bản PHP trước 5.2 bởi vì bạn đang sử dụng filter_var – Ray

+0

tôi đoán bạn nên thay thế 'array_search ($ key, $ this-> validations)' bởi 'array_key_exists ($ key, $ this-> validations)' .Là đúng? – UnLoCo

+0

Anh chàng tuyệt vời! –

12

Nếu bạn muốn tự mình lập trình và bạn có PHP 5.2.0 trở lên. Sau đó, bạn có thể xem xét filter functions.

2

Bạn có một phần của khung công tác symfony có tên là các mẫu biểu mẫu symfony, có thể được sử dụng ngoài toàn bộ khuôn khổ.

Hãy xem the framework documentation.

4

Có một trong khuôn khổ Code Igniter, có một cái nhìn here

Tôi khuyên bạn nên bắt đầu bằng một trong những khuôn khổ PHP;)

5

Zend Forms Mà có thể được sử dụng mà không cần toàn bộ khuôn khổ Zend

23

Câu trả lời từ SchizoDuckie trên thật tuyệt vời. Tôi đã sử dụng mã của mình trong dự án tôi đang làm việc với sự cho phép của tác giả. Một vấn đề tôi đã sử dụng mã này là nếu một trường bắt buộc không được gửi thì nó sẽ không đăng ký lỗi. Tôi đã sửa đổi mã để trình bày kịch bản này. Tôi cũng đã loại bỏ các mã để tạo ra HTML và javascript như dự án của tôi yêu cầu tách UI từ logic cho mỗi mô hình MVC. Mã đã sửa đổi chỉ trả về kết quả được mã hóa JSON. Tôi repost mã sửa đổi ở đây trong trường hợp nó là một số sử dụng cho người khác.

<? 
/** 
* Pork Formvalidator. validates fields by regexes and can sanatize them. Uses PHP  filter_var built-in functions and extra regexes 
* @package pork 
*/ 


/** 
* Pork.FormValidator 
* Validates arrays or properties by setting up simple arrays 
* 
* @package pork 
* @author SchizoDuckie 
* @copyright SchizoDuckie 2009 
* @version 1.0 
* @access public 
*/ 
class FormValidator 
{ 
    public static $regexes = Array(
      'date' => "^[0-9]{4}[-/][0-9]{1,2}[-/][0-9]{1,2}\$", 
      'amount' => "^[-]?[0-9]+\$", 
      'number' => "^[-]?[0-9,]+\$", 
      'alfanum' => "^[0-9a-zA-Z ,.-_\\s\?\!]+\$", 
      'not_empty' => "[a-z0-9A-Z]+", 
      'words' => "^[A-Za-z]+[A-Za-z \\s]*\$", 
      'phone' => "^[0-9]{10,11}\$", 
      'zipcode' => "^[1-9][0-9]{3}[a-zA-Z]{2}\$", 
      'plate' => "^([0-9a-zA-Z]{2}[-]){2}[0-9a-zA-Z]{2}\$", 
      'price' => "^[0-9.,]*(([.,][-])|([.,][0-9]{2}))?\$", 
      '2digitopt' => "^\d+(\,\d{2})?\$", 
      '2digitforce' => "^\d+\,\d\d\$", 
      'anything' => "^[\d\D]{1,}\$", 
      'username' => "^[\w]{3,32}\$" 
); 

private $validations, $sanatations, $mandatories, $equal, $errors, $corrects, $fields; 


public function __construct($validations=array(), $mandatories = array(), $sanatations = array(), $equal=array()) 
{ 
    $this->validations = $validations; 
    $this->sanatations = $sanatations; 
    $this->mandatories = $mandatories; 
    $this->equal = $equal; 
    $this->errors = array(); 
    $this->corrects = array(); 
} 

/** 
* Validates an array of items (if needed) and returns true or false 
* 
* JP modofied this function so that it checks fields even if they are not submitted. 
* for example the original code did not check for a mandatory field if it was not submitted. 
* Also the types of non mandatory fields were not checked. 
*/ 
public function validate($items) 
{ 
    $this->fields = $items; 
    $havefailures = false; 

    //Check for mandatories 
    foreach($this->mandatories as $key=>$val) 
    { 
     if(!array_key_exists($val,$items)) 
     { 
      $havefailures = true; 
      $this->addError($val); 
     } 
    } 

    //Check for equal fields 
    foreach($this->equal as $key=>$val) 
    { 
     //check that the equals field exists 
     if(!array_key_exists($key,$items)) 
     { 
      $havefailures = true; 
      $this->addError($val); 
     } 

     //check that the field it's supposed to equal exists 
     if(!array_key_exists($val,$items)) 
     { 
      $havefailures = true; 
      $this->addError($val); 
     } 

     //Check that the two fields are equal 
     if($items[$key] != $items[$val]) 
     { 
      $havefailures = true; 
      $this->addError($key); 
     } 
    } 

    foreach($this->validations as $key=>$val) 
    { 
      //An empty value or one that is not in the list of validations or one that is not in our list of mandatories 
      if(!array_key_exists($key,$items)) 
      { 
        $this->addError($key, $val); 
        continue; 
      } 

      $result = self::validateItem($items[$key], $val); 

      if($result === false) { 
        $havefailures = true; 
        $this->addError($key, $val); 
      } 
      else 
      { 
        $this->corrects[] = $key; 
      } 
    } 

    return(!$havefailures); 
} 

/* JP 
* Returns a JSON encoded array containing the names of fields with errors and those without. 
*/ 
public function getJSON() { 

    $errors = array(); 

    $correct = array(); 

    if(!empty($this->errors)) 
    {    
     foreach($this->errors as $key=>$val) { $errors[$key] = $val; }    
    } 

    if(!empty($this->corrects)) 
    { 
     foreach($this->corrects as $key=>$val) { $correct[$key] = $val; }     
    } 

    $output = array('errors' => $errors, 'correct' => $correct); 

    return json_encode($output); 
} 



/** 
* 
* Sanatizes an array of items according to the $this->sanatations 
* sanatations will be standard of type string, but can also be specified. 
* For ease of use, this syntax is accepted: 
* $sanatations = array('fieldname', 'otherfieldname'=>'float'); 
*/ 
public function sanatize($items) 
{ 
    foreach($items as $key=>$val) 
    { 
      if(array_search($key, $this->sanatations) === false && !array_key_exists($key, $this->sanatations)) continue; 
      $items[$key] = self::sanatizeItem($val, $this->validations[$key]); 
    } 
    return($items); 
} 


/** 
* 
* Adds an error to the errors array. 
*/ 
private function addError($field, $type='string') 
{ 
    $this->errors[$field] = $type; 
} 

/** 
* 
* Sanatize a single var according to $type. 
* Allows for static calling to allow simple sanatization 
*/ 
public static function sanatizeItem($var, $type) 
{ 
    $flags = NULL; 
    switch($type) 
    { 
      case 'url': 
        $filter = FILTER_SANITIZE_URL; 
      break; 
      case 'int': 
        $filter = FILTER_SANITIZE_NUMBER_INT; 
      break; 
      case 'float': 
        $filter = FILTER_SANITIZE_NUMBER_FLOAT; 
        $flags = FILTER_FLAG_ALLOW_FRACTION | FILTER_FLAG_ALLOW_THOUSAND; 
      break; 
      case 'email': 
        $var = substr($var, 0, 254); 
        $filter = FILTER_SANITIZE_EMAIL; 
      break; 
      case 'string': 
      default: 
        $filter = FILTER_SANITIZE_STRING; 
        $flags = FILTER_FLAG_NO_ENCODE_QUOTES; 
      break; 

    } 
    $output = filter_var($var, $filter, $flags);    
    return($output); 
} 

/** 
* 
* Validates a single var according to $type. 
* Allows for static calling to allow simple validation. 
* 
*/ 
public static function validateItem($var, $type) 
{ 
    if(array_key_exists($type, self::$regexes)) 
    { 
      $returnval = filter_var($var, FILTER_VALIDATE_REGEXP, array("options"=> array("regexp"=>'!'.self::$regexes[$type].'!i'))) !== false; 
      return($returnval); 
    } 
    $filter = false; 
    switch($type) 
    { 
      case 'email': 
        $var = substr($var, 0, 254); 
        $filter = FILTER_VALIDATE_EMAIL;   
      break; 
      case 'int': 
        $filter = FILTER_VALIDATE_INT; 
      break; 
      case 'boolean': 
        $filter = FILTER_VALIDATE_BOOLEAN; 
      break; 
      case 'ip': 
        $filter = FILTER_VALIDATE_IP; 
      break; 
      case 'url': 
        $filter = FILTER_VALIDATE_URL; 
      break; 
    } 
    return ($filter === false) ? false : filter_var($var, $filter) !== false ? true :  false; 
}   
} 
?> 
Các vấn đề liên quan