PageRenderTime 47ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/plugins/dataTypes/PAN/PAN.class.php

https://gitlab.com/adamlwalker/generatedata
PHP | 531 lines | 432 code | 70 blank | 29 comment | 43 complexity | 4a2a190df77575e65312f38c6167315c MD5 | raw file
  1. <?php
  2. /**
  3. * @author Ben Keen <ben.keen@gmail.com>, origin code Zeeshan Shaikh <zeeshanyshaikh@gmail.com>
  4. * @package DataTypes
  5. */
  6. class DataType_PAN extends DataTypePlugin {
  7. protected $isEnabled = true;
  8. protected $dataTypeName = "PAN";
  9. protected $dataTypeFieldGroup = "credit_card_data";
  10. protected $dataTypeFieldGroupOrder = 10;
  11. protected $jsModules = array("PAN.js");
  12. private static $creditCardData = array(
  13. "visa" => array(
  14. "prefix" => array(4539, 4556, 4916, 4532, 4929, 40240071, 4485, 4716, 4),
  15. "length" => "13,16",
  16. "formats" => array(
  17. "XXXXXXXXXXXXX",
  18. "XXXX XXX XX XXXX",
  19. "XXXXXXXXXXXXXXXX",
  20. "XXXX XXXX XXXX XXXX",
  21. "XXXXXX XXXXXX XXXX",
  22. "XXX XXXXX XXXXX XXX",
  23. "XXXXXX XXXXXXXXXX"
  24. )
  25. ),
  26. "visaElectron" => array(
  27. "prefix" => array(4026, 417500, 4508, 4844, 4913, 4917),
  28. "length" => "16",
  29. "formats" => array(
  30. "XXXXXXXXXXXXXXXX",
  31. "XXXX XXXX XXXX XXXX",
  32. "XXXXXX XXXXXX XXXX",
  33. "XXX XXXXX XXXXX XXX",
  34. "XXXXXX XXXXXXXXXX"
  35. )
  36. ),
  37. "mastercard" => array(
  38. "prefix" => array(51, 52, 53, 54, 55),
  39. "length" => "16",
  40. "formats" => array(
  41. "XXXXXXXXXXXXXXXX",
  42. "XXXX XXXX XXXX XXXX",
  43. "XXXXXX XXXXXX XXXX",
  44. "XXX XXXXX XXXXX XXX",
  45. "XXXXXX XXXXXXXXXX"
  46. )
  47. ),
  48. "amex" => array(
  49. "prefix" => array(34, 37),
  50. "length" => "15",
  51. "formats" => array(
  52. "XXXXXXXXXXXXXXX",
  53. "XXXX XXXXXX XXXXX"
  54. )
  55. ),
  56. "discover" => array(
  57. "prefix" => array(6011, 644, 645, 646, 647, 648, 649, 65),
  58. "length" => "16",
  59. "formats" => array(
  60. "XXXXXXXXXXXXXXXX",
  61. "XXXX XXXX XXXX XXXX",
  62. "XXXXXX XXXXXX XXXX",
  63. "XXX XXXXX XXXXX XXX",
  64. "XXXXXX XXXXXXXXXX"
  65. )
  66. ),
  67. "carteBlanche" => array(
  68. "prefix" => array(300, 301, 302, 303, 304, 305),
  69. "length" => "14",
  70. "formats" => array(
  71. "XXXXXXXXXXXXXXX",
  72. "XXXX XXXXXX XXXXX"
  73. )
  74. ),
  75. "dinersClubInt" => array(
  76. "prefix" => array(36),
  77. "length" => "14",
  78. "formats" => array(
  79. "XXXXXXXXXXXXXXX",
  80. "XXXX XXXXXX XXXXX"
  81. )
  82. ),
  83. "dinersClubEnRoute" => array(
  84. "prefix" => array(2014, 2149),
  85. "length" => "15",
  86. "formats" => array(
  87. "XXXXXXXXXXXXXXX",
  88. "XXXX XXXXXX XXXXX"
  89. )
  90. ),
  91. "jcb15" => array(
  92. "prefix" => array(2131, 1800),
  93. "length" => "15,16",
  94. "formats" => array(
  95. "XXXXXXXXXXXXXXX",
  96. "XXXX XXXXXX XXXXX",
  97. "XXXXXXXXXXXXXXXX",
  98. "XXXX XXXX XXXX XXXX",
  99. "XXXXXX XXXXXX XXXX",
  100. "XXX XXXXX XXXXX XXX",
  101. "XXXXXX XXXXXXXXXX"
  102. )
  103. ),
  104. "jcb16" => array(
  105. "prefix" => array(31, 309),
  106. "length" => "15,16",
  107. "formats" => array(
  108. "XXXXXXXXXXXXXXX",
  109. "XXXX XXXXXX XXXXX",
  110. "XXXXXXXXXXXXXXXX",
  111. "XXXX XXXX XXXX XXXX",
  112. "XXXXXX XXXXXX XXXX",
  113. "XXX XXXXX XXXXX XXX",
  114. "XXXXXX XXXXXXXXXX"
  115. )
  116. ),
  117. "maestro" => array(
  118. "prefix" => array(5018, 5038, 6304, 6759, 6761, 6762, 6763, 5893, 56, 57, 58),
  119. "length" => "12-19",
  120. "formats" => array(
  121. "XXXXXXXXXXXX",
  122. "XXXXXXXXXXXXX",
  123. "XXXX XXX XX XXXX",
  124. "XXXXXXXXXXXXXX",
  125. "XXXX XXXXXX XXXX",
  126. "XXXXXXXXXXXXXXX",
  127. "XXXX XXXXXX XXXXX",
  128. "XXXXXXXXXXXXXXXX",
  129. "XXXX XXXX XXXX XXXX",
  130. "XXXXXX XXXXXX XXXX",
  131. "XXX XXXXX XXXXX XXX",
  132. "XXXXXX XXXXXXXXXX",
  133. "XXXXXXXXXXXXXXXXX",
  134. "XXXXXXXXXXXXXXXXXX",
  135. "XXXXXXXXXXXXXXXXXXX",
  136. "XXXXXX XX XXXX XXXX XXX"
  137. )
  138. ),
  139. "solo" => array(
  140. "prefix" => array(6334, 6767),
  141. "length" => "16,18,19",
  142. "formats" => array(
  143. "XXXXXXXXXXXXXXXX",
  144. "XXXX XXXX XXXX XXXX",
  145. "XXXXXX XXXXXX XXXX",
  146. "XXX XXXXX XXXXX XXX",
  147. "XXXXXX XXXXXXXXXX",
  148. "XXXXXXXXXXXXXXXXXX",
  149. "XXXXXXXXXXXXXXXXXXX",
  150. "XXXXXX XX XXXX XXXX XXX"
  151. )
  152. ),
  153. "switch" => array(
  154. "prefix" => array(4903, 4905, 4905, 4911, 4936, 564182, 633110, 6333, 6759),
  155. "length" => "16,18,19",
  156. "formats" => array(
  157. "XXXXXXXXXXXXXXXX",
  158. "XXXX XXXX XXXX XXXX",
  159. "XXXXXX XXXXXX XXXX",
  160. "XXX XXXXX XXXXX XXX",
  161. "XXXXXX XXXXXXXXXX",
  162. "XXXXXXXXXXXXXXXXXX",
  163. "XXXXXXXXXXXXXXXXXXX",
  164. "XXXXXX XX XXXX XXXX XXX"
  165. )
  166. ),
  167. "laser" => array(
  168. "prefix" => array(6304, 6706, 6771, 6709),
  169. "length" => "16-19",
  170. "formats" => array(
  171. "XXXXXXXXXXXXXXXX",
  172. "XXXX XXXX XXXX XXXX",
  173. "XXXXXX XXXXXX XXXX",
  174. "XXX XXXXX XXXXX XXX",
  175. "XXXXXX XXXXXXXXXX",
  176. "XXXXXXXXXXXXXXXXX",
  177. "XXXXXXXXXXXXXXXXXX",
  178. "XXXXXXXXXXXXXXXXXXX",
  179. "XXXXXX XX XXXX XXXX XXX"
  180. )
  181. )
  182. );
  183. public function __construct($runtimeContext) {
  184. for ($i=622126; $i<=622925; $i++) {
  185. $this->creditCardData["discover"][] = $i;
  186. }
  187. for ($i=3528; $i<=3589; $i++) {
  188. $this->creditCardData["jcb16"][] = $i;
  189. }
  190. parent::__construct($runtimeContext);
  191. }
  192. public function generate($generator, $generationContextData) {
  193. $options = $generationContextData["generationOptions"];
  194. if ($options["cc_brand"] == "rand_card") {
  195. $options = $this->setRandomCardInfo($options);
  196. }
  197. $ccLength = self::getRandomPANLength($options["cc_length"]);
  198. $ccFormat = self::getRandomPANFormat($options["cc_format"], $options["cc_length"]);
  199. $ccSeparator = self::getRandomPANSeparator($options["cc_separator"], $options["cc_format"]);
  200. $ccData = self::getCreditCardData($options["cc_brand"]);
  201. $card = self::generateCreditCardNumber($ccData["prefix"], $ccLength);
  202. $cardNumber = $this->convertFormat($ccLength, $ccFormat, $ccSeparator, $card);
  203. if (empty($cardNumber)) {
  204. $cardNumber = "$ccLength, $ccFormat, {$options["cc_brand"]}, {$options["cc_format"]}";
  205. }
  206. return array(
  207. "display" => $cardNumber
  208. );
  209. }
  210. public function setRandomCardInfo($options) {
  211. $selectedCard = $options["cc_random_card"][array_rand($options["cc_random_card"])];
  212. if ($selectedCard == "jcb") {
  213. $jcbCards = array("jcb15", "jcb16");
  214. $selectedCard = $jcbCards[mt_rand(0, 1)];
  215. }
  216. $cardData = self::getCreditCardData($selectedCard);
  217. $options["cc_brand"] = $selectedCard;
  218. $options["cc_format"] = $cardData["formats"][array_rand($cardData["formats"])];
  219. $options["cc_length"] = self::getRandomPANLength($cardData["length"]);
  220. return $options;
  221. }
  222. public function getRowGenerationOptions($generator, $postdata, $colNum, $numCols) {
  223. return array(
  224. "cc_brand" => $postdata["dtExample_$colNum"],
  225. "cc_separator" => $postdata["dtOptionPAN_sep_$colNum"],
  226. "cc_format" => $postdata["dtOption_$colNum"],
  227. "cc_length" => $postdata["dtOptionPAN_digit_$colNum"],
  228. "cc_random_card" => $postdata["dtOptionPAN_randomCardFormat_$colNum"]
  229. );
  230. }
  231. public function getExampleColumnHTML() {
  232. $L = Core::$language->getCurrentLanguageStrings();
  233. $html =<<< END
  234. <select name="dtExample_%ROW%" id="dtExample_%ROW%">
  235. <option value="">{$L["please_select"]}</option>
  236. <option value="mastercard">{$this->L["mastercard"]}</option>
  237. <option value="visa">{$this->L["visa"]}</option>
  238. <option value="visaElectron">{$this->L["visa_electron"]}</option>
  239. <option value="amex">{$this->L["americanexpress"]}</option>
  240. <option value="discover">{$this->L["discover"]}</option>
  241. <option value="carteBlanche">{$this->L["carte_blanche"]}</option>
  242. <option value="dinersClubInt">{$this->L["diners_club_international"]}</option>
  243. <option value="dinersClubEnRoute">{$this->L["enRoute"]}</option>
  244. <option value="jcb">{$this->L["jcb"]}</option>
  245. <option value="maestro">{$this->L["maestro"]}</option>
  246. <option value="solo">{$this->L["solo"]}</option>
  247. <option value="switch">{$this->L["switch"]}</option>
  248. <option value="laser">{$this->L["laser"]}</option>
  249. <option value="rand_card">{$this->L["rand_card"]}</option>
  250. </select>
  251. END;
  252. return $html;
  253. }
  254. public function getOptionsColumnHTML() {
  255. $html =<<< END
  256. <span id="dtOptionPAN_cardDigitSection_%ROW%" style="display:inline;">
  257. {$this->L["length"]}
  258. <input type="text" name="dtOptionPAN_digit_%ROW%" id="dtOptionPAN_digit_%ROW%" style="width: 60px" readonly="readonly" />
  259. </span>
  260. <span id="dtOptionPAN_cardSeparator_%ROW%" style="display:inline;">
  261. {$this->L["separators"]}
  262. <input type="text" name="dtOptionPAN_sep_%ROW%" id="dtOptionPAN_sep_%ROW%" style="width: 78px" value=" " title="{$this->L["separator_help"]}" />
  263. </span>
  264. <span id="dtOptionPAN_cardFormat_%ROW%">
  265. {$this->L["ccformats"]}
  266. <textarea name="dtOption_%ROW%" id="dtOption_%ROW%" title="{$this->L["format_title"]}" style="height: 100px; width: 260px"></textarea>
  267. </span>
  268. <div id="dtOptionPAN_randomCardFormatSection_%ROW%" style="display:none;">
  269. {$this->L["ccrandom"]}
  270. <select multiple="multiple" name="dtOptionPAN_randomCardFormat_%ROW%[]" id="dtOptionPAN_randomCardFormat_%ROW%" title="{$this->L["rand_brand_title"]}" style="height: 100px; width: 260px">
  271. <option value="mastercard">{$this->L["mastercard"]}</option>
  272. <option value="visa">{$this->L["visa"]}</option>
  273. <option value="visaElectron">{$this->L["visa_electron"]}</option>
  274. <option value="amex">{$this->L["americanexpress"]}</option>
  275. <option value="discover">{$this->L["discover"]}</option>
  276. <option value="carteBlanche">{$this->L["carte_blanche"]}</option>
  277. <option value="dinersClubInt">{$this->L["diners_club_international"]}</option>
  278. <option value="dinersClubEnRoute">{$this->L["enRoute"]}</option>
  279. <option value="jcb">{$this->L["jcb"]}</option>
  280. <option value="maestro">{$this->L["maestro"]}</option>
  281. <option value="solo">{$this->L["solo"]}</option>
  282. <option value="switch">{$this->L["switch"]}</option>
  283. <option value="laser">{$this->L["laser"]}</option>
  284. </select>
  285. </div>
  286. END;
  287. return $html;
  288. }
  289. public function getDataTypeMetadata() {
  290. return array(
  291. "SQLField" => "varchar(255)",
  292. "SQLField_Oracle" => "varchar2(255)",
  293. "SQLField_MSSQL" => "VARCHAR(255) NULL"
  294. );
  295. }
  296. public function getHelpHTML() {
  297. $html =<<<EOF
  298. <p>
  299. {$this->L["pan_help_intro"]}
  300. <b>{$this->L["mastercard"]}</b>, <b>{$this->L["visa"]}</b>, <b>{$this->L["visa_electron"]}</b>,
  301. <b>{$this->L["americanexpress"]}</b>, <b>{$this->L["discover"]}</b>, <b>{$this->L["american_diners"]}</b>,
  302. <b>{$this->L["carte_blanche"]}</b>, <b>{$this->L["diners_club_international"]}</b>, <b>{$this->L["enroute"]}</b>,
  303. <b>{$this->L["jcb"]}</b>, <b>{$this->L["maestro"]}</b>, <b>{$this->L["solo"]}</b>,
  304. <b>{$this->L["switch"]}</b>, <b>{$this->L["laser"]}</b>.
  305. </p>
  306. EOF;
  307. return $html;
  308. }
  309. /**
  310. * @param $ccLength
  311. * @param $ccFormat
  312. * @param $ccSeparator
  313. * @param $ccNumber
  314. * @return array|bool|string
  315. */
  316. private static function convertFormat($ccLength, $ccFormat, $ccSeparator, $ccNumber) {
  317. // TODO pity we need this extra test on each call
  318. if ($ccLength == strlen($ccNumber)) {
  319. $a = self::convertXtoNumber($ccFormat, $ccNumber);
  320. if ($a == $ccNumber) {
  321. return $a;
  322. } else {
  323. return implode($ccSeparator, $a);
  324. }
  325. } else {
  326. return false;
  327. }
  328. }
  329. /**
  330. * Convert X's to the specified number
  331. */
  332. private static function convertXtoNumber($chosen_format, $ccnumber){
  333. $positions = array();
  334. $pos = -1;
  335. while (($pos = strpos($chosen_format, " ", $pos+1)) !== false) {
  336. $positions[] = $pos;
  337. }
  338. if (empty($positions)) {
  339. return $ccnumber;
  340. }
  341. $result = array();
  342. $result_f = array();
  343. $j = 1;
  344. $numPositions = count($positions);
  345. for ($i=0; $i<$numPositions; $i++) {
  346. $result[$i] = substr($ccnumber, 0, $positions[$i]-$i);
  347. }
  348. $result_f[0] = ($result[0]);
  349. for ($i=0; $i<$numPositions-1; $i++) {
  350. $result_f[$j] = substr($result[$j], $positions[$i]-$i);
  351. $j++;
  352. }
  353. $result_f[$numPositions] = substr($ccnumber, ($positions[$numPositions-1])-($numPositions-1));
  354. return $result_f;
  355. }
  356. private static function getRandomPANFormat($userSelectedFormats, $randCardLength) {
  357. // if no format is selected then by default continuous number of that length will be displayed
  358. if ($userSelectedFormats == "") {
  359. return str_repeat("X", $randCardLength);
  360. }
  361. $formats = explode("\n", $userSelectedFormats);
  362. $sortedFormat = array();
  363. $not_i = 0;
  364. $numFormats = count($formats);
  365. for ($fc=0; $fc<$numFormats; $fc++){
  366. $count_X = "0"; // get count of X's to match with the card length
  367. $len = strlen($formats[$fc]);
  368. for ($i=0; $i<$len; $i++) {
  369. if ($formats[$fc][$i] == "X") { // PHP version of a charAt
  370. $count_X++;
  371. }
  372. }
  373. if ($count_X == $randCardLength) {
  374. $sortedFormat[$not_i] = $formats[$fc];
  375. $not_i++;
  376. }
  377. }
  378. $chosenFormat = "";
  379. $sortedFormatCount = count($sortedFormat);
  380. if ($sortedFormatCount >= 1) {
  381. $chosenFormat = $sortedFormat[mt_rand(0, $sortedFormatCount-1)];
  382. }
  383. return trim($chosenFormat);
  384. }
  385. // will give a random separator
  386. private static function getRandomPANSeparator($separators, $randCardFormat) {
  387. $chosenSep = "";
  388. if (preg_match("/[^X]/", $randCardFormat)) {
  389. $separatorList = explode("|", $separators);
  390. $chosenSep = $separatorList[rand(0, count($separatorList)-1)];
  391. // if no separator was entered
  392. if ($separators == "") {
  393. $chosenSep = " ";
  394. }
  395. }
  396. return $chosenSep;
  397. }
  398. private static function getRandomPANLength($userSelectedLength) {
  399. // this would be better
  400. // $groups = explode(",", $userSelectedLength);
  401. // for ($i=0; $i<count($groups); $i++) {
  402. // $groups = explode(",", $groups[$i]);
  403. // }
  404. // if there's more than 1 card length then pick a random one
  405. if ($userSelectedLength == "12-19") {
  406. $userSelectedLength = "12,13,14,15,16,17,18,19";
  407. } else if ($userSelectedLength == "16-19") {
  408. $userSelectedLength = "16,17,18,19";
  409. }
  410. $lengths = explode(",", $userSelectedLength);
  411. $chosenLength = 0;
  412. if (count($lengths) >= 1) {
  413. $chosenLength = $lengths[mt_rand(0, count($lengths)-1)];
  414. }
  415. return $chosenLength;
  416. }
  417. // --------------------------------------------------------------------------------------------
  418. // Public functions
  419. public static function generateCreditCardNumber($prefixList, $length) {
  420. $ccNumber = $prefixList[array_rand($prefixList)];
  421. // generate digits
  422. $count = strlen($ccNumber);
  423. while ($count < ($length - 1)) {
  424. $ccNumber .= mt_rand(0, 9);
  425. $count++;
  426. }
  427. // calculate sum
  428. $sum = 0;
  429. $pos = 0;
  430. $reversedCCnumber = strrev($ccNumber);
  431. while ($pos < $length - 1) {
  432. $odd = $reversedCCnumber[$pos]*2;
  433. if ($odd > 9) {
  434. $odd -= 9;
  435. }
  436. $sum += $odd;
  437. if ($pos != ($length - 2)) {
  438. $sum += $reversedCCnumber[$pos+1];
  439. }
  440. $pos += 2;
  441. }
  442. // calculate check digit
  443. $checkDigit = ((floor($sum/10) + 1) * 10 - $sum) % 10;
  444. $ccNumber .= $checkDigit;
  445. return $ccNumber;
  446. }
  447. public static function getCreditCardData($ccBrand) {
  448. $data = array();
  449. reset(self::$creditCardData);
  450. while (list($currBrand, $ccData) = each(self::$creditCardData)) {
  451. if ($ccBrand != $currBrand) {
  452. continue;
  453. }
  454. $data = $ccData;
  455. }
  456. return $data;
  457. }
  458. public static function getAllCreditCardData() {
  459. return self::$creditCardData;
  460. }
  461. }