2009-04-10 58 views
30

我需要一個簡單的php庫,它可以用來輕鬆地傳遞規則和字段名稱,然後驗證可以很容易地執行。還應該有一個簡單的方法來檢索錯誤。最簡單的PHP驗證庫?

有什麼建議嗎?

回答

61

我寫了一個我自己的簡單的類,結合了多年來我用PHP的sanatize和filter函數收集的一些正則表達式。

<? 
/** 
* 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; 
    }  



} 

現在,這需要一些你在這裏看到的JavaScript的MooTools的,但你可以很容易地改變您最喜愛的JavaScript框架。它所做的就是查找元素,並向其添加「未驗證的」CSS類。因爲我一直沒有想

用法很簡單:

例子:

$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()); 
} 

要驗證一個元素:

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

要sanatize只有一個元素:

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

T關於這個類最酷的事情是,你可以發送你的表單與ajax或iframe目標並執行結果腳本。沒有必要刷新頁面或重新發送相同的表格數據回瀏覽器:)另外,如果腳本需要改變,沒有困難的過分設計的框架來分析,只需要改變任何你想要的方式:)

哦是的,隨時在任何你想要的地方使用。無許可證

+3

注意,這不會對PHP版本的工作在5.2之前,因爲你正在使用filter_var – Ray 2013-03-06 21:56:23

+0

我想你應該用'array_key_exists($ key,$ this-> validations)'替換'array_search($ key,$ this-> validations)''。那對嗎? – UnLoCo 2013-07-09 16:53:55

+0

真棒班的老兄! – 2014-11-27 09:00:18

12

如果你想自己編程一些,你有PHP 5.2.0或更高版本。然後,你可以看看到filter functions.

4

有一個包含代碼點火器的框架,看看here

我建議開始使用PHP框架之一;)

23

從SchizoDuckie答案是真棒。我在作者許可的項目中使用他的代碼。我使用這個代碼的一個問題是,如果沒有提交必填字段,那麼它不會註冊錯誤。我修改了代碼以涵蓋這種情況。我還刪除了生成HTML和JavaScript的代碼,因爲我的項目要求按照MVC模式將UI與邏輯分開。修改後的代碼只是返回JSON編碼結果。我在這裏重新發布修改後的代碼,以防其他人使用它。

<? 
/** 
* 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; 
}   
} 
?>