Location: PHPKode > projects > Cartboard Box Manager > cboxmanager_0.1.4/lib/class.validation.php
<?php
/**
 *  This class implements a generic validation for any web form.
 *
 *  Was originally devepoled by Ben Keen with additional code contributed
 *    by Mihai Ionescu and Nathan Howard
 *  ( {@link http://www.benjaminkeen.com/software/php_validation PHP validation} )
 *
 *  There is only a little modification from original script: the function
 *    validate() ( which originally was validateFields() ) now returns
 *    an associative array of errors with as key the name of the field
 *    where validation error starts and as value the error string.
 * 
 *  Rules must be strings of the form:<pre>
 * "[if:FIELDNAME=VALUE,],REQUIREMENT,fieldname[,fieldname2 [,fieldname3, date_flag]],error message"
 * 
 *  if:FIELDNAME=VALUE,   This allows us to only validate a field only if
 *    a fieldname FIELDNAME has a value VALUE. This option allows for
 *    nesting; i.e. you can have multiple if clauses, separated by a
 *    comma. They will be examined in the order in which they appear in
 *    the line.
 *
 *  Valid REQUIREMENT strings are:
 *    "required"     - field must be filled in
 *    "digits_only"  - field must contain digits only
 *    "is_alpha"     - field must only contain alphanumeric characters
 *      (0-9, a-Z)
 *    "custom_alpha" - field must be of the custom format specified.
 *      fieldname:  the name of the field
 *      fieldname2: a character or sequence of special characters. These
 *        characters are:
 *        L   An uppercase Letter          V   An uppercase Vowel
 *        l   A lowercase letter           v   A lowercase vowel
 *        D   A letter (upper or lower)    F   A vowel (upper or lower)
 *        C   An uppercase Consonant       x   Any number, 0-9
 *        c   A lowercase consonant        X   Any number, 1-9
 *        E   A consonant (upper or lower)
 *    "reg_exp"      - field must match the supplied regular expression.
 *      fieldname:  the name of the field
 *      fieldname2: the regular expression
 *      fieldname3: (optional) flags for the reg exp (like i for case
 *        insensitive )
 *    "letters_only" - field must only contains letters (a-Z)
 *
 *    "length=X"     - field has to be X characters long
 *    "length=X-Y"   - field has to be between X and Y (inclusive)
 *      characters long
 *    "length>X"     - field has to be greater than X characters long
 *    "length>=X"    - field has to be greater than or equal to X
 *      characters long
 *    "length<X"     - field has to be less than X characters long
 *    "length<=X"    - field has to be less than or equal to X
 *      characters long
 *
 *    "valid_email"  - field has to be valid email address
 *    "valid_date"   - field has to be a valid date
 *      fieldname:  MONTH
 *      fieldname2: DAY
 *      fieldname3: YEAR
 *      date_flag:  "later_date" / "any_date"
 *    "same_as"     - fieldname is the same as fieldname2 (for password
 *      comparison)
 *
 *    "range=X-Y"    - field must be a number between the range of X and
 *      Y inclusive
 *    "range>X"      - field must be a number greater than X
 *    "range>=X"     - field must be a number greater than or equal to X
 *    "range<X"      - field must be a number less than X
 *    "range<=X"     - field must be a number less than or equal to X
 *
 *  Comments:   With both digits_only, valid_email and is_alpha options,
 *    if the empty string is passed in it won't generate an error, thus
 *    allowing validation of non-required fields. So, for example, if
 *    you want a field to be a valid email address, provide validation
 *    for both "required" and "valid_email".</pre>
 *
 *  @version    1.0.0
 *  @author     Edoardo Tenani <hide@address.com>
 *  @license    GNU Public License 2.0 or greater
 *          <http://opensource.org/licenses/gpl-2.0.php>
 *  @copyright    Edoardo Tenani
 *
 *  @package    cboxmanager
 *  @subpackage   utility
 *  @category   validation
 *  @since      0.1.1
 */
class Validation {

  /**
   *  Field list. All elements in this array will be validated.
   *
   *  @access protected
   *  @var array
   */
  protected $fields = array();

  /**
   *  Rule list. The fields in the field list will be validated using
   *  this set of rules.
   *
   *  @access protected
   *  @var array
   */
  protected $rules = array();

  /**
   *  Initialize an istance of the class.
   *
   *  @access public
   *  @param  array $fields the list of fields to be validated
   *  @param  array $rules the rules to valiadte fields
   *
   *  @return true
   */
  public function __construct() {
    $this->fields = $fields;
    $this->relus = $rules;

    return true;
  }
  
/*  OBJECT FUNCTION OVERRIDE
 ************************************************/

