3 #******************************************************************************
5 #* Description : The objects for PX Payment page
6 #* Copyright (c) : 2004 Direct Payment solutions
8 #* Modifications : 2003-12-24 MifMessage class
9 #* : 2004-09-01 PxAccess, PxPayRequest, PxPayResponse classes
10 #* which encapsulate 3-DES to handle payment requests and
12 #* 2004-10-14 Implements complete transactions
13 #* 2005-03-14 change unpack("H*", $enc); to unpack("H$enclen", $enc);
14 #* due to the version 4.3.10 Php unpack function bugs
16 #******************************************************************************
19 # Use this class to parse a DPS PX MifMessage in XML form,
20 # and access the content.
28 # Create a MifMessage with the specified XML text.
29 # The constructor returns a null object if there is a parsing error.
30 function MifMessage($xml)
32 $p = xml_parser_create();
33 xml_parser_set_option($p,XML_OPTION_CASE_FOLDING
,0);
34 $ok = xml_parse_into_struct($p, $xml, $value, $index);
39 $this->xml_value_
= $value;
40 $this->xml_index_
= $index;
42 #print_r($this->xml_value_); # JH_DEBUG
45 # Return the value of the specified top-level attribute.
46 # This method can only return attributes of the root element.
47 # If the attribute is not found, return "".
48 function get_attribute($attribute)
50 #$attribute = strtoupper($attribute);
51 $attributes = $this->xml_value_
[0]["attributes"];
52 return $attributes[$attribute];
55 # Return the text of the specified element.
56 # The element is given as a simplified XPath-like name.
57 # For example, "Link/ServerOk" refers to the ServerOk element
58 # nested in the Link element (nested in the root element).
59 # If the element is not found, return "".
60 function get_element_text($element)
62 #print_r($this->xml_value_); # JH_DEBUG
63 $index = $this->get_element_index($element, 0);
70 ## TW2004-09-24: Fixed bug when elemnt existent but empty
72 $elementObj = $this->xml_value_
[$index];
73 if (! array_key_exists("value", $elementObj))
76 return $this->xml_value_
[$index]["value"];
81 # Return the index of the specified element,
82 # relative to some given root element index.
84 function get_element_index($element, $rootindex = 0)
86 #$element = strtoupper($element);
87 $pos = strpos($element, "/");
90 # element contains '/': find first part
91 $start_path = substr($element,0,$pos);
92 $remain_path = substr($element,$pos+
1);
93 $index = $this->get_element_index($start_path, $rootindex);
96 # couldn't find first part; give up.
99 # recursively find rest
100 return $this->get_element_index($remain_path, $index);
104 # search from the parent across all its children
105 # i.e. until we get the parent's close tag.
106 $level = $this->xml_value_
[$rootindex]["level"];
107 if ($this->xml_value_
[$rootindex]["type"] == "complete")
109 return 0; # no children
111 $index = $rootindex+
1;
112 while ($index<count($this->xml_value_
) &&
113 !($this->xml_value_
[$index]["level"]==$level &&
114 $this->xml_value_
[$index]["type"]=="close"))
116 # if one below parent and tag matches, bingo
117 if ($this->xml_value_
[$index]["level"] == $level+
1 &&
118 # $this->xml_value_[$index]["type"] == "complete" &&
119 $this->xml_value_
[$index]["tag"] == $element)
132 var $Mac_Key, $Des_Key;
134 var $PxAccess_Userid;
135 function PxAccess($Url, $UserId, $Des_Key, $Mac_Key){
136 error_reporting(E_ERROR
);
137 $this->Mac_Key
= pack("H*",$Mac_Key);
138 $this->Des_Key
= pack("H*", $Des_Key);
139 $this->PxAccess_Url
= $Url;
140 $this->PxAccess_Userid
= $UserId;
142 function makeRequest($request)
144 #Validate the REquest
145 if($request->validData() == false) return "" ;
147 #$txnId=rand(1,100000);
148 $txnId = uniqid("MI"); #You need to generate you own unqiue reference. JZ:2004-08-12
149 $request->setTxnId($txnId);
150 $request->setTs($this->getCurrentTS());
151 $request->setSwVersion("2.01.01");
152 $request->setAppletType("PHPPxAccess");
155 $xml = $request->toXml();
157 if (strlen($xml)%8
!= 0)
159 $xml = str_pad($xml, strlen($xml) +
8-strlen($xml)%8
); # pad to multiple of 8
161 #add MAC code JZ2004-8-16
162 $mac = $this->makeMAC($xml,$this->Mac_Key
);
165 $enc = $this->encrypt_tripledes($msg, $this->Des_Key
); #JZ2004-08-16: Include the MAC code
167 $enclen = strlen($enc) * 2;
169 $enc_hex = unpack("H$enclen", $enc); #JZ2005-03-14: there is a bug in the new version php unpack function
170 #$enc_hex = @unpack("H*", $enc); #JZ2005-03-14: there is a bug in the new version php unpack function
172 #$enc_hex = $enc_hex[""]; #use this function if PHP version before 4.3.4
173 #$enc_hex = $enc_hex[1]; #use this function if PHP version after 4.3.4
174 $enc_hex = (version_compare(PHP_VERSION
, "4.3.4", ">=")) ?
$enc_hex[1] :$enc_hex[""];
176 $PxAccess_Redirect = "$this->PxAccess_Url?userid=$this->PxAccess_Userid&request=$enc_hex";
178 return $PxAccess_Redirect;
182 #******************************************************************************
183 # This function ecrypts data using 3DES via libmcrypt
184 #******************************************************************************
185 function encrypt_tripledes($data, $key)
187 # deprecated libmcrypt 2.2 encryption: use this if you have libmcrypt 2.2.x
188 # $result = mcrypt_ecb(MCRYPT_DES, $key, $data, MCRYPT_ENCRYPT);
191 # otherwise use this for libmcrypt 2.4.x and above:
192 $td = mcrypt_module_open('tripledes', '', 'ecb', '');
193 $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND
);
194 mcrypt_generic_init($td, $key, $iv);
195 $result = mcrypt_generic($td, $data);
196 #mcrypt_generic_deinit($td); #Might cause problem in some PHP version
201 #******************************************************************************
202 # This function decrypts data using 3DES via libmcrypt
203 #******************************************************************************
204 function decrypt_tripledes($data, $key)
206 # deprecated libmcrypt 2.2 encryption: use this if you have libmcrypt 2.2.x
207 # $result = mcrypt_ecb(MCRYPT_DES, $key, $data, MCRYPT_DECRYPT);
210 # otherwise use this for libmcrypt 2.4.x and above:
211 $td = mcrypt_module_open('tripledes', '', 'ecb', '');
212 $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND
);
213 mcrypt_generic_init($td, $key, $iv);
214 $result = mdecrypt_generic($td, $data);
215 #mcrypt_generic_deinit($td); #Might cause problem in some PHP version
221 #******************************************************************************
222 # Generate and return a message authentication code (MAC) for a string.
223 # (Uses ANSI X9.9 procedure.)
224 #******************************************************************************
225 function makeMAC($msg,$Mackey){
227 if (strlen($msg)%8
!= 0)
229 $extra = 8 - strlen($msg)%8
;
230 $msg .= str_repeat(" ", $extra); # pad to multiple of 8
232 $mac = pack("C*", 0, 0, 0, 0, 0, 0, 0, 0); # start with all zeros
233 #$mac_result = unpack("C*", $mac);
235 for ( $i=0; $i<strlen($msg)/8; $i++
)
237 $msg8 = substr($msg, 8*$i, 8);
240 $mac = $this->encrypt_des($mac,$Mackey);
243 #$mac = pack("C*", $mac);
244 #$mac_result= encrypt_des($mac, $Mackey);
246 $mac_result = unpack("H8", $mac);
247 #$mac_result = $mac_result[""]; #use this function if PHP version before 4.3.4
248 #$mac_result = $mac_result[1]; #use this function if PHP version after 4.3.4
249 $mac_result = (version_compare(PHP_VERSION
, "4.3.4", ">=")) ?
$mac_result[1]: $mac_result[""];
256 #******************************************************************************
257 # This function ecrypts data using DES via libmcrypt
259 #******************************************************************************
260 function encrypt_des($data, $key)
262 # deprecated libmcrypt 2.2 encryption: use this if you have libmcrypt 2.2.x
263 # $result = mcrypt_ecb(MCRYPT_3DES, $key, $data, MCRYPT_ENCRYPT);
266 # otherwise use this for libmcrypt 2.4.x and above:
267 $td = mcrypt_module_open('des', '', 'ecb', '');
268 $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND
);
269 mcrypt_generic_init($td, $key, $iv);
270 $result = mcrypt_generic($td, $data);
271 #mcrypt_generic_deinit($td); #Might cause problem in some PHP version
272 mcrypt_module_close($td);
279 function getResponse($resp_enc){
281 $enc = pack("H*", $resp_enc);
282 $resp = trim($this->decrypt_tripledes($enc, $this->Des_Key
));
283 $xml = substr($resp, 0, strlen($resp)-8);
284 $mac = substr($resp, -8);
285 $checkmac = $this->makeMac($xml, $this->Mac_Key
);
286 if($mac != $checkmac){
287 $xml = "<success>0</success><ResponseText>Response MAC Invalid</ResponseText>";
290 $pxresp = new PxPayResponse($xml);
297 #******************************************************************************
298 # Return the current time (GMT/UTC).The return time formatted YYYYMMDDHHMMSS.
300 #******************************************************************************
301 function getCurrentTS()
304 return gmstrftime("%Y%m%d%H%M%S", time());
311 #******************************************************************************
312 # Class for PxPay request messages.
313 #******************************************************************************
314 class PxPayRequest
extends PxPayMessage
316 var $TxnId,$UrlFail,$UrlSuccess;
317 var $AmountInput, $AppletVersion, $InputCurrency;
318 var $EnableAddBillCard;
324 function PxPayRequest(){
325 $this->PxPayMessage();
329 function setAppletType($AppletType){
330 $this->AppletType
= $AppletType;
333 function getAppletType(){
334 return $this->AppletType
;
342 function setEnableAddBillCard($EnableBillAddCard){
343 $this->EnableAddBillCard
= $EnableBillAddCard;
346 function getEnableAddBillCard(){
347 return $this->EnableAddBillCard
;
349 function setInputCurrency($InputCurrency){
350 $this->InputCurrency
= $InputCurrency;
352 function getInputCurrency(){
353 return $this->InputCurrency
;
355 function setTxnId( $TxnId)
357 $this->TxnId
= $TxnId;
363 function setUrlFail($UrlFail){
364 $this->UrlFail
= $UrlFail;
366 function getUrlFail(){
367 return $this->UrlFail
;
369 function setUrlSuccess($UrlSuccess){
370 $this->UrlSuccess
= $UrlSuccess;
372 function setAmountInput($AmountInput){
373 $this->AmountInput
= sprintf("%9.2f",$AmountInput);
376 function getAmountInput(){
377 return $this->AmountInput
;
379 function setSwVersion($SwVersion){
380 $this->AppletVersion
= $SwVersion;
383 function getSwVersion(){
384 return $this->AppletVersion
;
386 #******************************************************************
388 #******************************************************************
389 function validData(){
391 if($this->TxnType
!= "Purchase")
392 if($this->TxnType
!= "Auth")
393 if($this->TxnType
!= "GetCurrRate")
394 if($this->TxnType
!= "Refund")
395 if($this->TxnType
!= "Complete")
396 if($this->TxnType
!= "Order1")
397 $msg = "Invalid TxnType[$this->TxnType]<br>";
399 if(strlen($this->MerchantReference
) > 64)
400 $msg = "Invalid MerchantReference [$this->MerchantReference]<br>";
402 if(strlen($this->TxnId
) > 16)
403 $msg = "Invalid TxnId [$this->TxnId]<br>";
404 if(strlen($this->TxnData1
) > 255)
405 $msg = "Invalid TxnData1 [$this->TxnData1]<br>";
406 if(strlen($this->TxnData2
) > 255)
407 $msg = "Invalid TxnData2 [$this->TxnData2]<br>";
408 if(strlen($this->TxnData3
) > 255)
409 $msg = "Invalid TxnData3 [$this->TxnData3]<br>";
411 if(strlen($this->EmailAddress
) > 255)
412 $msg = "Invalid EmailAddress [$this->EmailAddress]<br>";
414 if(strlen($this->UrlFail
) > 255)
415 $msg = "Invalid UrlFail [$this->UrlFail]<br>";
416 if(strlen($this->UrlSuccess
) > 255)
417 $msg = "Invalid UrlSuccess [$this->UrlSuccess]<br>";
418 if(strlen($this->BillingId
) > 32)
419 $msg = "Invalid BillingId [$this->BillingId]<br>";
420 if(strlen($this->DpsBillingId
) > 16)
421 $msg = "Invalid DpsBillingId [$this->DpsBillingId]<br>";
424 trigger_error($msg,E_USER_ERROR
);
432 #******************************************************************************
433 # Abstract base class for PxPay messages.
434 # These are messages with certain defined elements, which can be serialized to XML.
436 #******************************************************************************
442 var $MerchantReference;
448 function PxPayMessage(){
451 function setDpsTxnRef($DpsTxnRef){
452 $this->DpsTxnRef
= $DpsTxnRef;
455 function getDpsTxnRef(){
456 return $this->DpsTxnRef
;
459 function setDpsBillingId($DpsBillingId){
460 $this->DpsBillingId
= $DpsBillingId;
463 function getDpsBillingId(){
464 return $this->DpsBillingId
;
466 function setBillingId($BillingId){
467 $this->BillingId
= $BillingId;
470 function getBillingId(){
471 return $this->BillingId
;
473 function setTxnType($TxnType){
474 $this->TxnType
= $TxnType;
476 function getTxnType(){
477 return $this->TxnType
;
479 function setMerchantReference($MerchantReference){
480 $this->MerchantReference
= $MerchantReference;
483 function getMerchantReference(){
484 return $this->MerchantReference
;
486 function setEmailAddress($EmailAddress){
487 $this->EmailAddress
= $EmailAddress;
491 function getEmailAddress(){
492 return $this->EmailAddress
;
495 function setTxnData1($TxnData1){
496 $this->TxnData1
= $TxnData1;
499 function getTxnData1(){
500 return $this->TxnData1
;
502 function setTxnData2($TxnData2){
503 $this->TxnData2
= $TxnData2;
506 function getTxnData2(){
507 return $this->TxnData2
;
510 function getTxnData3(){
511 return $this->TxnData3
;
513 function setTxnData3($TxnData3){
514 $this->TxnData3
= $TxnData3;
518 $arr = get_object_vars($this);
519 $root = get_class($this);
520 if($root == "PxPayRequest")
522 elseif ($root == "PxPayResponse")
528 while (list($prop, $val) = each($arr))
529 $xml .= "<$prop>$val</$prop>" ;
538 #******************************************************************************
539 # Class for PxPay response messages.
540 #******************************************************************************
542 class PxPayResponse
extends PxPayMessage
548 var $AmountSettlement;
549 var $CurrencySettlement;
558 function PxPayResponse($xml){
559 $msg = new MifMessage($xml);
560 $this->PxPayMessage();
562 $TS = $msg->get_element_text("TS");
563 $expiryTS = $this->getExpiredTS();
564 if(strcmp($TS, $expiryTS) < 0 ){
565 $this->Success
= "0";
566 $this->ResponseText
= "Response TS out of range";
570 $this->setBillingId($msg->get_element_text("BillingId"));
571 $this->setDpsBillingId($msg->get_element_text("DpsBillingId"));
572 $this->setEmailAddress($msg->get_element_text("EmailAddress"));
573 $this->setMerchantReference($msg->get_element_text("MerchantReference"));
574 $this->setTxnData1($msg->get_element_text("TxnData1"));
575 $this->setTxnData2($msg->get_element_text("TxnData2"));
576 $this->setTxnData3($msg->get_element_text("TxnData3"));
577 $this->setTxnType($msg->get_element_text("TxnType"));
579 $this->Success
= $msg->get_element_text("Success");
580 $this->StatusRequired
= $msg->get_element_text("StatusRequired");
581 $this->Retry
= $msg->get_element_text("Retry");
582 $this->AuthCode
= $msg->get_element_text("AuthCode");
583 $this->AmountSettlement
= $msg->get_element_text("AmountSettlement");
584 $this->CurrencySettlement
= $msg->get_element_text("CurrencySettlement");
585 $this->CardName
= $msg->get_element_text("CardName");
586 $this->CurrencyInput
= $msg->get_element_text("CurrencyInput");
587 $this->UserId
= $msg->get_element_text("UserId");
588 $this->ResponseText
= $msg->get_element_text("ResponseText");
589 $this->DpsTxnRef
= $msg->get_element_text("DpsTxnRef");
590 $this->MerchantTxnId
= $msg->get_element_text("MerchantTxnId");
591 $this->TS
= $msg->get_element_text("TS");
596 function getMerchantTxnId(){
597 return $this->MerchantTxnId
;
600 function getResponseText(){
601 return $this->ResponseText
;
603 function getUserId(){
604 return $this->UserId
;
606 function getCurrencyInput(){
607 return $this->CurrencyInput
;
609 function getCardName(){
610 return $this->CardName
;
612 function getCurrencySettlement(){
613 $this->CurrencySettlement
;
615 function getAmountSettlement(){
616 return $this->AmountSettlement
;
618 function getSuccess(){
619 return $this->Success
;
621 function getStatusRequired(){
622 return $this->StatusRequired
;
627 function getAuthCode(){
628 return $this->AuthCode
;
630 #******************************************************************************
631 # Return the expired time, i.e. 2 days ago (GMT/UTC).
633 #******************************************************************************
634 function getExpiredTS()
637 return gmstrftime("%Y%m%d%H%M%S", time()- 2 * 24 * 60 * 60);