In Industry, Web Development by attercopia

Integrating Sage Pay with ColdFusion

While integrating Sage Pay for one of our clients using the Form Integration process, we soon found that Sage Pay provided some great code examples for a couple of programming languages (PHP & ASP.NET), but nothing for ColdFusion (you will need to be logged into Sage Pay to view the code samples).

So, here are a few key functions we created to integrate SagePay using ColdFusion.

(If you haven’t already, log into Sage Pay and download the Form Integration & Protocol Guideline document – this will be your Bible for this development!)

The Crypt Field

These functions are used to encrypt the data that you send to Sage Pay and then later to decrypt the returned data. simpleXor takes two parameters, the string you wish to encrypt/decrypt and the key that SagePay provided you with (we store this as sagePay.key, along with other data in a structure).

<cfscript>
function simpleXor(crypt, key) {
    var keyList = ArrayNew(1);
    var output = "";
    var result = "";
    var i = "";
    for(i = 1; i LTE Len(arguments.key); i=i+1)
        keyList[i] = Asc(Mid(arguments.key, i, 1));
    for(i = 0; i LTE  Len(arguments.crypt)-1; i=i+1){
        result = (bitXor((Asc(Mid(arguments.crypt, i+1,1))),(keyList[(i MOD Len(arguments.key))+1])));
        if (result eq 0)
            output = output & URLDecode("%00");
        else
            output = output & Chr(result);
    }
    return output;
}

function base64Decode(scrambled) {
    return toString(toBinary(Replace(arguments.scrambled," ","+","all")));;
}
</cfscript>

To encrypt the string you would call it using:

strCrypt = ToBase64(SimpleXor(variables.strToEncrypt,sagePay.key));

strCrypt is the value which you add to the Crypt field in the form that’s posted to Sage Pay:

<form action="<cfoutput>#sagePay.gateway#</cfoutput>" method="post">
    <input type="hidden" name="VPSProtocol" value="2.23" />
    <input type="hidden" name="TxType" value="PAYMENT" />
    <input type="hidden" name="Vendor" value="<cfoutput>#sagePay.vendor#</cfoutput>" />
    <input type="hidden" name="Crypt" value="<cfoutput>#variables.strCrypt#</cfoutput>" />
    ...
</form>

Decrypt and Extract the Response

Sage Pay will respond to either your Success or Failure page passing the query string crypt. Although you do not have to do anything with this data, we would recommend decrypting and extracting the data as this will give you more detail about the status of the payment. This process is made easy by using our functions. You can use the ones above to decrypt, and getSagePayResponse below to extract the contents into a manageable data format.

<cffunction name="getSagePayResponse" returntype="Struct" access="private" output="false">
    <cfargument name="crypt" type="string" required="true">

    <cfset var r = "">
    <cfset var structResult =  {}>

    <cfloop list="#arguments.crypt#" index="r" delimiters="&">
        <cfset structResult[listFirst(r,"=")] = listLast(r,"=")>
    </cfloop>

    <cfreturn structResult>
</cffunction>

At the top of you Success and Failure pages, add:

structResult = getSagePayResponse(SimpleXor(base64decode(URL.crypt),sagePay.key))

This will decrypt and extract the response into a ColdFusion structure:

struct
STATUSSUCCESS
STATUSDETAIL0000 : The Authorisation was Successful.
VENDORTXCODE1234567890
VPSTXID{123456A7-B890-CD12-3E4F-56G78901234H}
TXAUTHNO123456789
AMOUNT100.00
AVSCV2ALL MATCH
ADDRESSRESULTMATCHED
POSTCODERESULTMATCHED
CV2RESULTMATCHED
3DSECURESTATUSOK
CAVVAAABBBCCCaBBBBCCcDeFGGGGGGG
CARDTYPESWITCH
LAST4DIGITS1234

Record Response

Although you don’t have to store the returned data, we would again recommend it. Simply pass the structure which is returned from the getSagePayResponse function (e.g. variables.structResult).

<cffunction name="recordSagePayResponse" returntype="void" access="private" output="false">
    <cfargument name="structResult" type="struct" required="true">

    <cfparam name="arguments.structResult.Status" default="">
    <cfparam name="arguments.structResult.StatusDetail" default="">
    <cfparam name="arguments.structResult.VendorTxCode" default="">
    <cfparam name="arguments.structResult.VPSTxId" default="">
    <cfparam name="arguments.structResult.TxAuthNo" default="0">
    <cfparam name="arguments.structResult.Amount" default="0.00">
    <cfparam name="arguments.structResult.AVSCV2" default="">
    <cfparam name="arguments.structResult.AddressResult" default="">
    <cfparam name="arguments.structResult.PostCodeResult" default="">
    <cfparam name="arguments.structResult.CV2Result" default="">
    <cfparam name="arguments.structResult.3DSecureStatus" default="">
    <cfparam name="arguments.structResult.CAVV" default="">
    <cfparam name="arguments.structResult.CardType" default="">
    <cfparam name="arguments.structResult.Last4Digits" default="">

    <cfquery datasource="#Application.dsn#">
        UPDATE tblPayments
        SET responseStatus = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.structResult.Status#">,
        responseStatusDetail = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.structResult.StatusDetail#">,
        responseVendorTxCode = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.structResult.VendorTxCode#">,
        responseVPSTxId = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.structResult.VPSTxId#">,
        responseTxAuthNo = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.structResult.TxAuthNo#">,
        <!--- Sage Pay returns £1000 as '1,000.00'. The docs say it returns a Numeric value, but in my opinion this is a string. So need to remove formatting as this field is of type decimal (10,2) --->
        responseAmount = <cfqueryparam cfsqltype="cf_sql_numeric" value="#replace(arguments.structResult.Amount,",","","all")#">,
        responseAVSCV2 = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.structResult.AVSCV2#">,
        responseAddressResult = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.structResult.AddressResult#">,
        responsePostCodeResult = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.structResult.PostCodeResult#">,
        responseCV2Result = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.structResult.CV2Result#">,
        response3DSecureStatus = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.structResult.3DSecureStatus#">,
        responseCAVV = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.structResult.CAVV#">,
        responseCardType = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.structResult.CardType#">,
        responseLast4Didgits = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.structResult.Last4Digits#">
        WHERE vendorTxCode = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.structResult.VendorTxCode#">
    </cfquery>

</cffunction>

If you have any questions about the process, or are looking for an e-commerce solution, get in touch.

Share this Post

Want great digital content? Join our mailing list today!

* indicates required