  /**
   *  When the class is destroyed this function is called.
   *
   *  @return void
   */
  public function __destruct() {  }

  /**
   *  When an inaccesible method of the class is invoked this function
   *  is called.
   *
   *  @return void
   */
  public function __call($name, $arguments) {
        echo get_class($this)."::Error in calling object method <b>'$name'</b>"."<br>\n";
    }

  /**
   *  When an inaccesible static method of the class is invoked this
   *  function is called.
   *
   *  @return void
   */
  public static function __callStatic($name, $arguments) {
        echo get_class($this)."::Error in calling object static method <b>'$name'</b>"."<br>\n";
    }

  /**
   *  When the object is converted to a string this function is used to
   *  format the result string.
   *  Values are separated by "|". If the class var is an array, values
   *  in it will be separated by ",", or NULL if is not set.
   *  The string starts and ends with "-".
   *
   *  @access public
   *  @return a string with all class vars values separated by |
   */
  public function __toString() {    
    return NULL;
  }

/*  SET & GET FUNCTION
 ************************************************/

  /**
   *  The function set a specified class var.
   *  Is not case sensitive.
   *
   *  @access public
   *  @param  string $var the name of the var to be set
   *  @param  mixed $value the new value to set
   * 
   *  @return true
   */
  public function set($var, $value = NULL) {
    $this->{$var} = $value;
    return true;
  }

  /**
   *  The function get a specified class var.
   *  Is case sensitive.
   *
   *  @access public
   *  @param  string $var the name of the var to be get
   *
   *  @return the class var
   */
  public function get($var) {
    return $this->{$var};
  }


/*  PUBLIC FUNCTION
 ************************************************/

  /**
   *  This function add a single field to the fields list.
   *
   *  @access public
   *  @param  string $name use as index in the fields array
   *  @param  mixed $value the value to be added
   *
   *  @return void
   */
  public function add_field($name = false, $value) {
    $this->fields[$name] = $value;
  }

  /**
   *  Add a rule to the $rules array.
   *
   *  @param  string $rule a rule as specified by documentation
   *
   *  @return void
   */
  public function add_rule($rule) {
    $this->rules[] = $rule;
  }


