1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
15:
16: App::uses('Multibyte', 'I18n');
17: App::uses('File', 'Utility');
18: App::uses('CakeNumber', 'Utility');
19:
20:
21: if (!function_exists('mb_strlen')) {
22: class_exists('Multibyte');
23: }
24:
25: 26: 27: 28: 29: 30: 31:
32: class Validation {
33:
34: 35: 36: 37: 38:
39: protected static $_pattern = array(
40: 'hostname' => '(?:[_\p{L}0-9][-_\p{L}0-9]*\.)*(?:[\p{L}0-9][-\p{L}0-9]{0,62})\.(?:(?:[a-z]{2}\.)?[a-z]{2,})'
41: );
42:
43: 44: 45: 46: 47: 48:
49: public static $errors = array();
50:
51: 52: 53: 54: 55: 56: 57: 58:
59: public static function notEmpty($check) {
60: trigger_error('Validation::notEmpty() is deprecated. Use Validation::notBlank() instead.', E_USER_DEPRECATED);
61: return static::notBlank($check);
62: }
63:
64: 65: 66: 67: 68: 69: 70: 71:
72: public static function notBlank($check) {
73: if (empty($check) && !is_bool($check) && !is_numeric($check)) {
74: return false;
75: }
76:
77: return static::_check($check, '/[^\s]+/m');
78: }
79:
80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90:
91: public static function alphaNumeric($check) {
92: if (empty($check) && $check != '0') {
93: return false;
94: }
95: return static::_check($check, '/^[\p{Ll}\p{Lm}\p{Lo}\p{Lt}\p{Lu}\p{Nd}]+$/Du');
96: }
97:
98: 99: 100: 101: 102: 103: 104: 105: 106: 107:
108: public static function lengthBetween($check, $min, $max) {
109: $length = mb_strlen($check);
110: return ($length >= $min && $length <= $max);
111: }
112:
113: 114: 115: 116: 117: 118: 119: 120: 121: 122:
123: public static function between($check, $min, $max) {
124: return static::lengthBetween($check, $min, $max);
125: }
126:
127: 128: 129: 130: 131: 132: 133: 134: 135: 136:
137: public static function blank($check) {
138: return !static::_check($check, '/[^\\s]/');
139: }
140:
141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154:
155: public static function cc($check, $type = 'fast', $deep = false, $regex = null) {
156: if (!is_scalar($check)) {
157: return false;
158: }
159:
160: $check = str_replace(array('-', ' '), '', $check);
161: if (mb_strlen($check) < 13) {
162: return false;
163: }
164:
165: if ($regex !== null) {
166: if (static::_check($check, $regex)) {
167: return static::luhn($check, $deep);
168: }
169: }
170: $cards = array(
171: 'all' => array(
172: 'amex' => '/^3[4|7]\\d{13}$/',
173: 'bankcard' => '/^56(10\\d\\d|022[1-5])\\d{10}$/',
174: 'diners' => '/^(?:3(0[0-5]|[68]\\d)\\d{11})|(?:5[1-5]\\d{14})$/',
175: 'disc' => '/^(?:6011|650\\d)\\d{12}$/',
176: 'electron' => '/^(?:417500|4917\\d{2}|4913\\d{2})\\d{10}$/',
177: 'enroute' => '/^2(?:014|149)\\d{11}$/',
178: 'jcb' => '/^(3\\d{4}|2131|1800)\\d{11}$/',
179: 'maestro' => '/^(?:5020|6\\d{3})\\d{12}$/',
180: 'mc' => '/^(5[1-5]\\d{14})|(2(?:22[1-9]|2[3-9][0-9]|[3-6][0-9]{2}|7[0-1][0-9]|720)\\d{12})$/',
181: 'solo' => '/^(6334[5-9][0-9]|6767[0-9]{2})\\d{10}(\\d{2,3})?$/',
182: 'switch' =>
183: '/^(?:49(03(0[2-9]|3[5-9])|11(0[1-2]|7[4-9]|8[1-2])|36[0-9]{2})\\d{10}(\\d{2,3})?)|(?:564182\\d{10}(\\d{2,3})?)|(6(3(33[0-4][0-9])|759[0-9]{2})\\d{10}(\\d{2,3})?)$/',
184: 'visa' => '/^4\\d{12}(\\d{3})?$/',
185: 'voyager' => '/^8699[0-9]{11}$/'
186: ),
187: 'fast' =>
188: '/^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6011[0-9]{12}|3(?:0[0-5]|[68][0-9])[0-9]{11}|3[47][0-9]{13})$/'
189: );
190:
191: if (is_array($type)) {
192: foreach ($type as $value) {
193: $regex = $cards['all'][strtolower($value)];
194:
195: if (static::_check($check, $regex)) {
196: return static::luhn($check, $deep);
197: }
198: }
199: } elseif ($type === 'all') {
200: foreach ($cards['all'] as $value) {
201: $regex = $value;
202:
203: if (static::_check($check, $regex)) {
204: return static::luhn($check, $deep);
205: }
206: }
207: } else {
208: $regex = $cards['fast'];
209:
210: if (static::_check($check, $regex)) {
211: return static::luhn($check, $deep);
212: }
213: }
214: return false;
215: }
216:
217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227:
228: public static function comparison($check1, $operator = null, $check2 = null) {
229: if ((float)$check1 != $check1) {
230: return false;
231: }
232: $operator = str_replace(array(' ', "\t", "\n", "\r", "\0", "\x0B"), '', strtolower($operator));
233:
234: switch ($operator) {
235: case 'isgreater':
236: case '>':
237: if ($check1 > $check2) {
238: return true;
239: }
240: break;
241: case 'isless':
242: case '<':
243: if ($check1 < $check2) {
244: return true;
245: }
246: break;
247: case 'greaterorequal':
248: case '>=':
249: if ($check1 >= $check2) {
250: return true;
251: }
252: break;
253: case 'lessorequal':
254: case '<=':
255: if ($check1 <= $check2) {
256: return true;
257: }
258: break;
259: case 'equalto':
260: case '==':
261: if ($check1 == $check2) {
262: return true;
263: }
264: break;
265: case 'notequal':
266: case '!=':
267: if ($check1 != $check2) {
268: return true;
269: }
270: break;
271: default:
272: static::$errors[] = __d('cake_dev', 'You must define the $operator parameter for %s', 'Validation::comparison()');
273: }
274: return false;
275: }
276:
277: 278: 279: 280: 281: 282: 283: 284:
285: public static function custom($check, $regex = null) {
286: if (!is_scalar($check)) {
287: return false;
288: }
289: if ($regex === null) {
290: static::$errors[] = __d('cake_dev', 'You must define a regular expression for %s', 'Validation::custom()');
291: return false;
292: }
293: return static::_check($check, $regex);
294: }
295:
296: 297: 298: 299: 300: 301: 302: 303: 304: 305: 306: 307: 308: 309: 310: 311: 312: 313: 314: 315: 316: 317: 318: 319:
320: public static function date($check, $format = 'ymd', $regex = null) {
321: if ($regex !== null) {
322: return static::_check($check, $regex);
323: }
324: $month = '(0[123456789]|10|11|12)';
325: $separator = '([- /.])';
326: $fourDigitYear = '(([1][8-9][0-9][0-9])|([2][0-9][0-9][0-9]))';
327: $twoDigitYear = '([0-9]{2})';
328: $year = '(?:' . $fourDigitYear . '|' . $twoDigitYear . ')';
329:
330: $regex['dmy'] = '%^(?:(?:31(\\/|-|\\.|\\x20)(?:0?[13578]|1[02]))\\1|(?:(?:29|30)' .
331: $separator . '(?:0?[1,3-9]|1[0-2])\\2))(?:(?:1[6-9]|[2-9]\\d)?\\d{2})$|^(?:29' .
332: $separator . '0?2\\3(?:(?:(?:1[6-9]|[2-9]\\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:0?[1-9]|1\\d|2[0-8])' .
333: $separator . '(?:(?:0?[1-9])|(?:1[0-2]))\\4(?:(?:1[6-9]|[2-9]\\d)?\\d{2})$%';
334:
335: $regex['mdy'] = '%^(?:(?:(?:0?[13578]|1[02])(\\/|-|\\.|\\x20)31)\\1|(?:(?:0?[13-9]|1[0-2])' .
336: $separator . '(?:29|30)\\2))(?:(?:1[6-9]|[2-9]\\d)?\\d{2})$|^(?:0?2' . $separator . '29\\3(?:(?:(?:1[6-9]|[2-9]\\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:(?:0?[1-9])|(?:1[0-2]))' .
337: $separator . '(?:0?[1-9]|1\\d|2[0-8])\\4(?:(?:1[6-9]|[2-9]\\d)?\\d{2})$%';
338:
339: $regex['ymd'] = '%^(?:(?:(?:(?:(?:1[6-9]|[2-9]\\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00)))' .
340: $separator . '(?:0?2\\1(?:29)))|(?:(?:(?:1[6-9]|[2-9]\\d)?\\d{2})' .
341: $separator . '(?:(?:(?:0?[13578]|1[02])\\2(?:31))|(?:(?:0?[1,3-9]|1[0-2])\\2(29|30))|(?:(?:0?[1-9])|(?:1[0-2]))\\2(?:0?[1-9]|1\\d|2[0-8]))))$%';
342:
343: $regex['dMy'] = '/^((31(?!\\ (Feb(ruary)?|Apr(il)?|June?|(Sep(?=\\b|t)t?|Nov)(ember)?)))|((30|29)(?!\\ Feb(ruary)?))|(29(?=\\ Feb(ruary)?\\ (((1[6-9]|[2-9]\\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00)))))|(0?[1-9])|1\\d|2[0-8])\\ (Jan(uary)?|Feb(ruary)?|Ma(r(ch)?|y)|Apr(il)?|Ju((ly?)|(ne?))|Aug(ust)?|Oct(ober)?|(Sep(?=\\b|t)t?|Nov|Dec)(ember)?)\\ ((1[6-9]|[2-9]\\d)\\d{2})$/';
344:
345: $regex['Mdy'] = '/^(?:(((Jan(uary)?|Ma(r(ch)?|y)|Jul(y)?|Aug(ust)?|Oct(ober)?|Dec(ember)?)\\ 31)|((Jan(uary)?|Ma(r(ch)?|y)|Apr(il)?|Ju((ly?)|(ne?))|Aug(ust)?|Oct(ober)?|(Sep)(tember)?|(Nov|Dec)(ember)?)\\ (0?[1-9]|([12]\\d)|30))|(Feb(ruary)?\\ (0?[1-9]|1\\d|2[0-8]|(29(?=,?\\ ((1[6-9]|[2-9]\\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00)))))))\\,?\\ ((1[6-9]|[2-9]\\d)\\d{2}))$/';
346:
347: $regex['My'] = '%^(Jan(uary)?|Feb(ruary)?|Ma(r(ch)?|y)|Apr(il)?|Ju((ly?)|(ne?))|Aug(ust)?|Oct(ober)?|(Sep(?=\\b|t)t?|Nov|Dec)(ember)?)' .
348: $separator . '((1[6-9]|[2-9]\\d)\\d{2})$%';
349:
350: $regex['my'] = '%^(' . $month . $separator . $year . ')$%';
351: $regex['ym'] = '%^(' . $year . $separator . $month . ')$%';
352: $regex['y'] = '%^(' . $fourDigitYear . ')$%';
353:
354: $format = (is_array($format)) ? array_values($format) : array($format);
355: foreach ($format as $key) {
356: if (static::_check($check, $regex[$key]) === true) {
357: return true;
358: }
359: }
360: return false;
361: }
362:
363: 364: 365: 366: 367: 368: 369: 370: 371: 372: 373: 374:
375: public static function datetime($check, $dateFormat = 'ymd', $regex = null) {
376: $valid = false;
377: $parts = explode(' ', $check);
378: if (!empty($parts) && count($parts) > 1) {
379: $time = array_pop($parts);
380: $date = implode(' ', $parts);
381: $valid = static::date($date, $dateFormat, $regex) && static::time($time);
382: }
383: return $valid;
384: }
385:
386: 387: 388: 389: 390: 391: 392: 393:
394: public static function time($check) {
395: return static::_check($check, '%^((0?[1-9]|1[012])(:[0-5]\d){0,2} ?([AP]M|[ap]m))$|^([01]\d|2[0-3])(:[0-5]\d){0,2}$%');
396: }
397:
398: 399: 400: 401: 402: 403:
404: public static function boolean($check) {
405: $booleanList = array(0, 1, '0', '1', true, false);
406: return in_array($check, $booleanList, true);
407: }
408:
409: 410: 411: 412: 413: 414: 415: 416: 417: 418: 419: 420: 421: 422:
423: public static function decimal($check, $places = null, $regex = null) {
424: if ($regex === null) {
425: $lnum = '[0-9]+';
426: $dnum = "[0-9]*[\.]{$lnum}";
427: $sign = '[+-]?';
428: $exp = "(?:[eE]{$sign}{$lnum})?";
429:
430: if ($places === null) {
431: $regex = "/^{$sign}(?:{$lnum}|{$dnum}){$exp}$/";
432:
433: } elseif ($places === true) {
434: if (is_float($check) && floor($check) === $check) {
435: $check = sprintf("%.1f", $check);
436: }
437: $regex = "/^{$sign}{$dnum}{$exp}$/";
438:
439: } elseif (is_numeric($places)) {
440: $places = '[0-9]{' . $places . '}';
441: $dnum = "(?:[0-9]*[\.]{$places}|{$lnum}[\.]{$places})";
442: $regex = "/^{$sign}{$dnum}{$exp}$/";
443: }
444: }
445:
446:
447: $data = localeconv();
448: $check = str_replace($data['thousands_sep'], '', $check);
449: $check = str_replace($data['decimal_point'], '.', $check);
450:
451: return static::_check($check, $regex);
452: }
453:
454: 455: 456: 457: 458: 459: 460: 461: 462: 463: 464:
465: public static function email($check, $deep = false, $regex = null) {
466: if ($regex === null) {
467: $regex = '/^[\p{L}0-9!#$%&\'*+\/=?^_`{|}~-]+(?:\.[\p{L}0-9!#$%&\'*+\/=?^_`{|}~-]+)*@' . static::$_pattern['hostname'] . '$/ui';
468: }
469: $return = static::_check($check, $regex);
470: if ($deep === false || $deep === null) {
471: return $return;
472: }
473:
474: if ($return === true && preg_match('/@(' . static::$_pattern['hostname'] . ')$/i', $check, $regs)) {
475: if (function_exists('getmxrr') && getmxrr($regs[1], $mxhosts)) {
476: return true;
477: }
478: if (function_exists('checkdnsrr') && checkdnsrr($regs[1], 'MX')) {
479: return true;
480: }
481: return is_array(gethostbynamel($regs[1] . '.'));
482: }
483: return false;
484: }
485:
486: 487: 488: 489: 490: 491: 492:
493: public static function equalTo($check, $comparedTo) {
494: return ($check === $comparedTo);
495: }
496:
497: 498: 499: 500: 501: 502: 503:
504: public static function extension($check, $extensions = array('gif', 'jpeg', 'png', 'jpg')) {
505: if (is_array($check)) {
506: return static::extension(array_shift($check), $extensions);
507: }
508: $extension = strtolower(pathinfo($check, PATHINFO_EXTENSION));
509: foreach ($extensions as $value) {
510: if ($extension === strtolower($value)) {
511: return true;
512: }
513: }
514: return false;
515: }
516:
517: 518: 519: 520: 521: 522: 523:
524: public static function ip($check, $type = 'both') {
525: $type = strtolower($type);
526: $flags = 0;
527: if ($type === 'ipv4') {
528: $flags = FILTER_FLAG_IPV4;
529: }
530: if ($type === 'ipv6') {
531: $flags = FILTER_FLAG_IPV6;
532: }
533: return (bool)filter_var($check, FILTER_VALIDATE_IP, array('flags' => $flags));
534: }
535:
536: 537: 538: 539: 540: 541: 542:
543: public static function minLength($check, $min) {
544: return mb_strlen($check) >= $min;
545: }
546:
547: 548: 549: 550: 551: 552: 553:
554: public static function maxLength($check, $max) {
555: return mb_strlen($check) <= $max;
556: }
557:
558: 559: 560: 561: 562: 563: 564:
565: public static function minLengthBytes($check, $min) {
566: return strlen($check) >= $min;
567: }
568:
569: 570: 571: 572: 573: 574: 575:
576: public static function maxLengthBytes($check, $max) {
577: return strlen($check) <= $max;
578: }
579:
580: 581: 582: 583: 584: 585: 586:
587: public static function money($check, $symbolPosition = 'left') {
588: $money = '(?!0,?\d)(?:\d{1,3}(?:([, .])\d{3})?(?:\1\d{3})*|(?:\d+))((?!\1)[,.]\d{1,2})?';
589: if ($symbolPosition === 'right') {
590: $regex = '/^' . $money . '(?<!\x{00a2})\p{Sc}?$/u';
591: } else {
592: $regex = '/^(?!\x{00a2})\p{Sc}?' . $money . '$/u';
593: }
594: return static::_check($check, $regex);
595: }
596:
597: 598: 599: 600: 601: 602: 603: 604: 605: 606: 607: 608: 609: 610:
611: public static function multiple($check, $options = array(), $caseInsensitive = false) {
612: $defaults = array('in' => null, 'max' => null, 'min' => null);
613: $options += $defaults;
614:
615: $check = array_filter((array)$check, 'strlen');
616: if (empty($check)) {
617: return false;
618: }
619: if ($options['max'] && count($check) > $options['max']) {
620: return false;
621: }
622: if ($options['min'] && count($check) < $options['min']) {
623: return false;
624: }
625: if ($options['in'] && is_array($options['in'])) {
626: if ($caseInsensitive) {
627: $options['in'] = array_map('mb_strtolower', $options['in']);
628: }
629: foreach ($check as $val) {
630: $strict = !is_numeric($val);
631: if ($caseInsensitive) {
632: $val = mb_strtolower($val);
633: }
634: if (!in_array((string)$val, $options['in'], $strict)) {
635: return false;
636: }
637: }
638: }
639: return true;
640: }
641:
642: 643: 644: 645: 646: 647:
648: public static function numeric($check) {
649: return is_numeric($check);
650: }
651:
652: 653: 654: 655: 656: 657: 658: 659:
660: public static function naturalNumber($check, $allowZero = false) {
661: $regex = $allowZero ? '/^(?:0|[1-9][0-9]*)$/' : '/^[1-9][0-9]*$/';
662: return static::_check($check, $regex);
663: }
664:
665: 666: 667: 668: 669: 670: 671: 672:
673: public static function phone($check, $regex = null, $country = 'all') {
674: if ($regex === null) {
675: switch ($country) {
676: case 'us':
677: case 'ca':
678: case 'can':
679: case 'all':
680:
681:
682: $regex = '/^(?:(?:\+?1\s*(?:[.-]\s*)?)?';
683:
684:
685: $areaCode = '(?![2-9]11)(?!555)([2-9][0-8][0-9])';
686: $regex .= '(?:\(\s*' . $areaCode . '\s*\)|' . $areaCode . ')';
687: $regex .= '\s*(?:[.-]\s*)?)';
688:
689:
690: $regex .= '(?!(555(?:\s*(?:[.\-\s]\s*))(01([0-9][0-9])|1212)))';
691: $regex .= '(?!(555(01([0-9][0-9])|1212)))';
692: $regex .= '([2-9]1[02-9]|[2-9][02-9]1|[2-9][0-9]{2})\s*(?:[.-]\s*)';
693:
694:
695: $regex .= '?([0-9]{4})';
696: $regex .= '(?:\s*(?:#|x\.?|ext\.?|extension)\s*(\d+))?$/';
697: break;
698: }
699: }
700: if (empty($regex)) {
701: return static::_pass('phone', $check, $country);
702: }
703: return static::_check($check, $regex);
704: }
705:
706: 707: 708: 709: 710: 711: 712: 713:
714: public static function postal($check, $regex = null, $country = 'us') {
715: if ($regex === null) {
716: switch ($country) {
717: case 'uk':
718: $regex = '/\\A\\b[A-Z]{1,2}[0-9][A-Z0-9]? [0-9][ABD-HJLNP-UW-Z]{2}\\b\\z/i';
719: break;
720: case 'ca':
721: $district = '[ABCEGHJKLMNPRSTVYX]';
722: $letters = '[ABCEGHJKLMNPRSTVWXYZ]';
723: $regex = "/\\A\\b{$district}[0-9]{$letters} [0-9]{$letters}[0-9]\\b\\z/i";
724: break;
725: case 'it':
726: case 'de':
727: $regex = '/^[0-9]{5}$/i';
728: break;
729: case 'be':
730: $regex = '/^[1-9]{1}[0-9]{3}$/i';
731: break;
732: case 'us':
733: $regex = '/\\A\\b[0-9]{5}(?:-[0-9]{4})?\\b\\z/i';
734: break;
735: }
736: }
737: if (empty($regex)) {
738: return static::_pass('postal', $check, $country);
739: }
740: return static::_check($check, $regex);
741: }
742:
743: 744: 745: 746: 747: 748: 749: 750: 751: 752:
753: public static function range($check, $lower = null, $upper = null) {
754: if (!is_numeric($check)) {
755: return false;
756: }
757: if ((float)$check != $check) {
758: return false;
759: }
760: if (isset($lower) && isset($upper)) {
761: return ($check > $lower && $check < $upper);
762: }
763: return is_finite($check);
764: }
765:
766: 767: 768: 769: 770: 771: 772: 773: 774:
775: public static function ssn($check, $regex = null, $country = null) {
776: if ($regex === null) {
777: switch ($country) {
778: case 'dk':
779: $regex = '/\\A\\b[0-9]{6}-[0-9]{4}\\b\\z/i';
780: break;
781: case 'nl':
782: $regex = '/\\A\\b[0-9]{9}\\b\\z/i';
783: break;
784: case 'us':
785: $regex = '/\\A\\b[0-9]{3}-[0-9]{2}-[0-9]{4}\\b\\z/i';
786: break;
787: }
788: }
789: if (empty($regex)) {
790: return static::_pass('ssn', $check, $country);
791: }
792: return static::_check($check, $regex);
793: }
794:
795: 796: 797: 798: 799: 800: 801: 802: 803: 804: 805: 806: 807: 808: 809: 810: 811:
812: public static function url($check, $strict = false) {
813: static::_populateIp();
814: $validChars = '([' . preg_quote('!"$&\'()*+,-.@_:;=~[]') . '\/0-9\p{L}\p{N}]|(%[0-9a-f]{2}))';
815: $regex = '/^(?:(?:https?|ftps?|sftp|file|news|gopher):\/\/)' . (!empty($strict) ? '' : '?') .
816: '(?:' . static::$_pattern['IPv4'] . '|\[' . static::$_pattern['IPv6'] . '\]|' . static::$_pattern['hostname'] . ')(?::[1-9][0-9]{0,4})?' .
817: '(?:\/?|\/' . $validChars . '*)?' .
818: '(?:\?' . $validChars . '*)?' .
819: '(?:#' . $validChars . '*)?$/iu';
820: return static::_check($check, $regex);
821: }
822:
823: 824: 825: 826: 827: 828: 829: 830:
831: public static function inList($check, $list, $caseInsensitive = false) {
832: if ($caseInsensitive) {
833: $list = array_map('mb_strtolower', $list);
834: $check = mb_strtolower($check);
835: } else {
836: $list = array_map('strval', $list);
837: }
838: return in_array((string)$check, $list, true);
839: }
840:
841: 842: 843: 844: 845: 846: 847: 848: 849:
850: public static function userDefined($check, $object, $method, $args = null) {
851: return call_user_func_array(array($object, $method), array($check, $args));
852: }
853:
854: 855: 856: 857: 858: 859:
860: public static function uuid($check) {
861: $regex = '/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[0-5][a-fA-F0-9]{3}-[089aAbB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/';
862: return static::_check($check, $regex);
863: }
864:
865: 866: 867: 868: 869: 870: 871: 872: 873: 874:
875: protected static function _pass($method, $check, $classPrefix) {
876: $className = ucwords($classPrefix) . 'Validation';
877: if (!class_exists($className)) {
878: trigger_error(__d('cake_dev', 'Could not find %s class, unable to complete validation.', $className), E_USER_WARNING);
879: return false;
880: }
881: if (!method_exists($className, $method)) {
882: trigger_error(__d('cake_dev', 'Method %s does not exist on %s unable to complete validation.', $method, $className), E_USER_WARNING);
883: return false;
884: }
885: $check = (array)$check;
886: return call_user_func_array(array($className, $method), $check);
887: }
888:
889: 890: 891: 892: 893: 894: 895:
896: protected static function _check($check, $regex) {
897: if (is_string($regex) && is_scalar($check) && preg_match($regex, $check)) {
898: return true;
899: }
900: return false;
901: }
902:
903: 904: 905: 906: 907: 908: 909: 910:
911: public static function luhn($check, $deep = false) {
912: if (!is_scalar($check)) {
913: return false;
914: }
915: if ($deep !== true) {
916: return true;
917: }
918: if ((int)$check === 0) {
919: return false;
920: }
921: $sum = 0;
922: $length = strlen($check);
923:
924: for ($position = 1 - ($length % 2); $position < $length; $position += 2) {
925: $sum += $check[$position];
926: }
927:
928: for ($position = ($length % 2); $position < $length; $position += 2) {
929: $number = $check[$position] * 2;
930: $sum += ($number < 10) ? $number : $number - 9;
931: }
932:
933: return ($sum % 10 === 0);
934: }
935:
936: 937: 938: 939: 940: 941: 942: 943:
944: public static function mimeType($check, $mimeTypes = array()) {
945: if (is_array($check) && isset($check['tmp_name'])) {
946: $check = $check['tmp_name'];
947: }
948:
949: $File = new File($check);
950: $mime = $File->mime();
951:
952: if ($mime === false) {
953: throw new CakeException(__d('cake_dev', 'Can not determine the mimetype.'));
954: }
955:
956: if (is_string($mimeTypes)) {
957: return static::_check($mime, $mimeTypes);
958: }
959:
960: foreach ($mimeTypes as $key => $val) {
961: $mimeTypes[$key] = strtolower($val);
962: }
963: return in_array($mime, $mimeTypes);
964: }
965:
966: 967: 968: 969: 970: 971: 972: 973:
974: public static function fileSize($check, $operator = null, $size = null) {
975: if (is_array($check) && isset($check['tmp_name'])) {
976: $check = $check['tmp_name'];
977: }
978:
979: if (is_string($size)) {
980: $size = CakeNumber::fromReadableSize($size);
981: }
982: $filesize = filesize($check);
983:
984: return static::comparison($filesize, $operator, $size);
985: }
986:
987: 988: 989: 990: 991: 992: 993: 994:
995: public static function uploadError($check, $allowNoFile = false) {
996: if (is_array($check) && isset($check['error'])) {
997: $check = $check['error'];
998: }
999: if ($allowNoFile) {
1000: return in_array((int)$check, array(UPLOAD_ERR_OK, UPLOAD_ERR_NO_FILE), true);
1001: }
1002:
1003: return (int)$check === UPLOAD_ERR_OK;
1004: }
1005:
1006: 1007: 1008: 1009: 1010: 1011: 1012: 1013: 1014: 1015: 1016: 1017: 1018: 1019: 1020: 1021: 1022: 1023: 1024: 1025:
1026: public static function uploadedFile($file, $options = array()) {
1027: $options += array(
1028: 'minSize' => null,
1029: 'maxSize' => null,
1030: 'types' => null,
1031: 'optional' => false,
1032: );
1033: if (!is_array($file)) {
1034: return false;
1035: }
1036: $keys = array('error', 'name', 'size', 'tmp_name', 'type');
1037: ksort($file);
1038: if (array_keys($file) != $keys) {
1039: return false;
1040: }
1041: if (!static::uploadError($file, $options['optional'])) {
1042: return false;
1043: }
1044: if ($options['optional'] && (int)$file['error'] === UPLOAD_ERR_NO_FILE) {
1045: return true;
1046: }
1047: if (isset($options['minSize']) && !static::fileSize($file, '>=', $options['minSize'])) {
1048: return false;
1049: }
1050: if (isset($options['maxSize']) && !static::fileSize($file, '<=', $options['maxSize'])) {
1051: return false;
1052: }
1053: if (isset($options['types']) && !static::mimeType($file, $options['types'])) {
1054: return false;
1055: }
1056: return static::_isUploadedFile($file['tmp_name']);
1057: }
1058:
1059: 1060: 1061: 1062: 1063: 1064:
1065: protected static function _isUploadedFile($path) {
1066: return is_uploaded_file($path);
1067: }
1068:
1069: 1070: 1071: 1072: 1073:
1074: protected static function _populateIp() {
1075: if (!isset(static::$_pattern['IPv6'])) {
1076: $pattern = '((([0-9A-Fa-f]{1,4}:){7}(([0-9A-Fa-f]{1,4})|:))|(([0-9A-Fa-f]{1,4}:){6}';
1077: $pattern .= '(:|((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})';
1078: $pattern .= '|(:[0-9A-Fa-f]{1,4})))|(([0-9A-Fa-f]{1,4}:){5}((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})';
1079: $pattern .= '(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:)';
1080: $pattern .= '{4}(:[0-9A-Fa-f]{1,4}){0,1}((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2}))';
1081: $pattern .= '{3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:){3}(:[0-9A-Fa-f]{1,4}){0,2}';
1082: $pattern .= '((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|';
1083: $pattern .= '((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:){2}(:[0-9A-Fa-f]{1,4}){0,3}';
1084: $pattern .= '((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2}))';
1085: $pattern .= '{3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:)(:[0-9A-Fa-f]{1,4})';
1086: $pattern .= '{0,4}((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)';
1087: $pattern .= '|((:[0-9A-Fa-f]{1,4}){1,2})))|(:(:[0-9A-Fa-f]{1,4}){0,5}((:((25[0-5]|2[0-4]';
1088: $pattern .= '\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4})';
1089: $pattern .= '{1,2})))|(((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})))(%.+)?';
1090:
1091: static::$_pattern['IPv6'] = $pattern;
1092: }
1093: if (!isset(static::$_pattern['IPv4'])) {
1094: $pattern = '(?:(?:25[0-5]|2[0-4][0-9]|(?:(?:1[0-9])?|[1-9]?)[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|(?:(?:1[0-9])?|[1-9]?)[0-9])';
1095: static::$_pattern['IPv4'] = $pattern;
1096: }
1097: }
1098:
1099: 1100: 1101: 1102: 1103:
1104: protected static function _reset() {
1105: static::$errors = array();
1106: }
1107:
1108: }
1109: