hodge
26th September 2006, 09:43 AM
Hi,
I've just finished writing and testing the following script for use with Safepay Solutions (http://www.safepaysolutions.com). It works for single sales, and recurring bills. It should go in the scripts directory (safepay_subscr.php or something), and be set as the Notify URL for Safepay buttons:
<?php
// include files
require_once('global.php');
if($GLOBALS['Auth']->getProgramType() == PROG_TYPE_PRO || $GLOBALS['Auth']->getProgramType() == PROG_TYPE_ECOMMAGNET) {
$GLOBALS['Auth']->setAccountID(DEFAULT_ACCOUNT);
} else {
if($GLOBALS['Auth']->getAccountID() == '') {
QCore_History::log(WLOG_ERROR, "Safepay Solutions callback: Cannot recognize account from domain '".getHostName()."'", __FILE__, __LINE__);
return;
}
}
DebugMsg("Safepay Solutions callback: started, params result_full='".$_REQUEST['result_full']."', custom1='".$_REQUEST['custom1']."', iamount='".$_REQUEST['iamount']."', tid='".$_REQUEST['tid']."', itemNum='".$_REQUEST['itemNum']."', subscrID='".$_REQUEST['subscrID']."', subscrid='".$_REQUEST['subscrid']."'", __FILE__, __LINE__);
if($_REQUEST['result_full'] == 'CANCEL'){
$recComm = QUnit_Global::newObj('Affiliate_Scripts_Bl_Recurri ngCommissions');
$recComm->cancelRecurring($SubscriptionID);
$errorMsg = "Safepay Solutions callback: subscription was cancelled. SubscriptionID=".$SubscriptionID;
DebugMsg($errorMsg, __FILE__, __LINE__);
return; // subscription was cancelled
}
$saleReg = QUnit_Global::newObj('Affiliate_Scripts_Bl_SaleReg istrator');;
if($_REQUEST["result"] == 1) {
if(isset($_REQUEST["_ipn_act"]) && $_REQUEST['_ipn_act']=="_ipn_subscription"){
// it is subscription (recurring) payment
$ABid = $_REQUEST['custom1'];
$amount = $_REQUEST['iamount'];
$itemQuantity = $_REQUEST["iquantity"];
$trialAmount = $_REQUEST["trialAmount"];
$ProductID = $_REQUEST["itemNum"];
if ($itemQuantity > 1) {
$TotalCost = $amount*$itemQuantity;
} else {
$TotalCost = $amount;
}
//Bug in Safepay IPN Data - first call sends variable 'subscrid'. Rebill sends 'subscrID'
if ($_REQUEST["subscrID"] != "") {
$SubscriptionID = trim($_REQUEST['subscrID']);
} else if ($_REQUEST["subscrid"] != "") {
$SubscriptionID = trim($_REQUEST['subscrid']);
}
DebugMsg("Safepay Solutions callback: Amount: ".$TotalCost, __FILE__, __LINE__);
DebugMsg("Safepay Solutions callback, SubscriptionID: ".$SubscriptionID, __FILE__, __LINE__);
DebugMsg("Safepay Solutions callback: Start registering subscription (recurring) payment, custom field: ".$ABid, __FILE__, __LINE__);
DebugMsg("Safepay Solutions callback: Send SubscriptionID to findPaymentBySubscription()", __FILE__, __LINE__);
// register sale
$saleReg->setdefaultAccountID();
if($saleReg->findPaymentBySubscriptionID($SubscriptionID)) {
// we got affiliate id and campaign id filled by findPaymentBySubscriptionID() function
// it is recurring call
DebugMsg("Safepay Solutions callback: Start registering subscription (Rebill) payment", __FILE__, __LINE__);
$saleReg->setSaleTypeAndKind(TRANSTYPE_RECURRING, TRANSKIND_RECURRING);
$saleReg->registerSale($TotalCost, $SubscriptionID, $ProductID);
DebugMsg("Safepay Solutions callback: End registering subscription (Rebill) payment", __FILE__, __LINE__);
} else {
DebugMsg("Safepay Solutions callback: SubscriptionID not found by findPaymentBySubscription()", __FILE__, __LINE__);
// it is first subscription call
if($saleReg->decodeData($ABid)) {
DebugMsg("Safepay Solutions callback: Start registering subscription (First Call), params TotalCost='".$TotalCost."', OrderID='".$SubscriptionID."', ProductID='".$ProductID."'", __FILE__, __LINE__);
//Check for Trial Period Amount (first call only)
if ($trialAmount > 0) {
$TotalCost = $trialAmount;
}
$saleReg->registerSale($TotalCost, $SubscriptionID, $ProductID);
DebugMsg("Safepay Solutions callback: End registering subscription (First Call)", __FILE__, __LINE__);
} else {
DebugMsg("Safepay Solutions callback: SaleRegistrator->decodeData returned false", __FILE__, __LINE__);
}
}
DebugMsg("Safepay Solutions callback: End registering subscription (recurring) payment", __FILE__, __LINE__);
} else {
// normal single purchase
if($_REQUEST['custom1'] == '') {
DebugMsg("Safepay Solutions callback: no affiliate parameter given, customer was not referred by any affiliate, or error in passed parameters", __FILE__, __LINE__);
return; // no affiliate parameter given, customer was not referred by any affilliate
}
$ABid = preg_replace('/[\'\"\ ]/', '', $_REQUEST['custom1']);
$amount = $_REQUEST['iamount'];
$itemQuantity = $_REQUEST["iquantity"];
$trialAmount = $_REQUEST["trialAmount"];
$ProductID = $_REQUEST["itemNum"];
$OrderID = $_REQUEST["tid"];
if ($itemQuantity > 1) {
$TotalCost = $amount*$itemQuantity;
} else {
$TotalCost = $amount;
}
$saleReg = QUnit_Global::newObj('Affiliate_Scripts_Bl_SaleReg istrator');
// register sale
DebugMsg("Safepay Solutions callback: Start registering normal sale, params TotalCost='".$TotalCost."', OrderID='".$OrderID."', ProductID='".$ProductID."'", __FILE__, __LINE__);
if($saleReg->decodeData($ABid))
$saleReg->registerSale($TotalCost, $OrderID, $ProductID);
else
DebugMsg("Safepay Solutions callback: Data not decoded, failed to save sale", __FILE__, __LINE__);
DebugMsg("Safepay Solutions callback: End registering normal sale", __FILE__, __LINE__);
}
} else {
$errorMsg = "Safepay Solutions callback: transaction was not in SUCCESS state";
LogError($errorMsg, __FILE__, __LINE__);
return; // transaction was cancelled
}
?>
If necessary, the following two pieces of code can be added, to check the POST data with Safepay. This code should be added to the very TOP of the script:
//Check POST data with Safepay Solutions
$confirmUsing = "curl"; // values: "curl" or "socket"
function confirmTransaction(){
global $confirmUsing, $confirmScript, $confirmationID, $transactionID, $totalAmount;
$confirmScriptFull = $confirmScript["host"] . "/" . $confirmScript["path"];
if(isset($confirmationID) && is_numeric($confirmationID) && $confirmationID > 0){
$data = "confirmID=$confirmationID&trid=$transactionID&amount=$totalAmount";
if($confirmUsing == "curl"){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $confirmScriptFull);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$answer = curl_exec($ch);
$curlErr = curl_error($ch);
if(strlen($curlErr) > 0) report("CURL ERROR on <$confirmScriptFull>: " . $curlErr . "\n");
curl_close($ch);
report("Confirmation script answer: " . $answer . "\n");
if(strlen($answer) > 0 && strpos($answer, "SUCCESS") !== false) $answer = 1;
else $answer = 0;
}
elseif($confirmUsing == "socket"){
if($confirmScript["ssl"]){
$port = "443";
$ssl = "ssl://";
}
else $port = "80";
$fp = @fsockopen($ssl . $confirmScript["host"], $port, $errnum, $errstr, 30);
if(!$fp){
report("SOCKET ERROR! $errnum: $errstr\n");
$answer = 0;
}
else{
fputs($fp, "POST {$confirmScript[path]} HTTP/1.1\r\n"); // PATH
fputs($fp, "Host: {$confirmScript[host]}\r\n"); // HOST
fputs($fp, "Content-type: application/x-www-form-urlencoded\r\n");
fputs($fp, "Content-length: ".strlen($data)."\r\n");
fputs($fp, "Connection: close\r\n\r\n");
fputs($fp, $data . "\r\n\r\n");
while(!feof($fp)) $answer .= @fgets($fp, 1024);
fclose($fp);
report("Confirmation script answer: " . $answer . "\n");
if(strlen($answer) > 0 && strpos($answer, "SUCCESS") !== false) $answer = 1;
else $answer = 0;
}
}
}
else $answer = 1;
return $answer;
}
$confirmed = confirmTransaction();
if($confirmed == 1) {
And the following to the very BOTTOM:
} else {
//Transaction not confirmed from Safepay Solutions
$errorMsg = "Safepay Solutions callback: transaction was not confirmed";
LogError($errorMsg, __FILE__, __LINE__);
return; // transaction was not confirmed
}
It's also possible to add a further security check if you use the hashed passphrase, but I have left this out to make it more portable.
Hope this helps somebody!
Hodge.
I've just finished writing and testing the following script for use with Safepay Solutions (http://www.safepaysolutions.com). It works for single sales, and recurring bills. It should go in the scripts directory (safepay_subscr.php or something), and be set as the Notify URL for Safepay buttons:
<?php
// include files
require_once('global.php');
if($GLOBALS['Auth']->getProgramType() == PROG_TYPE_PRO || $GLOBALS['Auth']->getProgramType() == PROG_TYPE_ECOMMAGNET) {
$GLOBALS['Auth']->setAccountID(DEFAULT_ACCOUNT);
} else {
if($GLOBALS['Auth']->getAccountID() == '') {
QCore_History::log(WLOG_ERROR, "Safepay Solutions callback: Cannot recognize account from domain '".getHostName()."'", __FILE__, __LINE__);
return;
}
}
DebugMsg("Safepay Solutions callback: started, params result_full='".$_REQUEST['result_full']."', custom1='".$_REQUEST['custom1']."', iamount='".$_REQUEST['iamount']."', tid='".$_REQUEST['tid']."', itemNum='".$_REQUEST['itemNum']."', subscrID='".$_REQUEST['subscrID']."', subscrid='".$_REQUEST['subscrid']."'", __FILE__, __LINE__);
if($_REQUEST['result_full'] == 'CANCEL'){
$recComm = QUnit_Global::newObj('Affiliate_Scripts_Bl_Recurri ngCommissions');
$recComm->cancelRecurring($SubscriptionID);
$errorMsg = "Safepay Solutions callback: subscription was cancelled. SubscriptionID=".$SubscriptionID;
DebugMsg($errorMsg, __FILE__, __LINE__);
return; // subscription was cancelled
}
$saleReg = QUnit_Global::newObj('Affiliate_Scripts_Bl_SaleReg istrator');;
if($_REQUEST["result"] == 1) {
if(isset($_REQUEST["_ipn_act"]) && $_REQUEST['_ipn_act']=="_ipn_subscription"){
// it is subscription (recurring) payment
$ABid = $_REQUEST['custom1'];
$amount = $_REQUEST['iamount'];
$itemQuantity = $_REQUEST["iquantity"];
$trialAmount = $_REQUEST["trialAmount"];
$ProductID = $_REQUEST["itemNum"];
if ($itemQuantity > 1) {
$TotalCost = $amount*$itemQuantity;
} else {
$TotalCost = $amount;
}
//Bug in Safepay IPN Data - first call sends variable 'subscrid'. Rebill sends 'subscrID'
if ($_REQUEST["subscrID"] != "") {
$SubscriptionID = trim($_REQUEST['subscrID']);
} else if ($_REQUEST["subscrid"] != "") {
$SubscriptionID = trim($_REQUEST['subscrid']);
}
DebugMsg("Safepay Solutions callback: Amount: ".$TotalCost, __FILE__, __LINE__);
DebugMsg("Safepay Solutions callback, SubscriptionID: ".$SubscriptionID, __FILE__, __LINE__);
DebugMsg("Safepay Solutions callback: Start registering subscription (recurring) payment, custom field: ".$ABid, __FILE__, __LINE__);
DebugMsg("Safepay Solutions callback: Send SubscriptionID to findPaymentBySubscription()", __FILE__, __LINE__);
// register sale
$saleReg->setdefaultAccountID();
if($saleReg->findPaymentBySubscriptionID($SubscriptionID)) {
// we got affiliate id and campaign id filled by findPaymentBySubscriptionID() function
// it is recurring call
DebugMsg("Safepay Solutions callback: Start registering subscription (Rebill) payment", __FILE__, __LINE__);
$saleReg->setSaleTypeAndKind(TRANSTYPE_RECURRING, TRANSKIND_RECURRING);
$saleReg->registerSale($TotalCost, $SubscriptionID, $ProductID);
DebugMsg("Safepay Solutions callback: End registering subscription (Rebill) payment", __FILE__, __LINE__);
} else {
DebugMsg("Safepay Solutions callback: SubscriptionID not found by findPaymentBySubscription()", __FILE__, __LINE__);
// it is first subscription call
if($saleReg->decodeData($ABid)) {
DebugMsg("Safepay Solutions callback: Start registering subscription (First Call), params TotalCost='".$TotalCost."', OrderID='".$SubscriptionID."', ProductID='".$ProductID."'", __FILE__, __LINE__);
//Check for Trial Period Amount (first call only)
if ($trialAmount > 0) {
$TotalCost = $trialAmount;
}
$saleReg->registerSale($TotalCost, $SubscriptionID, $ProductID);
DebugMsg("Safepay Solutions callback: End registering subscription (First Call)", __FILE__, __LINE__);
} else {
DebugMsg("Safepay Solutions callback: SaleRegistrator->decodeData returned false", __FILE__, __LINE__);
}
}
DebugMsg("Safepay Solutions callback: End registering subscription (recurring) payment", __FILE__, __LINE__);
} else {
// normal single purchase
if($_REQUEST['custom1'] == '') {
DebugMsg("Safepay Solutions callback: no affiliate parameter given, customer was not referred by any affiliate, or error in passed parameters", __FILE__, __LINE__);
return; // no affiliate parameter given, customer was not referred by any affilliate
}
$ABid = preg_replace('/[\'\"\ ]/', '', $_REQUEST['custom1']);
$amount = $_REQUEST['iamount'];
$itemQuantity = $_REQUEST["iquantity"];
$trialAmount = $_REQUEST["trialAmount"];
$ProductID = $_REQUEST["itemNum"];
$OrderID = $_REQUEST["tid"];
if ($itemQuantity > 1) {
$TotalCost = $amount*$itemQuantity;
} else {
$TotalCost = $amount;
}
$saleReg = QUnit_Global::newObj('Affiliate_Scripts_Bl_SaleReg istrator');
// register sale
DebugMsg("Safepay Solutions callback: Start registering normal sale, params TotalCost='".$TotalCost."', OrderID='".$OrderID."', ProductID='".$ProductID."'", __FILE__, __LINE__);
if($saleReg->decodeData($ABid))
$saleReg->registerSale($TotalCost, $OrderID, $ProductID);
else
DebugMsg("Safepay Solutions callback: Data not decoded, failed to save sale", __FILE__, __LINE__);
DebugMsg("Safepay Solutions callback: End registering normal sale", __FILE__, __LINE__);
}
} else {
$errorMsg = "Safepay Solutions callback: transaction was not in SUCCESS state";
LogError($errorMsg, __FILE__, __LINE__);
return; // transaction was cancelled
}
?>
If necessary, the following two pieces of code can be added, to check the POST data with Safepay. This code should be added to the very TOP of the script:
//Check POST data with Safepay Solutions
$confirmUsing = "curl"; // values: "curl" or "socket"
function confirmTransaction(){
global $confirmUsing, $confirmScript, $confirmationID, $transactionID, $totalAmount;
$confirmScriptFull = $confirmScript["host"] . "/" . $confirmScript["path"];
if(isset($confirmationID) && is_numeric($confirmationID) && $confirmationID > 0){
$data = "confirmID=$confirmationID&trid=$transactionID&amount=$totalAmount";
if($confirmUsing == "curl"){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $confirmScriptFull);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$answer = curl_exec($ch);
$curlErr = curl_error($ch);
if(strlen($curlErr) > 0) report("CURL ERROR on <$confirmScriptFull>: " . $curlErr . "\n");
curl_close($ch);
report("Confirmation script answer: " . $answer . "\n");
if(strlen($answer) > 0 && strpos($answer, "SUCCESS") !== false) $answer = 1;
else $answer = 0;
}
elseif($confirmUsing == "socket"){
if($confirmScript["ssl"]){
$port = "443";
$ssl = "ssl://";
}
else $port = "80";
$fp = @fsockopen($ssl . $confirmScript["host"], $port, $errnum, $errstr, 30);
if(!$fp){
report("SOCKET ERROR! $errnum: $errstr\n");
$answer = 0;
}
else{
fputs($fp, "POST {$confirmScript[path]} HTTP/1.1\r\n"); // PATH
fputs($fp, "Host: {$confirmScript[host]}\r\n"); // HOST
fputs($fp, "Content-type: application/x-www-form-urlencoded\r\n");
fputs($fp, "Content-length: ".strlen($data)."\r\n");
fputs($fp, "Connection: close\r\n\r\n");
fputs($fp, $data . "\r\n\r\n");
while(!feof($fp)) $answer .= @fgets($fp, 1024);
fclose($fp);
report("Confirmation script answer: " . $answer . "\n");
if(strlen($answer) > 0 && strpos($answer, "SUCCESS") !== false) $answer = 1;
else $answer = 0;
}
}
}
else $answer = 1;
return $answer;
}
$confirmed = confirmTransaction();
if($confirmed == 1) {
And the following to the very BOTTOM:
} else {
//Transaction not confirmed from Safepay Solutions
$errorMsg = "Safepay Solutions callback: transaction was not confirmed";
LogError($errorMsg, __FILE__, __LINE__);
return; // transaction was not confirmed
}
It's also possible to add a further security check if you use the hashed passphrase, but I have left this out to make it more portable.
Hope this helps somebody!
Hodge.