How to Integrate Sage Pay with PHP

Here we will guide you through how to integrate Sage Pay’s “Form” method of integration. Sage aren’t much help here with their overly complicated integration kits, but a huge shoutout goes to Timur Olzhabayev and his library on Github which simplifies the process.

Step 1

Download the afforementioned library from Github – https://github.com/tolzhabayev/sagepayForm-php – and include it on your payment page (you only need /lib/SagePay.php).

Within the class I populated encryptPassword, currency, vendorName, vendorEMail and both successURL and failureURL. One thing to note is that the encryptPassword is different on your test and live accounts, so make sure you’re using the right one.

Step 2

Set up the order with necessary details. The first section below is pretty self-explanatory; set the order amount, description, your own transaction/order ID, the customer’s email address and billing/postal address.

$sagePay = new SagePay();
$sagePay->setAmount($total);
$sagePay->setDescription("[description of the order");
$sagePay->setVendorTxCode($orderid);

$sagePay->setCustomerEMail($email);

$sagePay->setBillingSurname($lastname);
$sagePay->setBillingFirstnames($firstname);
$sagePay->setBillingAddress1($addr1);
$sagePay->setBillingAddress2($addr2);
$sagePay->setBillingCity($city);
$sagePay->setBillingPostCode($postcode);
$sagePay->setBillingCountry($country);

$sagePay->setDeliverySurname($del_lastname);
$sagePay->setDeliveryFirstnames($del_firstname);
$sagePay->setDeliveryAddress1($del_addr1);
$sagePay->setDeliveryAddress2($del_addr2);
$sagePay->setDeliveryCity($del_city);
$sagePay->setDeliveryPostCode($del_postcode);
$sagePay->setDeliveryCountry($del_country);

Step 3

Create an XML version of the basket. This is optional but will confirm to users what they’re buying at the payment stage (on Sage Pay’s servers) plus in the email confirmation from Sage. I presume it will also display this in Sage’s admin which shows transactions.

In this code snippet $contents is the contents of the customer’s basket. Obviously this, along with $info, will vary in your code-base but it shows how it works; it’s a bit long-winded but all that’s happening is a loop through each line of the basket adding product name, quantity and price to the XML.

$xml = new DOMDocument();
$basketNode = $xml->createElement("basket");
foreach($contents as $info){
    $itemNode = $xml->createElement("item");

    $descriptionNode = $xml->createElement("description");
    $descriptionNode->nodeValue = substr($info->product->name, 0, 100);
    $itemNode->appendChild($descriptionNode);

    $quantityNode = $xml->createElement("quantity");
    $quantityNode->nodeValue = $info->quantity;
    $itemNode->appendChild($quantityNode);

    $unitNetAmountNode = $xml->createElement("unitNetAmount");
    $unitNetAmountNode->nodeValue = round($info->product->netprice, 2);
    $itemNode->appendChild($unitNetAmountNode);

    $unitTaxAmountNode =  $xml->createElement("unitTaxAmount");
    $unitTaxAmountNode->nodeValue = round($info->product->grossprice - $info->product->netprice, 2);
    $itemNode -> appendChild($unitTaxAmountNode);

    $unitGrossAmountNode =  $xml->createElement("unitGrossAmount");
    $unitGrossAmountNode->nodeValue = $info->product->grossprice;
    $itemNode->appendChild($unitGrossAmountNode);

    $totalGrossAmountNode = $xml->createElement("totalGrossAmount");
    $totalGrossAmountNode->nodeValue = $info->product->grossprice * $info->quantity;
    $itemNode->appendChild($totalGrossAmountNode);

    $basketNode->appendChild($itemNode);
    $xml->appendChild($basketNode);
}
$sagePay->setBasketXML($xml->saveHTML());

Step 4

Now we need to send all the information, along with the customer, to Sage. The URL varies if you’re using the test or live environment (as shown below).

$sage_url = "https://test.sagepay.com/gateway/service/vspform-register.vsp";
$sage_url = "https://live.sagepay.com/gateway/service/vspform-register.vsp";

<form action="<?=$sage_url?>" method="post">
 <input type="hidden" name="VPSProtocol" value="3.00"/>
 <input type="hidden" name="TxType" value="PAYMENT"/>
 <input type="hidden" name="Vendor" value="<?=$sagePay->vendorName?>"/>
 <input type="hidden" name="Crypt" value="<?=$sagePay->getCrypt()?>"/>
 <input type="submit" value="Pay"/>
</form>

As you can see all you need to send to Sage is the Protocol (currently 3), Transaction Type (which is almost always “PAYMENT”), Vendor (which you use to log in to Sage) and Crypt (which contains all the information we added above, encrypted).

Step 5

After the customer has input their payment information on Sage they will be redirected to the successURL or failureURL. We use the same URL then use logic within the file to work out if the order has been succesful or not.

if($_REQUEST['crypt']){
    $sagePay = new SagePay();
    $responseArray = $sagePay->decode($_REQUEST['crypt']);

    $orderid = $responseArray['VendorTxCode'];

    //Check status of response
    if($responseArray['Status'] === "OK"){
        // Success
    }elseif($responseArray['Status'] === "ABORT"){
        // Payment Cancelled
    }else{
        // Payment Failed
    }
}

Obviously at this stage you will need to update the order on your system and display the relevant information to your customer. Some security checks would also be benficial here to make sure the customer has indeed come from Sage and that the order actually exists before doing anything.

This code is free to use at your own discretion. It comes without warranty. Please feel free to feedback any edits.


We'd love to hear from you!

If you think Bronco has the skills to take your business forward then what are you waiting for?

Get in Touch Today!

Discussion

Write a comment...
  • Kiran S

    Will this support PHP 7.0 ? I have stumbled across few repos and their official docs too, but I didn’t see any one referring the versions here.

    • Chris Antcliff

      I don’t know to be honest Kiran but the SagePay library is just 1 file so it wouldn’t take too much time to test and edit if necessary. It’s not doing anything that complex anyway.

Add a Comment