2009-04-10 28 views

Respuesta

61

Escribí una clase simple por mi cuenta, combinando algunas expresiones regulares que recopilé a lo largo de los años con las funciones de filtro y sanatize de 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; 
    }  



} 

Ahora bien, esto requiere mootools para algunos de los javascript que se ve aquí, pero se puede cambiar fácilmente que a su marco de JavaScript favorito. Todo lo que hace es buscar el elemento y agregarle la clase de CSS 'no validado'.

El uso es tan sencillo como siempre lo que quería:

Ejemplo:

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

Para validar un solo elemento:

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

Para sanatize un solo elemento:

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

T Lo mejor de esta clase es que puedes enviar tu formulario con un objetivo ajax o iframe y ejecutar el script resultante. No es necesario actualizar la página o volver a enviar los mismos datos del formulario al navegador :) Además, si el script necesita cambiarse, no hay un framework sobredesignado difícil de analizar, simplemente cámbielo de la manera que desee :)

Oh sí, siéntase libre de usar esto en cualquier lugar que desee. No hay licencias

+3

nota que esto no funcionará en versiones de PHP 5.2 antes porque está utilizando filter_var – Ray

+0

supongo se debe reemplazar 'array_search ($ key, $ this-> validaciones)' 'por array_key_exists ($ clave, $ this-> validaciones)' .IS ese derecho? – UnLoCo

+0

clase impresionante amigo! –

12

Si desea programar algunas por su cuenta, tiene PHP 5.2.0 o superior. A continuación, se puede mirar en la filter functions.

2

Usted tiene una parte del framework Symfony llamado formas de Symfony, que se pueden utilizar, aparte de todo el marco.

Eche un vistazo a the framework documentation.

4

Hay uno incluido en el marco CodeIgniter, echar un vistazo here

me recomiendan para empezar a utilizar uno de los marcos de PHP;)

23

La respuesta de SchizoDuckie anterior fue impresionante. He usado su código en el proyecto en el que estoy trabajando con el permiso del autor. Un problema que tuve al utilizar este código fue que si no se enviaba un campo obligatorio, no se registraba un error. Modifiqué el código para cubrir este escenario. También eliminé el código para generar HTML y javascript ya que mi proyecto exige la separación de UI de la lógica por patrón MVC. El código modificado simplemente devuelve el resultado codificado JSON. Replico el código modificado aquí en caso de que sea de alguna utilidad para otros.

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