"; exit(); } if ($value) { if (!CRM_Utils_Type::validate($value, $type)) { CRM_Core_Error::debug_log_message("Could not find a valid entry for $name"); echo "Failure: Invalid Parameter
";
exit();
}
}
return $value;
}
/**
* Constructor.
*
* @param string $mode
* The mode of operation: live or test.
*
* @param $paymentProcessor
*
* @return \CRM_Core_Payment_PaymentExpressIPN
*/
public function __construct($mode, &$paymentProcessor) {
parent::__construct();
$this->_mode = $mode;
$this->_paymentProcessor = $paymentProcessor;
}
/**
* The function gets called when a new order takes place.
*
* @param $success
* @param array $privateData
* Contains the name value pair of ";
return FALSE;
}
// lets replace invoice-id with Payment Processor -number because thats what is common and unique
// in subsequent calls or notifications sent by google.
$contribution->invoice_id = $input['newInvoice'];
$input['amount'] = $amount;
if ($contribution->total_amount != $input['amount']) {
CRM_Core_Error::debug_log_message("Amount values dont match between database and IPN request");
echo "Failure: Amount values dont match between database and IPN request. " . $contribution->total_amount . "/" . $input['amount'] . " ";
return FALSE;
}
$transaction = new CRM_Core_Transaction();
// check if contribution is already completed, if so we ignore this ipn
if ($contribution->contribution_status_id == 1) {
CRM_Core_Error::debug_log_message("returning since contribution has already been handled");
echo "Success: Contribution has already been handled ";
return TRUE;
}
else {
/* Since trxn_id hasn't got any use here,
* lets make use of it by passing the eventID/membershipTypeID to next level.
* And change trxn_id to the payment processor reference before finishing db update */
if ($ids['event']) {
$contribution->trxn_id = $ids['event'] . CRM_Core_DAO::VALUE_SEPARATOR . $ids['participant'];
}
else {
$contribution->trxn_id = $ids['membership'];
}
}
$this->completeTransaction($input, $ids, $objects, $transaction);
return TRUE;
}
/**
*
* /**
* The function returns the component(Event/Contribute..)and whether it is Test or not
*
* @param array $privateData
* Contains the name-value pairs of transaction related data.
* @param int $orderNo
* ";
exit();
}
if (stristr($contribution->source, 'Online Contribution')) {
$component = 'contribute';
}
elseif (stristr($contribution->source, 'Online Event Registration')) {
$component = 'event';
}
$isTest = $contribution->is_test;
$duplicateTransaction = 0;
if ($contribution->contribution_status_id == 1) {
//contribution already handled. (some processors do two notifications so this could be valid)
$duplicateTransaction = 1;
}
if ($component == 'contribute') {
if (!$contribution->contribution_page_id) {
CRM_Core_Error::debug_log_message("Could not find contribution page for contribution record: $contributionID");
echo "Failure: Could not find contribution page for contribution record: $contributionID ";
exit();
}
}
else {
$eventID = $privateData['eventID'];
if (!$eventID) {
CRM_Core_Error::debug_log_message("Could not find event ID");
echo "Failure: Could not find eventID ";
exit();
}
// we are in event mode
// make sure event exists and is valid
$event = new CRM_Event_DAO_Event();
$event->id = $eventID;
if (!$event->find(TRUE)) {
CRM_Core_Error::debug_log_message("Could not find event: $eventID");
echo "Failure: Could not find event: $eventID ";
exit();
}
}
return [$isTest, $component, $duplicateTransaction];
}
/**
* Main notification processing method.
*
* hex string from paymentexpress is passed to this function as hex string. Code based on googleIPN
* mac_key is only passed if the processor is pxaccess as it is used for decryption
* $dps_method is either pxaccess or pxpay
*
* @param string $dps_method
* @param array $rawPostData
* @param string $dps_url
* @param string $dps_user
* @param string $dps_key
* @param string $mac_key
*
* @throws \Exception
*/
public static function main($dps_method, $rawPostData, $dps_url, $dps_user, $dps_key, $mac_key) {
$config = CRM_Core_Config::singleton();
define('RESPONSE_HANDLER_LOG_FILE', $config->uploadDir . 'CiviCRM.PaymentExpress.log');
//Setup the log file
if (!$message_log = fopen(RESPONSE_HANDLER_LOG_FILE, "a")) {
error_func("Cannot open " . RESPONSE_HANDLER_LOG_FILE . " file.\n", 0);
exit(1);
}
if ($dps_method == "pxpay") {
$processResponse = CRM_Core_Payment_PaymentExpressUtils::_valueXml([
'PxPayUserId' => $dps_user,
'PxPayKey' => $dps_key,
'Response' => $_GET['result'],
]);
$processResponse = CRM_Core_Payment_PaymentExpressUtils::_valueXml('ProcessResponse', $processResponse);
fwrite($message_log, sprintf("\n\r%s:- %s\n", date("D M j G:i:s T Y"),
$processResponse
));
// Send the XML-formatted validation request to DPS so that we can receive a decrypted XML response which contains the transaction results
$curl = CRM_Core_Payment_PaymentExpressUtils::_initCURL($processResponse, $dps_url);
fwrite($message_log, sprintf("\n\r%s:- %s\n", date("D M j G:i:s T Y"),
$curl
));
$success = FALSE;
if ($response = curl_exec($curl)) {
$info = curl_getinfo($curl);
if ($info['http_code'] < 200 || $info['http_code'] > 299) {
$log_message = "DPS error: HTTP {$info['http_code']} retrieving {$info['url']}.";
CRM_Core_Error::fatal($log_message);
}
else {
fwrite($message_log, sprintf("\n\r%s:- %s\n", date("D M j G:i:s T Y"), $response));
curl_close($curl);
// Assign the returned XML values to variables
$valid = CRM_Core_Payment_PaymentExpressUtils::_xmlAttribute($response, 'valid');
// CRM_Core_Payment_PaymentExpressUtils::_xmlAttribute() returns NULL if preg fails.
if (is_null($valid)) {
CRM_Core_Error::fatal(ts("DPS error: Unable to parse XML response from DPS.", [1 => $valid]));
}
$success = CRM_Core_Payment_PaymentExpressUtils::_xmlElement($response, 'Success');
$txnId = CRM_Core_Payment_PaymentExpressUtils::_xmlElement($response, 'TxnId');
$responseText = CRM_Core_Payment_PaymentExpressUtils::_xmlElement($response, 'ResponseText');
$authCode = CRM_Core_Payment_PaymentExpressUtils::_xmlElement($response, 'AuthCode');
$DPStxnRef = CRM_Core_Payment_PaymentExpressUtils::_xmlElement($response, 'DpsTxnRef');
$qfKey = CRM_Core_Payment_PaymentExpressUtils::_xmlElement($response, "TxnData1");
$privateData = CRM_Core_Payment_PaymentExpressUtils::_xmlElement($response, "TxnData2");
list($component, $paymentProcessorID,) = explode(',', CRM_Core_Payment_PaymentExpressUtils::_xmlElement($response, "TxnData3"));
$amount = CRM_Core_Payment_PaymentExpressUtils::_xmlElement($response, "AmountSettlement");
$merchantReference = CRM_Core_Payment_PaymentExpressUtils::_xmlElement($response, "MerchantReference");
}
}
else {
// calling DPS failed
CRM_Core_Error::fatal(ts('Unable to establish connection to the payment gateway to verify transaction response.'));
exit;
}
}
elseif ($dps_method == "pxaccess") {
require_once 'PaymentExpress/pxaccess.inc.php';
global $pxaccess;
$pxaccess = new PxAccess($dps_url, $dps_user, $dps_key, $mac_key);
// GetResponse method in PxAccess object returns PxPayResponse object
// which encapsulates all the response data
$rsp = $pxaccess->getResponse($rawPostData);
$qfKey = $rsp->getTxnData1();
$privateData = $rsp->getTxnData2();
list($component, $paymentProcessorID) = explode(',', $rsp->getTxnData3());
$success = $rsp->getSuccess();
$authCode = $rsp->getAuthCode();
$DPStxnRef = $rsp->getDpsTxnRef();
$amount = $rsp->getAmountSettlement();
$MerchantReference = $rsp->getMerchantReference();
}
$privateData = $privateData ? self::stringToArray($privateData) : '';
// Record the current count in array, before we start adding things (for later checks)
$countPrivateData = count($privateData);
// Private Data consists of : a=contactID, b=contributionID,c=contributionTypeID,d=invoiceID,e=membershipID,f=participantID,g=eventID
$privateData['contactID'] = $privateData['a'];
$privateData['contributionID'] = $privateData['b'];
$privateData['contributionTypeID'] = $privateData['c'];
$privateData['invoiceID'] = $privateData['d'];
if ($component == "event") {
$privateData['participantID'] = $privateData['f'];
$privateData['eventID'] = $privateData['g'];
}
elseif ($component == "contribute") {
if ($countPrivateData == 5) {
$privateData["membershipID"] = $privateData['e'];
}
}
$transactionReference = $authCode . "-" . $DPStxnRef;
list($mode, $component, $duplicateTransaction) = self::getContext($privateData, $transactionReference);
$mode = $mode ? 'test' : 'live';
$paymentProcessor = CRM_Financial_BAO_PaymentProcessor::getPayment($paymentProcessorID,
$mode
);
$ipn = self::singleton($mode, $component, $paymentProcessor);
//Check status and take appropriate action
if ($success == 1) {
if ($duplicateTransaction == 0) {
$ipn->newOrderNotify($success, $privateData, $component, $amount, $transactionReference);
}
if ($component == "event") {
$finalURL = CRM_Utils_System::url('civicrm/event/register',
"_qf_ThankYou_display=1&qfKey=$qfKey",
FALSE, NULL, FALSE
);
}
elseif ($component == "contribute") {
$finalURL = CRM_Utils_System::url('civicrm/contribute/transact',
"_qf_ThankYou_display=1&qfKey=$qfKey",
FALSE, NULL, FALSE
);
}
CRM_Utils_System::redirect($finalURL);
}
else {
if ($component == "event") {
$finalURL = CRM_Utils_System::url('civicrm/event/confirm',
"reset=1&cc=fail&participantId=$privateData[participantID]",
FALSE, NULL, FALSE
);
}
elseif ($component == "contribute") {
$finalURL = CRM_Utils_System::url('civicrm/contribute/transact',
"_qf_Main_display=1&cancel=1&qfKey=$qfKey",
FALSE, NULL, FALSE
);
}
CRM_Utils_System::redirect($finalURL);
}
}
/**
* Converts the comma separated name-value pairs in