PayTrace Client Side Encryption (PHP / IIS)

This is a quick for-developers-only guide of how to get your PHP/JS code (Windows) talking to PayTrace’s API.  I chose the Client Side Encryption as being our first time out, I wanted the least amount of strictness in PCI compliance.   This guide assumes you know PHP, JS, JQuery, a little of what an API does, enough to paste some JSON together and of course your HTML, CSS, etc.   You’re a developer, you have all the code provided open source, but this is a quick A-B-C of what code I used and how I got it working on Windows (IIS7) and hurdles I ran into.

All code here is readily available on GitHub, but if you’d like my version of it, download it on my Gist.

Ready to hit Submit?

Before doing this, I had already built out a complete cart system for our customers.  They can view invoices, choose what to pay on those invoices, and when totaled, choose to pay by check or credit card.  The employee end is nearly identical, except, they must choose which customer to pay for.  In both cases,  they are at a form ready to hit “Checkout” and complete the transaction.  The method below only supports credit card, I used a different solution for checks.  There, I will submit that amount and needed billing information to PayTrace and await for the response.  The response (payment failure or success) goes directly back to our database.

Get What You Need

  1. Request a Sandbox Account (it took about an hour for them to respond)
  2. Login Sandbox Account
  3. Use the guide for Security Settings
  4. In your sandbox account Go to: Integration and Download Public Key (.pem)
  5. Download the PHP Github code

Preparing your Server

SSL TLS 1.2

PayTrace requires SSL TLS 1.2.   What if you’ve set up your server with SSL but don’t know if it quite makes it up to grade?  Run the website you’ll be using thru SSL Labs testing tool for a quick check to see if you have SSL TLS 1.2.   This nifty site will do a scan and give you a letter grade.  If you do not make an “A”, it tells you exactly what you are missing.  You can work with your Server Admin to bring the server up to standards and move on.

MIME Type

If you’re using client-side encryption you’ll need to save that public key you downloaded to your web server and you’ll need to add its MIME type.

extension: pem
type: application/x-pem-file

If you don’t do this, you’ll likely get Ajax “key not found” errors.

PHP Version

In some initial curl tests I was trying out, I specifically had problems passing the SSL handshake with version 5.3 of PHP.  I upgraded to 7.0 and the errors disappeared.  Only noting this for those who might have done everything else and are still getting errors.

Test Your Server

  1. Upload the files you got from GitHub’s PhpJsonApiSamples folder to a test folder on your webserver
  2. Browse to its /default.html file
  3. Click KeyedSaleJson

If this runs correctly, you should see in the response:

Keyed sale : Success !
Http Status : 200 OK

Great, your server is up to par. Lets move on to the code.

Utilizing Code from PayTrace

Begin by uploading:

  • PhpApiSettings.php
  • Utilities.php
  • Json.php
  • public_key.pem

The first three from the GitHub’s PhpJsonApiSamples to your webserver, for the public_key.pem you log in to the sandbox account / API Integration / download.


You’ll be creating two pages, checkoutInfo.php and checkoutResponse.php.  After the user has a total and hits “Checkout”,  I send them to checkoutInfo.php to collect billing information.  This particular page has:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<!-- This is the PayTrace End-to-End Encryption library: -->
<script src="https://api.paytrace.com/assets/e2ee/paytrace-e2ee.js"></script>
<script>
 
    // set the key from an AJAX call
    $(document).ready(function(){
        paytrace.setKeyAjax('/public_key.pem') ;// set the key from an AJAX call (in this case via a relative URL)
    });
 
    $(document).ready( function(){
        $("#DemoForm").submit(function(e){
            //To prevent the default action of the submit
            e.preventDefault();
 
            // Do your validation and if all validations are met,
            // Next is to submit the form with paytrace.submitEncrypted.
            if ($("#ccNumber").val() && $("#ccCSC").val()) {
                //if all validations are met, submit the form to Paytrace library for encyption.
                paytrace.submitEncrypted("#DemoForm");
            }
            else{
                alert("CCNumber and CSC number are required ! ");
            }
        });
    });
 
 $(document).ready( function(){
      $("#DemoForm").submit(function(){
        $.post($(this).attr('action'), $(this).serialize(), function(json) {
          alert(json);
        }, 'json');
        return false;
      });
    });
