Commit 24069bf0 authored by David Weston's avatar David Weston

moving into the 21st century

parent a3f902af
{
"name": "outragelib/payment-stpp",
"description": "STPP/STAPI",
"type": "library",
"license": "MIT",
"authors": [
{
"name": "David Weston",
"email": "westie@typefish.co.uk"
}
],
"minimum-stability": "dev",
"require": {},
"autoload": {
"psr-4": {
"OUTRAGElib\\Payment\\STPP\\": "./lib"
}
},
"autoload-dev": {
"psr-4": {
"OUTRAGElib\\Payment\\STPP\\Tests\\": "./tests"
}
}
}
\ No newline at end of file
......@@ -6,17 +6,20 @@
* quite a lot of functionality is shared between billing and customers, for
* example.
*
* @version: 1.0
* @version: 2.0.0
* @author: David Weston <stpp@typefish.co.uk>
*/
abstract class STPPAddressable extends STPPObject
namespace OUTRAGElib\Payment\STPP\Fragment;
abstract class AddressFragmentAbstract extends FragmentAbstract
{
/**
* Store all of the options this object holds in here.
*/
protected $options = array();
protected $options = [];
/**
......@@ -95,7 +98,7 @@ abstract class STPPAddressable extends STPPObject
public function setNamePrefix($prefix)
{
if(!isset($this->options["name"]))
$this->options["name"] = array();
$this->options["name"] = [];
$this->options["name"]["prefix"] = $prefix;
......@@ -109,7 +112,7 @@ abstract class STPPAddressable extends STPPObject
public function setFirstName($prefix)
{
if(!isset($this->options["name"]))
$this->options["name"] = array();
$this->options["name"] = [];
$this->options["name"]["first"] = $prefix;
......@@ -123,7 +126,7 @@ abstract class STPPAddressable extends STPPObject
public function setMiddleName($middle)
{
if(!isset($this->options["name"]))
$this->options["name"] = array();
$this->options["name"] = [];
$this->options["name"]["middle"] = $middle;
......@@ -137,7 +140,7 @@ abstract class STPPAddressable extends STPPObject
public function setLastName($last)
{
if(!isset($this->options["name"]))
$this->options["name"] = array();
$this->options["name"] = [];
$this->options["name"]["last"] = $last;
......@@ -151,7 +154,7 @@ abstract class STPPAddressable extends STPPObject
public function setNameSuffix($suffix)
{
if(!isset($this->options["name"]))
$this->options["name"] = array();
$this->options["name"] = [];
$this->options["name"]["suffix"] = $suffix;
......@@ -166,7 +169,7 @@ abstract class STPPAddressable extends STPPObject
public function setTelephone($phone)
{
if(!isset($this->options["telephone"]))
$this->options["telephone"] = array();
$this->options["telephone"] = [];
if(empty($this->options["telephone"]["type"]))
$this->options["telephone"]["type"] = "H";
......@@ -184,7 +187,7 @@ abstract class STPPAddressable extends STPPObject
public function setTelephoneType($type)
{
if(!isset($this->options["telephone"]))
$this->options["telephone"] = array();
$this->options["telephone"] = [];
$this->options["telephone"]["type"] = $type;
......
......@@ -7,17 +7,20 @@
* this class matches the name registered on the card. Addresses
* are also key.
*
* @version: 1.0
* @author: David Weston <stpp@typefish.co.uk>
* @version: 2.0.0
* @author: David Weston <westie@typefish.co.uk>
*/
class STPPBilling extends STPPAddressable
namespace OUTRAGElib\Payment\STPP\Fragment;
class Billing extends AddressFragmentAbstract
{
/**
* Store all of the options this object holds in here.
*/
protected $options = array();
protected $options = [];
/**
......@@ -28,7 +31,7 @@ class STPPBilling extends STPPAddressable
public function setAmount($amount)
{
if(!isset($this->options["amount"]))
$this->options["amount"] = array();
$this->options["amount"] = [];
if(empty($this->options["amount"]["currencycode"]))
$this->options["amount"]["currencycode"] = "GBP";
......@@ -45,7 +48,7 @@ class STPPBilling extends STPPAddressable
public function setCurrency($currency)
{
if(!isset($this->options["amount"]))
$this->options["amount"] = array();
$this->options["amount"] = [];
$this->options["amount"]["currencycode"] = $currency;
......@@ -60,7 +63,7 @@ class STPPBilling extends STPPAddressable
public function setPaymentType($type)
{
if(!isset($this->options["payment"]))
$this->options["payment"] = array();
$this->options["payment"] = [];
$this->options["payment"]["type"] = strtoupper($type);
......@@ -74,7 +77,7 @@ class STPPBilling extends STPPAddressable
public function setPaymentCardNumber($number)
{
if(!isset($this->options["payment"]))
$this->options["payment"] = array();
$this->options["payment"] = [];
$set = array
(
......@@ -99,7 +102,7 @@ class STPPBilling extends STPPAddressable
public function setPaymentExpiryDate($expirydate)
{
if(!isset($this->options["payment"]))
$this->options["payment"] = array();
$this->options["payment"] = [];
if(is_array($expirydate))
{
......@@ -141,7 +144,7 @@ class STPPBilling extends STPPAddressable
public function setPaymentSecurityCode($code)
{
if(!isset($this->options["payment"]))
$this->options["payment"] = array();
$this->options["payment"] = [];
$this->options["payment"]["securitycode"] = $code;
......
......@@ -10,17 +10,20 @@
* no real need to fill in anything like addresses and such - however there
* /is/ a recommendation from ST to do so.
*
* @version: 1.0
* @author: David Weston <stpp@typefish.co.uk>
* @version: 2.0.0
* @author: David Weston <westie@typefish.co.uk>
*/
class STPPCustomer extends STPPAddressable
namespace OUTRAGElib\Payment\STPP\Fragment;
class Customer extends AddressFragmentAbstract
{
/**
* Store all of the options this object holds in here.
*/
protected $options = array();
protected $options = [];
/**
......
......@@ -5,17 +5,20 @@
* This is the god object for all parts of the request, such as
* the merchant, operations and such.
*
* @version: 1.0
* @author: David Weston <stpp@typefish.co.uk>
* @version: 2.0.0
* @author: David Weston <westie@typefish.co.uk>
*/
abstract class STPPObject
namespace OUTRAGElib\Payment\STPP\Fragment;
abstract class FragmentAbstract
{
/**
* Store all of the options this object holds in here.
*/
protected $options = array();
protected $options = [];
/**
......
......@@ -10,12 +10,15 @@
* it is a required feature for 3D-Secure, which most if not all
* transactions should be performed using (if available).
*
* @version: 1.0
* @author: David Weston <stpp@typefish.co.uk>
* @version: 2.0.0
* @author: David Weston <westie@typefish.co.uk>
*/
class STPPMerchant extends STPPObject
namespace OUTRAGElib\Payment\STPP\Fragment;
class Merchant extends FragmentAbstract
{
/**
* Set the name of the merchant.
......
......@@ -5,12 +5,15 @@
* The operation object contains some other information that is needed
* to complete the request.
*
* @version: 1.0
* @author: David Weston <stpp@typefish.co.uk>
* @version: 2.0.0
* @author: David Weston <westie@typefish.co.uk>
*/
class STPPOperation extends STPPObject
namespace OUTRAGElib\Payment\STPP\Fragment;
class Operation extends FragmentAbstract
{
/**
* Set the account type description of the call. Would normally
......
......@@ -4,12 +4,15 @@
*
* This is the object that represents updated settlement details.
*
* @version: 1.0
* @author: David Weston <stpp@typefish.co.uk>
* @version: 2.0.0
* @author: David Weston <westie@typefish.co.uk>
*/
class STPPSettlement extends STPPObject
namespace OUTRAGElib\Payment\STPP\Fragment;
class Settlement extends FragmentAbstract
{
/**
* Set the settlement due date. Please note that you cannot
......@@ -18,6 +21,9 @@ class STPPSettlement extends STPPObject
*/
public function setDate($settledate)
{
if(!isset($this->options["payment"]))
$this->options["payment"] = [];
if(is_array($settledate))
{
$day = null;
......@@ -62,6 +68,9 @@ class STPPSettlement extends STPPObject
*/
public function setStatus($status)
{
if(!isset($this->options["payment"]))
$this->options["payment"] = [];
$this->options["payment"]["settlestatus"] = (string) $settledate;
return $this;
......
<?php
/**
* PHP based wrapper for SecureTrading's new STPP protocol.
*
* This won't allow you to connect your system immediately
* to a setup, however, it'll allow you to with ease create
* and maintain a new contract with a SecureTrading node.
*
* @version: 1.0
* Request for STPP/STAPI
*
* @version: 2.0.0
* @author: David Weston <stpp@typefish.co.uk>
*/
/**
* Okay, so it's probably a good thing to include quite a lot of
* classes that we need for this object to work properly.
*/
require "objects/stppobject.php";
require "objects/stppaddressableobject.php";
namespace OUTRAGElib\Payment\STPP;
require "objects/stppbilling.php";
require "objects/stppcustomer.php";
require "objects/stppmerchant.php";
require "objects/stppoperation.php";
require "objects/stppsettlement.php";
use \OUTRAGElib\Payment\STPP\Fragment\Billing;
use \OUTRAGElib\Payment\STPP\Fragment\Customer;
use \OUTRAGElib\Payment\STPP\Fragment\Merchant;
use \OUTRAGElib\Payment\STPP\Fragment\Operation;
use \OUTRAGElib\Payment\STPP\Fragment\Settlement;
use \OUTRAGElib\Payment\STPP\Response;
use \SimpleXMLElement;
require "objects/stppresponse.php";
/**
* Actual STAPI object
*/
class STAPI
class Request
{
/**
* Details about the connection to our local endpoint.
* Alias information.
*/
protected $alias = null;
protected $connection = null;
/**
* Stores each of the objects used in this request.
*/
protected $objects = array();
/**
* Called whenever we want to start talking with SecureTrading.
*/
public function __construct($address = "127.0.0.1", $port = 5000)
{
if($address != null)
$this->connect($address, $port);
}
/**
* A destructor, destructing things.
*/
public function __destruct()
{
$this->disconnect();
}
/**
* Begin a connection to ST.
*/
protected function connect($address, $port)
{
$errno = null;
$errstr = null;
if($this->connection = @fsockopen($address, $port, $errno, $errstr))
return true;
return false;
}
/**
* Kills our connection to ST.
*/
protected function disconnect()
{
if($this->connection)
return fclose($this->connection);
return true;
}
protected $objects = [];
/**
......@@ -106,7 +47,7 @@ class STAPI
* that represents a billing, or you can use the simulated methods which
* will do pretty much the same thing.
*/
public function setBilling($billing)
public function setBilling(Billing $billing)
{
$this->objects["billing"] = $billing;
return $this;
......@@ -119,28 +60,18 @@ class STAPI
public function getBilling()
{
if(!isset($this->objects["billing"]))
$this->resetBilling();
$this->objects["billing"] = new Billing();
return $this->objects["billing"];
}
/**
* Clears the merchant to a blank state.
*/
public function resetBilling()
{
$this->objects["billing"] = new STPPBilling();
return $this;
}
/**
* Sets the customer object - you can either separately supply an object
* that represents a customer, or you can use the simulated methods which
* will do pretty much the same thing.
*/
public function setCustomer($customer)
public function setCustomer(Customer $customer)
{
$this->objects["customer"] = $customer;
return $this;
......@@ -153,28 +84,18 @@ class STAPI
public function getCustomer()
{
if(!isset($this->objects["customer"]))
$this->resetCustomer();
$this->objects["customer"] = new Customer();
return $this->objects["customer"];
}
/**
* Clears the merchant to a blank state.
*/
public function resetCustomer()
{
$this->objects["customer"] = new STPPCustomer();
return $this;
}
/**
* Sets the merchant object - you can either separately supply an object
* that represents a merchant, or you can use the simulated methods which
* will do pretty much the same thing.
*/
public function setMerchant($merchant)
public function setMerchant(Merchant $merchant)
{
$this->objects["merchant"] = $merchant;
return $this;
......@@ -187,28 +108,18 @@ class STAPI
public function getMerchant()
{
if(!isset($this->objects["merchant"]))
$this->resetMerchant();
$this->objects["merchant"] = new Merchant();
return $this->objects["merchant"];
}
/**
* Clears the merchant to a blank state.
*/
public function resetMerchant()
{
$this->objects["merchant"] = new STPPMerchant();
return $this;
}
/**
* Sets the operation object - you can either separately supply an object
* that represents an operation, or you can use the simulated methods which
* will do pretty much the same thing.
*/
public function setOperation($operation)
public function setOperation(Operation $operation)
{
$this->objects["operation"] = $operation;
return $this;
......@@ -221,28 +132,18 @@ class STAPI
public function getOperation()
{
if(!isset($this->objects["operation"]))
$this->resetOperation();
$this->objects["operation"] = new Operation();
return $this->objects["operation"];
}
/**
* Clears the operation to a blank state.
*/
public function resetOperation()
{
$this->objects["operation"] = new STPPOperation();
return $this;
}
/**
* Sets the settlement object - you can either separately supply an object
* that represents a settlement, or you can use the simulated methods which
* will do pretty much the same thing.
*/
public function setSettlement($settlement)
public function setSettlement(Settlement $settlement)
{
$this->objects["settlement"] = $settlement;
return $this;
......@@ -255,146 +156,17 @@ class STAPI
public function getSettlement()
{
if(!isset($this->objects["settlement"]))
$this->resetSettlement();
$this->objects["settlement"] = new Settlement();
return $this->objects["settlement"];
}
/**
* Clears the settlement to a blank state.
*/
public function resetSettlement()
{
$this->objects["settlement"] = new STPPSettlement();
return $this;
}
/**
* Some fancy __call abuse - we'll manhandle the supplied function name, then
* try to figure out what component it needs to call, then call it. Simple!
*
* If the result call returns an instance of STPPObject (IE: something like billing)
* then /this/ class will be returned instead, to maintain the similiarities in
* calling conventions.
*
* Otherwise, the correct value will be returned unmolested.
*
* @todo: Fix this so that stuff like setOperation3DSecure... works.
*/
public function __call($method, $arguments)
{
$set = array();
preg_match_all("/((?:^|[A-Z])[a-z]+)/", $method, $set);
$set = $set[0];
$caller = "get".$set[1];
unset($set[1]);
$method = implode("", $set);
if(!method_exists($this, $caller))
return null;
$callback = array
(
$this->$caller(),
$method,
);
if(!method_exists($callback[0], $callback[1]))
return null;
$result = call_user_func_array($callback, $arguments);
if($result instanceof STPPObject)
return $this;
return $result;
}
/**
* Some __get abuse - if there is an object getter, call it and
* return its value.
*/
public function __get($property)
{
$caller = "get".ucfirst($property);
if(!method_exists($this, $caller))
return null;
return $this->$caller();
}
/**
* Some __set abuse - pretty much shorthand for the set?
* methods.
*/
public function __set($property, $value)
{
$caller = "set".ucfirst($property);
if(!method_exists($this, $caller))
return null;
return $this->$caller($value);
}
/**
* Some __unset abuse - pretty much shorthand for the reset?
* methods.
*/
public function __unset($property)
{
$caller = "reset".ucfirst($property);
if(!method_exists($this, $caller))
return null;
return $this->$caller($value);
}
/**
* Used to push a request off to the SecureTrading endpoint.
*/
public function call($type)
{
$failure = new STPPResponse("<responseblock></responseblock>");
if(!$this->connection)
return $failure;
$request = $this->compile($type);
$outbound = $request->asXML()."\r\n";
if(!fwrite($this->connection, $outbound, strlen($outbound)))
return $failure;
$response = "";
while(($chunk = fread($this->connection, 4096)) != false)
$response .= $chunk;
if(!$response)
return $failure;
return new STPPResponse($response, $request);
}
/**
* Called when compiling all of the nodes required for this request to properly proceed.
* Nothing like inter-breeding SimpleXML and DOM!
*/
public function compile($method)
public function getRequestXML($method)
{
$envelope = new SimpleXMLElement("<?xml version='1.0' encoding='UTF-8'?><requestblock></requestblock>");
......@@ -423,8 +195,6 @@ class STAPI
$document->appendChild($component);
}
return $envelope;
}
}
return $envelope->asXML();
}
}
\ No newline at end of file
<?php
/**
* Response for STPP/STAPI
*
* @version: 2.0.0
* @author: David Weston <stpp@typefish.co.uk>
*/
namespace OUTRAGElib\Payment\STPP;
use \OUTRAGElib\Payment\STPP\Request;
use \OUTRAGElib\Payment\STPP\Response;
class RequestHandler
{
/**
* HTTPS Request information
*/
protected $endpoint = null;
protected $username = null;
protected $password = null;
/**
* Request object
*/
protected $request = null;
/**
* Set endpoint
*/
public function setEndpoint($endpoint)
{
$this->endpoint = $endpoint;
return $this;
}
/**
* Set username
*/
public function setUsername($username)
{
$this->username = $username;
return $this;
}
/**
* Set password
*/
public function setPassword($password)
{
$this->password = $password;
return $this;
}
/**
* Set request
*/
public function setRequest(Request $request)
{
$this->request = $request;
return $this;
}
/**
* Used to push a request off to the SecureTrading endpoint.
*/
public function call($method)
{
$ch = curl_init();
$headers = [
"Content-Type: text/xml",
"Accept: text/xml",
"Authorization: Basic ".base64_encode($this->username.":".$this->password),
];
curl_setopt($ch, CURLOPT_URL, $this->endpoint);
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $this->request->getRequestXML());
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$output = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE) == 200;
curl_close($ch);
if($status)
return new Response($request, $output);
return false;
}
}
\ No newline at end of file
<?php
/**
* PHP based wrapper for SecureTrading's new STPP protocol.
*
* The STPPResponse object parses the response from the SecureTrading endpoint,
* and puts it into a nice easy to use output.
* Response for STPP/STAPI
*
* This class can be used to revisit previous transactions. All you need to do is
* give the XML response as the argument to the constructor and all will be
* revealed.
*
* @version: 1.0
* @version: 2.0.0
* @author: David Weston <stpp@typefish.co.uk>
*/
class STPPResponse
namespace OUTRAGElib\Payment\STPP;
use \OUTRAGElib\Payment\STPP\Request;
use \SimpleXMLElement;
class Response
{
/**
* Store the XML response somewhere...
*/
private $feed = null;
/**
* The request?
*/
private $request = null;
/**
* Called when the response has been constructed.
*/
public function __construct($response = null, $request = null)
public function __construct(Request $request, $response)
{
$this->feed = simplexml_load_string($response);
$this->request = $request;
......@@ -84,6 +88,9 @@ class STPPResponse
*/
public function getTransactionReference()
{
if(!isset($this->feed->response->transactionreference))
return null;
return (string) $this->feed->response->transactionreference;
}
......@@ -99,9 +106,9 @@ class STPPResponse
public function getSecurityRating()
{
if(!isset($this->feed->response->security))
return array();
return [];
$set = array();
$set = [];
foreach($this->feed->response->security as $node)
{
......@@ -109,22 +116,16 @@ class STPPResponse
{
case 0:
case 1:
{
$set[$node->getName()] = null;
break;
}
break;
case 2:
{
$set[$node->getName()] = true;
break;
}
break;
case 4:
{
$set[$node->getName()] = false;
break;
}
break;
}
}
......@@ -141,6 +142,6 @@ class STPPResponse
if(!isset($this->feed->response->live))
return null;
return ((integer) $this->feed->response->live == 1);
return (integer) $this->feed->response->live === 1;
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment