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