</script>

In case you skipped through documentation: PayTrace uses JQuery-1.11.1.  I used Google’s CDN in the script above.

In this same form, I also had a place for billing address.  I pre-filled it out with their billing address from the account (the random PHP variables you see) but the user can change each field as needed before hitting submit.

My sample form:

<form name="DemoForm" id="DemoForm" action="checkoutResponse.php" method="post">
    <label>Company Name:</label>
    <input id="name" name="name" class="form-control" type="text" value="<?php echo $name ?>" />
    <label>Address Line 1: </label>
    <input id="street_address" name="street_address" class="form-control" type="text" value="<?php echo $addr1 ?>" />
    <label>Address Line 2:</label>
    <input id="street_address2" name="street_address2" class="form-control" type="text" value="<?php echo $addr2 ?>" />
    <label>City:</label>
    <input id="city" name="city" type="text" class="form-control" value="<?php echo $city ?>" />
    <label>State:</label>
    <input id="state" name="state" type="text" class="form-control" value="<?php echo $state ?>" />
    <label>Zip:</label>
    <input id="zip" name="zip" type="text" class="form-control" value="<?php echo $zip ?>" />
    <label>Country:</label>
    <input id="country" name="country" type="hidden" class="form-control" value="US" />
    <label>Payment Amount:</label> 
    <input id="amount" type="text" readonly name="amount" value="<?php echo $amount ?>" />">
    <label>First Name:</label>
    <input type="text" name="firstName" id="firstName" class="form-control" />
    <label>Last Name:</label>
    <input type="text" name="lastName" id="lastName" class="form-control" />
    <label>Credit Card Number:</label>
    <input id="ccNumber" type="text" class="form-control pt-encrypt" name="ccNumber" placeholder="Credit card number" />
    <label>Expiration Month</label>
    <select name="expiration_month" id="expiration_month" class="form-control">
        <option>01</option>
        <option>02</option>
        <option>03</option>
        <option>04</option>
        <option>05</option>
        <option>06</option>
        <option>07</option>
        <option>08</option>
        <option>09</option>
        <option>10</option>
        <option>11</option>
        <option>12</option>
    </select>
    <label>Expiration Year</label>
    <select name="expiration_year" id="expiration_year" class="form-control">
        <option> <?php echo date("Y")?> </option>
        <option> <?php echo date("Y")+1 ?> </option>
        <option> <?php echo date("Y")+2 ?> </option>
        <option> <?php echo date("Y")+3 ?> </option>
        <option> <?php echo date("Y")+4 ?> </option>
        <option> <?php echo date("Y")+5 ?> </option>
        <option> <?php echo date("Y")+6 ?> </option>
        <option> <?php echo date("Y")+7 ?> </option>
        <option> <?php echo date("Y")+8 ?> </option>
        <option> <?php echo date("Y")+9 ?> </option>
        <option> <?php echo date("Y")+10 ?> </option>
        <option> <?php echo date("Y")+11 ?> </option>
        <option> <?php echo date("Y")+12 ?> </option>
        <option> <?php echo date("Y")+13 ?> </option>
        <option> <?php echo date("Y")+14 ?> </option>
        <option> <?php echo date("Y")+15 ?> </option>
        <option> <?php echo date("Y")+16 ?> </option>
        <option> <?php echo date("Y")+17 ?> </option>
        <option> <?php echo date("Y")+18 ?> </option>
        <option> <?php echo date("Y")+19 ?> </option>
        <option> <?php echo date("Y")+20 ?> </option>
    </select>
    <label>Security code:</label>
    <input id="ccCSC" type="text" class="form-control pt-encrypt" name="ccCSC" placeholder="Card security code" />
    <input type="submit" id="enterPayment" value="Submit Your Payment" name="commit" />
</form>

