Thunder Data Systems

Using PHP’s preg_match() to Parse Credit Card Data from Magnetic Swipe Readers

Using PHP’s preg_match() to Parse Credit Card Data from Magnetic Swipe Readers

Magnetic swipe card readers via USB can facilitate faster credit card processing. This is particularly important for our ThunderTix clients whose box offices must move patrons past the ticket window as quickly as possible. This week, a client from one of our legacy PHP apps asked us if we could implement a swipe reader for his own administrative checkout page. I thought it would be a good time to create a tutorial for parsing the credit card string using PHP and regular expressions.

Our client wanted the ability to enter either all form fields during the checkout process by manual entry or only some of the required fields when swiping the card during a purchase. We create a form for the checkout:

<span style='required'>*</span> - Indicates required field.
<div class='fields'>First Name</div>
  <input type=text name='first_name'><span style='required'>*</span>
</div>
<div class='fields'>Last Name</div>
  <input type=text name='last_name'><span style='required'>*</span>
</div>
<div class='fields'>Expiration</div>
  <input type=text size=8 name='expiration'><span style='required'>*</span>(MMYY)
</div>
<div class='fields'>CVV Code</div>
  <input type=text size=8 name='cvv'><span style='required'>*</span>
</div>
<div class='fields'>Credit Card Number</div>
  <input type=text name='card'><span style='required'>*</span>
</div>

Now, how do we bypass the validation for the required fields? Using regular expressions, we can both assess whether the credit card post variable is from the magnetic stripe data and parse the string itself when a match exists.

The string generated from a magnetic stripe reader looks like this :

    %B4444490633714269^DOE/JANE B^12101010000000379000000?    

The data from the string is divided by the start sentinel (%B), the end sentinel (?), and field separators (^ and /). So, we need to create a regular expression to parse the pieces out. We’ll create the following regex pattern and save it to the $swipe variable.

$swipe = "/^(%B)([0-9]{16})(^)([a-zA-Z-s]*)(/)([a-zA-Z-s]*)(^)([0-9]{2})([0-9]{2})(.)*?$/";

Let’s break down our regular expression:

  /^(%B)  = Start Sentinel and format Code (alpha only)
([0-9]{16}) = Primary account number is 16 digits long, accepts only numeric characters
(^) = Field Separator
([a-zA-Z-]*) = Last Name contains only alpha characters, a space, or a dash. Note the - and sare escaped
(/) = Separator between first and last name (escaped forward slash)
([a-zA-Z-]*) = First Name accepts only alpha, spaces, or dashes
(^) = Field Separator
([0-9]{2}) = Expiration year is two digits, accepts only numeric characters
([0-9]{2}) = Expiration month is two digits, accepts only numeric characters
(.)*?$/ = The "(.)*" sequence is any other characters that follow through to the end sentinel for the mag data represented by a the Question Mark is reMagnetic Data 'end sentinenel'

So, now we’ll move onto the form’s action. We’ll use preg_match to compare our $_POST['card'] string to our regex contained in $swipe. The result is held in the $matches array. If a match exists, it is held in $matches[0], and $matches[1] contains the first parenthesized value, $matches[2] contains the next (of actual card number), and so on. We’ll assign these to the $_POST variables, so our form can be processed as if the data had been entered into the fields individually. If there is no match, standard validation processing occurs.

if($_POST['action'] == 'pay') {
  $swipe = "/^(%B)([0-9]{16})(^)([a-zA-Z-s]*)(/)([a-zA-Z-s]*)(^)([0-9]{2})([0-9]{2})(.)*?$/";
  
  if (preg_match($swipe, $_POST['x_card_num'], $matches)) {
    $_POST['card'] =  $matches[2];
    $_POST['first_name'] = $matches[6];
    $_POST['last_name'] =  $matches[4];
    $_POST['expiration'] = $matches[9]."".$matches[8];
  }  else {
    perform_validation_procedures ...
}

A couple of final notes: if using Authorize.net as your gateway, make sure you have the Address Verification Service (AVS) matching turned off. This will prevent swipes from passing and result in a declined transaction since no address is being passed. Likewise, you may also want to turn off the CVV requirement to prevent a rejection. Otherwise, you can enter the CVV number in the CVV form field prior to swiping the card. Also, make sure you properly order the expiration month and year and the first and last names, or your transaction will fail.

Happy parsing!

Leave a Reply

Your email address will not be published. Required fields are marked *