Added the zend framework 2 library, the path is specified in line no.26 in zend_modul...
[openemr.git] / interface / modules / zend_modules / library / Zend / Validator / CreditCard.php
blob8dd346175671ed8f39f9e0f04f8d4ec790b559c0
1 <?php
2 /**
3 * Zend Framework (http://framework.zend.com/)
5 * @link http://github.com/zendframework/zf2 for the canonical source repository
6 * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
7 * @license http://framework.zend.com/license/new-bsd New BSD License
8 */
10 namespace Zend\Validator;
12 use Traversable;
13 use Zend\Stdlib\ArrayUtils;
15 class CreditCard extends AbstractValidator
17 /**
18 * Detected CCI list
20 * @var string
22 const ALL = 'All';
23 const AMERICAN_EXPRESS = 'American_Express';
24 const UNIONPAY = 'Unionpay';
25 const DINERS_CLUB = 'Diners_Club';
26 const DINERS_CLUB_US = 'Diners_Club_US';
27 const DISCOVER = 'Discover';
28 const JCB = 'JCB';
29 const LASER = 'Laser';
30 const MAESTRO = 'Maestro';
31 const MASTERCARD = 'Mastercard';
32 const SOLO = 'Solo';
33 const VISA = 'Visa';
35 const CHECKSUM = 'creditcardChecksum';
36 const CONTENT = 'creditcardContent';
37 const INVALID = 'creditcardInvalid';
38 const LENGTH = 'creditcardLength';
39 const PREFIX = 'creditcardPrefix';
40 const SERVICE = 'creditcardService';
41 const SERVICEFAILURE = 'creditcardServiceFailure';
43 /**
44 * Validation failure message template definitions
46 * @var array
48 protected $messageTemplates = array(
49 self::CHECKSUM => "The input seems to contain an invalid checksum",
50 self::CONTENT => "The input must contain only digits",
51 self::INVALID => "Invalid type given. String expected",
52 self::LENGTH => "The input contains an invalid amount of digits",
53 self::PREFIX => "The input is not from an allowed institute",
54 self::SERVICE => "The input seems to be an invalid credit card number",
55 self::SERVICEFAILURE => "An exception has been raised while validating the input",
58 /**
59 * List of CCV names
61 * @var array
63 protected $cardName = array(
64 0 => self::AMERICAN_EXPRESS,
65 1 => self::DINERS_CLUB,
66 2 => self::DINERS_CLUB_US,
67 3 => self::DISCOVER,
68 4 => self::JCB,
69 5 => self::LASER,
70 6 => self::MAESTRO,
71 7 => self::MASTERCARD,
72 8 => self::SOLO,
73 9 => self::UNIONPAY,
74 10 => self::VISA,
77 /**
78 * List of allowed CCV lengths
80 * @var array
82 protected $cardLength = array(
83 self::AMERICAN_EXPRESS => array(15),
84 self::DINERS_CLUB => array(14),
85 self::DINERS_CLUB_US => array(16),
86 self::DISCOVER => array(16),
87 self::JCB => array(16),
88 self::LASER => array(16, 17, 18, 19),
89 self::MAESTRO => array(12, 13, 14, 15, 16, 17, 18, 19),
90 self::MASTERCARD => array(16),
91 self::SOLO => array(16, 18, 19),
92 self::UNIONPAY => array(16, 17, 18, 19),
93 self::VISA => array(16),
96 /**
97 * List of accepted CCV provider tags
99 * @var array
101 protected $cardType = array(
102 self::AMERICAN_EXPRESS => array('34', '37'),
103 self::DINERS_CLUB => array('300', '301', '302', '303', '304', '305', '36'),
104 self::DINERS_CLUB_US => array('54', '55'),
105 self::DISCOVER => array('6011', '622126', '622127', '622128', '622129', '62213',
106 '62214', '62215', '62216', '62217', '62218', '62219',
107 '6222', '6223', '6224', '6225', '6226', '6227', '6228',
108 '62290', '62291', '622920', '622921', '622922', '622923',
109 '622924', '622925', '644', '645', '646', '647', '648',
110 '649', '65'),
111 self::JCB => array('3528', '3529', '353', '354', '355', '356', '357', '358'),
112 self::LASER => array('6304', '6706', '6771', '6709'),
113 self::MAESTRO => array('5018', '5020', '5038', '6304', '6759', '6761', '6762', '6763',
114 '6764', '6765', '6766'),
115 self::MASTERCARD => array('51', '52', '53', '54', '55'),
116 self::SOLO => array('6334', '6767'),
117 self::UNIONPAY => array('622126', '622127', '622128', '622129', '62213', '62214',
118 '62215', '62216', '62217', '62218', '62219', '6222', '6223',
119 '6224', '6225', '6226', '6227', '6228', '62290', '62291',
120 '622920', '622921', '622922', '622923', '622924', '622925'),
121 self::VISA => array('4'),
125 * Options for this validator
127 * @var array
129 protected $options = array(
130 'service' => null, // Service callback for additional validation
131 'type' => array(), // CCIs which are accepted by validation
135 * Constructor
137 * @param string|array|Traversable $options OPTIONAL Type of CCI to allow
139 public function __construct($options = array())
141 if ($options instanceof Traversable) {
142 $options = ArrayUtils::iteratorToArray($options);
143 } elseif (!is_array($options)) {
144 $options = func_get_args();
145 $temp['type'] = array_shift($options);
146 if (!empty($options)) {
147 $temp['service'] = array_shift($options);
150 $options = $temp;
153 if (!array_key_exists('type', $options)) {
154 $options['type'] = self::ALL;
157 $this->setType($options['type']);
158 unset($options['type']);
160 if (array_key_exists('service', $options)) {
161 $this->setService($options['service']);
162 unset($options['service']);
165 parent::__construct($options);
169 * Returns a list of accepted CCIs
171 * @return array
173 public function getType()
175 return $this->options['type'];
179 * Sets CCIs which are accepted by validation
181 * @param string|array $type Type to allow for validation
182 * @return CreditCard Provides a fluid interface
184 public function setType($type)
186 $this->options['type'] = array();
187 return $this->addType($type);
191 * Adds a CCI to be accepted by validation
193 * @param string|array $type Type to allow for validation
194 * @return CreditCard Provides a fluid interface
196 public function addType($type)
198 if (is_string($type)) {
199 $type = array($type);
202 foreach ($type as $typ) {
203 if (defined('self::' . strtoupper($typ)) && !in_array($typ, $this->options['type'])) {
204 $this->options['type'][] = $typ;
207 if (($typ == self::ALL)) {
208 $this->options['type'] = array_keys($this->cardLength);
212 return $this;
216 * Returns the actual set service
218 * @return callable
220 public function getService()
222 return $this->options['service'];
226 * Sets a new callback for service validation
228 * @param callable $service
229 * @return CreditCard
230 * @throws Exception\InvalidArgumentException on invalid service callback
232 public function setService($service)
234 if (!is_callable($service)) {
235 throw new Exception\InvalidArgumentException('Invalid callback given');
238 $this->options['service'] = $service;
239 return $this;
243 * Returns true if and only if $value follows the Luhn algorithm (mod-10 checksum)
245 * @param string $value
246 * @return bool
248 public function isValid($value)
250 $this->setValue($value);
252 if (!is_string($value)) {
253 $this->error(self::INVALID, $value);
254 return false;
257 if (!ctype_digit($value)) {
258 $this->error(self::CONTENT, $value);
259 return false;
262 $length = strlen($value);
263 $types = $this->getType();
264 $foundp = false;
265 $foundl = false;
266 foreach ($types as $type) {
267 foreach ($this->cardType[$type] as $prefix) {
268 if (substr($value, 0, strlen($prefix)) == $prefix) {
269 $foundp = true;
270 if (in_array($length, $this->cardLength[$type])) {
271 $foundl = true;
272 break 2;
278 if ($foundp == false) {
279 $this->error(self::PREFIX, $value);
280 return false;
283 if ($foundl == false) {
284 $this->error(self::LENGTH, $value);
285 return false;
288 $sum = 0;
289 $weight = 2;
291 for ($i = $length - 2; $i >= 0; $i--) {
292 $digit = $weight * $value[$i];
293 $sum += floor($digit / 10) + $digit % 10;
294 $weight = $weight % 2 + 1;
297 if ((10 - $sum % 10) % 10 != $value[$length - 1]) {
298 $this->error(self::CHECKSUM, $value);
299 return false;
302 $service = $this->getService();
303 if (!empty($service)) {
304 try {
305 $callback = new Callback($service);
306 $callback->setOptions($this->getType());
307 if (!$callback->isValid($value)) {
308 $this->error(self::SERVICE, $value);
309 return false;
311 } catch (\Exception $e) {
312 $this->error(self::SERVICEFAILURE, $value);
313 return false;
317 return true;