How It Works

  1.  User fills out billing info on the form in checkoutInfo.php
  2.  The code above brings in PayTrace’s Client Side Encryption library (paytrace-e2ee.js)
  3.  The script captures the users “Submit” form action and stops it to …
  4.  Join it with your specific Public Key (.pem file) and uses the PayTrace library to encrypt the card number and csc number
  5.  ccNumber and csc becomes:  encrypted_number and encrypted_csc
  6.  The script then continues on submitting the form to the API, using an encrypted number/csc instead and letting you duck some strict PCI restrictions because you never keep the card nor sent the actual credit card number

Handle the Response

My checkoutInfo.php page submits to checkoutResponse.php.   This page preps your form data and sends it as JSON, waiting for a response.  Upon response, it displays a pretty checkmark or xmark image (you’ll have to get your own).

On checkoutResponse.php, I used PayTrace’s files:

<?php
    include 'PhpApiSettings.php';
    include 'Utilities.php';
    include 'Json.php';
?>

Adding a Card Scanner / Swiper

If you’re getting successful responses, it’s time to go back to checkoutInfo.php and add the ability to card swipe.

For testing, the card reader / scanner I used was the MagTek Dynamag with USB Keyboard Emulation (Part Number 21073062 – Set at Security Level 2 or 3).  We entered into contact with a third party advisor that suggested PayTrace for ease of use and suggested this as the most popular model.  It was as easy as plug and play as they promised, but use the USB cord it comes with.  I switched it out and cost myself an hour.  Also, take note of the status light.  If it is amber (as it was with my bad USB cord), it is not ready for action.  The light must be green.  Test your card reader simply by opening Notepad and swiping.  You should string of garbled characters, letters and numbers.

Download Carl Raymond’s JQuery Cardswipe plug-in to help translate that garbled string into data and include it in your checkoutInfo.php file.

<script src="/js/jquery.cardswipe.js"></script>

Then, initialize it to populate your form with the name, card number, etc.:

<script type="text/javascript">
    // Called by plugin on a successful scan.
    var complete = function (data) {
      // Is it a payment card?
      if (data.type == "generic")
        return;
      // Copy data fields to form
      $("#firstName").val(data.firstName);
      $("#lastName").val(data.lastName);
      $("#ccNumber").val(data.account);
      $("#expiration_month").val(data.expMonth);
      $("#expiration_year").val("20" + data.expYear);
      $("#type").val(data.type);
    };
    // Event handler for scanstart.cardswipe.
    var scanstart = function () {
      $("#overlay").fadeIn(200);
    };
    // Event handler for scanend.cardswipe.
    var scanend = function () {
      $("#overlay").fadeOut(200);
    };
    // Event handler for success.cardswipe.  Displays returned data in a dialog
    var success = function (event, data) {
      $("#properties").empty();
      // Iterate properties of parsed data
      for (var key in data) {
        if (data.hasOwnProperty(key)) {
          var text = key + ': ' + data[key];
          $("#properties").append('<div class="property">' + text + '</div>');
        }
      }
      $("#success").fadeIn().delay(3000).fadeOut();
    }
    var failure = function () {
      $("#failure").fadeIn().delay(1000).fadeOut();
    }
    // Initialize the plugin with default parser and callbacks.
    //
    // Set debug to true to watch the characters get captured and the state machine transitions
    // in the javascript console. This requires a browser that supports the console.log function.
    //
    // Set firstLineOnly to true to invoke the parser after scanning the first line. This will speed up the
    // time from the start of the scan to invoking your success callback.
    $.cardswipe({
      firstLineOnly: true,
      success: complete,
      parsers: ["visa", "amex", "mastercard", "discover", "generic"],
      debug: false
    });
    // Bind event listeners to the document
    $(document)
      .on("scanstart.cardswipe", scanstart)
      .on("scanend.cardswipe", scanend)
      .on("success.cardswipe", success)
      .on("failure.cardswipe", failure)
    ;
</script>

Of course, on submit, this goes through the same cycle as previously – the PayTrace library takes the card number and csc, encrypts and sends.  At this point, you should be swiping and all the form data auto-populating on swipe.

The code is a bit of a mess, but I think it might help some of us who approach mountains of documentation and just want a quick path to follow.

You may also like