What Are Payment Gateways?
- The means to collect payment from a user
- The means to authorise payment from a user
- The means to collect against authorisation
- All through web services
Drupal Payment Gateways
- Gateway modules built for projects
- Much duplication
- Inconsistent support of gateways
- Each of these projects have their own payments framework, modules, and way of
working.
- Inconsistent support: each e-commerce product supports a different set of
payment gateways, whatever happened to scratch people's itch at the time.
The Problems to Solve
- The gateways are all so different; can we abstract them?
- Difficult to switch between gateways
- Gateway supplied SDKs are awful
- To provide the common services easily(authorize/void/capture/payment)
- There are many gateways out there, all operating differently, and with their
own quirks. Which you use will depend largely on business needs, so you need
to be able to plug in whatever gateway at a technical level.
- To provide a simple way to add payment gateways to your system,
without having to understand too much about the specific gateways.
- To be able to switch between gateways easily through a consistent interface,
especially when your gateway does not yet exist for your particular application.
- To avoid needing to use the SDKs that gateway providers supply,
because most of them suck.
- Scope: authorize/void/capture/payment – simple shop stuff.
The Drupal Payment Module
- Plugable platform for processing payments
- Solves the duplication problem:
- The gateway modules still need to be written
- The Drupal Payment module provides some helper functions, GUIs, forms,
admin pages etc.
- Crutially, it knows how to interface to the projects, so the gateway
modules do not need to.
- These payment gateway modules can now be shared between lots of projects.
- But still these gateway modules need to be written by someone.
Introducing...
OmniPay
Not to be confused with a company with fancy logos in Ireland
OmniPay Basic Architecture
- Installed using composer
- Core omnipay/common package
- Official omnipay/{gateway-name} drivers
- Unofficial third party drivers
- All drivers built from message specs; no SDKs
- Unofficial drivers don't sit in the OmniPay namespace.
- Unofficial drivers are still listed on the OmniPay website.
- Only pull the drivers you want.
- composer package omnipay/omnipay will pull in all drivers it knows about.
Some Current Figures
- Version: 2.3.x
- PHP: 5.3+
- Official gateways: 27
- Unofficial gateways: 25
- Dependencies: Guzzle, Symfony
- Author: Adrian Macneil, now The PHP League with many contributors
- Activity: high
Official Gateways (1)
- omnipay/2checkout
- omnipay/authorizenet
- omnipay/buckaroo
- omnipay/cardsave
- omnipay/coinbase
- omnipay/eway
- omnipay/firstdata
- omnipay/gocardless
- omnipay/manual
- omnipay/migs
Official Gateways (2)
- omnipay/mollie
- omnipay/multisafepay
- omnipay/netaxept
- omnipay/netbanx
- omnipay/payfast
- omnipay/payflow
- omnipay/paymentexpress
- omnipay/paypal
- omnipay/pin
- omnipay/sagepay
Official Gateways (3)
- omnipay/securepay
- omnipay/stripe
- omnipay/targetpay
- omnipay/worldpay
Unofficial Gateways (1)
- academe/omnipay-helcim
- agmscode/omnipay-agms
- alfaproject/omnipay-neteller
- alfaproject/omnipay-skrill
- andreas22/omnipay-fasapay
- andylibrian/omnipay-veritrans
- cardgate/omnipay-cardgate
- coatesap/omnipay-datacash
- coatesap/omnipay-paymentsense
- coatesap/omnipay-realex
Unofficial Gateways (2)
- dabsquared/omnipay-cybersource-soap
- delatbabel/omnipay-fatzebra
- dercoder/omnipay-ecopayz
- dercoder/omnipay-globalcloudpay
- dioscouri/omnipay-cybersource
- fruitcakestudio/omnipay-sisow
- igaponov/omnipay-wirecard
- justinbusschau/omnipay-secpay
- lokielse/omnipay-alipay
- mfauveau/omnipay-nmi
Unofficial Gateways (3)
- mfauveau/omnipay-pacnet
- omnipay/payu
- paypronl/omnipay-paypro
- samvaughton/omnipay-barclays-epdq
- teaandcode/omnipay-worldpay-xml
That's a Lot of Payment Gateways
- Having these gateways available does not mean there is not some work involved
to integrate it, but it does make the life of the developer easier.
- Remember, the choice of gateway is often going to be a business decision and
not one based on technical reasons.
Composer - a slight diversion
- PHP dependency manager.
- Installs from a number of sources.
- Used in many frameworks and projects.
- Shared code; shared effort. DRY!
- More central to Drupal 8.
- The sources include packagist, other composer repositories (one for WordPress,
one for Drupal, private respos, git, svn, etc.)
- There is plenty of work going on to bring composer into Drupal 8.
- The "island" mentality is hard to discard, but it seems to be shifting.
- Once you base work around composer, you will find it hard to leave it.
Gateway Architectures
Traditionally:
- On-site
- User never leaves the site
- Server to Serverc comms
- High PCI responsibility
- Off-site
- User leaves the site (maybe only in an iframe)
- May use back-end notify channel
Onsite
- These gateway APIs just handle server talking to server.
There is no user interaction at all, so any user input must pass
through your server before it is passed to the gateway to get a
result. Only do this if you have a big budget to cater for the
intense PCI scrutiny to get compliance.
- Note that with 3D Secure and suchlike, the user may still have
to be sent to a third-party site to fill out some security details.
Offsite
- The user is taken to the payment gateway to complete their details.
On return, the transaction is completed according to the authorisation
result. There are variations on this:
- The remote site can be in an iframe, so the user appears not to
have left the main site.
- The result can be sent back via the user’s browser, with an
encrypted GET parameter.
- The result can be sent back via a notification URL. The
consequences of this, are that you need to keep the transaction
in non-volatile storage that can be shared between the user’s
session, and the session-less notification handler.
Shared
- In this type of gateway, the payment form is on your site, but the
credit card details are never submitted directly to your site.
There are two ways this works:
- JavaScript API, where the form submission is caught by JavaScript
and POSTed direct to the gateway site. The response is either an
error message indicating what needs to be corrected on the form,
or the result is added to the form and it is then allowed to post
direct back to you site (without the credit card details).
The user never leaves your site.
- The form is POSTed direct to the gateway site. The details are
verified and the result is POSTed direct to your site (usually
via a back-channel) and the user is then returned back to your
site. The user is taken away from your site, but only for a moment,
and with no interaction.
Onsite/Offsite is not Helpful
- Same thing to application.
- Want heavy PCI compliance? Take CC details.
- The meanings are blurred - Stripe, Authorize.Net DPM.
- OmniPay can handle all these.
- The application should not care where the user goes - it only needs to
know whether the payment has been authorised.
- If you let credit card details pass through your server, then you are
putting yourself and your customers at risk.
- Even offsite you are not risk free.
- The hybrid gateways offer forms on your site, but CC details are posted
direct to the gateway site.
- Direct posting does not mean your site is totally safe from PCI - some
malicious javascript on your site could still capture CC details from
your front-end form and send it off to a third party, so not a panacea.
How to Use OmniPay
- OmniPay handles the messaging
- You handle the routing and data
Common Use
1. Create the Gateway Object:
$gateway = OmniPay::create('SagePay\Direct')
->setVendor('academe')
->setTestMode(true);
All credentials are set at this stage:
->setAccount('myAccount')
->setKey('myKey')
->setSecret('mySecret')
Common Use
2. Create the Credit Card/Customer Object:
$card = new CreditCard([
'firstName' => 'Jason',
'lastName' => 'Judge',
'number' => '4929000000006',
'expiryMonth' => '12',
'expiryYear' => '2016',
'CVV' => '123',
'billingAddress1' => 'Campus North',
'billingCity' => 'Newcastle Upon Tyne',
// ...
'shippingAddress1' => 'Campus North',
// ...
]);
Common Use
3. Create the Request Message:
// Purchase Request
$requestMessage = $gateway->purchase([
'amount' => '99.99',
'currency' => 'GBP',
'card' => $card,
'transactionId' => $transactionId,
'description' => 'Pizzas for everyone',
'returnUrl' => 'http://example.com/complete',
'cancelUrl' => 'http://example.com/complete',
'errorUrl' => 'http://example.com/complete',
]);
Common Use
4. Send the request message:
$responseMessage = $requestMessage->send();
Get a Response message in return.
Handle any exceptions.
Common Use
5. Take next action based on response:
if ($responseMessage->isSuccessful()) {
// All finished and all successful.
// ...
} elseif ($responseMessage->isRedirect()) {
// Do the redirect.
$responseMessage->redirect();
} else {
// Some kind of error:
// Log $responseMessage->getMessage();
// ...
}
Some gateways may have other required actions.
Common Use
6. If returning from a redirect:
Repeat steps 1-5 with the "complete" version of the service.
// Use completePurchase() to complete the Purchase.
$requestMessage = $gateway->completePurchase([
'transactionId' => $transactionId,
'transactionReference' => $transactionReference,
]);
$responseMessage = $requestMessage->send();
// Then check the result as before.
Some notes:
- The messages are active messages; they “send” themselves.
- Sending a message may or may not involve the remote gateway.
For direct gateway APIs it will, for others, often not (but it may).
- The messages honour a standard interface, so details provided and results
received will be done through a common set of methods. Gateway drivers will
often extend those interfaces to support features only that gateway has.
- The messages translate the fields for you, between OmniPay field names
and gateway field names.
- The messages use the appropriate HTTP service of Guzzle to send and receive
data in the right format. You don’t need to worry about the HTTP body formats.
Integration
- drupal 8: Omnipay - Bart Feenstra
- So far all integration has one thing in common: they integrate at a low level,
and you have to build all the machinery around that (forms, storage, routing, etc.)
Integration
- composer: ignited/laravel-omnipay - Alex Whiteside
- composer: barryvdh/laravel-omnipay - Barry vd. Heuvel
The Ideal Situation
- The Omnipay module interfaces Drupal Payment, the gateway modules and
the composer OmniPay gateway packages.
- The gateway modules should be simple and quick to implement; most of
the common handling code is in the Drupal OmniPay and the Drupal Payment
modules.
Some Gateway Trends
- More "hybrid" options; JavaScript and direct POSTing.
- Token-based payments taking off; increasing number of subscription services grow.
- Stripe popularised the idea that payment gateways can rely on
JavaScript to perform the communications, and that can mean the
customer not ever having to leave your site. All the major gateways
are leaping into this approach. I hear a rumour that even SagePay
is going to launch one of these very soon. JavaScript posting makes
PCI compliance a little lighter.
- Token-based APIs are becoming more popular, allowing a site to get
authorization to take a payment, or multiple payments, at a later date
using a token that does not require the storage of credit card numbers
(which we hope no-one is doing anyway).
Coming Up Version 3.0
- Planned for end 2015
- Improved Documentation; more consistency
- Namespace change vendor to League
- Remove dependencies: Guzzle and Symfony
- PSR-7 HTTP models instead
- More classes to handle the data
- More metadata to automate plumbing better
- Maybe more metadata to help automate the plumbing, e.g. defining
capabilities in more detail and listing what fields are mandatory
or optional, and what validation needs to be applied to them.
Demo: Switch to SagePay Server
Demo: Switch to SagePay Server
- Three scripts (for the three steps):
- authorise.php
- sagepay-confirm.php
- final.php
- User redirected to SagePay site
Summary
- Fragmented Payment Modules are painful
- OmniPay pulls in skills from many sources
- composer is fab
- The core of 50 gateways in our hands
- Needs more work to join the pieces
Thank You
Feedback most welcome
OmniPay
The PHP Library for Payment Gateways
Presentation
for DrupalCamp North
/ @DrupalCampNE
by Jason Judge
/ @JasonDJudge
(Background notes are in these slides - press 'S' to see them)