  /**
   *  Generic form field validation.
   *
   *  @return an array of errors, if found; void otherwise; can return
   *    false if $this->fields and $this->rules are empty
   */
  public function validate() {
    if ( !empty($this->fields) && !empty($this->rules)) {
      $fields = $this->fields;
      $rules = $this->rules;
    }
    else
      return false;
    
    
    $errors = array();

    $count_rules = count($rules);

    // loop through rules
    for ( $i = 0; $i < $count_rules; $i++ ) {
      // split row into component parts 
      $row = explode(",", $rules[$i]);

      // while the row begins with "if:..." test the condition. If true, strip the if:..., part and 
      // continue evaluating the rest of the line. Keep repeating this while the line begins with an 
      // if-condition. If it fails any of the conditions, don't bother validating the rest of the line
      $satisfies_if_conditions = true;
      
      while ( preg_match("/^if:/", $row[0]) ) {
        $condition = preg_replace("/^if:/", "", $row[0]);

        // check if it's a = or != test
        $comparison = "equal";
        $parts = array();
        
        if ( preg_match("/!=/", $condition) ) {
          $parts = explode("!=", $condition);
          $comparison = "not_equal";
        }
        else 
          $parts = explode("=", $condition);

        $field_to_check = $parts[0];
        $value_to_check = $parts[1];

        // if the VALUE is NOT the same, we don't need to validate this field. Return.
        if ( $comparison == "equal" && $fields[$field_to_check] != $value_to_check ) {
          $satisfies_if_conditions = false;
          break;
        }
        else if ( $comparison == "not_equal" && $fields[$field_to_check] == $value_to_check ) {
          $satisfies_if_conditions = false;
          break;      
        }
        else 
          array_shift($row);
          // remove this if-condition from line, and continue validating line
        }

        if ( !$satisfies_if_conditions )
          continue;


        $requirement = $row[0];
        $field_name  = $row[1];

        // depending on the validation test, store the incoming strings for use later...
        // valid_date
        if ( count($row) == 6 ) {
          $field_name2   = $row[2];
          $field_name3   = $row[3];
          $date_flag     = $row[4];
          $error_message = $row[5];
        }
        // reg_exp (WITH flags like g, i, m)
        else if ( count($row) == 5 ) {
          $field_name2   = $row[2];
          $field_name3   = $row[3];
          $error_message = $row[4];
        }
        // same_as, custom_alpha, reg_exp (without flags like g, i, m)
        else if (count($row) == 4) {
          $field_name2   = $row[2];
          $error_message = $row[3];
        }
        else
          $error_message = $row[2];    // everything else!


        // if the requirement is "length=...", rename requirement to "length" for switch statement
        if (preg_match("/^length/", $requirement)) {
          $length_requirements = $requirement;
          $requirement         = "length";
        }

        // if the requirement is "range=...", rename requirement to "range" for switch statement
        if (preg_match("/^range/", $requirement)) {
          $range_requirements = $requirement;
          $requirement        = "range";
        }


        // now, validate whatever is required of the field
        switch ($requirement) {
          case "required":
            if ( !isset($fields[$field_name]) || $fields[$field_name] == "" )
            $errors[$field_name] = $error_message;
          break;

          case "digits_only":       
            if ( isset($fields[$field_name]) && preg_match("/\D/", $fields[$field_name]) )
            $errors[$field_name] = $error_message;
          break;

          case "letters_only": 
            if ( isset($fields[$field_name]) && preg_match("/[^a-zA-Z]/", $fields[$field_name]) )
            $errors[$field_name] = $error_message;
          break;

          // doesn't fail if field is empty
          case "valid_email":
            $regexp="/^[a-z0-9]+([_+\\.-][a-z0-9]+)*@([a-z0-9]+([\.-][a-z0-9]+)*)+\\.[a-z]{2,}$/i";    
            if (isset($fields[$field_name]) && !empty($fields[$field_name]) && !preg_match($regexp, $fields[$field_name]))
            $errors[$field_name] = $error_message;
          break;

          case "length":
            $comparison_rule = "";
            $rule_string     = "";

            if ( preg_match("/length=/", $length_requirements) ) {
              $comparison_rule = "equal";
              $rule_string = preg_replace("/length=/", "", $length_requirements);
            }
            else if ( preg_match("/length>=/", $length_requirements) ) {
              $comparison_rule = "greater_than_or_equal";
              $rule_string = preg_replace("/length>=/", "", $length_requirements);
            }
            else if (preg_match("/length<=/", $length_requirements) ) {
              $comparison_rule = "less_than_or_equal";
              $rule_string = preg_replace("/length<=/", "", $length_requirements);
            }
            else if ( preg_match("/length>/", $length_requirements) ) {
              $comparison_rule = "greater_than";
              $rule_string = preg_replace("/length>/", "", $length_requirements);
            }
            else if ( preg_match("/length</", $length_requirements) ) {
              $comparison_rule = "less_than";
              $rule_string = preg_replace("/length</", "", $length_requirements);
            }

            switch ( $comparison_rule ) {
              case "greater_than_or_equal":
                if ( !(strlen($fields[$field_name]) >= $rule_string) )
                $errors[$field_name] = $error_message;
              break;
              case "less_than_or_equal":
                if (!(strlen($fields[$field_name]) <= $rule_string) )
                $errors[$field_name] = $error_message;
              break;
              case "greater_than":
                if ( !(strlen($fields[$field_name]) > $rule_string) )
                $errors[$field_name] = $error_message;
              break;
              case "less_than":
                if ( !(strlen($fields[$field_name]) < $rule_string) )
                $errors[$field_name] = $error_message;
              break;
              case "equal":
              // if the user supplied two length fields, make sure the field is within that range
                if (preg_match("/-/", $rule_string)) {
                  list($start, $end) = explode("-", $rule_string);

                  if ( strlen($fields[$field_name]) < $start || strlen($fields[$field_name]) > $end )
                    $errors[$field_name] = $error_message;
                }
              // otherwise, check it's EXACTLY the size the user specified 
              else {
                if ( strlen($fields[$field_name]) != $rule_string )
                  $errors[$field_name] = $error_message;
              }     
              break;       
            }
          break;

          case "range":
            $comparison_rule = "";
            $rule_string     = "";

            if ( preg_match("/range=/", $range_requirements) ) {
              $comparison_rule = "equal";
              $rule_string = preg_replace("/range=/", "", $range_requirements);
            }
            else if ( preg_match("/range>=/", $range_requirements) ) {
              $comparison_rule = "greater_than_or_equal";
              $rule_string = preg_replace("/range>=/", "", $range_requirements);
            }
            else if ( preg_match("/range<=/", $range_requirements) ) {
              $comparison_rule = "less_than_or_equal";
              $rule_string = preg_replace("/range<=/", "", $range_requirements);
            }
            else if ( preg_match("/range>/", $range_requirements) ) {
              $comparison_rule = "greater_than";
              $rule_string = preg_replace("/range>/", "", $range_requirements);
            }
            else if ( preg_match("/range</", $range_requirements) ) {
              $comparison_rule = "less_than";
              $rule_string = preg_replace("/range</", "", $range_requirements);
            }

            switch ($comparison_rule) {
              case "greater_than":
                if ( !($fields[$field_name] > $rule_string) )
                  $errors[$field_name] = $error_message;
              break;
              case "less_than":
                if ( !($fields[$field_name] < $rule_string) )
                  $errors[$field_name] = $error_message;
              break;
              case "greater_than_or_equal":
                if ( !($fields[$field_name] >= $rule_string) )
                  $errors[$field_name] = $error_message;
              break;
              case "less_than_or_equal":
                if ( !($fields[$field_name] <= $rule_string) )
                  $errors[$field_name] = $error_message;
              break;
              case "equal":
                list($start, $end) = explode("-", $rule_string);

                if ( ($fields[$field_name] < $start) || ($fields[$field_name] > $end) )
                  $errors[$field_name] = $error_message;
              break;
            }
          break;

          case "same_as":
            if ( $fields[$field_name] != $fields[$field_name2] )
              $errors[$field_name] = $error_message;
          break;

          case "valid_date":
            // this is written for future extensibility of isValidDate function to allow 
            // checking for dates BEFORE today, AFTER today, IS today and ANY day.
            $is_later_date = false;

            if ( $date_flag == "later_date" )
              $is_later_date = true;
            else if ( $date_flag == "any_date" )
              $is_later_date = false;

            if ( !is_valid_date($fields[$field_name], $fields[$field_name2], $fields[$field_name3], $is_later_date) )
              $errors[$field_name] = $error_message;
          break;

          case "is_alpha":
            if ( preg_match('/[^A-Za-z0-9]/', $fields[$field_name]) )
              $errors[$field_name] = $error_message; 
          break;

          case "custom_alpha":
            $chars = array();
            $chars["L"] = "[A-Z]";
            $chars["V"] = "[AEIOU]";
            $chars["l"] = "[a-z]";
            $chars["v"] = "[aeiou]";
            $chars["D"] = "[a-zA-Z]";
            $chars["F"] = "[aeiouAEIOU]";
            $chars["C"] = "[BCDFGHJKLMNPQRSTVWXYZ]";
            $chars["x"] = "[0-9]";
            $chars["c"] = "[bcdfghjklmnpqrstvwxyz]";
            $chars["X"] = "[1-9]";
            $chars["E"] = "[bcdfghjklmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ]";

            $reg_exp_str = "";
            for ( $j = 0; $j < strlen($field_name2); $j++ ) {
              if ( array_key_exists($field_name2[$j], $chars) )
                $reg_exp_str .= $chars[$field_name2[$j]];
              else
                $reg_exp_str .= $field_name2[$j];
            }

            if ( !empty($fields[$field_name]) && !preg_match("/$reg_exp_str/", $fields[$field_name]) )
              $errors[$field_name] = $error_message;
          break;

          case "reg_exp":
            $reg_exp_str = $field_name2;

            // rather crumby, but...
            if ( count($row) == 5 )
              $reg_exp = $reg_exp_str . $row[3]; 
            else
              $reg_exp = $reg_exp_str; 
            
            if ( !empty($fields[$field_name]) && !preg_match($reg_exp, $fields[$field_name]) )
              $errors[$field_name] = $error_message;
          break;

          default:
            die("Unknown requirement flag in validate_fields(): $requirement");
          break;
        }
      }
    return $errors;
  }
  

/*  PRIVATE FUNCTION
 ************************************************/

