isEmpty('location_name', _("Location name cannot be blank."));
// $fv->checkRegex('cc_exp', '/^\d{4}$|^$/', true, _("CC exp date must be in MMYY format."));
// $fv->isInteger('client_id', _("Client id must be an integer."));
// $fv->numericRange('client_id', -32768, 32767, _("Client id must be a number between -32768 and 32767."));
// $fv->stringLength('zip', 0, 255, _("Zip must contain less than 256 characters."));
// $fv->validateEmail('invoice_email');
// $fv->validatePhone('phone1');
/**
* The FormValidator:: class provides a method for validating input from
* http requests and displaying errors.
*
* @requires This class requires App.inc.php
* @requires This class requires Utilities.inc.php
* @author Quinn Comendant
* @version 1.5
*/
require_once dirname(__FILE__) . '/App.inc.php';
require_once dirname(__FILE__) . '/Utilities.inc.php';
require_once dirname(__FILE__) . '/Prefs.inc.php';
class FormValidator
{
/**
* Array filling with errors. The key will be the name of the form where
* the data came from. The value will be a message to print to the user.
*/
var $errors = array();
/**
* Return the current list of errors.
*
* @return array an array of errors in the following arrangement:
* keys: the name of the variable with an error
* vals: the message to display for that error
*/
function getErrorList()
{
return $this->errors;
}
/**
* Add an error to the errors stack.
*
* @param string $form_name The name of the incoming form variable.
* @param string $msg The error message for that form.
* @param int $type The type of message: MSG_NOTICE,
* MSG_SUCCESS, MSG_WARNING, or MSG_ERR.
* @param string $file __FILE__.
* @param string $line __LINE__.
*/
function addError($form_name, $msg='', $type=MSG_ERR, $file=null, $line=null)
{
$this->errors[] = array(
'name' => $form_name,
'message' => $msg,
'type' => $type,
'file' => $file,
'line' => $line
);
}
/**
* Check whether any errors have been triggered.
*
* @param string $form_name the name of the incoming form variable
*
* @return bool true if any errors were found, or if found for
* a variable of $form_name, false otherwise
*/
function anyErrors($form_name=null)
{
if (isset($form_name)) {
foreach ($this->errors as $err) {
if ($err['name'] == $form_name) {
return true;
}
}
return false;
}
return (sizeof($this->errors) > 0);
}
/**
* Reset the error list.
*/
function resetErrorList()
{
$this->errors = array();
}
/**
* If this form has an error, print an error marker like "<<".
*
* @param string $form_name the name of the incoming form variable
* @param string $marker A string to print if there is an error. if
* not provided, use default.
*/
function err($form_name, $marker=null)
{
global $CFG;
if ($this->anyErrors($form_name)) {
if (isset($marker)) {
echo $marker;
} else {
echo '«';
}
}
}
/**
* Check whether input has a value. To be used when a value must be empty
* under certain circumstances.
*
* @param string $form_name the name of the incoming form variable
* @param string $msg the message to display on error
*
* @return bool true if form is not empty, false otherwise.
*/
function notEmpty($form_name, $msg='')
{
$val = getFormData($form_name);
if (is_array($val)) {
if (!empty($val)) {
$this->addError($form_name, $msg);
return true;
} else {
return false;
}
} else {
if (trim($val) != '') {
$this->addError($form_name, $msg);
return true;
} else {
return false;
}
}
}
/**
* Check whether input is blank.
*
* @param string $form_name the name of the incoming form variable
* @param string $msg the message to display on error
*
* @return bool true if form is empty, false otherwise.
*/
function isEmpty($form_name, $msg='')
{
$val = getFormData($form_name);
if (is_array($val)) {
if (empty($val)) {
$this->addError($form_name, $msg);
return true;
} else {
return false;
}
} else {
if (trim($val) == '') {
$this->addError($form_name, $msg);
return true;
} else {
return false;
}
}
}
/**
* Check whether input is a string.
*
* @param string $form_name the name of the incoming form variable
* @param string $msg the message to display on error
*
* @return bool true if form is a string, false otherwise.
*/
function isString($form_name, $msg='')
{
$val = getFormData($form_name);
if (!is_string($val) && $val != '') {
$this->addError($form_name, $msg);
return false;
} else {
return true;
}
}
/**
* Check whether input is a number. Allows negative numbers.
*
* @param string $form_name the name of the incoming form variable
* @param string $msg the message to display on error
*
* @return bool true if no errors found, false otherwise
*/
function isNumber($form_name, $msg='')
{
$val = getFormData($form_name);
if (!is_numeric($val) && $val != '') {
$this->addError($form_name, $msg);
return false;
} else {
return true;
}
}
/**
* addError if input is NOT an integer. Don't just use is_int() because the
* data coming from the user is *really* a string.
*
* @param string $form_name the name of the incoming form variable
* @param string $msg the message to display on error
*
* @return bool true if value is an integer
*/
function isInteger($form_name, $msg='', $negative_ok=false)
{
$val = getFormData($form_name);
$pattern = $negative_ok ? '/^-?[[:digit:]]+$/' : '/^[[:digit:]]+$/';
if ((!is_numeric($val) || !preg_match($pattern, $val)) && $val != '') {
$this->addError($form_name, $msg);
return false;
} else {
return true;
}
}
/**
* Check whether input is a float. Don't just use is_float() because the
* data coming from the user is *really* a string. Integers will also
* pass this test.
*
* @param string $form_name the name of the incoming form variable
* @param string $msg the message to display on error
*
* @return bool true if value is a float
*/
function isFloat($form_name, $msg='', $negative_ok=false)
{
$val = getFormData($form_name);
$pattern = $negative_ok ? '/^-?[[:digit:]]*(?:\.?[[:digit:]]+)$/' : '/^[[:digit:]]*(?:\.?[[:digit:]]+)$/';
if ((!is_numeric($val) || !preg_match($pattern, $val)) && $val != '') {
$this->addError($form_name, $msg);
return false;
} else {
return true;
}
}
/**
* Check whether input is an array.
*
* @param string $form_name the name of the incoming form variable
* @param string $msg the message to display on error
*
* @return bool true if value is a float
*/
function isArray($form_name, $msg='')
{
$val = getFormData($form_name);
if (!is_array($val) && !empty($val)) {
$this->addError($form_name, $msg);
return false;
} else {
return true;
}
}
/**
* Check whether input matches the specified perl regular expression
* pattern.
*
* @param string $form_name the name of the incoming form variable
* @param int $regex perl regex that the string must match
* @param bool $not set to false to be valid if match, or true
* to be valid on no match
* @param string $msg the message to display on error
*
* @return bool true if value passes regex test
*/
function checkRegex($form_name, $regex, $not, $msg='')
{
$val = getFormData($form_name);
if ($not) {
if (!preg_match($regex, $val)) {
$this->addError($form_name, $msg);
return false;
} else {
return true;
}
} else {
if (preg_match($regex, $val)) {
$this->addError($form_name, $msg);
return false;
} else {
return true;
}
}
}
/**
* Tests if the string length is between specified values. Whitespace excluded for min.
*
* @param string $form_name the name of the incoming form variable
* @param int $min minimum length of string, inclusive
* @param int $max maximum length of string, inclusive
* @param string $msg the message to display on error
*
* @return bool true if string length is within given boundaries
*/
function stringLength($form_name, $min, $max, $msg='')
{
$val = getFormData($form_name);
if (strlen(trim($val)) < $min || strlen($val) > $max) {
$this->addError($form_name, $msg);
return false;
} else {
return true;
}
}
/**
* Check whether input is within a valid numeric range.
*
* @param string $form_name the name of the incoming form variable
* @param int $min minimum value of number, inclusive
* @param int $max maximum value of number, inclusive
* @param string $msg the message to display on error
*
* @return bool true if no errors found, false otherwise
*/
function numericRange($form_name, $min, $max, $msg='')
{
$val = getFormData($form_name);
if ($val != '' && is_numeric($val)) {
if ($val < $min || $val > $max) {
$this->addError($form_name, $msg);
return false;
}
return true;
} else {
// Not a number!
return false;
}
}
/**
* Validates email address length, domain name existence, format.
*
* @param string $form_name The name of the incoming form variable
* @param bool $strict Run strict tests (check if the domain exists and has an MX record assigned)
* @return bool true if no errors found, false otherwise
*/
function validateEmail($form_name, $strict=false)
{
$email = getFormData($form_name);
if ('' == trim($email)) {
return false;
}
$regex = '/^(?:[^,@]*\s+|[^,@]*(<)|)' // Display name
. '((?:[^.<>\s@\",\[\]]+[^<>\s@\",\[\]])*[^.<>\s@\",\[\]]+)' // Local-part
. '@' // @
. '((?:(\[)|[A-Z0-9]?)' // Domain, first char
. '(?(4)' // Domain conditional for if first domain char is [
. '(?:[0-9]{1,3}\.){3}[0-9]{1,3}\]' // TRUE, matches IP address
. '|'
. '[.-]?(?:[A-Z0-9]+[-.])*(?:[A-Z0-9]+\.)+[A-Z]{2,6}))' // FALSE, matches domain name
. '(?(1)' // Comment conditional for if initial < exists
. '(?:>\s*|>\s+\([^,@]+\)\s*)' // TRUE, ensure ending >
. '|'
. '(?:|\s*|\s+\([^,@]+\)\s*))$/i';
// Test email address format.
if (!preg_match($regex, getFormData($form_name), $e_parts)) {
$this->addError($form_name, sprintf(_("The email address %s is formatted incorrectly."), oTxt(getFormData($form_name))), MSG_ERR, __FILE__, __LINE__);
logMsg(sprintf('The email address %s is not valid.', getFormData($form_name)), LOG_DEBUG, __FILE__, __LINE__);
return false;
}
// We have a match! Here are the captured subpatterns, on which further tests are run.
// The part before the @.
$local = $e_parts[2];
// The part after the @.
// If domain is an IP [XXX.XXX.XXX.XXX] strip off the brackets.
$domain = $e_parts[3]{0} == '[' ? mb_substr($e_parts[3], 1, -1) : $e_parts[3];
// Test length.
if (mb_strlen($local) > 64 || mb_strlen($domain) > 191) {
$this->addError($form_name, sprintf(_("The email address %s is too long."), oTxt(getFormData($form_name))), MSG_ERR, __FILE__, __LINE__);
logMsg(sprintf('The email address %s is too long.', getFormData($form_name)), LOG_DEBUG, __FILE__, __LINE__);
return false;
}
if ($strict) {
// Strict tests.
if (ip2long($domain) === false && function_exists('checkdnsrr') && !checkdnsrr($domain . '.', 'MX') && gethostbyname($domain) == $domain) {
// Check domain exists: It's a domain if ip2long fails; checkdnsrr ensures a MX record exists; gethostbyname() ensures the domain exists.
$this->addError($form_name, sprintf(_("The email address %s does not have a valid domain name."), oTxt(getFormData($form_name))), MSG_ERR, __FILE__, __LINE__);
logMsg(sprintf('%s (line %s) failed: %s', __METHOD__, __LINE__, getDump($email)));
return false;
}
}
return true;
}
/**
* Check whether input is a valid phone number. Notice: it is now set
* to allow characters like - or () or + so people can type in a phone
* number that looks like: +1 (530) 624-4410
*
* @param string $form_name the name of the incoming form variable
*
* @return bool true if no errors found, false otherwise
*/
function validatePhone($form_name)
{
$phone = getFormData($form_name);
if ($this->checkRegex($form_name, '/^[0-9 +().-]*$/', true, sprintf(_("The phone number %s is not valid."), $phone))
&& $this->stringLength($form_name, 0, 25, sprintf(_("The phone number %s is too long"), $phone))) {
return true;
}
return false;
}
/**
* Verifies that date can be processed by the strtotime function.
*
* @param string $form_name the name of the incoming form variable
* @param string $msg the message to display on error
*
* @return bool true if no errors found, false otherwise
*/
function validateStrDate($form_name, $msg='')
{
if (false === strtotime($val)) {
$this->addError($form_name, $msg);
logMsg(sprintf('The string date %s is not valid.', getFormData($form_name)), LOG_DEBUG, __FILE__, __LINE__);
return false;
} else {
return true;
}
}
/**
* Verifies credit card number.
*
* @param string $form_name The name of the incoming form variable.
* @param string $cc_num Card number to verify.
* @param string $cc_type Optional, card type to do specific checks.
*
* @return bool true if no errors found, false otherwise
*/
function validateCCNumber($form_name, $cc_num=null, $cc_type=null)
{
if (!isset($cc_num)) {
$cc_num = getFormData($form_name);
}
if ('' == $cc_num) {
return false;
}
// Innocent until proven guilty
$card_is_valid = true;
// Get rid of any non-digits
$cc_num = preg_replace('/[^\d]/', '', $cc_num);
// Perform card-specific checks, if applicable
switch (strtolower($cc_type)) {
case 'visa' :
$card_is_valid = preg_match('/^4\d{15}$|^4\d{12}$/', $cc_num);
break;
case 'mastercard' :
case 'mc' :
$card_is_valid = preg_match('/^5[1-5]\d{14}$/', $cc_num);
break;
case 'american_express' :
case 'american_ex' :
case 'americanexpress' :
case 'americanex' :
case 'am_ex' :
case 'amex' :
case 'ae' :
$card_is_valid = preg_match('/^3[47]\d{13}$/', $cc_num);
break;
case 'discover' :
$card_is_valid = preg_match('/^6011\d{12}$/', $cc_num);
break;
case 'diners_club' :
case 'dinersclub' :
case 'diners' :
case 'diner' :
case 'dc' :
$card_is_valid = preg_match('/^30[0-5]\d{11}$|^3[68]\d{12}$/', $cc_num);
break;
case 'jcb' :
$card_is_valid = preg_match('/^3\d{15}$|^2131|1800\d{11}$/', $cc_num);
break;
}
// The Luhn formula works right to left, so reverse the number.
$cc_num = strrev($cc_num);
$luhn_total = 0;
$num = strlen($cc_num);
for ($i=0; $i<$num; $i++) {
// Get each digit.
$digit = substr($cc_num,$i,1);
// If it's an odd digit, double it.
if ($i / 2 != floor($i / 2)) {
$digit *= 2;
}
// If the result is two digits, add them.
if (strlen($digit) == 2) {
$digit = substr($digit,0,1) + substr($digit,1,1);
}
// Add the current digit to the $luhn_total.
$luhn_total += $digit;
}
// If it passed (or bypassed) the card-specific check and the Total is evenly divisible by 10, it's cool!
if ($card_is_valid && $luhn_total % 10 == 0) {
return true;
} else {
$this->addError($form_name, _("The credit card number you entered is not valid."));
return false;
}
}
/**
* Check whether uploaded file is valid.
*
* @param string $form_name the name of the incoming form variable
* @param string $msg the message to display on error
*
* @return bool true if no errors found, false otherwise
*/
function validateFile($form_name, $msg='')
{
if (!isset($_FILES[$form_name]['tmp_name']) || '' == trim($_FILES[$form_name]['tmp_name'])) {
$this->addError($form_name, $msg);
return false;
} else {
return true;
}
}
} // THE END
?>