<?php
/**
* A validation agent.
*
* This agent is able to perform a comprehensive set of standard basic validations, returning
* localised messages, should this be the case.
* @package Piragibe
* @author Francisco Piragibe
* @version 1.00
* @copyright Copyright © 2006, Francisco Piragibe
* This file is part of The PIRAGIBE Framework.
*
* The PIRAGIBE Framework is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* The PIRAGIBE Framework is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with The PIRAGIBE Framework; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
class PGBValidator {
/**
* Extracts the numerical characters (digits, comma, point and the minus sign) from
* a string.
*
* 123a.5g7 would become 123.57, for instance.
* @return string the numerical characters in the base string
* @param string $pBase the base string
*/
function toDigits( $pBase ) {
// extrai os digitos de um string qualquer
$resp = '';
for( $i=0; $i < strlen($pBase); $i++ ) {
$c = substr( $pBase, $i, 1 );
if ( ( $c >= '0' and $c <= '9' ) or ( $c == '-' and $i == 0 ) or ( $c == ',' ) or ( $c == '.' ) ) {
$resp .= $c;
}
}
return $resp;
}
/**
* Checks if the base string contains only numerical characters.
*
* This is done by comparing the base to the toDigits() version of it.
* @return boolean true or false, depending on the result
* @param string $pBase the base string
*/
function isNumber( $pBase ) {
// verifica se o string base e puramente numerico
return ( $this->toDigits($pBase) == $pBase );
}
/**
* Checks to see if the base string is a valid brazilian CPF (taxpayer ID).
* @return boolean true or false, depending on the result
* @param string $pBase the base string to verify
*/
function isCPF( $pBase ) {
// verifica se o string base e um CPF valido
$base = sprintf ("%011s",$this->toDigits($pBase));
if ( $base == '00000000000' ) {
return false;
}
$soma = 0;
for ($i=0, $p=10; $i<9; $i++, $p--) {
$soma += (substr($base,$i,1)*$p);
}
$dv1 = (($soma*10) % 11) % 10;
if ( $dv1 != substr($base,9,1) ) {
return (false);
}
$soma = 0;
for ($i=0, $p=11; $i<10; $i++, $p--) {
$soma += (substr($base,$i,1)*$p);
}
$dv2 = (($soma*10) % 11) % 10;
if ( $dv2 != substr($base,10,1) ) {
return (false);
}
return (true);
}
/**
* Checks to see if the base string is a valid CNPJ (brazilian company taxpayer ID).
* @return boolean true or false, depending on the result
* @param string $pBase the base string to verify
*/
function isCNPJ( $pBase ) {
// verifica se o string base e um CNPJ valido
$base = sprintf ("%014s",$this->toDigits($pBase));
if ( $base == '00000000000000' ) {
return false;
}
$soma = 0;
for ($i=0, $p=5; $i<12; $i++, $p--) {
if ( $p < 2 ) {
$p = 9;
}
$soma += (substr($base,$i,1)*$p);
}
$dv1 = (($soma*10) % 11) % 10;
if ( $dv1 != substr($base,12,1) ) {
return (false);
}
$soma = 0;
for ($i=0, $p=6; $i<13; $i++, $p--) {
if ( $p < 2 ) {
$p = 9;
}
$soma += (substr($base,$i,1)*$p);
}
$dv2 = (($soma*10) % 11) % 10;
if ( $dv2 != substr($base,13,1) ) {
return (false);
}
return (true);
}
/**
* Breaks a date string into an array having the year, the month and the day as
* elements.
*
* The resulting array has always three elements: 'Y' => the year, 'M' => the month
* and 'D' => the day. The format should have marks for the day, month and year positions.
* DD would mark the day, MM the month and YY or YYYY the year. A format such as
* 'DD-MM====YYYY' would break a date formatted as 23-02....2006 into an array
* correctly.
* @return array the broken date
* @param string $pData the date string
* @param string $pFmt the date format do use when separating date pieces
*/
function dateToArray( $pData, $pFmt ) {
$r = array();
$wpd = strpos( $pFmt, 'DD' );
$wpm = strpos( $pFmt, 'MM' );
$wpa = strpos( $pFmt, 'YY' );
$wpal = strpos( $pFmt, 'YYYY' );
if ( $wpd === false or $wpm === false or $wpa === false ) {
return $r;
}
$wd = substr( $pData, $wpd, 2 );
$wm = substr( $pData, $wpm, 2 );
$wa = substr( $pData, $wpa, $wpal ? 4 : 2 );
$r['Y'] = $wa;
$r['M'] = $wm;
$r['D'] = $wd;
return $r;
}
/**
* Compares two date strings, returning their relative position in time.
*
* The dates are supposed to adhere to the user's language default date format.
* @return integer 1 (date#1 > date#2), 0 (dates are the same) or 2 (date#2 > date#1)
* @param string $d1 the first date
* @param string $d2 the second date
*/
function dateCompare( $d1, $d2 ) {
$o_nls = new PGBNlsAgent( 'pt' );
$w_fmt = $o_nls->getDateFormat();
if ( !$this->isDate( $d1, $w_fmt ) or !$this->isDate( $d2, $w_fmt ) ) {
return NULL;
}
$a_d1 = $this->dateToArray( $d1, $w_fmt );
$a_d2 = $this->dateToArray( $d2, $w_fmt );
$w_diff = ( ($a_d1['Y'] * 10000) + ($a_d1['M'] * 100) + $a_d1['D'] ) -
( ($a_d2['Y'] * 10000) + ($a_d2['M'] * 100) + $a_d2['D'] );
return ( $w_diff>0 ? 1 : ( $w_diff==0 ? 0 : 2 ) );
}
/**
* Checks whether the base string is a date valid and complyant to the given format.
* @return boolean true or false, depending on the result
* @param string $pBase the base string
* @param string $pFmt the date format
*/
function isDate( $pBase, $pFmt ) {
$a_dt = $this->dateToArray( $pBase, $pFmt );
$wd = $a_dt['D'];
$wm = $a_dt['M'];
$wa = $a_dt['Y'];
if ( !$this->isNumber( $wd ) or !$this->isNumber( $wm ) or !$this->isNumber( $wa ) ) {
return false;
}
else {
//print '<pre>' . checkdate( $wm+0, $wd+0, $wa+0 )?'true':'false' . '</pre>';
return checkdate( $wm+0, $wd+0, $wa+0 );
}
}
/**
* Validate a PGBField against a PGBValidationDefs
*
* @return String error message or NULL, if everything is fine
* @param mixed $pBase the value to validate
* @param PGBValidationDefs $pValDef the validation definitions to check against
*/
function isValid( $pBase, $pValDef ) {
// our messages
$ma = array(
'required' => array(
'pt' => 'campo obrigatório não preenchido',
'en' => 'required field missing'
),
'invnum' => array(
'pt' => 'número inválido',
'en' => 'invalid number'
),
'invdate' => array(
'pt' => 'data inválida',
'en' => 'invalid date'
),
'toohigh' => array(
'pt' => 'deve ser igual ou inferior a ',
'en' => 'this must be less than or equal to '
),
'toolow' => array(
'pt' => 'deve ser igual ou superior a ',
'en' => 'this must be greater than or equal to '
),
'cpf' => array(
'pt' => 'CPF inválido',
'en' => 'invalid CPF number'
),
'cnpj' => array(
'pt' => 'CNPJ inválido',
'en' => 'invalid CNPJ number'
),
'notinset' => array(
'pt' => 'não está no conjunto de valores possíveis',
'en' => 'is not in the set of allowable values'
),
'notinquery' => array(
'pt' => 'não está na base de dados',
'en' => 'is not in the database'
)
);
$o_nls = new PGBNlsAgent( 'pt', $ma );
// required and missing?
//print '<pre>' . $pValDef->isRequired()?'true':'false' . '</pre>';
if ( $pValDef->isRequired() and (is_null( $pBase ) or $pBase == '') ) {
//print '<pre>req</pre>';
return $o_nls->getMessage( 'required' );
}
if ( is_null( $pBase ) or $pBase == '' ) {
return NULL;
}
// has the correct type?
$w_typ = $pValDef->getType();
//print '<pre>' . $w_typ . '</pre>';
if ( $w_typ == 'number' and !$this->isNumber( $pBase ) ) {
return $o_nls->getMessage( 'invnum' );
}
elseif ( $w_typ == 'date' and !$this->isDate( $pBase, $o_nls->getDateFormat() ) ) {
return $o_nls->getMessage( 'invdate' );
}
elseif ( $w_typ == 'cpf' and !$this->isCPF( $pBase ) ) {
return $o_nls->getMessage( 'cpf' );
}
elseif ( $w_typ == 'cnpj' and !$this->isCPF( $pBase ) ) {
return $o_nls->getMessage( 'cnpj' );
}
// is between given boundaries?
$wlb = $pValDef->getLowerBound();
$wub = $pValDef->getUpperBound();
if ( !is_null($wlb) ) {
if ( $pBase < $wlb ) {
return $o_nls->getMessage( 'toolow' ) . $wlb;
}
}
if ( !is_null($wub) ) {
if ( $pBase > $wub ) {
return $o_nls->getMessage( 'toohigh' ) . $wub;
}
}
// is in the given discrete set?
$w_set = $pValDef->getBaseSet();
if ( $w_set ) {
if ( !isset( $w_set[ $pBase ] ) ) {
return $o_nls->getMessage( 'notinset' );
}
}
// is in the given SQL query?
$w_bq = $pValDef->getBaseQuery();
if ( is_array( $w_bq ) ) {
$w_sql = $w_bq[ 'sql' ];
$o_con = $w_bq[ 'conn' ];
// substitui ? pelo valor do campo corrente
$w_sqlr= str_replace( '?', $pBase, $w_sql );
$o_rs = $o_con->query( $w_sqlr );
//print $w_sqlr . ' - ' . $o_rs->rowCount() . "\n";
if ( $o_rs->rowCount() == 0 ) {
return $o_nls->getMessage( 'notinquery' );
}
}
// return OK
return NULL;
}
}
?>