-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit c925cb3
Showing
5 changed files
with
388 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
<?php | ||
|
||
define('MODULE_PAYMENT_PLISIO_TEXT_TITLE', 'Plisio Payment Gateway'); | ||
define('MODULE_PAYMENT_PLISIO_TEXT_DESCRIPTION', 'Plisio is a payment gateway for Bitcoin, Litecoin, Ethereum and 30 other cryptocurrencies. With our API, any website can accept crypto payments.'); | ||
define('MODULE_PAYMENT_PLISIO_TEXT_EMAIL_FOOTER', 'You have attempted to make an order using Plisio!'); | ||
define('MODULE_PAYMENT_PLISIO_CREATE_INVOICE_FAILED', 'Unable to process payment using Plisio.'); | ||
define('MODULE_PAYMENT_PLISIO_ORDER_ERROR_TITLE', 'There has been an error processing your order'); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
<?php | ||
|
||
namespace PlisioClient; | ||
|
||
class PlisioClient | ||
{ | ||
protected $secretKey = ''; | ||
public $apiEndPoint = 'https://plisio.net/api/v1'; | ||
|
||
|
||
public function __construct($secretKey) | ||
{ | ||
$this->secretKey = $secretKey; | ||
} | ||
|
||
protected function getApiUrl($commandUrl) | ||
{ | ||
return trim($this->apiEndPoint, '/') . '/' . $commandUrl; | ||
} | ||
|
||
public function getBalances($currency) | ||
{ | ||
return $this->apiCall('balances', array('currency' => $currency)); | ||
} | ||
|
||
public function getCurrencies($source_currency = 'USD') | ||
{ | ||
$currencies = $this->guestApiCall("currencies/$source_currency"); | ||
return array_filter($currencies['data'], function ($currency) { | ||
return $currency['hidden'] == 0; | ||
}); | ||
} | ||
|
||
public function createTransaction($req) | ||
{ | ||
return $this->apiCall('invoices/new', $req); | ||
} | ||
|
||
|
||
/** | ||
* Creates a withdrawal from your account to a specified address.<br /> | ||
* @param amount The amount of the transaction (floating point to 8 decimals). | ||
* @param currency The cryptocurrency to withdraw. | ||
* @param address The address to send the coins to. | ||
* @param auto_confirm If auto_confirm is TRUE, then the withdrawal will be performed without an email confirmation. | ||
*/ | ||
public function createWithdrawal($amount, $currency, $address) | ||
{ | ||
$req = array( | ||
'currency' => $currency, | ||
'amount' => $amount, | ||
'to' => $address, | ||
'type' => 'cash_out', | ||
); | ||
return $this->apiCall('operations/withdraw', $req); | ||
} | ||
|
||
/** | ||
* Creates a withdrawal from your account to a specified address.<br /> | ||
* @param payments array of addresses and amounts. | ||
* @param currency The cryptocurrency to withdraw. | ||
*/ | ||
public function createMassWithdrawal($payments, $currency) | ||
{ | ||
$req = array( | ||
'currency' => $currency, | ||
'amount' => implode(',', array_values($payments)), | ||
'to' => implode(',', array_keys($payments)), | ||
'type' => 'mass_cash_out', | ||
); | ||
return $this->apiCall('operations/withdraw', $req); | ||
} | ||
|
||
|
||
private function isSetup() | ||
{ | ||
return !empty($this->secretKey); | ||
} | ||
|
||
protected function getCurlOptions($url) | ||
{ | ||
return [ | ||
CURLOPT_URL => $url, | ||
CURLOPT_HTTPGET => true, | ||
CURLOPT_FAILONERROR => false, | ||
CURLOPT_RETURNTRANSFER => true, | ||
CURLOPT_SSL_VERIFYPEER => false, | ||
CURLOPT_HEADER => true, | ||
CURLOPT_HTTPHEADER => [ | ||
'Content-Type: application/json', | ||
'Accept: application/json' | ||
], | ||
]; | ||
} | ||
|
||
private function apiCall($cmd, $req = array()) | ||
{ | ||
if (!$this->isSetup()) { | ||
return array('error' => 'You have not called the Setup function with your private and public keys!'); | ||
} | ||
return $this->guestApiCall($cmd, $req); | ||
} | ||
|
||
private function guestApiCall($cmd, $req = array()) | ||
{ | ||
// Generate the query string | ||
$queryString = ''; | ||
if (!empty($this->secretKey)) { | ||
$req['api_key'] = $this->secretKey; | ||
} | ||
if (!empty($req)) { | ||
$post_data = http_build_query($req, '', '&'); | ||
$queryString = '?' . $post_data; | ||
} | ||
|
||
try { | ||
$apiUrl = $this->getApiUrl($cmd . $queryString); | ||
|
||
$ch = curl_init(); | ||
curl_setopt_array($ch, $this->getCurlOptions($apiUrl)); | ||
$data = curl_exec($ch); | ||
|
||
if ($data !== FALSE) { | ||
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE); | ||
$body = substr($data, $header_size); | ||
$dec = $this->jsonDecode($body); | ||
if ($dec !== NULL && count($dec)) { | ||
return $dec; | ||
} else { | ||
// If you are using PHP 5.5.0 or higher you can use json_last_error_msg() for a better error message | ||
return array('status' => 'error', 'message' => 'Unable to parse JSON result (' . json_last_error() . ')'); | ||
} | ||
} else { | ||
return array('status' => 'error', 'message' => 'cURL error: ' . curl_error($ch)); | ||
} | ||
} catch (\Exception $e) { | ||
return array('status' => 'error', 'message' => 'Could not send request to API : ' . $apiUrl); | ||
} | ||
} | ||
|
||
private function jsonDecode($data) | ||
{ | ||
if (PHP_INT_SIZE < 8 && version_compare(PHP_VERSION, '5.4.0') >= 0) { | ||
// We are on 32-bit PHP, so use the bigint as string option. If you are using any API calls with Satoshis it is highly NOT recommended to use 32-bit PHP | ||
$dec = json_decode($data, TRUE, 512, JSON_BIGINT_AS_STRING); | ||
} else { | ||
$dec = json_decode($data, TRUE); | ||
} | ||
return $dec; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
<?php | ||
|
||
define('PLISIO_ZENCART_EXTENSION_VERSION', '1.0.0'); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
<?php | ||
|
||
class plisio extends base | ||
{ | ||
public $code; | ||
public $title; | ||
public $description; | ||
public $enabled; | ||
|
||
function __construct() | ||
{ | ||
$this->code = 'plisio'; | ||
$this->title = MODULE_PAYMENT_PLISIO_TEXT_TITLE; | ||
$this->description = MODULE_PAYMENT_PLISIO_TEXT_DESCRIPTION; | ||
$this->api_key = MODULE_PAYMENT_PLISIO_API_KEY; | ||
$this->sort_order = MODULE_PAYMENT_PLISIO_SORT_ORDER; | ||
$this->enabled = ((MODULE_PAYMENT_PLISIO_STATUS == 'True') ? true : false); | ||
} | ||
|
||
function javascript_validation() | ||
{ | ||
return false; | ||
} | ||
|
||
function selection() | ||
{ | ||
return array('id' => $this->code, 'module' => $this->title); | ||
} | ||
|
||
function pre_confirmation_check() | ||
{ | ||
return false; | ||
} | ||
|
||
function confirmation() | ||
{ | ||
return false; | ||
} | ||
|
||
function process_button() | ||
{ | ||
return false; | ||
} | ||
|
||
function before_process() | ||
{ | ||
return false; | ||
} | ||
|
||
function after_process() | ||
{ | ||
require_once(dirname(__FILE__) . "/Plisio/version.php"); | ||
require_once(dirname(__FILE__) . "/Plisio/Lib/PlisioClient.php"); | ||
global $insert_id, $order, $messageStack; | ||
|
||
$info = $order->info; | ||
|
||
$callback = zen_href_link('plisio_callback.php', $parameters='', $connection='NONSSL', $add_session_id=true, $search_engine_safe=true, $static=true ); | ||
|
||
$client = new PlisioClient\PlisioClient(MODULE_PAYMENT_PLISIO_API_KEY); | ||
$params = array( | ||
'order_name' => 'Order #' . $insert_id, | ||
'order_number' => $insert_id, | ||
'source_amount' => number_format($info['total'], 2, '.', ''), | ||
'source_currency' => $info['currency'], | ||
'callback_url' => $callback, | ||
'cancel_url' => zen_href_link(FILENAME_CHECKOUT_PAYMENT), | ||
'success_url' => zen_href_link(FILENAME_CHECKOUT_SUCCESS), | ||
'email' => $order->customer['email_address'], | ||
'plugin' => 'ZenCart', | ||
'version' => PLISIO_ZENCART_EXTENSION_VERSION | ||
); | ||
|
||
$response = $client->createTransaction($params); | ||
if ($response && $response['status'] !== 'error' && !empty($response['data'])) { | ||
$_SESSION['cart']->reset(true); | ||
zen_redirect($response['data']['invoice_url']); | ||
} else { | ||
$messageStack->add_session('checkout_payment', implode(',', json_decode($response['data']['message'], true)), 'error'); | ||
zen_redirect(zen_href_link(FILENAME_CHECKOUT_PAYMENT)); | ||
return 'failed'; | ||
} | ||
} | ||
|
||
function get_error() | ||
{ | ||
global $HTTP_GET_VARS; | ||
return array('title' => MODULE_PAYMENT_PLISIO_ORDER_ERROR_TITLE, | ||
'error' => $HTTP_GET_VARS['error']); | ||
} | ||
|
||
function check() | ||
{ | ||
global $db; | ||
if (!isset($this->_check)) { | ||
$check_query = $db->Execute("select configuration_value from " . TABLE_CONFIGURATION . " where configuration_key = 'MODULE_PAYMENT_PLISIO_STATUS'"); | ||
$this->_check = $check_query->RecordCount(); | ||
} | ||
|
||
return $this->_check; | ||
} | ||
|
||
function install() | ||
{ | ||
global $db, $messageStack; | ||
if (defined('MODULE_PAYMENT_PLISIO_STATUS')) { | ||
$messageStack->add_session('Plisio module already installed.', 'error'); | ||
zen_redirect(zen_href_link(FILENAME_MODULES, 'set=payment&module=plisio', 'NONSSL')); | ||
return 'failed'; | ||
} | ||
$status_query = $db->Execute("select max(orders_status_id) as status_id from " . TABLE_ORDERS_STATUS); | ||
|
||
$status_id = $status_query->fields['status_id']+1; | ||
$status_id_paid = $status_id; | ||
$status_id_pending = $status_id + 1; | ||
$status_id_expired = $status_id + 2; | ||
$status_id_cancelled = $status_id + 3; | ||
|
||
$languages = zen_get_languages(); | ||
|
||
foreach ($languages as $lang) { | ||
$db->Execute("insert into " . TABLE_ORDERS_STATUS . " (orders_status_id, language_id, orders_status_name) values ('" . $status_id_paid . "', '" . $lang['id'] . "', 'Plisio [Paid]')"); | ||
$db->Execute("insert into " . TABLE_ORDERS_STATUS . " (orders_status_id, language_id, orders_status_name) values ('" . $status_id_pending . "', '" . $lang['id'] . "', 'Plisio [Pending]')"); | ||
$db->Execute("insert into " . TABLE_ORDERS_STATUS . " (orders_status_id, language_id, orders_status_name) values ('" . $status_id_expired . "', '" . $lang['id'] . "', 'Plisio [Expired]')"); | ||
$db->Execute("insert into " . TABLE_ORDERS_STATUS . " (orders_status_id, language_id, orders_status_name) values ('" . $status_id_cancelled . "', '" . $lang['id'] . "', 'Plisio [Cancelled]')"); | ||
} | ||
|
||
$flags_query = $db->Execute("describe " . TABLE_ORDERS_STATUS . " public_flag"); | ||
if ($flags_query->RecordCount() == 1) { | ||
$db->Execute("update " . TABLE_ORDERS_STATUS . " set public_flag = 0 and downloads_flag = 0 where orders_status_id = '" . $status_id_paid . "'"); | ||
$db->Execute("update " . TABLE_ORDERS_STATUS . " set public_flag = 0 and downloads_flag = 0 where orders_status_id = '" . $status_id_pending . "'"); | ||
$db->Execute("update " . TABLE_ORDERS_STATUS . " set public_flag = 0 and downloads_flag = 0 where orders_status_id = '" . $status_id_expired . "'"); | ||
$db->Execute("update " . TABLE_ORDERS_STATUS . " set public_flag = 0 and downloads_flag = 0 where orders_status_id = '" . $status_id_cancelled . "'"); | ||
} | ||
|
||
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Enable Plisio Module', 'MODULE_PAYMENT_PLISIO_STATUS', 'False', 'Enable Plisio Payment Gateway plugin?', '6', '0', 'zen_cfg_select_option(array(\'True\', \'False\'), ', now())"); | ||
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Plisio API Key', 'MODULE_PAYMENT_PLISIO_API_KEY', '0', 'Your Plisio API Key', '6', '0', now())"); | ||
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Sort order of display.', 'MODULE_PAYMENT_PLISIO_SORT_ORDER', '0', 'Sort order of display. Lowest is displayed first.', '6', '8', now())"); | ||
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, use_function, date_added) values ('Set Plisio Order Status when order is pending', 'MODULE_PAYMENT_PLISIO_PENDING_STATUS_ID', '" . $status_id_pending . "', 'Status in your store when order is pending.<br />(\'Plisio [Pending]\' recommended)', '6', '5', 'zen_cfg_pull_down_order_statuses(', 'zen_get_order_status_name', now())"); | ||
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, use_function, date_added) values ('Set Plisio Order Status when order is cancelled', 'MODULE_PAYMENT_PLISIO_CANCELLED_STATUS_ID', '" . $status_id_cancelled . "', 'Status in your store when order is cancelled.<br />(\'Plisio [Cancelled]\' recommended)', '6', '5', 'zen_cfg_pull_down_order_statuses(', 'zen_get_order_status_name', now())"); | ||
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, use_function, date_added) values ('Set Plisio Order Status when order is expired', 'MODULE_PAYMENT_PLISIO_EXPIRED_STATUS_ID', '" . $status_id_expired . "', 'Status in your store when order is expired.<br />(\'Plisio [Expired]\' recommended)', '6', '5', 'zen_cfg_pull_down_order_statuses(', 'zen_get_order_status_name', now())"); | ||
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, use_function, date_added) values ('Set Plisio Order Status when order is paid', 'MODULE_PAYMENT_PLISIO_PAID_STATUS_ID', '" . $status_id_paid . "', 'Status in your store when order is paid.<br />(\'Plisio [Paid]\' recommended)', '6', '5', 'zen_cfg_pull_down_order_statuses(', 'zen_get_order_status_name', now())"); | ||
} | ||
|
||
function remove () | ||
{ | ||
global $db; | ||
$db->Execute("delete from " . TABLE_CONFIGURATION . " where configuration_key LIKE 'MODULE\_PAYMENT\_PLISIO\_%'"); | ||
$db->Execute("delete from " . TABLE_ORDERS_STATUS . " where LOWER(orders_status_name) LIKE '%plisio%'"); | ||
} | ||
|
||
function keys() | ||
{ | ||
return array( | ||
'MODULE_PAYMENT_PLISIO_STATUS', | ||
'MODULE_PAYMENT_PLISIO_API_KEY', | ||
'MODULE_PAYMENT_PLISIO_SORT_ORDER', | ||
'MODULE_PAYMENT_PLISIO_PENDING_STATUS_ID', | ||
'MODULE_PAYMENT_PLISIO_PAID_STATUS_ID', | ||
'MODULE_PAYMENT_PLISIO_CANCELLED_STATUS_ID', | ||
'MODULE_PAYMENT_PLISIO_EXPIRED_STATUS_ID', | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
<?php | ||
|
||
require('includes/application_top.php'); | ||
|
||
function verifyCallbackData($post, $apiKey) | ||
{ | ||
if (!isset($post['verify_hash'])) { | ||
return false; | ||
} | ||
|
||
$verifyHash = $post['verify_hash']; | ||
unset($post['verify_hash']); | ||
ksort($post); | ||
if (isset($post['expire_utc'])){ | ||
$post['expire_utc'] = (string)$post['expire_utc']; | ||
} | ||
if (isset($post['tx_urls'])){ | ||
$post['tx_urls'] = html_entity_decode($post['tx_urls']); | ||
} | ||
$postString = serialize($post); | ||
$checkKey = hash_hmac('sha1', $postString, $apiKey); | ||
if ($checkKey != $verifyHash) { | ||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
global $db; | ||
|
||
if (verifyCallbackData($_POST, MODULE_PAYMENT_PLISIO_API_KEY)) { | ||
$order_id = $_REQUEST['order_number']; | ||
|
||
$order = $db->Execute("select orders_id from " . TABLE_ORDERS . " where orders_id = '" . intval($order_id) . "' limit 1"); | ||
if ($order->RecordCount() <= 0) { | ||
throw new Exception('Order #' . $order_id . ' does not exists'); | ||
} | ||
|
||
switch ($_REQUEST['status']) { | ||
case 'completed': | ||
case 'mismatch': | ||
$pl_order_status = MODULE_PAYMENT_PLISIO_PAID_STATUS_ID; | ||
break; | ||
case 'cancelled': | ||
$pl_order_status = MODULE_PAYMENT_PLISIO_CANCELLED_STATUS_ID; | ||
break; | ||
case 'expired': | ||
$pl_order_status = MODULE_PAYMENT_PLISIO_EXPIRED_STATUS_ID; | ||
break; | ||
case 'new': | ||
$pl_order_status = MODULE_PAYMENT_PLISIO_PENDING_STATUS_ID; | ||
break; | ||
default: | ||
$pl_order_status = NULL; | ||
} | ||
|
||
if ($pl_order_status) { | ||
$db->Execute("update " . TABLE_ORDERS . " set orders_status = " . $pl_order_status . " where orders_id = " . intval($order_id)); | ||
} | ||
echo 'OK'; | ||
} else { | ||
echo 'Verify callback data failed'; | ||
} |