PageRenderTime 208ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/Server/SWXPHP/2.00/php/lib/Validate.php

http://swx-format.googlecode.com/
PHP | 809 lines | 667 code | 23 blank | 119 comment | 92 complexity | a6fe3aba0b3728ae2c80a68328538283 MD5 | raw file
Possible License(s): LGPL-2.1, GPL-2.0
  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4: */
  3. // +----------------------------------------------------------------------+
  4. // | Copyright (c) 1997-2006 Pierre-Alain Joye,Tomas V.V.Cox, Amir Saied |
  5. // +----------------------------------------------------------------------+
  6. // | This source file is subject to the New BSD license, That is bundled |
  7. // | with this package in the file LICENSE, and is available through |
  8. // | the world-wide-web at |
  9. // | http://www.opensource.org/licenses/bsd-license.php |
  10. // | If you did not receive a copy of the new BSDlicense and are unable |
  11. // | to obtain it through the world-wide-web, please send a note to |
  12. // | pajoye@php.net so we can mail you a copy immediately. |
  13. // +----------------------------------------------------------------------+
  14. // | Author: Tomas V.V.Cox <cox@idecnet.com> |
  15. // | Pierre-Alain Joye <pajoye@php.net> |
  16. // | Amir Mohammad Saied <amir@php.net> |
  17. // +----------------------------------------------------------------------+
  18. //
  19. /**
  20. * Validation class
  21. *
  22. * Package to validate various datas. It includes :
  23. * - numbers (min/max, decimal or not)
  24. * - email (syntax, domain check)
  25. * - string (predifined type alpha upper and/or lowercase, numeric,...)
  26. * - date (min, max, rfc822 compliant)
  27. * - uri (RFC2396)
  28. * - possibility valid multiple data with a single method call (::multiple)
  29. *
  30. * @category Validate
  31. * @package Validate
  32. * @author Tomas V.V.Cox <cox@idecnet.com>
  33. * @author Pierre-Alain Joye <pajoye@php.net>
  34. * @author Amir Mohammad Saied <amir@php.net>
  35. * @copyright 1997-2006 Pierre-Alain Joye,Tomas V.V.Cox,Amir Mohammad Saied
  36. * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
  37. * @version CVS: $Id: Validate.php,v 1.104 2006/11/17 16:32:06 amir Exp $
  38. * @link http://pear.php.net/package/Validate
  39. */
  40. /**
  41. * Methods for common data validations
  42. */
  43. define('VALIDATE_NUM', '0-9');
  44. define('VALIDATE_SPACE', '\s');
  45. define('VALIDATE_ALPHA_LOWER', 'a-z');
  46. define('VALIDATE_ALPHA_UPPER', 'A-Z');
  47. define('VALIDATE_ALPHA', VALIDATE_ALPHA_LOWER . VALIDATE_ALPHA_UPPER);
  48. define('VALIDATE_EALPHA_LOWER', VALIDATE_ALPHA_LOWER . 'áéíóú?????äë?öüâ?îô??ç????ý');
  49. define('VALIDATE_EALPHA_UPPER', VALIDATE_ALPHA_UPPER . 'ÁÉÍÓÚ?????ÄË?ÖÜÂ?ÎÔ??Ç????Ý');
  50. define('VALIDATE_EALPHA', VALIDATE_EALPHA_LOWER . VALIDATE_EALPHA_UPPER);
  51. define('VALIDATE_PUNCTUATION', VALIDATE_SPACE . '\.,;\:&"\'\?\!\(\)');
  52. define('VALIDATE_NAME', VALIDATE_EALPHA . VALIDATE_SPACE . "'");
  53. define('VALIDATE_STREET', VALIDATE_NAME . "/\\??\.");
  54. /**
  55. * Validation class
  56. *
  57. * Package to validate various datas. It includes :
  58. * - numbers (min/max, decimal or not)
  59. * - email (syntax, domain check)
  60. * - string (predifined type alpha upper and/or lowercase, numeric,...)
  61. * - date (min, max)
  62. * - uri (RFC2396)
  63. * - possibility valid multiple data with a single method call (::multiple)
  64. *
  65. * @category Validate
  66. * @package Validate
  67. * @author Tomas V.V.Cox <cox@idecnet.com>
  68. * @author Pierre-Alain Joye <pajoye@php.net>
  69. * @author Amir Mohammad Saied <amir@php.net>
  70. * @copyright 1997-2006 Pierre-Alain Joye,Tomas V.V.Cox,Amir Mohammad Saied
  71. * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
  72. * @version Release: @package_version@
  73. * @link http://pear.php.net/package/Validate
  74. */
  75. class Validate
  76. {
  77. /**
  78. * Validate a number
  79. *
  80. * @param string $number Number to validate
  81. * @param array $options array where:
  82. * 'decimal' is the decimal char or false when decimal not allowed
  83. * i.e. ',.' to allow both ',' and '.'
  84. * 'dec_prec' Number of allowed decimals
  85. * 'min' minimum value
  86. * 'max' maximum value
  87. *
  88. * @return boolean true if valid number, false if not
  89. *
  90. * @access public
  91. */
  92. function number($number, $options = array())
  93. {
  94. $decimal = $dec_prec = $min = $max = null;
  95. if (is_array($options)) {
  96. extract($options);
  97. }
  98. $dec_prec = $dec_prec ? "{1,$dec_prec}" : '+';
  99. $dec_regex = $decimal ? "[$decimal][0-9]$dec_prec" : '';
  100. if (!preg_match("|^[-+]?\s*[0-9]+($dec_regex)?\$|", $number)) {
  101. return false;
  102. }
  103. if ($decimal != '.') {
  104. $number = strtr($number, $decimal, '.');
  105. }
  106. $number = (float)str_replace(' ', '', $number);
  107. if ($min !== null && $min > $number) {
  108. return false;
  109. }
  110. if ($max !== null && $max < $number) {
  111. return false;
  112. }
  113. return true;
  114. }
  115. /**
  116. * Converting a string to UTF-7 (RFC 2152)
  117. *
  118. * @param $string string to be converted
  119. *
  120. * @return string converted string
  121. *
  122. * @access private
  123. */
  124. function __stringToUtf7($string) {
  125. $return = '';
  126. $utf7 = array(
  127. 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
  128. 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
  129. 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
  130. 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
  131. 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2',
  132. '3', '4', '5', '6', '7', '8', '9', '+', ','
  133. );
  134. $state = 0;
  135. if (!empty($string)) {
  136. $i = 0;
  137. while ($i <= strlen($string)) {
  138. $char = substr($string, $i, 1);
  139. if ($state == 0) {
  140. if ((ord($char) >= 0x7F) || (ord($char) <= 0x1F)) {
  141. if ($char) {
  142. $return .= '&';
  143. }
  144. $state = 1;
  145. } elseif ($char == '&') {
  146. $return .= '&-';
  147. } else {
  148. $return .= $char;
  149. }
  150. } elseif (($i == strlen($string) ||
  151. !((ord($char) >= 0x7F)) || (ord($char) <= 0x1F))) {
  152. if ($state != 1) {
  153. if (ord($char) > 64) {
  154. $return .= '';
  155. } else {
  156. $return .= $utf7[ord($char)];
  157. }
  158. }
  159. $return .= '-';
  160. $state = 0;
  161. } else {
  162. switch($state) {
  163. case 1:
  164. $return .= $utf7[ord($char) >> 2];
  165. $residue = (ord($char) & 0x03) << 4;
  166. $state = 2;
  167. break;
  168. case 2:
  169. $return .= $utf7[$residue | (ord($char) >> 4)];
  170. $residue = (ord($char) & 0x0F) << 2;
  171. $state = 3;
  172. break;
  173. case 3:
  174. $return .= $utf7[$residue | (ord($char) >> 6)];
  175. $return .= $utf7[ord($char) & 0x3F];
  176. $state = 1;
  177. break;
  178. }
  179. }
  180. $i++;
  181. }
  182. return $return;
  183. }
  184. return '';
  185. }
  186. /**
  187. * Validate an email according to full RFC822 (inclusive human readable part)
  188. *
  189. * @param string $email email to validate,
  190. * will return the address for optional dns validation
  191. * @param array $options email() options
  192. *
  193. * @return boolean true if valid email, false if not
  194. *
  195. * @access private
  196. */
  197. function __emailRFC822(&$email, &$options)
  198. {
  199. if (Validate::__stringToUtf7($email) != $email) {
  200. return false;
  201. }
  202. static $address = null;
  203. static $uncomment = null;
  204. if (!$address) {
  205. // atom = 1*<any CHAR except specials, SPACE and CTLs>
  206. $atom = '[^][()<>@,;:\\".\s\000-\037\177-\377]+\s*';
  207. // qtext = <any CHAR excepting <">, ; => may be folded
  208. // "\" & CR, and including linear-white-space>
  209. $qtext = '[^"\\\\\r]';
  210. // quoted-pair = "\" CHAR ; may quote any char
  211. $quoted_pair = '\\\\.';
  212. // quoted-string = <"> *(qtext/quoted-pair) <">; Regular qtext or
  213. // ; quoted chars.
  214. $quoted_string = '"(?:' . $qtext . '|' . $quoted_pair . ')*"\s*';
  215. // word = atom / quoted-string
  216. $word = '(?:' . $atom . '|' . $quoted_string . ')';
  217. // local-part = word *("." word) ; uninterpreted
  218. // ; case-preserved
  219. $local_part = $word . '(?:\.\s*' . $word . ')*';
  220. // dtext = <any CHAR excluding "[", ; => may be folded
  221. // "]", "\" & CR, & including linear-white-space>
  222. $dtext = '[^][\\\\\r]';
  223. // domain-literal = "[" *(dtext / quoted-pair) "]"
  224. $domain_literal = '\[(?:' . $dtext . '|' . $quoted_pair . ')*\]\s*';
  225. // sub-domain = domain-ref / domain-literal
  226. // domain-ref = atom ; symbolic reference
  227. $sub_domain = '(?:' . $atom . '|' . $domain_literal . ')';
  228. // domain = sub-domain *("." sub-domain)
  229. $domain = $sub_domain . '(?:\.\s*' . $sub_domain . ')*';
  230. // addr-spec = local-part "@" domain ; global address
  231. $addr_spec = $local_part . '@\s*' . $domain;
  232. // route = 1#("@" domain) ":" ; path-relative
  233. $route = '@' . $domain . '(?:,@\s*' . $domain . ')*:\s*';
  234. // route-addr = "<" [route] addr-spec ">"
  235. $route_addr = '<\s*(?:' . $route . ')?' . $addr_spec . '>\s*';
  236. // phrase = 1*word ; Sequence of words
  237. $phrase = $word . '+';
  238. // mailbox = addr-spec ; simple address
  239. // / phrase route-addr ; name & addr-spec
  240. $mailbox = '(?:' . $addr_spec . '|' . $phrase . $route_addr . ')';
  241. // group = phrase ":" [#mailbox] ";"
  242. $group = $phrase . ':\s*(?:' . $mailbox . '(?:,\s*' . $mailbox . ')*)?;\s*';
  243. // address = mailbox ; one addressee
  244. // / group ; named list
  245. $address = '/^\s*(?:' . $mailbox . '|' . $group . ')$/';
  246. $uncomment =
  247. '/((?:(?:\\\\"|[^("])*(?:' . $quoted_string .
  248. ')?)*)((?<!\\\\)\((?:(?2)|.)*?(?<!\\\\)\))/';
  249. }
  250. // strip comments
  251. $email = preg_replace($uncomment, '$1 ', $email);
  252. return preg_match($address, $email);
  253. }
  254. /**
  255. * Validate an email
  256. *
  257. * @param string $email email to validate
  258. * @param mixed boolean (BC) $check_domain Check or not if the domain exists
  259. * array $options associative array of options
  260. * 'check_domain' boolean Check or not if the domain exists
  261. * 'use_rfc822' boolean Apply the full RFC822 grammar
  262. *
  263. * @return boolean true if valid email, false if not
  264. *
  265. * @access public
  266. */
  267. function email($email, $options = null)
  268. {
  269. $check_domain = false;
  270. $use_rfc822 = false;
  271. if (is_bool($options)) {
  272. $check_domain = $options;
  273. } elseif (is_array($options)) {
  274. extract($options);
  275. }
  276. // the base regexp for address
  277. $regex = '&^(?: # recipient:
  278. ("\s*(?:[^"\f\n\r\t\v\b\s]+\s*)+")| #1 quoted name
  279. ([-\w!\#\$%\&\'*+~/^`|{}]+(?:\.[-\w!\#\$%\&\'*+~/^`|{}]+)*)) #2 OR dot-atom
  280. @(((\[)? #3 domain, 4 as IPv4, 5 optionally bracketed
  281. (?:(?:(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:[0-1]?[0-9]?[0-9]))\.){3}
  282. (?:(?:25[0-5])|(?:2[0-4][0-9])|(?:[0-1]?[0-9]?[0-9]))))(?(5)\])|
  283. ((?:[a-z0-9](?:[-a-z0-9]*[a-z0-9])?\.)*[a-z0-9](?:[-a-z0-9]*[a-z0-9])?) #6 domain as hostname
  284. \.((?:([^- ])[-a-z]*[-a-z])?)) #7 TLD
  285. $&xi';
  286. if ($use_rfc822? Validate::__emailRFC822($email, $options) :
  287. preg_match($regex, $email)) {
  288. if ($check_domain && function_exists('checkdnsrr')) {
  289. list (, $domain) = explode('@', $email);
  290. if (checkdnsrr($domain, 'MX') || checkdnsrr($domain, 'A')) {
  291. return true;
  292. }
  293. return false;
  294. }
  295. return true;
  296. }
  297. return false;
  298. }
  299. /**
  300. * Validate a string using the given format 'format'
  301. *
  302. * @param string $string String to validate
  303. * @param array $options Options array where:
  304. * 'format' is the format of the string
  305. * Ex: VALIDATE_NUM . VALIDATE_ALPHA (see constants)
  306. * 'min_length' minimum length
  307. * 'max_length' maximum length
  308. *
  309. * @return boolean true if valid string, false if not
  310. *
  311. * @access public
  312. */
  313. function string($string, $options)
  314. {
  315. $format = null;
  316. $min_length = $max_length = 0;
  317. if (is_array($options)) {
  318. extract($options);
  319. }
  320. if ($format && !preg_match("|^[$format]*\$|s", $string)) {
  321. return false;
  322. }
  323. if ($min_length && strlen($string) < $min_length) {
  324. return false;
  325. }
  326. if ($max_length && strlen($string) > $max_length) {
  327. return false;
  328. }
  329. return true;
  330. }
  331. /**
  332. * Validate an URI (RFC2396)
  333. * This function will validate 'foobarstring' by default, to get it to validate
  334. * only http, https, ftp and such you have to pass it in the allowed_schemes
  335. * option, like this:
  336. * <code>
  337. * $options = array('allowed_schemes' => array('http', 'https', 'ftp'))
  338. * var_dump(Validate::uri('http://www.example.org'), $options);
  339. * </code>
  340. *
  341. * NOTE 1: The rfc2396 normally allows middle '-' in the top domain
  342. * e.g. http://example.co-m should be valid
  343. * However, as '-' is not used in any known TLD, it is invalid
  344. * NOTE 2: As double shlashes // are allowed in the path part, only full URIs
  345. * including an authority can be valid, no relative URIs
  346. * the // are mandatory (optionally preceeded by the 'sheme:' )
  347. * NOTE 3: the full complience to rfc2396 is not achieved by default
  348. * the characters ';/?:@$,' will not be accepted in the query part
  349. * if not urlencoded, refer to the option "strict'"
  350. *
  351. * @param string $url URI to validate
  352. * @param array $options Options used by the validation method.
  353. * key => type
  354. * 'domain_check' => boolean
  355. * Whether to check the DNS entry or not
  356. * 'allowed_schemes' => array, list of protocols
  357. * List of allowed schemes ('http',
  358. * 'ssh+svn', 'mms')
  359. * 'strict' => string the refused chars
  360. * in query and fragment parts
  361. * default: ';/?:@$,'
  362. * empty: accept all rfc2396 foreseen chars
  363. *
  364. * @return boolean true if valid uri, false if not
  365. *
  366. * @access public
  367. */
  368. function uri($url, $options = null)
  369. {
  370. $strict = ';/?:@$,';
  371. $domain_check = false;
  372. $allowed_schemes = null;
  373. if (is_array($options)) {
  374. extract($options);
  375. }
  376. if (preg_match(
  377. '&^(?:([a-z][-+.a-z0-9]*):)? # 1. scheme
  378. (?:// # authority start
  379. (?:((?:%[0-9a-f]{2}|[-a-z0-9_.!~*\'();:\&=+$,])*)@)? # 2. authority-userinfo
  380. (?:((?:[a-z0-9](?:[-a-z0-9]*[a-z0-9])?\.)*[a-z](?:[a-z0-9]+)?\.?) # 3. authority-hostname OR
  381. |([0-9]{1,3}(?:\.[0-9]{1,3}){3})) # 4. authority-ipv4
  382. (?::([0-9]*))?) # 5. authority-port
  383. ((?:/(?:%[0-9a-f]{2}|[-a-z0-9_.!~*\'():@\&=+$,;])*)*/?)? # 6. path
  384. (?:\?([^#]*))? # 7. query
  385. (?:\#((?:%[0-9a-f]{2}|[-a-z0-9_.!~*\'();/?:@\&=+$,])*))? # 8. fragment
  386. $&xi', $url, $matches)) {
  387. $scheme = isset($matches[1]) ? $matches[1] : '';
  388. $authority = isset($matches[3]) ? $matches[3] : '' ;
  389. if (is_array($allowed_schemes) &&
  390. !in_array($scheme,$allowed_schemes)
  391. ) {
  392. return false;
  393. }
  394. if (!empty($matches[4])) {
  395. $parts = explode('.', $matches[4]);
  396. foreach ($parts as $part) {
  397. if ($part > 255) {
  398. return false;
  399. }
  400. }
  401. } elseif ($domain_check && function_exists('checkdnsrr')) {
  402. if (!checkdnsrr($authority, 'A')) {
  403. return false;
  404. }
  405. }
  406. if ($strict) {
  407. $strict = '#[' . preg_quote($strict, '#') . ']#';
  408. if ((!empty($matches[7]) && preg_match($strict, $matches[7]))
  409. || (!empty($matches[8]) && preg_match($strict, $matches[8]))) {
  410. return false;
  411. }
  412. }
  413. return true;
  414. }
  415. return false;
  416. }
  417. /**
  418. * Validate date and times. Note that this method need the Date_Calc class
  419. *
  420. * @param string $date Date to validate
  421. * @param array $options array options where :
  422. * 'format' The format of the date (%d-%m-%Y)
  423. * or rfc822_compliant
  424. * 'min' The date has to be greater
  425. * than this array($day, $month, $year)
  426. * or PEAR::Date object
  427. * 'max' The date has to be smaller than
  428. * this array($day, $month, $year)
  429. * or PEAR::Date object
  430. *
  431. * @return boolean true if valid date/time, false if not
  432. *
  433. * @access public
  434. */
  435. function date($date, $options)
  436. {
  437. $max = $min = false;
  438. $format = '';
  439. if (is_array($options)) {
  440. extract($options);
  441. }
  442. if (strtolower($format) == 'rfc822_compliant') {
  443. $preg = '&^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),) \s+
  444. (?:(\d{2})?) \s+
  445. (?:(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)?) \s+
  446. (?:(\d{2}(\d{2})?)?) \s+
  447. (?:(\d{2}?)):(?:(\d{2}?))(:(?:(\d{2}?)))? \s+
  448. (?:[+-]\d{4}|UT|GMT|EST|EDT|CST|CDT|MST|MDT|PST|PDT|[A-IK-Za-ik-z])$&xi';
  449. if (!preg_match($preg, $date, $matches)) {
  450. return false;
  451. }
  452. $year = (int)$matches[4];
  453. $months = array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
  454. 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec');
  455. $month = array_keys($months, $matches[3]);
  456. $month = (int)$month[0]+1;
  457. $day = (int)$matches[2];
  458. $weekday= $matches[1];
  459. $hour = (int)$matches[6];
  460. $minute = (int)$matches[7];
  461. isset($matches[9]) ? $second = (int)$matches[9] : $second = 0;
  462. if ((strlen($year) != 4) ||
  463. ($day > 31 || $day < 1)||
  464. ($hour > 23) ||
  465. ($minute > 59) ||
  466. ($second > 59)) {
  467. return false;
  468. }
  469. } else {
  470. $date_len = strlen($format);
  471. for ($i = 0; $i < $date_len; $i++) {
  472. $c = $format{$i};
  473. if ($c == '%') {
  474. $next = $format{$i + 1};
  475. switch ($next) {
  476. case 'j':
  477. case 'd':
  478. if ($next == 'j') {
  479. $day = (int)Validate::_substr($date, 1, 2);
  480. } else {
  481. $day = (int)Validate::_substr($date, 2);
  482. }
  483. if ($day < 1 || $day > 31) {
  484. return false;
  485. }
  486. break;
  487. case 'm':
  488. case 'n':
  489. if ($next == 'm') {
  490. $month = (int)Validate::_substr($date, 2);
  491. } else {
  492. $month = (int)Validate::_substr($date, 1, 2);
  493. }
  494. if ($month < 1 || $month > 12) {
  495. return false;
  496. }
  497. break;
  498. case 'Y':
  499. case 'y':
  500. if ($next == 'Y') {
  501. $year = Validate::_substr($date, 4);
  502. $year = (int)$year?$year:'';
  503. } else {
  504. $year = (int)(substr(date('Y'), 0, 2) .
  505. Validate::_substr($date, 2));
  506. }
  507. if (strlen($year) != 4 || $year < 0 || $year > 9999) {
  508. return false;
  509. }
  510. break;
  511. case 'g':
  512. case 'h':
  513. if ($next == 'g') {
  514. $hour = Validate::_substr($date, 1, 2);
  515. } else {
  516. $hour = Validate::_substr($date, 2);
  517. }
  518. if (!preg_match('/^\d+$/', $hour) || $hour < 0 || $hour > 12) {
  519. return false;
  520. }
  521. break;
  522. case 'G':
  523. case 'H':
  524. if ($next == 'G') {
  525. $hour = Validate::_substr($date, 1, 2);
  526. } else {
  527. $hour = Validate::_substr($date, 2);
  528. }
  529. if (!preg_match('/^\d+$/', $hour) || $hour < 0 || $hour > 24) {
  530. return false;
  531. }
  532. break;
  533. case 's':
  534. case 'i':
  535. $t = Validate::_substr($date, 2);
  536. if (!preg_match('/^\d+$/', $t) || $t < 0 || $t > 59) {
  537. return false;
  538. }
  539. break;
  540. default:
  541. trigger_error("Not supported char `$next' after % in offset " . ($i+2), E_USER_WARNING);
  542. }
  543. $i++;
  544. } else {
  545. //literal
  546. if (Validate::_substr($date, 1) != $c) {
  547. return false;
  548. }
  549. }
  550. }
  551. }
  552. // there is remaing data, we don't want it
  553. if (strlen($date) && (strtolower($format) != 'rfc822_compliant')) {
  554. return false;
  555. }
  556. if (isset($day) && isset($month) && isset($year)) {
  557. if (!checkdate($month, $day, $year)) {
  558. return false;
  559. }
  560. if (strtolower($format) == 'rfc822_compliant') {
  561. if ($weekday != date("D", mktime(0, 0, 0, $month, $day, $year))) {
  562. return false;
  563. }
  564. }
  565. if ($min) {
  566. include_once 'Date/Calc.php';
  567. if (is_a($min, 'Date') &&
  568. (Date_Calc::compareDates($day, $month, $year,
  569. $min->getDay(), $min->getMonth(), $min->getYear()) < 0))
  570. {
  571. return false;
  572. } elseif (is_array($min) &&
  573. (Date_Calc::compareDates($day, $month, $year,
  574. $min[0], $min[1], $min[2]) < 0))
  575. {
  576. return false;
  577. }
  578. }
  579. if ($max) {
  580. include_once 'Date/Calc.php';
  581. if (is_a($max, 'Date') &&
  582. (Date_Calc::compareDates($day, $month, $year,
  583. $max->getDay(), $max->getMonth(), $max->getYear()) > 0))
  584. {
  585. return false;
  586. } elseif (is_array($max) &&
  587. (Date_Calc::compareDates($day, $month, $year,
  588. $max[0], $max[1], $max[2]) > 0))
  589. {
  590. return false;
  591. }
  592. }
  593. }
  594. return true;
  595. }
  596. function _substr(&$date, $num, $opt = false)
  597. {
  598. if ($opt && strlen($date) >= $opt && preg_match('/^[0-9]{'.$opt.'}/', $date, $m)) {
  599. $ret = $m[0];
  600. } else {
  601. $ret = substr($date, 0, $num);
  602. }
  603. $date = substr($date, strlen($ret));
  604. return $ret;
  605. }
  606. function _modf($val, $div) {
  607. if (function_exists('bcmod')) {
  608. return bcmod($val, $div);
  609. } elseif (function_exists('fmod')) {
  610. return fmod($val, $div);
  611. }
  612. $r = $val / $div;
  613. $i = intval($r);
  614. return intval($val - $i * $div + .1);
  615. }
  616. /**
  617. * Calculates sum of product of number digits with weights
  618. *
  619. * @param string $number number string
  620. * @param array $weights reference to array of weights
  621. *
  622. * @returns int returns product of number digits with weights
  623. *
  624. * @access protected
  625. */
  626. function _multWeights($number, &$weights) {
  627. if (!is_array($weights)) {
  628. return -1;
  629. }
  630. $sum = 0;
  631. $count = min(count($weights), strlen($number));
  632. if ($count == 0) { // empty string or weights array
  633. return -1;
  634. }
  635. for ($i = 0; $i < $count; ++$i) {
  636. $sum += intval(substr($number, $i, 1)) * $weights[$i];
  637. }
  638. return $sum;
  639. }
  640. /**
  641. * Calculates control digit for a given number
  642. *
  643. * @param string $number number string
  644. * @param array $weights reference to array of weights
  645. * @param int $modulo (optionsl) number
  646. * @param int $subtract (optional) number
  647. * @param bool $allow_high (optional) true if function can return number higher than 10
  648. *
  649. * @returns int -1 calculated control number is returned
  650. *
  651. * @access protected
  652. */
  653. function _getControlNumber($number, &$weights, $modulo = 10, $subtract = 0, $allow_high = false) {
  654. // calc sum
  655. $sum = Validate::_multWeights($number, $weights);
  656. if ($sum == -1) {
  657. return -1;
  658. }
  659. $mod = Validate::_modf($sum, $modulo); // calculate control digit
  660. if ($subtract > $mod && $mod > 0) {
  661. $mod = $subtract - $mod;
  662. }
  663. if ($allow_high === false) {
  664. $mod %= 10; // change 10 to zero
  665. }
  666. return $mod;
  667. }
  668. /**
  669. * Validates a number
  670. *
  671. * @param string $number number to validate
  672. * @param array $weights reference to array of weights
  673. * @param int $modulo (optionsl) number
  674. * @param int $subtract (optional) numbier
  675. *
  676. * @returns bool true if valid, false if not
  677. *
  678. * @access protected
  679. */
  680. function _checkControlNumber($number, &$weights, $modulo = 10, $subtract = 0) {
  681. if (strlen($number) < count($weights)) {
  682. return false;
  683. }
  684. $target_digit = substr($number, count($weights), 1);
  685. $control_digit = Validate::_getControlNumber($number, $weights, $modulo, $subtract, $target_digit === 'X');
  686. if ($control_digit == -1) {
  687. return false;
  688. }
  689. if ($target_digit === 'X' && $control_digit == 10) {
  690. return true;
  691. }
  692. if ($control_digit != $target_digit) {
  693. return false;
  694. }
  695. return true;
  696. }
  697. /**
  698. * Bulk data validation for data introduced in the form of an
  699. * assoc array in the form $var_name => $value.
  700. * Can be used on any of Validate subpackages
  701. *
  702. * @param array $data Ex: array('name' => 'toto', 'email' => 'toto@thing.info');
  703. * @param array $val_type Contains the validation type and all parameters used in.
  704. * 'val_type' is not optional
  705. * others validations properties must have the same name as the function
  706. * parameters.
  707. * Ex: array('toto'=>array('type'=>'string','format'='toto@thing.info','min_length'=>5));
  708. * @param boolean $remove if set, the elements not listed in data will be removed
  709. *
  710. * @return array value name => true|false the value name comes from the data key
  711. *
  712. * @access public
  713. */
  714. function multiple(&$data, &$val_type, $remove = false)
  715. {
  716. $keys = array_keys($data);
  717. $valid = array();
  718. foreach ($keys as $var_name) {
  719. if (!isset($val_type[$var_name])) {
  720. if ($remove) {
  721. unset($data[$var_name]);
  722. }
  723. continue;
  724. }
  725. $opt = $val_type[$var_name];
  726. $methods = get_class_methods('Validate');
  727. $val2check = $data[$var_name];
  728. // core validation method
  729. if (in_array(strtolower($opt['type']), $methods)) {
  730. //$opt[$opt['type']] = $data[$var_name];
  731. $method = $opt['type'];
  732. unset($opt['type']);
  733. if (sizeof($opt) == 1) {
  734. $opt = array_pop($opt);
  735. }
  736. $valid[$var_name] = call_user_func(array('Validate', $method), $val2check, $opt);
  737. /**
  738. * external validation method in the form:
  739. * "<class name><underscore><method name>"
  740. * Ex: us_ssn will include class Validate/US.php and call method ssn()
  741. */
  742. } elseif (strpos($opt['type'], '_') !== false) {
  743. $validateType = explode('_', $opt['type']);
  744. $method = array_pop($validateType);
  745. $class = implode('_', $validateType);
  746. $classPath = str_replace('_', DIRECTORY_SEPARATOR, $class);
  747. $class = 'Validate_' . $class;
  748. if (!@include_once "Validate/$classPath.php") {
  749. trigger_error("$class isn't installed or you may have some permissoin issues", E_USER_ERROR);
  750. }
  751. $ce = substr(phpversion(), 0, 1) > 4 ? class_exists($class, false) : class_exists($class);
  752. if (!$ce ||
  753. !in_array($method, get_class_methods($class)))
  754. {
  755. trigger_error("Invalid validation type $class::$method", E_USER_WARNING);
  756. continue;
  757. }
  758. unset($opt['type']);
  759. if (sizeof($opt) == 1) {
  760. $opt = array_pop($opt);
  761. }
  762. $valid[$var_name] = call_user_func(array($class, $method), $data[$var_name], $opt);
  763. } else {
  764. trigger_error("Invalid validation type {$opt['type']}", E_USER_WARNING);
  765. }
  766. }
  767. return $valid;
  768. }
  769. }
  770. ?>