1: <?php
2: 3: 4: 5: 6: 7:
8:
9: namespace Wei\Validator;
10:
11: 12: 13: 14: 15: 16: 17: 18:
19: class CreditCard extends BaseValidator
20: {
21: protected $invalidMessage = '%name% must be valid credit card number';
22:
23: protected $negativeMessage = '%name% must not be valid credit card number';
24:
25: 26: 27: 28: 29:
30: protected $type = array();
31:
32: 33: 34: 35: 36: 37:
38: protected $cards = array(
39: 'Amex' => array(
40: 'length' => 15,
41: 'pattern' => '34|37'
42: ),
43: 'DinersClub' => array(
44: 'length' => 14,
45: 'pattern' => '30|36|38'
46: ),
47: 'Discover' => array(
48: 'length' => 16,
49: 'pattern' => '6011|64|65'
50: ),
51: 'JCB' => array(
52: 'length' => array(15, 16),
53: 'pattern' => '2131|1800|35'
54: ),
55: 'MasterCard' => array(
56: 'length' => 16,
57: 'pattern' => '51|52|53|54|55'
58: ),
59: 'UnionPay' => array(
60: 'length' => 16,
61: 'pattern' => '62'
62: ),
63: 'Visa' => array(
64: 'length' => array(13, 16),
65: 'pattern' => '4'
66: )
67: );
68:
69: 70: 71:
72: public function __invoke($input, $type = null)
73: {
74: $type && $this->storeOption('type', $type);
75:
76: return $this->isValid($input);
77: }
78:
79: 80: 81:
82: protected function doValidate($input)
83: {
84: if (!$this->isString($input)) {
85: $this->addError('notString');
86: return false;
87: }
88:
89: if (!$this->validateLuhn($input)) {
90: $this->addError('invalid');
91: return false;
92: }
93:
94: if (!$this->validateType($input)) {
95: $this->addError('invalid');
96: return false;
97: }
98:
99: return true;
100: }
101:
102: 103: 104: 105: 106: 107: 108:
109: public function validateLuhn($input)
110: {
111: $checksum = '';
112: foreach (str_split(strrev($input)) as $i => $d) {
113: $checksum .= ($i %2 !== 0) ? ($d * 2) : $d;
114: }
115: return array_sum(str_split($checksum)) % 10 === 0;
116: }
117:
118: public function validateType($input)
119: {
120: if (!$this->type) {
121: return true;
122: }
123: foreach ($this->type as $type) {
124: $card = $this->cards[$type];
125: if (!preg_match('/^' . $card['pattern'] . '/', $input)) {
126: continue;
127: }
128: if (!in_array(strlen($input), (array)$card['length'])) {
129: continue;
130: }
131: return true;
132: }
133: return false;
134: }
135:
136: 137: 138: 139: 140: 141: 142: 143:
144: public function setType($type)
145: {
146: if (is_string($type)) {
147: if ('all' == strtolower($type)) {
148: $this->type = array_keys($this->cards);
149: } else {
150: $this->type = explode(',', $type);
151: }
152: } elseif (is_array($type)) {
153: $this->type = $type;
154: } else {
155: throw new \InvalidArgumentException(sprintf(
156: 'Expected argument of type array or string, "%s" given',
157: is_object($type) ? get_class($type) : gettype($type)
158: ));
159: }
160:
161: return $this;
162: }
163: }
164: