OmniPay
The PHP Library for Payment Gateways
Presentation
for @PHPNE
by Jason Judge
/ @JasonDJudge
(Speaker notes are in this slideshow for more background - press 'S' to see them)
The Problems to Solve
- To abstract the gateway
- To switch gateways more easily
- To avoid supplied SDKs - they are awful
- To provide the common services(authorize/void/capture/payment)
- 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.
- To avoid needing to use the SDKs that gateway providers supply,
because most of them are awful.
- Scope: authorize/void/capture/payment – simple shop stuff.
Basic Architecture
- Composer-based
- Core omnipay/common package
- Official omnipay/{gateway-name} drivers
- Unofficial third party drivers
- All drivers built from low-level 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; not composer package
omnipay/omnipay, which pulls in everything it knows about.
Some 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
Official Gateways (1)
- omnipay/2checkout
- omnipay/authorizenet
- omnipay/buckaroo
- omnipay/cardsave
- omnipay/coinbase
- omnipay/common
- omnipay/dummy
- omnipay/eway
- omnipay/firstdata
- omnipay/gocardless
Official Gateways (2)
- omnipay/manual
- omnipay/migs
- omnipay/mollie
- omnipay/multisafepay
- omnipay/netaxept
- omnipay/netbanx
- omnipay/payfast
- omnipay/payflow
- omnipay/paymentexpress
- omnipay/paypal
Official Gateways (3)
- omnipay/pin
- omnipay/sagepay
- 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
Refresh the page if you don't see the logos in their animated glory!
Gateway Architectures
- Direct
- Server to Server
- High PCI responsibility
- Hosted
- User leaves the site (can use iframe)
- Result sent back by notify channel
- Shared
- JavaScript or direct POST from browser
- Back channel used to check the results
Direct
- 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.
Hosted
- 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.
How to Use OmniPay
- OmniPay handles the messaging
- You handle the routing and data
General 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')
General 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',
// ...
]);
General 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',
]);
General Use
4. Send the request message:
$responseMessage = $requestMessage->send();
Get a Response message in return.
Handle any exceptions.
General 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.
General 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
- composer: ignited/laravel-omnipay - Alex Whiteside
- composer: barryvdh/laravel-omnipay - Barry vd. Heuvel
Example Application
- github: thephpleague/omnipay-example
Gateway Trends
- More going for "shared" option, using JavaScript or direct POSTing.
- Token-based payments are becoming more popular as the 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).
OmniPay Version 3.0
- Planned for end 2015
- Improved Documentation
- Namespace change to League\Omnipay\{gateway-name}
- Remove dependencies: Guzzle and Symfony
- PSR-7 HTTP models will be used instead
- Splitting the credid card and the payee details
- 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
Thank You
Feedback most welcome
OmniPay
The PHP Library for Payment Gateways
Presentation
for @PHPNE
by Jason Judge
/ @JasonDJudge
(Speaker notes are in this slideshow for more background - press 'S' to see them)