From 532ee4505891995b8a51b27a6fe06f3542b8fe8e Mon Sep 17 00:00:00 2001 From: rkbi Date: Tue, 5 Nov 2024 22:12:43 +0600 Subject: [PATCH] Tested for WHMCS v8 and later --- README.md | 6 +- modules/gateways/callback/sslcommerz.php | 241 +++++++----------- .../gateways/callback/sslcommerz_checkout.php | 1 + modules/gateways/callback/sslcommerz_ipn.php | 53 ++-- modules/gateways/sslcommerz.php | 70 ++--- 5 files changed, 131 insertions(+), 240 deletions(-) diff --git a/README.md b/README.md index 5d65d34..55fad9c 100644 --- a/README.md +++ b/README.md @@ -4,16 +4,16 @@ SSLCOMMERZ is the first payment gateway in Bangladesh opening doors for merchant ### Prerequisites -1. WHMCS V6-V7 +1. WHMCS V8.0 or later 2. cURL php extension. -3. [Sandbox Account](https://developer.sslcommerz.com/registration/ "SSLCommerz Sandbox Registration") +3. [Sandbox](https://developer.sslcommerz.com/registration/ "SSLCommerz Sandbox Registration") or [Live](https://join.sslcommerz.com/ "SSLCommerz Live Registration") API credentials ### Change Log 1. New version 4 API. 2. New easyCheckout Hosted & Popup UI. 3. Dynamic IPN URL(Auto Configure) -4. Tested upto V7.5.1 R2 +4. Tested upto V8.8 ### How to install the WHMCS module? diff --git a/modules/gateways/callback/sslcommerz.php b/modules/gateways/callback/sslcommerz.php index 02f7cfa..d5c1f25 100644 --- a/modules/gateways/callback/sslcommerz.php +++ b/modules/gateways/callback/sslcommerz.php @@ -1,159 +1,100 @@ $invoiceid))); - - $order_amount = $orderData['total']; - - $handle = curl_init(); - curl_setopt($handle, CURLOPT_URL, $requested_url); - curl_setopt($handle, CURLOPT_RETURNTRANSFER, true); - curl_setopt($handle, CURLOPT_SSL_VERIFYHOST, false); - curl_setopt($handle, CURLOPT_SSL_VERIFYPEER, false); - $results = curl_exec($handle); - $code = curl_getinfo($handle, CURLINFO_HTTP_CODE); - - if($code == 200 && !( curl_errno($handle))) - { - $result = json_decode($results); - - $status = $result->status; - $tran_date = $result->tran_date; - $tran_id = $result->tran_id; - $val_id = $result->val_id; - $amount = intval($result->amount); - $store_amount = $result->store_amount; - $amount = intval($result->amount); - $bank_tran_id = $result->bank_tran_id; - $card_type = $result->card_type; - $base_amount = $result->currency_amount; - $risk_level = $result->risk_level; - $base_fair=$result->base_fair; - $value_total=$result->value_b; - - if(($status=='VALID' || $status=='VALIDATED') && ($order_amount == $base_amount) && $risk_level == 0) - { - $status = 'success'; - } - else - { - $status = 'failed'; - } - } - $invoiceid = checkCbInvoiceID($invoiceid,$GATEWAY["name"]); # Checks invoice ID is a valid invoice number or ends processing - - $orderStatus = mysql_fetch_assoc(select_query('tblinvoices', 'status', array("id" => $invoiceid))); - - if($orderStatus['status'] == "Paid") - { - logTransaction($GATEWAY["name"], array("Gateway Response" => $_POST, "Validation Response" => json_decode($results, true), "Response" => "Already Succeed By IPN"), "Successful"); # Save to Gateway Log: name, data array, status - if($url_last_slash == "/") - { - header("Location: ".$systemurl."clientarea.php?action=services"); /* Redirect browser */ - } - else{ - header("Location: ".$systemurl."/clientarea.php?action=services"); /* Redirect browser */ - } - exit(); - } - - checkCbTransID($transid); # Checks transaction number isn't already in the database and ends processing if it does - - if ($status=="success") { - $fee = 0; - addInvoicePayment($invoiceid, $transid, $base_amount, $fee, $gatewaymodule); - logTransaction($GATEWAY["name"], $_POST, "Successful"); # Save to Gateway Log: name, data array, status - if($url_last_slash == "/") - { - header("Location: ".$systemurl."clientarea.php?action=services"); /* Redirect browser */ - } - else{ - header("Location: ".$systemurl."/clientarea.php?action=services"); /* Redirect browser */ - } - exit(); - - } - else { - logTransaction($GATEWAY["name"], $_POST, "Unsuccessful"); # Save to Gateway Log: name, data array, status - if($url_last_slash == "/") - { - header("Location: ".$systemurl."clientarea.php?action=services"); /* Redirect browser */ - } - else{ - header("Location: ".$systemurl."/clientarea.php?action=services"); /* Redirect browser */ - } - exit(); - } +# Required File Includes +include("../../../init.php"); +include("../../../includes/functions.php"); +include("../../../includes/gatewayfunctions.php"); +include("../../../includes/invoicefunctions.php"); + +$gatewaymodule = "sslcommerz"; # Enter your gateway module name here replacing template + + +$GATEWAY = getGatewayVariables($gatewaymodule); +if (!$GATEWAY["type"]) + die("Module Not Activated"); # Checks gateway module is active before accepting callback +if (!isset($_POST)) + die("No Post Data To Validate!"); + +$invoiceid = $_POST["value_c"]; +$tran_id = $_POST["tran_id"]; +$val_id = $_POST["val_id"]; + + +$store_id = $GATEWAY["store_id"]; +$store_passwd = $GATEWAY["store_password"]; +$systemurl = rtrim($GATEWAY['systemurl'], '/'); + +if ($_POST['status'] == 'VALID' && !empty($_POST['val_id']) && !empty($_POST['tran_id'])) { + if ($GATEWAY["testmode"] == "on") { + $validation_url = "https://sandbox.sslcommerz.com/validator/api/validationserverAPI.php?val_id=" . $val_id . "&store_id=" . $store_id . "&store_passwd=" . $store_passwd . "&v=1&format=json"; + } else { + $validation_url = "https://securepay.sslcommerz.com/validator/api/validationserverAPI.php?val_id=" . $val_id . "&store_id=" . $store_id . "&store_passwd=" . $store_passwd . "&v=1&format=json"; } - else if($_POST['status']=='FAILED' && (isset($_POST['tran_id']) && $_POST['tran_id'] != "")) - { - logTransaction($GATEWAY["name"], $_POST, "Unsuccessful"); # Save to Gateway Log: name, data array, status - if($url_last_slash == "/") - { - header("Location: ".$systemurl."clientarea.php?action=services"); /* Redirect browser */ - } - else{ - header("Location: ".$systemurl."/clientarea.php?action=services"); /* Redirect browser */ - } - exit(); + + $handle = curl_init(); + curl_setopt_array($handle, [ + CURLOPT_URL => $validation_url, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_SSL_VERIFYHOST => true, + CURLOPT_SSL_VERIFYPEER => true, + ]); + $results = curl_exec($handle); + $code = curl_getinfo($handle, CURLINFO_HTTP_CODE); + + if ($code == 200 && !(curl_errno($handle))) { + $result = json_decode($results); + + $status = $result->status; + $tran_date = $result->tran_date; + $tran_id = $result->tran_id; + $val_id = $result->val_id; + $amount = $result->amount; + $store_amount = $result->store_amount; + $bank_tran_id = $result->bank_tran_id; + $card_type = $result->card_type; + $base_amount = $result->currency_amount; + $risk_level = $result->risk_level; + $base_fair = $result->base_fair; + $value_total = $result->value_b; + + if (($status == 'VALID' || $status == 'VALIDATED') && $risk_level == 0) { + $status = 'success'; + } else { + $status = 'failed'; + } + } else { + $status = 'failed'; } - else if($_POST['status']=='CANCELLED') - { - logTransaction($GATEWAY["name"], $_POST, "Unsuccessful"); # Save to Gateway Log: name, data array, status - if($url_last_slash == "/") - { - header("Location: ".$systemurl."viewinvoice.php?id=" . $invoiceid); - } - else{ - header("Location: ".$systemurl."/viewinvoice.php?id=" . $invoiceid); - } - + checkCbInvoiceID($invoiceid, $GATEWAY["name"]); # Checks invoice ID is a valid invoice number or ends processing + checkCbTransID($tran_id); + + if ($status == "success") { + logTransaction($GATEWAY["name"], array("Gateway Response" => $_POST, "Validation Response" => json_decode($results, true), "Response" => "Already Succeed By IPN"), "Successful"); # Save to Gateway Log: name, data array, status + header("Location: " . $systemurl . "/clientarea.php?action=services"); /* Redirect browser */ exit(); } - else - { + + checkCbTransID($tran_id); # Checks transaction number isn't already in the database and ends processing if it does + + if ($status == "success") { + $fee = 0; + addInvoicePayment($invoiceid, $tran_id, $base_amount, $fee, $gatewaymodule); + logTransaction($GATEWAY["name"], $_POST, "Successful"); # Save to Gateway Log: name, data array, status + header("Location: " . $systemurl . "/clientarea.php?action=services"); /* Redirect browser */ + exit(); + + } else { logTransaction($GATEWAY["name"], $_POST, "Unsuccessful"); # Save to Gateway Log: name, data array, status - if($url_last_slash == "/") - { - header("Location: ".$systemurl."clientarea.php?action=services"); /* Redirect browser */ - } - else{ - header("Location: ".$systemurl."/clientarea.php?action=services"); /* Redirect browser */ - } - exit(); + header("Location: " . $systemurl . "/clientarea.php?action=services"); /* Redirect browser */ + exit(); } - -?> +} else if (in_array($_POST['status'], ['FAILED', 'CANCELLED', 'UNATTEMPTED', 'EXPIRED']) && !empty($_POST['tran_id']) && !empty($_POST['value_c'])) { + logTransaction($GATEWAY["name"], $_POST, "Unsuccessful"); # Save to Gateway Log: name, data array, status + header("Location: " . $systemurl . "/clientarea.php?action=services"); /* Redirect browser */ + exit(); +} else { + logTransaction($GATEWAY["name"], $_POST, "Unsuccessful"); # Save to Gateway Log: name, data array, status + header("Location: " . $systemurl . "/clientarea.php?action=services"); /* Redirect browser */ + exit(); +} diff --git a/modules/gateways/callback/sslcommerz_checkout.php b/modules/gateways/callback/sslcommerz_checkout.php index c10151b..4e8e5dc 100644 --- a/modules/gateways/callback/sslcommerz_checkout.php +++ b/modules/gateways/callback/sslcommerz_checkout.php @@ -43,6 +43,7 @@ $post_data['cus_country'] = $json_data['cus_country']; $post_data['value_a'] = $json_data['value_a']; $post_data['value_b'] = $json_data['value_b']; + $post_data['value_c'] = $json_data['value_c']; $post_data['shipping_method'] = 'NO'; $post_data['num_of_item'] = '1'; $post_data['product_name'] = $json_data['product_name']; diff --git a/modules/gateways/callback/sslcommerz_ipn.php b/modules/gateways/callback/sslcommerz_ipn.php index d6ad4f9..8c06da4 100644 --- a/modules/gateways/callback/sslcommerz_ipn.php +++ b/modules/gateways/callback/sslcommerz_ipn.php @@ -13,34 +13,26 @@ if (!$GATEWAY["type"]) die("Module Not Activated"); # Checks gateway module is active before accepting callback if (!isset($_POST)) die("No Post Data To Validate!"); - $invoiceid = $_POST["tran_id"]; - $transid = $_POST["tran_id"]; + $invoiceid = $_POST["value_c"]; + $tran_id = $_POST["tran_id"]; + $val_id = $_POST["val_id"]; $store_id = $GATEWAY["store_id"]; $store_passwd = $GATEWAY["store_password"]; $systemurl = $GATEWAY['systemurl']; - $url_last_slash = substr($systemurl, strrpos($systemurl, '/') + 0); - if($_POST['status']=='VALID' && (isset($_POST['val_id']) && $_POST['val_id'] != "") && (isset($_POST['tran_id']) && $_POST['tran_id'] != "")) + if($_POST['status']=='VALID' && !empty($_POST['val_id']) && !empty($_POST['tran_id'])) { - if ($GATEWAY["testmode"] == "on") - { - $requested_url = ("https://sandbox.sslcommerz.com/validator/api/validationserverAPI.php?val_id=".$val_id."&Store_Id=".$store_id."&Store_Passwd=".$store_passwd."&v=1&format=json"); - } - else - { - $requested_url = ("https://securepay.sslcommerz.com/validator/api/validationserverAPI.php?val_id=".$val_id."&Store_Id=".$store_id."&Store_Passwd=".$store_passwd."&v=1&format=json"); - } - - $orderData = mysql_fetch_assoc(select_query('tblinvoices', 'total', array("id" => $invoiceid))); - - $order_amount = $orderData['total']; - + $subdomain = $GATEWAY["testmode"] == "on" ? "sandbox" : "securepay"; + $validation_url = "https://." .$subdomain. ".com/validator/api/validationserverAPI.php?val_id=".$val_id."&store_id=".$store_id."&store_passwd=".$store_passwd."&v=1&format=json"; + $handle = curl_init(); - curl_setopt($handle, CURLOPT_URL, $requested_url); - curl_setopt($handle, CURLOPT_RETURNTRANSFER, true); - curl_setopt($handle, CURLOPT_SSL_VERIFYHOST, false); - curl_setopt($handle, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt_array($handle, [ + CURLOPT_URL => $validation_url, + CURLOPT_RETURNTRANSFER=> true, + CURLOPT_SSL_VERIFYHOST=> true, + CURLOPT_SSL_VERIFYPEER=> true, + ]); $result = curl_exec($handle); $code = curl_getinfo($handle, CURLINFO_HTTP_CODE); @@ -49,20 +41,13 @@ $result = json_decode($result); $status = $result->status; - $tran_date = $result->tran_date; $tran_id = $result->tran_id; - $val_id = $result->val_id; - $amount = intval($result->amount); - $store_amount = $result->store_amount; - $amount = intval($result->amount); + $amount = $result->amount; $bank_tran_id = $result->bank_tran_id; - $card_type = $result->card_type; - $base_amount = $result->currency_amount; + $currency_amount = $result->currency_amount; $risk_level = $result->risk_level; - $base_fair=$result->base_fair; - $value_total=$result->value_b; - if(($status=='VALID' || $status=='VALIDATED') && ($order_amount == $base_amount) && $risk_level == 0) + if(($status=='VALID' || $status=='VALIDATED') && $risk_level == 0) { $status = 'success'; } @@ -72,12 +57,12 @@ } } - $invoiceid = checkCbInvoiceID($invoiceid,$GATEWAY["name"]); # Checks invoice ID is a valid invoice number or ends processing - checkCbTransID($transid); # Checks transaction number isn't already in the database and ends processing if it does + checkCbInvoiceID($invoiceid,$GATEWAY["name"]); # Checks invoice ID is a valid invoice number or ends processing + checkCbTransID($tran_id); # Checks transaction number isn't already in the database and ends processing if it does if ($status=="success") { $fee = 0; - addInvoicePayment($invoiceid, $transid, $base_amount, $fee, $gatewaymodule); + addInvoicePayment($invoiceid, $tran_id, $currency_amount, $fee, $gatewaymodule); logTransaction($GATEWAY["name"], array("Gateway Response" => $_POST, "IPN Response" => "Succeed By IPN"), "Successful"); # Save to Gateway Log: name, data array, status exit(); diff --git a/modules/gateways/sslcommerz.php b/modules/gateways/sslcommerz.php index efd30c5..3dd9ae2 100644 --- a/modules/gateways/sslcommerz.php +++ b/modules/gateways/sslcommerz.php @@ -3,9 +3,9 @@ /** * WHMCS SSLCommerz Payment Gateway Module - * @see https://developer.sslcommerz.com/doc/v4/ - * @author: Prabal Mallick - * @copyright Copyright (c) SSL Wireless 2020 + * @see https://developer.sslcommerz.com/ + * @author: SSLCommerz Integration Team + * @copyright Copyright (c) SSLCommerz 2020-2024 * @license http://www.whmcs.com/license/ WHMCS Eula **/ @@ -30,11 +30,11 @@ function sslcommerz_MetaData() function sslcommerz_config() { $configarray = array( "FriendlyName" => array("Type" => "System", "Value"=>"SSLCommerz Payment Gateway"), - "button_text" => array("FriendlyName" => "Payment Button Label", "Type" => "text", "Size" => "1000", ), - "store_id" => array("FriendlyName" => "Store ID", "Type" => "text", "Size" => "1000", ), - "store_password" => array("FriendlyName" => "Store Password", "Type" => "text", "Size" => "100", ), - "testmode" => array("FriendlyName" => "Test Mode", "Type" => "yesno", "Description" => "Enable for Sandbox", ), - "gateway_type" => array("FriendlyName" => "easyCheckout", "Type" => "yesno", "Description" => "Enable for easyCheckout Popup", ) + "button_text" => array("FriendlyName" => "Payment Button Label", "Type" => "text", "Size" => "50", 'Default' => 'Proceed to Payment',), + "store_id" => array("FriendlyName" => "Store ID", "Type" => "text", "Size" => "100", ), + "store_password" => array("FriendlyName" => "Store Password", "Type" => "password", "Size" => "100", ), + "testmode" => array("FriendlyName" => "Enable Sandbox / Testmode?", "Type" => "yesno", "Description" => "Choose 'NO' in live environment.", ), + "gateway_type" => array("FriendlyName" => "easyCheckout", "Type" => "yesno", "Description" => "Use easycheckout popup?", ) ); return $configarray; } @@ -50,12 +50,12 @@ function sslcommerz_link($params) { $gatewaytype = $params['gateway_type']; if ($gatewaytestmode == "on") { - $url ='https://sandbox.sslcommerz.com/gwprocess/v4/api.php'; + $api_endpoint ='https://sandbox.sslcommerz.com/gwprocess/v4/api.php'; $easy_url = 'https://sandbox.sslcommerz.com/embed.min.js'; } else { - $url ='https://securepay.sslcommerz.com/gwprocess/v4/api.php'; + $api_endpoint ='https://securepay.sslcommerz.com/gwprocess/v4/api.php'; $easy_url = 'https://seamless-epay.sslcommerz.com/embed.min.js'; } @@ -84,27 +84,9 @@ function sslcommerz_link($params) { $systemurl = $params['systemurl']; $currency = $params['currency']; $returnurl = $params['returnurl']; - - $url_last_slash = substr($systemurl, strrpos($systemurl, '/') + 0); - - if($url_last_slash == "/") - { - $success_url = $systemurl.'modules/gateways/callback/sslcommerz.php'; - $fail_url = $systemurl.'modules/gateways/callback/sslcommerz.php'; - $cancel_url = $systemurl.'modules/gateways/callback/sslcommerz.php'; - $ipn_url = $systemurl.'modules/gateways/callback/sslcommerz_ipn.php'; - $easy_end_point = $systemurl.'modules/gateways/callback/sslcommerz_checkout.php'; - } - else - { - $success_url = $systemurl.'/modules/gateways/callback/sslcommerz.php'; - $fail_url = $systemurl.'/modules/gateways/callback/sslcommerz.php'; - $cancel_url = $systemurl.'/modules/gateways/callback/sslcommerz.php'; - $ipn_url = $systemurl.'/modules/gateways/callback/sslcommerz_ipn.php'; - $easy_end_point = $systemurl.'/modules/gateways/callback/sslcommerz_checkout.php'; - } - - $api_endpoint = $url; + $success_url = $fail_url = $cancel_url = rtrim($systemurl, '/').'/modules/gateways/callback/sslcommerz.php'; + $ipn_url = rtrim($systemurl, '/').'/modules/gateways/callback/sslcommerz_ipn.php'; + $easy_end_point = rtrim($systemurl, '/').'/modules/gateways/callback/sslcommerz_checkout.php'; $post_data = array(); $post_data['store_id'] = $gatewaystore_id; @@ -112,7 +94,7 @@ function sslcommerz_link($params) { $post_data['total_amount'] = $amount; $post_data['currency'] = $currency; - $post_data['tran_id'] = $invoiceid; + $post_data['tran_id'] = uniqid(); $post_data['success_url'] = $success_url; $post_data['fail_url'] = $fail_url; $post_data['cancel_url'] = $cancel_url; @@ -127,6 +109,7 @@ function sslcommerz_link($params) { $post_data['cus_country'] = $country; $post_data['value_a'] = $description; $post_data['value_b'] = $returnurl; + $post_data['value_c'] = $invoiceid; $post_data['shipping_method'] = 'NO'; $post_data['num_of_item'] = '1'; @@ -161,7 +144,7 @@ function sslcommerz_link($params) {