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:
~~~php
$gateway = OmniPay::create('SagePay\Direct')
->setVendor('academe')
->setTestMode(true);
~~~
All credentials are set at this stage:
~~~php
->setAccount('myAccount')
->setKey('myKey')
->setSecret('mySecret')
~~~
General Use
2. Create the Credit Card/Customer Object:
~~~php
$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:
~~~php
// 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:
~~~php
$responseMessage = $requestMessage->send();
~~~
Get a Response message in return.
Handle any exceptions.
General Use
5. Take next action based on response:
~~~php
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.
~~~php
// 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 Time
Demo: SagePay Direct
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