Integrate MIGS 2-party payments in PHP.

20

A MasterCard Internet Gateway Service solution using cURL and PHP.

on 9/5/10

We needed a solution to handle 2-party payments to a Bendigo bank merchant account for one of our websites. Although I've only implemented 2-party payments, the following notes and code should provide a good foundation for adding additional functionality.

In 2-party payments the application connects directly to the Virtual Payment Client (VPC) using a form POST operation that directly returns a response. This is in contrast to 3-party payments where the payment server manages the payment pages (and collection of the cardholder's card details) from their website.

Like many other banks in Australia, Bendigo bank are using MIGS to facilitate card not present transactions, via their virtual payment client API. MIGS allows payments from other card providers (not just MasterCard), including: Amex, Bankcard, Diners Club and Visa.

At a high level:

  • we capture the user's card details via a form on our own website.
  • we package up the payment data according to MIGS documentation.
  • we send the request to the MIGS payment gateway using cURL.
  • we get a response from MIGS containing a response code and message.
  • we check the response code and handle successful/invalid requests accordingly.

- "Look ma, it's a MIG!"

An overview of the Migs class:

There are a few constants/variables declared at the top of the Migs class, I don't expect these would need modification. Any variables I thought might need changing are placed in the MigsConfig class.

The MigsConfig class is included in the same file, down the very bottom. This is where your configuration settings go; more on this further down.

function __construct() { ... } - This is the constructor. It is simply here to instantiate the $this->config variable.

function digitalOrder($data) { ... } - This is the 2-party payment method. It takes in the data as an associative array. It expects all of the user's details to be present and following the naming conventions specified in the MIGS manual, however it does not perform any validation of this.

The user's payment details (vpc_CardNum, vpc_CardExp, vpc_vpc_Amount, vpc_MerchTxnRef, etc) are merged in with the merchant account details (vpc_AccessCode, vpc_Merchant - taken from the MigsConfig) as well as the constants (vpc_Version, vpc_Command & vpc_TxSource).

This combined data associative array is then packaged into a query string and processed using cURL. Lastly, the response is unpackaged from a string into an associative array and returned.

function __package($values) { ... } - Takes the associative array and packages it into a query string.

function __process($url, $postfields=false) { ... } - Takes a base url and a query string and makes a cURL request, returning the response as a string.

function __unpackage($queryString) { ... } - Takes a string in the query string format (E.g. 'key=value&foo=bar') and returns it as an associate array.

function getResponseCodeDescription($responseCode) { ... } - Gets the response description for the given response code. This helper function can be called in a static fashion.

Configuration:

Configuration has been extracted to the MigsConfig class (at the bottom of the file); it is the only code that should require modifying. These values are case sensitive.


var $merchant = array(
	'test' => array(
		'vpc_AccessCode' => '80####77',
		'vpc_Merchant' => 'TESTBBL96###74',
	),
	'production' => array(
		'vpc_AccessCode' => '80####77',
		'vpc_Merchant' => 'BBL96###74',
	)
);

As a side note for Joomla users:

Since I was using the Migs class from a couple of custom developed Joomla components, I wanted the ability to configure the MIGS values through the Joomla admin. This is achieved through a configuration helper method which populates the MigsConfig variables from my component's parameters. It works in an unobtrusive manner so you can ignore it or modify it to suit your framework/CMS. It works because the Migs constructor creates an instance of the MigsConfig class using the values declared in the code, allowing you to directly configure it. Alternatively, after instantiating the Migs class, you can call $migs->getJoomlaParams($component) to read the Joomla component parameters and override your initial MigsConfig values.

Using the Migs class in your code:

You'll want to validate and sanitize the form inputs in your own code. This is typically a responsibility of your model. Some frameworks have utility methods to handle this. For example, I was using Joomla's JRequest class: JRequest::getInt('vpc_cardNum', null, 'post').

If the framework/CMS you are working with has this, you should use it; otherwise do some research, maybe it's time to upgrade.

Now that you've got all of the mandatory fields, valid and ready to go, you can create an instance of the Migs class and make the payment. The following is a very rough example of what your code might look like:


	require_once('migs.core.php');

	// [ Some code... ]

	// Get the user's payment details in a sanatized format.
	$data = array(); // [ Your code here... ]

	// Validate the user's payment details.
	$isValid = true; // [ Your code here... ]

	if ($isValid) {
		$migs = new Migs();
		// [Optional] load the config from a Joomla component parameters.
		$migs->config->getJoomlaParams('com_example');

		$response = $migs->digitalOrder($data);
		if ($response) {
			$responseCode = $response['vpc_TxnResponseCode'];
			if ($responseCode == '0') {
				$msg = $response['vpc_Message'];
				$msg .= 'Receipt number: ' . $response['vpc_ReceiptNo'];
			}
			else {
				$msg = Migs::getResponseCodeDescription($responseCode);
				$msg .= $response['vpc_Message'];
			}
		}
		else {
			$msg = 'Unexpected error connecting to the payment gateway.';
		}

		// Let the user know what happened with the payment.
		echo $msg;
	}
	else {
		// Invalid data, let them know.
		echo 'Please ensure all data is entered correctly';
	}

Testing the MIGS solution:

Switching between test and production is as easy as changing the mode.


var $mode = 'test'; // 'production'
var $ALLOWED_MODES = array('test', 'production');

As could be expected: when in test mode, test merchant values are used; similarly, when in production mode, production merchant values are used.

When in test mode, the cURL settings specify to skip SSL verification. This was an issue on a different project, so I have gotten into the habit of turning off those settings during development. They should be enabled in production mode (which they are by default).


// Some localhost/test environments might need relaxed security.
if ($mode == 'test') {
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
	curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
}

As for test data, here are some test card numbers and expiry dates you can use on the MIGS payment server:

Card Type: Number: Expiry:
MasterCard 5123456789012346 05/2013
Visa 4005550000000001 05/2013
Amex 345678901234564 05/2013
Bankcard (Australian Domestic) 5610901234567899 05/2013
Diners Club 30123456789019 05/2013

Furthermore, the payment amount is translated to cents and needs to be divisible by 100 to be valid. E.g. an amount of $23.00 would work, but $23.50 would return an error response (when using the test payment server).

Get yourself an SSL certificate, srsly!

SSL protects data submitted over the Internet from being intercepted and viewed by unintended recipients. You really should be rocking SSL if you're allowing users to authenticate to your website or you're collecting sensitive information such as a cardholder's credit card number or address.

Even if you are using 3-party payments, you'd still benefit from SSL; it would prevent possible browser alerts about being redirected to an unsecured site (on the return trip from the payment server to your website).

Download the Migs class (and integration guide):

migs.zip [4kb]

MIGS-Virtual-Payment-Client-Guide-Rev-2.1.0.pdf [1.5mb]

Please note: This code is provided as is, use it at your own discretion.
That said, if you do notice anything that you think is potentially unsecure, or that you think could be improved upon - feel free to let me know.

I'd also be interested in hearing if you have success using this class in any of your own projects.

Mike Soden

on 21/5/10

Hi Tony,

Thanks for the post..!

I have a Joomla Bendigo Bank MIGS integration I'm struggling to get working using 2-Party payments.. Your post has given me new hope..!

Looks like you were using Joomla in your example post? I'm fairly new to Payment Intregration and am missing something getting your example integrated to Joomla/ VirtueMart.. Any help or advice would be greatly appreciated..!

Cheers, Mike

Tony Milne

  -  http://tonymilne.com.au

on 23/5/10

Hey Mike,

I've sent you an email - might be easier to chat about what you're working on and if there's any thing I can help with via email.

Tones.

Tony Milne

  -  http://tonymilne.com.au

on 30/5/10

I've just written a follow up post in regards to Mike's comment. Mike and I took the discussion to email and were able to resolve his VirtueMart MIGS integration problem quite quickly.

The result is a great looking and fully functioning site: http://billylids.com.au.

You can read the follow up post here: MIGS payments in Joomla VirtueMart.

jamie

on 2/10/10

hi,
im looking to intergrate with the migs platform to process payments, will this give me direct access to all banks. Or do i still need to deal with each induvidual banking process.

thanks jamie

Ricky

on 12/11/10

Hi Tony, I'm helping a friend trying to get the MIGS up and running. Although, I haven't worked with the VirtueMart framework before. Would you be interested in doing some freelance work?

Tony Milne

  -  http://tonymilne.com.au

on 14/11/10

Hi Ricky, I've sent you a follow-up email regarding freelance work. Thanks for dropping by and leaving a comment.

Omar Kassim

  -  http://omarkassim.com

on 25/1/11

Hi Tony,

We're currently trying to integrate with MIGS - our testing environment gets a successful response, however we are unable to re-direct back to a confirmation page - is this something that MIGS handles or are we meant to be handling this on our end?

"HTTP GET is disabled for 2 party VPC"

Thanks for your help!

Andrew

on 26/1/11

Have been living with MIGS for about 6 years now (via Bendigo Bank) and it's been working a treat.

Client has changed to NAB Transact and I'm seeking support as it's causing grief.

Apologies for the hijack but not getting anywhere very fast ;-(

You able to assist?

Miguel

  -  http://lamp99.com

on 28/1/11

hi Tony,
"Error: Failure in Processing the Payment (ps_migs)"
on
"http://www.billylids.com.au"
why?
user:evebit_demo1
pass:123456
Visa:4005550000000001 05/13
------------------------------------------------------------
thanks.....

Ezhil

on 6/9/11

Hi tony,

do u have any idea for 3 party(server hosted) payment capture code?

1Rover1

on 8/2/12

A couple of suggestions for the next version ;)

1. cURL options to verify peer should be used, that's just good security practise.
2. As far as I know secure hash secret isn't required for 2-party transactions.
3. In my humble experience, most MIGS accounts are already set to TxSource=INTERNET and most accounts are NOT given privilege to set/change this value. Removing it should make it work better for most integrations.

Compatibility: looks like this would be valid for CommWeb, TNS, Suncorp, et al

vinod

on 9/3/12

how i include the card type (eg: Visa) in the data, what is the field name? Is it possible?

Gurnam Bhodey

on 8/4/12

Hi Tony,
are you still available for advise? !
Thanks
G.B

Alex

on 18/5/12

Hi,

I was reading through the documentation and couldnt see how to take a deferred payment that I can later capture/release/void.

Please can you offer some guidance?

Thanks
Hello very cool website!! Guy .. Beautiful .. Amazing .

. I will bookmark your website and take the feeds also?

I am glad to search out so many helpful information right here
within the publish, we'd like work out more strategies on this regard, thank you for sharing. . . . . .
Hmm it looks like your blog ate my first comment (it was super long) so I guess I'll just sum it up what I had written and say, I'm
thoroughly enjoying your blog. I too am an aspiring blog writer but I'm still new to everything. Do you have any suggestions for inexperienced blog writers? I'd certainly appreciate
it.
Howdy, I do believe your web site might be having browser compatibility problems.
Whenever I look at your website in Safari, it looks fine however, if opening
in Internet Explorer, it's got some overlapping issues. I simply wanted to give you a quick heads up! Besides that, excellent site!

more information

  -  http://Easygardens.co.za/

2 weeks ago

If you desire to get a good deal from this piece of writing then you have
to apply these techniques to your won weblog.
Hello there! This is my first visit to your blog! We are a collection of volunteers and starting a
new initiative in a community in the same niche.

Your blog provided us useful information to work on.
You have done a outstanding job!

frey wille

  -  http://www.cheapfreywillesale.com

3 days, 2 hours ago

Austrian brand Frey Wille well-known because of its luxury enameled surface jewellery and founded within 1951 in Vienna simply by Michaela Frey, will be remembering its sixtieth loved-one’s birthday. Previewing the newest models at its fresh stand-alone Birmingham store located at forty five Piccadilly (merely reverse the enduring Fortnum and Builder English store) and next to the Regal Academy associated with Disciplines, I had been reminded of what tends to make this diamond jewelry brand unique. frey wille http://www.cheapfreywillesale.co

You should leave a comment:

Some tags are allowed: (a, b, blockquote, code, em, i, u, pre, strong).

who am I?

I live in Melbourne. I work at Inlight Media. I'm passionate about web and software development. I like jQuery, CakePHP, Flex. I can code. I can't draw. I play basketball with the Spiderpigs and the Generals. I love snowboarding in the winter and wakeboarding in the summer. I play computer games too often.