setCcNum($ccNum); } if (null !== $expMonth && null !== $expYear) { $this->setExp($expMonth, $expYear); } if (null !== $cvm) { $this->setCvm($ccNum); } if (null !== $cvmState) { $this->setCvmState($cvmState); } } /** * Validates and sets the credit card number. * * @param string $ccNum * @return \LinkPoint\Payment_CreditCard * @throws \LinkPoint\Exception */ public function setCcNum($ccNum) { if ($ccNum == 0) { throw new \LinkPoint\Exception('Invalid credit card number'); } $revcode = strrev($ccNum); $sum = 0; for ($i = 0; $i < strlen($revcode); $i++) { $current_num = intval($revcode[$i]); if ($i & 1) { $current_num *= 2; } $sum += ($current_num % 10); if ($current_num > 9) { $sum += 1; } } if (($sum % 10) !== 0) { throw new \LinkPoint\Exception('Invalid credit card number'); } $this->_ccNum = $ccNum; return $this; } /** * Returns the credit card number. * @return string */ public function getCcNum() { return $this->_ccNum; } /** * Sets the raw MagStripe data from a card * @param string $track * @return \LinkPoint\Payment_CreditCard * @throws \LinkPoint\Exception */ public function setTrack($track) { if (substr($track, 0, 2) != '%B') { throw new \LinkPoint\Exception('Invalid track data'); } if (!preg_match('/^%B(\d{0,19})\^[\w\s\/]{2,26}\^(\d{7})\w*\?/', $track, $matches)) { throw new \LinkPoint\Exception('Could not parse track data'); } $this->setCcNum($matches[1]); $this->setExp(substr($matches[2], 3, 2), substr($matches[2], 0, 2)); $this->_track = $track; return $this; } /** * Returns the raw MagStripe data from a card * * @return string|bool */ public function getTrack() { if (!empty($this->_track)) { return $this->_track; } return false; } /** * Sets the expiration date. * * @param int $expMonth * @param int $expYear * @return \LinkPoint\Payment_CreditCard * @throws \LinkPoint\Exception */ public function setExp($expMonth, $expYear) { if (((int) substr($expYear, -2, 2) < (int) date('y')) && ((int) $expMonth < (int) date('j'))) { throw new \LinkPoint\Exception('Expiration date is in the past: '.$expMonth.'/'.$expYear); } $this->_expMonth = $expMonth; $this->_expYear = $expYear; return $this; } /** * @param null $part * @return array|int */ public function getExp($part = null) { if ($part == 'month') { return $this->_expMonth; } elseif ($part == 'year') { return $this->_expYear; } return array($this->_expMonth, $this->_expYear); } /** * Sets the CVM value. * * @param int $cvm * @param string|null $cvmState * @return \LinkPoint\Payment_CreditCard * @throws \LinkPoint\Exception */ public function setCvm($cvm, $cvmState = null) { $this->_cvm = $cvm; if (!empty($cvmState)) { $this->setCvmState($cvmState); } return $this; } /** * Returns the CVM value, or FALSE if no CVM is provided. * * @return int|boolean */ public function getCvm() { if ($this->_cvm) { return $this->_cvm; } return false; } /** * Sets the CVM state. * * @param string $reason * @return \LinkPoint\Payment_CreditCard * @throws \LinkPoint\Exception */ public function setCvmState($reason) { if (!in_array($reason, array('provided','not_provided','illegible','not_present','no_imprint'))) { throw new \LinkPoint\Exception('Invalid CVM reason'); } $this->_cvmState = $reason; return $this; } /** * Returns the CVM state. * * @return string */ public function getCvmState() { if (($this->_cvmState == Payment_CreditCard::CVM_NOT_PROVIDED) && !empty($this->_cvm)) { return Payment_CreditCard::CVM_PROVIDED; } return $this->_cvmState; } /** * Get global CVM/CVV2 states * * @return array */ public function getCvmStates() { $cvmStates = array( Payment_CreditCard::CVM_NOT_PROVIDED, Payment_CreditCard::CVM_ILLEGIBLE, Payment_CreditCard::CVM_NOT_PRESENT, Payment_CreditCard::CVM_NO_IMPRINT ); return $cvmStates; } /** * Generate credit card number for testing * * @param int $prefix start of the CC number as a string * @param int $length length of the CC number to generate * @return string */ public function genNumber($prefix = 4227, $length = 16) { $ccnumber = $prefix; while(strlen($ccnumber) < ($length - 1)) { $ccnumber .= rand(0, 9); } $sum = 0; $pos = 0; $reversedCCnumber = strrev($ccnumber); while($pos < ($length - 1)) { $odd = ($reversedCCnumber[$pos] * 2); if ($odd > 9) { $odd -= 9; } $sum += $odd; if ($pos != ($length - 2)) { $sum += $reversedCCnumber[($pos + 1)]; } $pos += 2; } $checkdigit = ((((floor(($sum / 10)) + 1) * 10) - $sum) % 10); $ccnumber .= $checkdigit; return $ccnumber; } /** * Convert the credit card object into an XML entity * that can be sent to the payment processor. */ public function __toString() { $doc = new \DOMDocument(); // Root Element $xml = $doc->createElement(Payment_CreditCard::XML_ENTITY); if (empty($this->_track)) { // cc num $xml->appendChild($doc->createElement('cardnumber', $this->getCcNum())); // cc exp month $xml->appendChild($doc->createElement('cardexpmonth', str_pad($this->getExp('month'), 2, '0', STR_PAD_LEFT))); // cc exp year $xml->appendChild($doc->createElement('cardexpyear', substr($this->getExp('year'), -2, 2))); } else { $xml->appendChild($doc->createElement('track', $this->getTrack())); } // cvm if ($this->_cvm != false) { $xml->appendChild($doc->createElement('cvmvalue', $this->getCvm())); } // cvm state $xml->appendChild($doc->createElement('cvmindicator', $this->getCvmState())); $doc->appendChild($xml); return $doc->saveHTML(); } }