drupal-civicrm/sites/all/modules/civicrm/packages/PaymentExpress/pxaccess.inc.php
2018-01-14 13:10:16 +00:00

643 lines
19 KiB
PHP

<?php
#******************************************************************************
#* Name : PxAccess.inc
#* Description : The objects for PX Payment page
#* Copyright (c) : 2004 Direct Payment solutions
#* Date : 2003-12-24
#* Modifications : 2003-12-24 MifMessage class
#* : 2004-09-01 PxAccess, PxPayRequest, PxPayResponse classes
#* which encapsulate 3-DES to handle payment requests and
#* response.
#* 2004-10-14 Implements complete transactions
#* 2005-03-14 change unpack("H*", $enc); to unpack("H$enclen", $enc);
#* due to the version 4.3.10 Php unpack function bugs
#*Version : 2.01.08
#******************************************************************************
# MifMessage.
# Use this class to parse a DPS PX MifMessage in XML form,
# and access the content.
class MifMessage
{
var $xml_;
var $xml_index_;
var $xml_value_;
# Constructor:
# Create a MifMessage with the specified XML text.
# The constructor returns a null object if there is a parsing error.
function __construct($xml)
{
$p = xml_parser_create();
xml_parser_set_option($p,XML_OPTION_CASE_FOLDING,0);
$ok = xml_parse_into_struct($p, $xml, $value, $index);
xml_parser_free($p);
if ($ok)
{
$this->xml_ = $xml;
$this->xml_value_ = $value;
$this->xml_index_ = $index;
}
#print_r($this->xml_value_); # JH_DEBUG
}
# Return the value of the specified top-level attribute.
# This method can only return attributes of the root element.
# If the attribute is not found, return "".
function get_attribute($attribute)
{
#$attribute = strtoupper($attribute);
$attributes = $this->xml_value_[0]["attributes"];
return $attributes[$attribute];
}
# Return the text of the specified element.
# The element is given as a simplified XPath-like name.
# For example, "Link/ServerOk" refers to the ServerOk element
# nested in the Link element (nested in the root element).
# If the element is not found, return "".
function get_element_text($element)
{
#print_r($this->xml_value_); # JH_DEBUG
$index = $this->get_element_index($element, 0);
if ($index == 0)
{
return "";
}
else
{
## TW2004-09-24: Fixed bug when elemnt existent but empty
#
$elementObj = $this->xml_value_[$index];
if (! array_key_exists("value", $elementObj))
return "";
return $this->xml_value_[$index]["value"];
}
}
# (internal method)
# Return the index of the specified element,
# relative to some given root element index.
#
function get_element_index($element, $rootindex = 0)
{
#$element = strtoupper($element);
$pos = strpos($element, "/");
if ($pos !== false)
{
# element contains '/': find first part
$start_path = substr($element,0,$pos);
$remain_path = substr($element,$pos+1);
$index = $this->get_element_index($start_path, $rootindex);
if ($index == 0)
{
# couldn't find first part; give up.
return 0;
}
# recursively find rest
return $this->get_element_index($remain_path, $index);
}
else
{
# search from the parent across all its children
# i.e. until we get the parent's close tag.
$level = $this->xml_value_[$rootindex]["level"];
if ($this->xml_value_[$rootindex]["type"] == "complete")
{
return 0; # no children
}
$index = $rootindex+1;
while ($index<count($this->xml_value_) &&
!($this->xml_value_[$index]["level"]==$level &&
$this->xml_value_[$index]["type"]=="close"))
{
# if one below parent and tag matches, bingo
if ($this->xml_value_[$index]["level"] == $level+1 &&
# $this->xml_value_[$index]["type"] == "complete" &&
$this->xml_value_[$index]["tag"] == $element)
{
return $index;
}
$index++;
}
return 0;
}
}
}
class PxAccess
{
var $Mac_Key, $Des_Key;
var $PxAccess_Url;
var $PxAccess_Userid;
function __construct($Url, $UserId, $Des_Key, $Mac_Key){
error_reporting(E_ERROR);
$this->Mac_Key = pack("H*",$Mac_Key);
$this->Des_Key = pack("H*", $Des_Key);
$this->PxAccess_Url = $Url;
$this->PxAccess_Userid = $UserId;
}
function makeRequest($request)
{
#Validate the REquest
if($request->validData() == false) return "" ;
#$txnId=rand(1,100000);
$txnId = uniqid("MI"); #You need to generate you own unqiue reference. JZ:2004-08-12
$request->setTxnId($txnId);
$request->setTs($this->getCurrentTS());
$request->setSwVersion("2.01.01");
$request->setAppletType("PHPPxAccess");
$xml = $request->toXml();
if (strlen($xml)%8 != 0)
{
$xml = str_pad($xml, strlen($xml) + 8-strlen($xml)%8); # pad to multiple of 8
}
#add MAC code JZ2004-8-16
$mac = $this->makeMAC($xml,$this->Mac_Key );
$msg = $xml.$mac;
#$msg = $xml;
$enc = $this->encrypt_tripledes($msg, $this->Des_Key); #JZ2004-08-16: Include the MAC code
$enclen = strlen($enc) * 2;
$enc_hex = unpack("H$enclen", $enc); #JZ2005-03-14: there is a bug in the new version php unpack function
#$enc_hex = @unpack("H*", $enc); #JZ2005-03-14: there is a bug in the new version php unpack function
#$enc_hex = $enc_hex[""]; #use this function if PHP version before 4.3.4
#$enc_hex = $enc_hex[1]; #use this function if PHP version after 4.3.4
$enc_hex = (version_compare(PHP_VERSION, "4.3.4", ">=")) ? $enc_hex[1] :$enc_hex[""];
$PxAccess_Redirect = "$this->PxAccess_Url?userid=$this->PxAccess_Userid&request=$enc_hex";
return $PxAccess_Redirect;
}
#******************************************************************************
# This function ecrypts data using 3DES via libmcrypt
#******************************************************************************
function encrypt_tripledes($data, $key)
{
# deprecated libmcrypt 2.2 encryption: use this if you have libmcrypt 2.2.x
# $result = mcrypt_ecb(MCRYPT_DES, $key, $data, MCRYPT_ENCRYPT);
# return $result;
#
# otherwise use this for libmcrypt 2.4.x and above:
$td = mcrypt_module_open('tripledes', '', 'ecb', '');
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
mcrypt_generic_init($td, $key, $iv);
$result = mcrypt_generic($td, $data);
#mcrypt_generic_deinit($td); #Might cause problem in some PHP version
return $result;
}
#******************************************************************************
# This function decrypts data using 3DES via libmcrypt
#******************************************************************************
function decrypt_tripledes($data, $key)
{
# deprecated libmcrypt 2.2 encryption: use this if you have libmcrypt 2.2.x
# $result = mcrypt_ecb(MCRYPT_DES, $key, $data, MCRYPT_DECRYPT);
# return $result;
#
# otherwise use this for libmcrypt 2.4.x and above:
$td = mcrypt_module_open('tripledes', '', 'ecb', '');
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
mcrypt_generic_init($td, $key, $iv);
$result = mdecrypt_generic($td, $data);
#mcrypt_generic_deinit($td); #Might cause problem in some PHP version
return $result;
}
#JZ2004-08-16
#******************************************************************************
# Generate and return a message authentication code (MAC) for a string.
# (Uses ANSI X9.9 procedure.)
#******************************************************************************
function makeMAC($msg,$Mackey){
if (strlen($msg)%8 != 0)
{
$extra = 8 - strlen($msg)%8;
$msg .= str_repeat(" ", $extra); # pad to multiple of 8
}
$mac = pack("C*", 0, 0, 0, 0, 0, 0, 0, 0); # start with all zeros
#$mac_result = unpack("C*", $mac);
for ( $i=0; $i<strlen($msg)/8; $i++)
{
$msg8 = substr($msg, 8*$i, 8);
$mac ^= $msg8;
$mac = $this->encrypt_des($mac,$Mackey);
}
#$mac = pack("C*", $mac);
#$mac_result= encrypt_des($mac, $Mackey);
$mac_result = unpack("H8", $mac);
#$mac_result = $mac_result[""]; #use this function if PHP version before 4.3.4
#$mac_result = $mac_result[1]; #use this function if PHP version after 4.3.4
$mac_result = (version_compare(PHP_VERSION, "4.3.4", ">=")) ? $mac_result[1]: $mac_result[""];
return $mac_result;
}
#******************************************************************************
# This function ecrypts data using DES via libmcrypt
# JZ2004-08-16
#******************************************************************************
function encrypt_des($data, $key)
{
# deprecated libmcrypt 2.2 encryption: use this if you have libmcrypt 2.2.x
# $result = mcrypt_ecb(MCRYPT_3DES, $key, $data, MCRYPT_ENCRYPT);
# return $result;
#
# otherwise use this for libmcrypt 2.4.x and above:
$td = mcrypt_module_open('des', '', 'ecb', '');
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
mcrypt_generic_init($td, $key, $iv);
$result = mcrypt_generic($td, $data);
#mcrypt_generic_deinit($td); #Might cause problem in some PHP version
mcrypt_module_close($td);
return $result;
}
#JZ2004-08-16
function getResponse($resp_enc){
#global $Mac_Key;
$enc = pack("H*", $resp_enc);
$resp = trim($this->decrypt_tripledes($enc, $this->Des_Key));
$xml = substr($resp, 0, strlen($resp)-8);
$mac = substr($resp, -8);
$checkmac = $this->makeMac($xml, $this->Mac_Key);
if($mac != $checkmac){
$xml = "<success>0</success><ResponseText>Response MAC Invalid</ResponseText>";
}
$pxresp = new PxPayResponse($xml);
return $pxresp;
}
#******************************************************************************
# Return the current time (GMT/UTC).The return time formatted YYYYMMDDHHMMSS.
#JZ2004-08-30
#******************************************************************************
function getCurrentTS()
{
return gmstrftime("%Y%m%d%H%M%S", time());
}
}
#******************************************************************************
# Class for PxPay request messages.
#******************************************************************************
class PxPayRequest extends PxPayMessage
{
var $TxnId,$UrlFail,$UrlSuccess;
var $AmountInput, $AppletVersion, $InputCurrency;
var $EnableAddBillCard;
var $TS;
var $AppletType;
#Constructor
function __construct(){
$this->PxPayMessage();
}
function setAppletType($AppletType){
$this->AppletType = $AppletType;
}
function getAppletType(){
return $this->AppletType;
}
function setTs($Ts){
$this->TS = $Ts;
}
function setEnableAddBillCard($EnableBillAddCard){
$this->EnableAddBillCard = $EnableBillAddCard;
}
function getEnableAddBillCard(){
return $this->EnableAddBillCard;
}
function setInputCurrency($InputCurrency){
$this->InputCurrency = $InputCurrency;
}
function getInputCurrency(){
return $this->InputCurrency;
}
function setTxnId( $TxnId)
{
$this->TxnId = $TxnId;
}
function getTxnId(){
return $this->TxnId;
}
function setUrlFail($UrlFail){
$this->UrlFail = $UrlFail;
}
function getUrlFail(){
return $this->UrlFail;
}
function setUrlSuccess($UrlSuccess){
$this->UrlSuccess = $UrlSuccess;
}
function setAmountInput($AmountInput){
$this->AmountInput = sprintf("%9.2f",$AmountInput);
}
function getAmountInput(){
return $this->AmountInput;
}
function setSwVersion($SwVersion){
$this->AppletVersion = $SwVersion;
}
function getSwVersion(){
return $this->AppletVersion;
}
#******************************************************************
#Data validation
#******************************************************************
function validData(){
$msg = "";
if($this->TxnType != "Purchase")
if($this->TxnType != "Auth")
if($this->TxnType != "GetCurrRate")
if($this->TxnType != "Refund")
if($this->TxnType != "Complete")
if($this->TxnType != "Order1")
$msg = "Invalid TxnType[$this->TxnType]<br>";
if(strlen($this->MerchantReference) > 64)
$msg = "Invalid MerchantReference [$this->MerchantReference]<br>";
if(strlen($this->TxnId) > 16)
$msg = "Invalid TxnId [$this->TxnId]<br>";
if(strlen($this->TxnData1) > 255)
$msg = "Invalid TxnData1 [$this->TxnData1]<br>";
if(strlen($this->TxnData2) > 255)
$msg = "Invalid TxnData2 [$this->TxnData2]<br>";
if(strlen($this->TxnData3) > 255)
$msg = "Invalid TxnData3 [$this->TxnData3]<br>";
if(strlen($this->EmailAddress) > 255)
$msg = "Invalid EmailAddress [$this->EmailAddress]<br>";
if(strlen($this->UrlFail) > 255)
$msg = "Invalid UrlFail [$this->UrlFail]<br>";
if(strlen($this->UrlSuccess) > 255)
$msg = "Invalid UrlSuccess [$this->UrlSuccess]<br>";
if(strlen($this->BillingId) > 32)
$msg = "Invalid BillingId [$this->BillingId]<br>";
if(strlen($this->DpsBillingId) > 16)
$msg = "Invalid DpsBillingId [$this->DpsBillingId]<br>";
if ($msg != "") {
trigger_error($msg,E_USER_ERROR);
return false;
}
return true;
}
}
#******************************************************************************
# Abstract base class for PxPay messages.
# These are messages with certain defined elements, which can be serialized to XML.
#******************************************************************************
class PxPayMessage {
var $TxnType;
var $TxnData1;
var $TxnData2;
var $TxnData3;
var $MerchantReference;
var $EmailAddress;
var $BillingId;
var $DpsBillingId;
var $DpsTxnRef;
function __construct(){
}
function setDpsTxnRef($DpsTxnRef){
$this->DpsTxnRef = $DpsTxnRef;
}
function getDpsTxnRef(){
return $this->DpsTxnRef;
}
function setDpsBillingId($DpsBillingId){
$this->DpsBillingId = $DpsBillingId;
}
function getDpsBillingId(){
return $this->DpsBillingId;
}
function setBillingId($BillingId){
$this->BillingId = $BillingId;
}
function getBillingId(){
return $this->BillingId;
}
function setTxnType($TxnType){
$this->TxnType = $TxnType;
}
function getTxnType(){
return $this->TxnType;
}
function setMerchantReference($MerchantReference){
$this->MerchantReference = $MerchantReference;
}
function getMerchantReference(){
return $this->MerchantReference;
}
function setEmailAddress($EmailAddress){
$this->EmailAddress = $EmailAddress;
}
function getEmailAddress(){
return $this->EmailAddress;
}
function setTxnData1($TxnData1){
$this->TxnData1 = $TxnData1;
}
function getTxnData1(){
return $this->TxnData1;
}
function setTxnData2($TxnData2){
$this->TxnData2 = $TxnData2;
}
function getTxnData2(){
return $this->TxnData2;
}
function getTxnData3(){
return $this->TxnData3;
}
function setTxnData3($TxnData3){
$this->TxnData3 = $TxnData3;
}
function toXml(){
$arr = get_object_vars($this);
$root = get_class($this);
if($root == "PxPayRequest")
$root = "Request";
elseif ($root == "PxPayResponse")
$root = "Response";
else
$root ="Request";
$xml = "<$root>";
while (list($prop, $val) = each($arr))
$xml .= "<$prop>$val</$prop>" ;
$xml .= "</$root>";
return $xml;
}
}
#******************************************************************************
# Class for PxPay response messages.
#******************************************************************************
class PxPayResponse extends PxPayMessage
{
var $Success;
var $StatusRequired;
var $Retry;
var $AuthCode;
var $AmountSettlement;
var $CurrencySettlement;
var $CardName;
var $CurrencyInput;
var $UserId;
var $ResponseText;
#var $DpsTxnRef;
var $MerchantTxnId;
var $TS;
function __construct($xml){
$msg = new MifMessage($xml);
$this->PxPayMessage();
$TS = $msg->get_element_text("TS");
$expiryTS = $this->getExpiredTS();
if(strcmp($TS, $expiryTS) < 0 ){
$this->Success = "0";
$this->ResponseText = "Response TS out of range";
return;
}
$this->setBillingId($msg->get_element_text("BillingId"));
$this->setDpsBillingId($msg->get_element_text("DpsBillingId"));
$this->setEmailAddress($msg->get_element_text("EmailAddress"));
$this->setMerchantReference($msg->get_element_text("MerchantReference"));
$this->setTxnData1($msg->get_element_text("TxnData1"));
$this->setTxnData2($msg->get_element_text("TxnData2"));
$this->setTxnData3($msg->get_element_text("TxnData3"));
$this->setTxnType($msg->get_element_text("TxnType"));
$this->Success = $msg->get_element_text("Success");
$this->StatusRequired = $msg->get_element_text("StatusRequired");
$this->Retry = $msg->get_element_text("Retry");
$this->AuthCode = $msg->get_element_text("AuthCode");
$this->AmountSettlement = $msg->get_element_text("AmountSettlement");
$this->CurrencySettlement = $msg->get_element_text("CurrencySettlement");
$this->CardName = $msg->get_element_text("CardName");
$this->CurrencyInput = $msg->get_element_text("CurrencyInput");
$this->UserId = $msg->get_element_text("UserId");
$this->ResponseText = $msg->get_element_text("ResponseText");
$this->DpsTxnRef = $msg->get_element_text("DpsTxnRef");
$this->MerchantTxnId = $msg->get_element_text("MerchantTxnId");
$this->TS = $msg->get_element_text("TS");
}
function getTS(){
return $this->TS;
}
function getMerchantTxnId(){
return $this->MerchantTxnId;
}
function getResponseText(){
return $this->ResponseText;
}
function getUserId(){
return $this->UserId;
}
function getCurrencyInput(){
return $this->CurrencyInput;
}
function getCardName(){
return $this->CardName;
}
function getCurrencySettlement(){
$this->CurrencySettlement;
}
function getAmountSettlement(){
return $this->AmountSettlement;
}
function getSuccess(){
return $this->Success;
}
function getStatusRequired(){
return $this->StatusRequired;
}
function getRetry(){
return $this->Retry;
}
function getAuthCode(){
return $this->AuthCode;
}
#******************************************************************************
# Return the expired time, i.e. 2 days ago (GMT/UTC).
#JZ2004-08-30
#******************************************************************************
function getExpiredTS()
{
return gmstrftime("%Y%m%d%H%M%S", time()- 2 * 24 * 60 * 60);
}
}
?>