  /**
   *  Checks a date is valid / is later than current date
   *
   *  @param  int $month numeric rapresentation of a month ( 1 - 12 )
   *  @param  int $day numeric rapresentation of a day in a month
   *    ( 1 - depending on month )
   *  @param  int $year a 4 digit integer value rapresenting a year
   *  @param  bool $is_later_date if true the function will check if the
   *    date being passed in is later than the current date
   *
   *  @return true if is a valid date, false otherwise
   */
  private function is_valid_date($month, $day, $year, $is_later_date) {
    // depending on the year, calculate the number of days in the month
    if ( $year % 4 == 0 )      // LEAP YEAR 
      $days_in_month = array(31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
    else
      $days_in_month = array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);


    // first, check the incoming month and year are valid. 
    if ( !$month || !$day || !$year )
      return false;
    if ( 1 > $month || $month > 12 )
      return false;
    if ($year < 0)
      return false;
    if ( 1 > $day || $day > $days_in_month[$month-1] )
      return false;


    // if required, verify the incoming date is LATER than the current date.
    if ( $is_later_date ) {    
      // get current date
      $today = date("U");
      $date = mktime(0, 0, 0, $month, $day, $year);

      if ( $date < $today )
        return false;
    }

    return true;
  }


}
?>
Return current item: Cartboard Box Manager