Skip to content

Instantly share code, notes, and snippets.

@t-oster
Created April 18, 2018 06:53
Show Gist options
  • Save t-oster/a1bed2bb82d566bbdb90706d521a8f83 to your computer and use it in GitHub Desktop.
Save t-oster/a1bed2bb82d566bbdb90706d521a8f83 to your computer and use it in GitHub Desktop.
Little helper class to request a payment on an OPI enabled Card Terminal
<?php
/**
* Little helper class to request a payment on an OPI enabled Card Terminal
*/
class OPIHelper {
private $ip;
private $port;
private $requestID = 0;
private function requestID()
{
return $this->requestID++;
}
private function loginXML()
{
return "
<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>
<ServiceRequest RequestType=\"Login\" WorkstationID=\"0\" RequestID=\"".$this->requestID()."\">
<POSdata>
<POSTimeStamp>".date("c")."</POSTimeStamp>
</POSdata>
</ServiceRequest>";
}
private function reconciliationXML()
{
return "
<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>
<ServiceRequest RequestType=\"Reconciliation\" WorkstationID=\"0\" RequestID=\"".$this->requestID()."\">
<POSdata>
<POSTimeStamp>".date("c")."</POSTimeStamp>
</POSdata>
</ServiceRequest>";
}
private function logoutXML()
{
return "
<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>
<ServiceRequest RequestType=\"Logoff\" WorkstationID=\"0\" RequestID=\"".$this->requestID()."\">
<POSdata>
<POSTimeStamp>".date("c")."</POSTimeStamp>
</POSdata>
</ServiceRequest>";
}
private function cardPaymentXML($amount)
{
return "
<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>
<CardServiceRequest RequestType=\"CardPayment\" WorkstationID=\"0\" RequestID=\"".$this->requestID()."\">
<POSdata>
<POSTimeStamp>".date("c")."</POSTimeStamp>
</POSdata>
<TotalAmount>$amount</TotalAmount>
</CardServiceRequest>";
}
private function ticketReprintXML($originalTransaction = null)
{
return "
<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>
<CardServiceRequest RequestType=\"TicketReprint\" WorkstationID=\"0\" RequestID=\"".$this->requestID()."\">
<POSdata>
<POSTimeStamp>".date("c")."</POSTimeStamp>
</POSdata>
</CardServiceRequest>";
//TODO: <OriginalTransaction TerminalID="" TerminalBatch="" STAN="" TimeStamp""/>
}
private function receiveXML($f)
{
$length = unpack("Ni", fread($f, 4));
$data = fread($f, $length["i"]);
return $data;
}
private function sendXML($data, $f)
{
fwrite($f, pack("N", strlen($data)));
fwrite($f, $data);
return $this->receiveXML($f);
}
public function __construct($ip = "10.10.10.212", $port = 20002)
{
$this->ip = $ip;
$this->port = $port;
}
public function requestMoney($amount)
{
$result = false;
$f = fsockopen($this->ip, $this->port);
$data = $this->sendXML($this->loginXML(), $f);
if (strpos($data, 'OverallResult="Success"') === false)
{
echo "Error during login.";
echo $data;
fclose($f);
return false;
}
$data = $this->sendXML($this->cardPaymentXML($amount), $f);
if (strpos($data, 'OverallResult="Aborted"') !== false)
{
//aborted...
}
else if (strpos($data, 'OverallResult="Success"') !== false)
{
$result = true;
}
$data = $this->sendXML($this->logoutXML(), $f);
if (strpos($data, 'OverallResult="Success"') === false)
{
echo "Error during logout.";
echo $data;
}
fclose($f);
return $result;
}
public function reprintTicket()
{
$result = false;
$f = fsockopen($this->ip, $this->port);
$data = $this->sendXML($this->loginXML(), $f);
if (strpos($data, 'OverallResult="Success"') === false)
{
echo "Error during login.";
echo $data;
fclose($f);
return false;
}
$data = $this->sendXML($this->ticketReprintXML(), $f);
if (strpos($data, 'OverallResult="Success"') !== false)
{
$result = true;
}
$data = $this->sendXML($this->logoutXML(), $f);
if (strpos($data, 'OverallResult="Success"') === false)
{
echo "Error during logout.";
echo $data;
}
fclose($f);
return $result;
}
public function listPayments()
{
$result = false;
$f = fsockopen($this->ip, $this->port);
$data = $this->sendXML($this->loginXML(), $f);
if (strpos($data, 'OverallResult="Success"') === false)
{
echo "Error during login.";
echo $data;
fclose($f);
return false;
}
$data = $this->sendXML($this->reconciliationXML(), $f);
$xml = new SimpleXMLElement($data);
if ($xml["OverallResult"] == "Success")
{
$result = array();
foreach ($xml->Reconciliation as $r)
{
foreach ($r->TotalAmount as $ta)
{
$r = array();
foreach (array("NumberPayments","PaymentType","Currency","CardCircuit","Acquirer") as $field)
{
if (isset($ta[$field]) && $ta[$field] !== "")
{
$r[$field] = $ta[$field];
}
}
$result []= $r;
}
}
}
$data = $this->sendXML($this->logoutXML(), $f);
if (strpos($data, 'OverallResult="Success"') === false)
{
echo "Error during logout.";
echo $data;
}
fclose($f);
return $result;
}
}
@samikarak
Copy link

@Niksac @t-oster The terminal reacts strangely since the script only covers one communication channel (from pc to terminal and back). In order for the payment to be successful, you need the second channel (from terminal to pc and back) as well. The corresponding section of the specification is DeviceRequest and DeviceResponse

@oliverschaefer does this mean, that there needs to be 2 open channels at the same time? In which order are the requests send? In which order are the responses received? can you elaborate a little more on you suggestion this would help me out a lot. Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment