First commit
This commit is contained in:
0
api/payment/index.htm
Normal file
0
api/payment/index.htm
Normal file
0
api/payment/notify/index.htm
Normal file
0
api/payment/notify/index.htm
Normal file
48
api/payment/notify/notify_alipay.php
Normal file
48
api/payment/notify/notify_alipay.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* [Discuz!] (C)2001-2099 Comsenz Inc.
|
||||
* This is NOT a freeware, use is subject to license terms
|
||||
*
|
||||
* $Id: notify_alipay.php 36342 2021-05-17 14:14:54Z dplugin $
|
||||
*/
|
||||
|
||||
define('IN_API', true);
|
||||
define('CURSCRIPT', 'api');
|
||||
define('DISABLEXSSCHECK', true);
|
||||
|
||||
require '../../../source/class/class_core.php';
|
||||
require '../payment_alipay.php';
|
||||
|
||||
$discuz = C::app();
|
||||
$discuz->init();
|
||||
|
||||
if(!$_POST['sign'] || !$_POST['sign_type']) {
|
||||
exit('fail');
|
||||
}
|
||||
$sign = $_POST['sign'];
|
||||
unset($_POST['sign']);
|
||||
|
||||
$payment = new payment_alipay();
|
||||
$isright = $payment->alipay_sign_verify($sign, $_POST);
|
||||
if(!$isright) {
|
||||
$_POST['sign'] = $sign;
|
||||
payment::paymentlog('alipay', 0, 0, 0, 50001, $_POST);
|
||||
exit('fail');
|
||||
}
|
||||
|
||||
if($_POST['trade_status'] == 'TRADE_SUCCESS') {
|
||||
$out_biz_no = $_POST['out_trade_no'];
|
||||
$payment_time = strtotime($_POST['gmt_payment']);
|
||||
|
||||
$is_success = payment::finish_order('alipay', $out_biz_no, $_POST['trade_no'], $payment_time);
|
||||
if($is_success) {
|
||||
exit('success');
|
||||
}
|
||||
} else {
|
||||
payment::paymentlog('alipay', 0, 0, 0, 50001, $_POST);
|
||||
}
|
||||
|
||||
exit('fail');
|
||||
|
||||
?>
|
37
api/payment/notify/notify_qpay.php
Normal file
37
api/payment/notify/notify_qpay.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* [Discuz!] (C)2001-2099 Comsenz Inc.
|
||||
* This is NOT a freeware, use is subject to license terms
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
define('IN_API', true);
|
||||
define('CURSCRIPT', 'api');
|
||||
define('DISABLEXSSCHECK', true);
|
||||
|
||||
require '../../../source/class/class_core.php';
|
||||
require '../payment_qpay.php';
|
||||
|
||||
$discuz = C::app();
|
||||
$discuz->init();
|
||||
|
||||
$payment = new payment_qpay();
|
||||
|
||||
$data = $payment->qpay_sign_verify();
|
||||
if($data && $data['code'] == 200) {
|
||||
$data = $data['data'];
|
||||
$out_biz_no = $data['out_trade_no'];
|
||||
$payment_time = strtotime(preg_replace('/^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})$/', '$1-$2-$3 $4:$5:$6', $data['time_end']));
|
||||
$is_success = payment::finish_order('qpay', $out_biz_no, $data['transaction_id'], $payment_time);
|
||||
if($is_success) {
|
||||
echo '<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
|
||||
exit();
|
||||
}
|
||||
} else {
|
||||
payment::paymentlog('qpay', 0, 0, 0, 50001, $data ? json_encode($data) : '');
|
||||
}
|
||||
|
||||
echo '<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[FAIL]]></return_msg></xml>';
|
||||
exit();
|
55
api/payment/notify/notify_wechat.php
Normal file
55
api/payment/notify/notify_wechat.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* [Discuz!] (C)2001-2099 Comsenz Inc.
|
||||
* This is NOT a freeware, use is subject to license terms
|
||||
*
|
||||
* $Id: notify_wechat.php 36342 2021-05-17 14:15:04Z dplugin $
|
||||
*/
|
||||
|
||||
define('IN_API', true);
|
||||
define('CURSCRIPT', 'api');
|
||||
define('DISABLEXSSCHECK', true);
|
||||
|
||||
require '../../../source/class/class_core.php';
|
||||
require '../payment_wechat.php';
|
||||
|
||||
$discuz = C::app();
|
||||
$discuz->init();
|
||||
|
||||
$payment = new payment_wechat();
|
||||
if($_SERVER['HTTP_WECHATPAY_SIGNATURE']) {
|
||||
$data = $payment->v3_wechat_sign_verify();
|
||||
if($data && $data['code'] == 200) {
|
||||
$data = json_decode($data['data'], true);
|
||||
if($data['trade_state'] == 'SUCCESS') {
|
||||
$out_biz_no = $data['out_trade_no'];
|
||||
$payment_time = strtotime($data['success_time']);
|
||||
$is_success = payment::finish_order('wechat', $out_biz_no, $data['transaction_id'], $payment_time);
|
||||
if($is_success) {
|
||||
exit('{"code":"SUCCESS","message":"ok"}');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
payment::paymentlog('wechat', 0, 0, 0, 50001, $data ? json_encode($data) : '');
|
||||
}
|
||||
exit('{"code":"fail","message":"fail"}');
|
||||
} else {
|
||||
$data = $payment->wechat_sign_verify();
|
||||
if($data && $data['code'] == 200) {
|
||||
$data = $data['data'];
|
||||
$out_biz_no = $data['out_trade_no'];
|
||||
$payment_time = strtotime(preg_replace('/^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})$/', '$1-$2-$3 $4:$5:$6', $data['time_end']));
|
||||
$is_success = payment::finish_order('wechat', $out_biz_no, $data['transaction_id'], $payment_time);
|
||||
if($is_success) {
|
||||
echo '<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
|
||||
exit();
|
||||
}
|
||||
} else {
|
||||
payment::paymentlog('wechat', 0, 0, 0, 50001, $data ? json_encode($data) : '');
|
||||
}
|
||||
echo '<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[FAIL]]></return_msg></xml>';
|
||||
exit();
|
||||
}
|
||||
|
||||
?>
|
496
api/payment/payment_alipay.php
Normal file
496
api/payment/payment_alipay.php
Normal file
@@ -0,0 +1,496 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* [Discuz!] (C)2001-2099 Comsenz Inc.
|
||||
* This is NOT a freeware, use is subject to license terms
|
||||
*
|
||||
* $Id: payment_alipay.php 36342 2021-05-17 14:15:14Z dplugin $
|
||||
*/
|
||||
|
||||
if(!defined('IN_DISCUZ')) {
|
||||
exit('Access Denied');
|
||||
}
|
||||
|
||||
define('SDK_ALIPAY_GATEWAYURL', 'https://openapi.alipay.com/gateway.do');
|
||||
|
||||
require DISCUZ_ROOT . './api/payment/payment_base.php';
|
||||
|
||||
class payment_alipay extends payment_base {
|
||||
|
||||
public function __construct() {
|
||||
global $_G;
|
||||
$this->settings = C::t('common_setting')->fetch_setting('ec_alipay', true);
|
||||
$this->notify_url = $_G['siteurl'] . 'api/payment/notify/notify_alipay.php';
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function pay($order) {
|
||||
if(!$this->enable()) {
|
||||
return array('code' => 500, 'message' => 'Did not open payment');
|
||||
}
|
||||
if(defined('IN_MOBILE')) {
|
||||
return $this->alipay_trade_wap_pay($order);
|
||||
} else {
|
||||
return $this->alipay_trade_page_pay($order);
|
||||
}
|
||||
}
|
||||
|
||||
public function status($out_biz_no) {
|
||||
if(!$this->enable()) {
|
||||
return array('code' => 500, 'message' => 'Did not open payment');
|
||||
}
|
||||
return $this->alipay_trade_query($out_biz_no);
|
||||
}
|
||||
|
||||
public function refund($refund_no, $trade_no, $total_amount, $refund_amount, $refund_desc) {
|
||||
if(!$this->enable()) {
|
||||
return array('code' => 500, 'message' => 'Did not open payment');
|
||||
}
|
||||
return $this->alipay_refund($refund_no, $trade_no, $refund_amount, $refund_desc);
|
||||
}
|
||||
|
||||
public function refund_status($refund_no, $trade_no) {
|
||||
if(!$this->enable()) {
|
||||
return array('code' => 500, 'message' => 'Did not open payment');
|
||||
}
|
||||
return $this->alipay_refund_status($refund_no, $trade_no);
|
||||
}
|
||||
|
||||
public function transfer($transfer_no, $amount, $realname, $account, $title = '', $desc = '') {
|
||||
if(!$this->enable()) {
|
||||
return array('code' => 500, 'message' => 'Did not open payment');
|
||||
}
|
||||
return $this->alipay_fund_trans_uni_transfer($transfer_no, $amount, $realname, $account, $title, $desc);
|
||||
}
|
||||
|
||||
public function transfer_status($transfer_no) {
|
||||
if(!$this->enable()) {
|
||||
return array('code' => 500, 'message' => 'Did not open payment');
|
||||
}
|
||||
return $this->alipay_fund_trans_order_query($transfer_no);
|
||||
}
|
||||
|
||||
public function alipay_sign_verify($sign, $data) {
|
||||
if(!$data) {
|
||||
return false;
|
||||
}
|
||||
if($this->settings['ec_alipay_sign_mode']) {
|
||||
$public_key = $this->settings['mode_b_alipay_cert'];
|
||||
} else {
|
||||
$public_key = "-----BEGIN PUBLIC KEY-----\n" . wordwrap($this->settings['mode_a_alipay_public_key'], 64, "\n", true) . "\n-----END PUBLIC KEY-----";
|
||||
}
|
||||
|
||||
$data = $this->alipay_make_notify_signstr($data);
|
||||
|
||||
$public_keyres = openssl_pkey_get_public($public_key);
|
||||
$result = (openssl_verify($data, base64_decode($sign), $public_keyres, OPENSSL_ALGO_SHA256) === 1);
|
||||
openssl_free_key($public_keyres);
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function alipay_trade_query($out_biz_no) {
|
||||
global $_G;
|
||||
$data = array(
|
||||
'method' => 'alipay.trade.query',
|
||||
'charset' => 'utf-8',
|
||||
'sign_type' => 'RSA2',
|
||||
'format' => 'JSON',
|
||||
'timestamp' => dgmdate(time(), 'Y-m-d H:i:s'),
|
||||
'version' => '1.0',
|
||||
'biz_content' => json_encode(array('out_trade_no' => $out_biz_no))
|
||||
);
|
||||
if($this->settings['ec_alipay_sign_mode']) {
|
||||
$appid = $this->settings['mode_b_appid'];
|
||||
$private_key = $this->settings['mode_b_app_private_key'];
|
||||
$data['app_cert_sn'] = $this->alipay_cert_sn($this->settings['mode_b_app_cert']);
|
||||
$data['alipay_root_cert_sn'] = $this->alipay_root_cert_sn($this->settings['mode_b_alipay_root_cert']);
|
||||
} else {
|
||||
$appid = $this->settings['mode_a_appid'];
|
||||
$private_key = $this->settings['mode_a_app_private_key'];
|
||||
}
|
||||
$data['app_id'] = $appid;
|
||||
|
||||
$signstr = $this->alipay_make_signstr($data);
|
||||
$data['sign'] = $this->alipay_sign($private_key, $signstr);
|
||||
$api = SDK_ALIPAY_GATEWAYURL . '?' . http_build_query($data);
|
||||
$res = $this->alipay_request($api);
|
||||
$res = json_decode($res, true);
|
||||
$res = $res['alipay_trade_query_response'];
|
||||
if($res['code'] == 10000) {
|
||||
if($res['trade_status'] == 'TRADE_SUCCESS') {
|
||||
return array('code' => 200, 'data' => array('trade_no' => $res['trade_no'], 'payment_time' => strtotime($res['send_pay_date'])));
|
||||
} else {
|
||||
return array('code' => 500, 'message' => $res['trade_status']);
|
||||
}
|
||||
} else {
|
||||
if(strtoupper($_G['charset'] != 'UTF-8')) {
|
||||
$res['sub_msg'] = diconv($res['sub_msg'], 'UTF-8', $_G['charset']);
|
||||
}
|
||||
return array('code' => $res['sub_code'], 'message' => $res['sub_msg']);
|
||||
}
|
||||
}
|
||||
|
||||
private function alipay_trade_page_pay($order) {
|
||||
global $_G;
|
||||
|
||||
if(strtoupper($_G['charset'] != 'UTF-8')) {
|
||||
$order['subject'] = diconv($order['subject'], $_G['charset'], 'UTF-8');
|
||||
$order['description'] = diconv($order['description'], $_G['charset'], 'UTF-8');
|
||||
}
|
||||
|
||||
$data = array(
|
||||
'method' => 'alipay.trade.page.pay',
|
||||
'charset' => 'utf-8',
|
||||
'sign_type' => 'RSA2',
|
||||
'format' => 'JSON',
|
||||
'timestamp' => dgmdate(time(), 'Y-m-d H:i:s'),
|
||||
'version' => '1.0',
|
||||
'biz_content' => json_encode(array(
|
||||
'out_trade_no' => $order['out_biz_no'],
|
||||
'product_code' => 'FAST_INSTANT_TRADE_PAY',
|
||||
'total_amount' => $order['amount'] / 100,
|
||||
'subject' => $order['subject'],
|
||||
'body' => $order['description'],
|
||||
'timeout_express' => '1d',
|
||||
'qr_pay_mode' => '2',
|
||||
'integration_type' => 'PCWEB'
|
||||
))
|
||||
);
|
||||
if($this->notify_url) {
|
||||
$data['notify_url'] = $this->notify_url;
|
||||
}
|
||||
if($order['return_url']) {
|
||||
$data['return_url'] = $order['return_url'];
|
||||
}
|
||||
if($this->settings['ec_alipay_sign_mode']) {
|
||||
$appid = $this->settings['mode_b_appid'];
|
||||
$private_key = $this->settings['mode_b_app_private_key'];
|
||||
$data['app_cert_sn'] = $this->alipay_cert_sn($this->settings['mode_b_app_cert']);
|
||||
$data['alipay_root_cert_sn'] = $this->alipay_root_cert_sn($this->settings['mode_b_alipay_root_cert']);
|
||||
} else {
|
||||
$appid = $this->settings['mode_a_appid'];
|
||||
$private_key = $this->settings['mode_a_app_private_key'];
|
||||
}
|
||||
$data['app_id'] = $appid;
|
||||
|
||||
$signstr = $this->alipay_make_signstr($data);
|
||||
$data['sign'] = $this->alipay_sign($private_key, $signstr);
|
||||
$api = SDK_ALIPAY_GATEWAYURL . '?' . http_build_query($data);
|
||||
$res = $this->alipay_request($api);
|
||||
if(strtoupper($_G['charset'] != 'GBK')) {
|
||||
$res = diconv($res, 'GB2312', $_G['charset']);
|
||||
}
|
||||
if(preg_match('/^https?:\/\/.+$/', $res)) {
|
||||
return array('code' => 200, 'url' => $res);
|
||||
} else {
|
||||
if(preg_match('/<div\s+class="Todo">([^<]+)<\/div>/i', $res, $matchers)) {
|
||||
return array('code' => 500, 'message' => $matchers[1]);
|
||||
} else {
|
||||
return array('code' => 501, 'message' => $res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function alipay_trade_wap_pay($order) {
|
||||
global $_G;
|
||||
if(strtoupper($_G['charset'] != 'UTF-8')) {
|
||||
$order['subject'] = diconv($order['subject'], $_G['charset'], 'UTF-8');
|
||||
$order['description'] = diconv($order['description'], $_G['charset'], 'UTF-8');
|
||||
}
|
||||
|
||||
$data = array(
|
||||
'method' => 'alipay.trade.wap.pay',
|
||||
'format' => 'JSON',
|
||||
'charset' => 'utf-8',
|
||||
'sign_type' => 'RSA2',
|
||||
'timestamp' => dgmdate(time(), 'Y-m-d H:i:s'),
|
||||
'version' => '1.0',
|
||||
'biz_content' => json_encode(array(
|
||||
'out_trade_no' => $order['out_biz_no'],
|
||||
'product_code' => 'FAST_INSTANT_TRADE_PAY',
|
||||
'total_amount' => $order['amount'] / 100,
|
||||
'subject' => $order['subject'],
|
||||
'body' => $order['description'],
|
||||
'timeout_express' => '1d',
|
||||
'qr_pay_mode' => '2',
|
||||
'integration_type' => 'PCWEB'
|
||||
))
|
||||
);
|
||||
if($this->notify_url) {
|
||||
$data['notify_url'] = $this->notify_url;
|
||||
}
|
||||
if($order['return_url']) {
|
||||
$data['return_url'] = $order['return_url'];
|
||||
}
|
||||
if($this->settings['ec_alipay_sign_mode']) {
|
||||
$appid = $this->settings['mode_b_appid'];
|
||||
$private_key = $this->settings['mode_b_app_private_key'];
|
||||
$data['app_cert_sn'] = $this->alipay_cert_sn($this->settings['mode_b_app_cert']);
|
||||
$data['alipay_root_cert_sn'] = $this->alipay_root_cert_sn($this->settings['mode_b_alipay_root_cert']);
|
||||
} else {
|
||||
$appid = $this->settings['mode_a_appid'];
|
||||
$private_key = $this->settings['mode_a_app_private_key'];
|
||||
}
|
||||
$data['app_id'] = $appid;
|
||||
|
||||
if($order['referer_url']) {
|
||||
$data['return_url'] = $order['referer_url'];
|
||||
$data['quit_url'] = $order['referer_url'];
|
||||
} else {
|
||||
$data['quit_url'] = $_G['siteurl'];
|
||||
}
|
||||
|
||||
$signstr = $this->alipay_make_signstr($data);
|
||||
$data['sign'] = $this->alipay_sign($private_key, $signstr);
|
||||
$api = SDK_ALIPAY_GATEWAYURL . '?' . http_build_query($data);
|
||||
$res = $this->alipay_request($api);
|
||||
if(!preg_match('/^https?:\/\/.+$/', $res) && strtoupper($_G['charset'] != 'GBK')) {
|
||||
$res = diconv($res, 'GB2312', $_G['charset']);
|
||||
}
|
||||
if(preg_match('/^https?:\/\/.+$/', $res)) {
|
||||
return array('code' => 200, 'url' => $res);
|
||||
} else {
|
||||
if(preg_match('/<div\s+class="Todo">([^<]+)<\/div>/i', $res, $matchers)) {
|
||||
return array('code' => 500, 'message' => $matchers[1]);
|
||||
} else {
|
||||
return array('code' => 501, 'message' => $res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function alipay_fund_trans_uni_transfer($transfer_no, $amount, $realname, $account, $title = '', $desc = '') {
|
||||
global $_G;
|
||||
if(strtoupper($_G['charset'] != 'UTF-8')) {
|
||||
$title = diconv($title, $_G['charset'], 'UTF-8');
|
||||
$desc = diconv($desc, $_G['charset'], 'UTF-8');
|
||||
}
|
||||
if(!$this->settings['ec_alipay_sign_mode']) {
|
||||
return array('code' => 500, 'message' => 'not support sign mode.');
|
||||
}
|
||||
|
||||
$data = array(
|
||||
'app_id' => $this->settings['mode_b_appid'],
|
||||
'method' => 'alipay.fund.trans.uni.transfer',
|
||||
'format' => 'JSON',
|
||||
'charset' => 'utf-8',
|
||||
'sign_type' => 'RSA2',
|
||||
'app_cert_sn' => $this->alipay_cert_sn($this->settings['mode_b_app_cert']),
|
||||
'alipay_root_cert_sn' => $this->alipay_root_cert_sn($this->settings['mode_b_alipay_root_cert']),
|
||||
'timestamp' => dgmdate(time(), 'Y-m-d H:i:s'),
|
||||
'version' => '1.0'
|
||||
);
|
||||
$biz_content = array(
|
||||
'out_biz_no' => $transfer_no,
|
||||
'trans_amount' => sprintf('%.2f', $amount / 100),
|
||||
'product_code' => 'TRANS_ACCOUNT_NO_PWD',
|
||||
'biz_scene' => 'DIRECT_TRANSFER',
|
||||
'payee_info' => array('identity' => $account, 'identity_type' => 'ALIPAY_LOGON_ID', 'name' => $realname)
|
||||
);
|
||||
if($title) {
|
||||
$biz_content['order_title'] = $title;
|
||||
}
|
||||
if($desc) {
|
||||
$biz_content['remark'] = $desc;
|
||||
}
|
||||
$data['biz_content'] = json_encode($biz_content);
|
||||
|
||||
$signstr = $this->alipay_make_signstr($data);
|
||||
$data['sign'] = $this->alipay_sign($this->settings['mode_b_app_private_key'], $signstr);
|
||||
$api = SDK_ALIPAY_GATEWAYURL . '?' . http_build_query($data);
|
||||
$res = $this->alipay_request($api);
|
||||
$res = json_decode($res, true);
|
||||
$res = $res['alipay_fund_trans_uni_transfer_response'];
|
||||
if($res['code'] == 10000) {
|
||||
if($res['status'] == 'SUCCESS') {
|
||||
return array('code' => 200, 'data' => array('transfer_time' => strtotime($res['trans_date'])));
|
||||
} elseif($res['status'] == 'DEALING') {
|
||||
return array('code' => 201, 'message' => 'DEALING');
|
||||
} else {
|
||||
return array('code' => 500, 'message' => $res['status']);
|
||||
}
|
||||
} else {
|
||||
if($res['sub_msg'] && strtoupper($_G['charset'] != 'UTF-8')) {
|
||||
$res['sub_msg'] = diconv($res['sub_msg'], 'UTF-8', $_G['charset']);
|
||||
}
|
||||
return array('code' => $res['sub_code'], 'message' => $res['sub_msg']);
|
||||
}
|
||||
}
|
||||
|
||||
private function alipay_fund_trans_order_query($transfer_no) {
|
||||
global $_G;
|
||||
$data = array('method' => 'alipay.fund.trans.order.query', 'format' => 'JSON', 'charset' => 'utf-8', 'sign_type' => 'RSA2', 'timestamp' => dgmdate(time(), 'Y-m-d H:i:s'), 'version' => '1.0',);
|
||||
if($this->settings['ec_alipay_sign_mode']) {
|
||||
$appid = $this->settings['mode_b_appid'];
|
||||
$private_key = $this->settings['mode_b_app_private_key'];
|
||||
$data['app_cert_sn'] = $this->alipay_cert_sn($this->settings['mode_b_app_cert']);
|
||||
$data['alipay_root_cert_sn'] = $this->alipay_root_cert_sn($this->settings['mode_b_alipay_root_cert']);
|
||||
} else {
|
||||
$appid = $this->settings['mode_a_appid'];
|
||||
$private_key = $this->settings['mode_a_app_private_key'];
|
||||
}
|
||||
$data['app_id'] = $appid;
|
||||
|
||||
$biz_content = array('out_biz_no' => $transfer_no,);
|
||||
$data['biz_content'] = json_encode($biz_content);
|
||||
|
||||
$signstr = $this->alipay_make_signstr($data);
|
||||
$data['sign'] = $this->alipay_sign($private_key, $signstr);
|
||||
$api = SDK_ALIPAY_GATEWAYURL . '?' . http_build_query($data);
|
||||
$res = $this->alipay_request($api);
|
||||
$res = json_decode($res, true);
|
||||
$res = $res['alipay_fund_trans_order_query_response'];
|
||||
if($res['code'] == 10000) {
|
||||
if($res['status'] == 'SUCCESS') {
|
||||
return array('code' => 200, 'data' => array('transfer_time' => strtotime($res['trans_date'])));
|
||||
} elseif($res['status'] == 'DEALING') {
|
||||
return array('code' => 201, 'message' => 'DEALING');
|
||||
} else {
|
||||
return array('code' => 500, 'message' => $res['status']);
|
||||
}
|
||||
} else {
|
||||
if($res['sub_msg'] && strtoupper($_G['charset'] != 'UTF-8')) {
|
||||
$res['sub_msg'] = diconv($res['sub_msg'], 'UTF-8', $_G['charset']);
|
||||
}
|
||||
return array('code' => $res['sub_code'], 'message' => $res['sub_msg']);
|
||||
}
|
||||
}
|
||||
|
||||
private function alipay_refund($refund_no, $trade_no, $amount, $refund_desc) {
|
||||
global $_G;
|
||||
if(strtoupper($_G['charset'] != 'UTF-8')) {
|
||||
$refund_desc = diconv($refund_desc, $_G['charset'], 'UTF-8');
|
||||
}
|
||||
$data = array('method' => 'alipay.trade.refund', 'format' => 'JSON', 'charset' => 'utf-8', 'sign_type' => 'RSA2', 'timestamp' => dgmdate(time(), 'Y-m-d H:i:s'), 'version' => '1.0', 'biz_content' => json_encode(array('trade_no' => $trade_no, 'refund_amount' => $amount / 100, 'out_request_no' => $refund_no, 'refund_reason' => $refund_desc)),);
|
||||
if($this->settings['ec_alipay_sign_mode']) {
|
||||
$appid = $this->settings['mode_b_appid'];
|
||||
$private_key = $this->settings['mode_b_app_private_key'];
|
||||
$data['app_cert_sn'] = $this->alipay_cert_sn($this->settings['mode_b_app_cert']);
|
||||
$data['alipay_root_cert_sn'] = $this->alipay_root_cert_sn($this->settings['mode_b_alipay_root_cert']);
|
||||
} else {
|
||||
$appid = $this->settings['mode_a_appid'];
|
||||
$private_key = $this->settings['mode_a_app_private_key'];
|
||||
}
|
||||
$data['app_id'] = $appid;
|
||||
|
||||
$signstr = $this->alipay_make_signstr($data);
|
||||
$data['sign'] = $this->alipay_sign($private_key, $signstr);
|
||||
$api = SDK_ALIPAY_GATEWAYURL . '?' . http_build_query($data);
|
||||
$res = $this->alipay_request($api);
|
||||
$res = json_decode($res, true);
|
||||
$res = $res['alipay_trade_refund_response'];
|
||||
if($res['code'] == 10000) {
|
||||
return array('code' => 200, 'data' => array('refund_time' => time()));
|
||||
} else {
|
||||
if(strtoupper($_G['charset'] != 'UTF-8')) {
|
||||
$res['sub_msg'] = diconv($res['sub_msg'], 'UTF-8', $_G['charset']);
|
||||
}
|
||||
return array('code' => $res['sub_code'], 'message' => $res['sub_msg']);
|
||||
}
|
||||
}
|
||||
|
||||
private function alipay_refund_status($refund_no, $trade_no) {
|
||||
global $_G;
|
||||
$data = array('method' => 'alipay.trade.fastpay.refund.query', 'format' => 'JSON', 'charset' => 'utf-8', 'sign_type' => 'RSA2', 'timestamp' => dgmdate(time(), 'Y-m-d H:i:s'), 'version' => '1.0', 'biz_content' => json_encode(array('trade_no' => $trade_no, 'out_request_no' => $refund_no,)),);
|
||||
if($this->settings['ec_alipay_sign_mode']) {
|
||||
$appid = $this->settings['mode_b_appid'];
|
||||
$private_key = $this->settings['mode_b_app_private_key'];
|
||||
$data['app_cert_sn'] = $this->alipay_cert_sn($this->settings['mode_b_app_cert']);
|
||||
$data['alipay_root_cert_sn'] = $this->alipay_root_cert_sn($this->settings['mode_b_alipay_root_cert']);
|
||||
} else {
|
||||
$appid = $this->settings['mode_a_appid'];
|
||||
$private_key = $this->settings['mode_a_app_private_key'];
|
||||
}
|
||||
$data['app_id'] = $appid;
|
||||
|
||||
$signstr = $this->alipay_make_signstr($data);
|
||||
$data['sign'] = $this->alipay_sign($private_key, $signstr);
|
||||
$api = SDK_ALIPAY_GATEWAYURL . '?' . http_build_query($data);
|
||||
$res = $this->alipay_request($api);
|
||||
$res = json_decode($res, true);
|
||||
$res = $res['alipay_trade_fastpay_refund_query_response'];
|
||||
if($res['code'] == 10000) {
|
||||
return array('code' => 200, 'data' => array('refund_time' => time()));
|
||||
} else {
|
||||
if(strtoupper($_G['charset'] != 'UTF-8')) {
|
||||
$res['sub_msg'] = diconv($res['sub_msg'], 'UTF-8', $_G['charset']);
|
||||
}
|
||||
return array('code' => $res['sub_code'], 'message' => $res['sub_msg']);
|
||||
}
|
||||
}
|
||||
|
||||
private function alipay_make_signstr($data) {
|
||||
ksort($data);
|
||||
$signstr = array();
|
||||
foreach($data as $key => $value) {
|
||||
$signstr[] = $key . '=' . $value;
|
||||
}
|
||||
$signstr = implode('&', $signstr);
|
||||
return $signstr;
|
||||
}
|
||||
|
||||
private function alipay_sign($private_key, $data) {
|
||||
$private_key = "-----BEGIN RSA PRIVATE KEY-----\n" . wordwrap($private_key, 64, "\n", true) . "\n-----END RSA PRIVATE KEY-----";
|
||||
openssl_sign($data, $sign, $private_key, OPENSSL_ALGO_SHA256);
|
||||
return base64_encode($sign);
|
||||
}
|
||||
|
||||
private function alipay_make_notify_signstr($data) {
|
||||
ksort($data);
|
||||
$signstr = array();
|
||||
foreach($data as $key => $value) {
|
||||
if(in_array($key, array('sign', 'sign_type')) || !$value) {
|
||||
continue;
|
||||
}
|
||||
if(is_array($value)) {
|
||||
$value = json_encode($value);
|
||||
}
|
||||
$signstr[] = $key . '=' . $value;
|
||||
}
|
||||
$signstr = implode('&', $signstr);
|
||||
return $signstr;
|
||||
}
|
||||
|
||||
private function alipay_array_to_string($data) {
|
||||
$str = [];
|
||||
foreach($data as $name => $value) {
|
||||
$str[] = $name . '=' . $value;
|
||||
}
|
||||
return implode(',', $str);
|
||||
}
|
||||
|
||||
private function alipay_cert_sn($appcert) {
|
||||
$ssl = openssl_x509_parse($appcert);
|
||||
$sn = md5($this->alipay_array_to_string(array_reverse($ssl['issuer'])) . $ssl['serialNumber']);
|
||||
return $sn;
|
||||
}
|
||||
|
||||
private function alipay_root_cert_sn($alipayrootcert) {
|
||||
$array = explode("-----END CERTIFICATE-----", $alipayrootcert);
|
||||
$sn = array();
|
||||
for($i = 0; $i < count($array) - 1; $i++) {
|
||||
$ssl = openssl_x509_parse($array[$i] . "-----END CERTIFICATE-----");
|
||||
if($ssl['signatureTypeLN'] == "sha256WithRSAEncryption") {
|
||||
$sn[] = md5($this->alipay_array_to_string(array_reverse($ssl['issuer'])) . $ssl['serialNumber']);
|
||||
}
|
||||
}
|
||||
return implode('_', $sn);
|
||||
}
|
||||
|
||||
private function alipay_request($api, $post = array()) {
|
||||
$client = filesock::open(array(
|
||||
'url' => $api,
|
||||
'method' => 'POST',
|
||||
'post' => $post
|
||||
));
|
||||
|
||||
$data = $client->request();
|
||||
|
||||
if($client->curlstatus['http_code'] == 200) {
|
||||
return $data;
|
||||
} elseif(preg_match('/^30\d+$/', $client->curlstatus['http_code'])) {
|
||||
return $client->curlstatus['redirect_url'];
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
41
api/payment/payment_base.php
Normal file
41
api/payment/payment_base.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* [Discuz!] (C)2001-2099 Comsenz Inc.
|
||||
* This is NOT a freeware, use is subject to license terms
|
||||
*
|
||||
* $Id: payment_base.php 36342 2021-05-17 14:15:31Z dplugin $
|
||||
*/
|
||||
|
||||
if(!defined('IN_DISCUZ')) {
|
||||
exit('Access Denied');
|
||||
}
|
||||
|
||||
class payment_base {
|
||||
|
||||
var $settings;
|
||||
var $notify_url;
|
||||
|
||||
public function __construct() {}
|
||||
|
||||
protected function enable() {
|
||||
if($this->settings && $this->settings['on']) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function pay($order) { }
|
||||
|
||||
public function status($out_biz_no) { }
|
||||
|
||||
public function refund($refund_no, $trade_no, $total_amount, $refund_amount, $refund_desc) { }
|
||||
|
||||
public function refund_status($refund_no, $trade_no) { }
|
||||
|
||||
public function transfer($transfer_no, $amount, $realname, $account, $title = '', $desc = '') { }
|
||||
|
||||
public function transfer_status($transfer_no) { }
|
||||
|
||||
}
|
245
api/payment/payment_qpay.php
Normal file
245
api/payment/payment_qpay.php
Normal file
@@ -0,0 +1,245 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* [Discuz!] (C)2001-2099 Comsenz Inc.
|
||||
* This is NOT a freeware, use is subject to license terms
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
if(!defined('IN_DISCUZ')) {
|
||||
exit('Access Denied');
|
||||
}
|
||||
|
||||
define('SDK_QPAY_PAY_UNIFIEDORDER', 'https://qpay.qq.com/cgi-bin/pay/qpay_unified_order.cgi');
|
||||
define('SDK_QPAY_PAY_ORDERQUERY', 'https://qpay.qq.com/cgi-bin/pay/qpay_order_query.cgi');
|
||||
define('SDK_QPAY_PAY_REFUND', 'https://api.qpay.qq.com/cgi-bin/pay/qpay_refund.cgi');
|
||||
define('SDK_QPAY_PAY_REFUNDQUERY', 'https://qpay.qq.com/cgi-bin/pay/qpay_refund_query.cgi');
|
||||
|
||||
require DISCUZ_ROOT . './api/payment/payment_base.php';
|
||||
|
||||
class payment_qpay extends payment_base {
|
||||
|
||||
public function __construct() {
|
||||
global $_G;
|
||||
$this->settings = C::t('common_setting')->fetch_setting('ec_qpay', true);
|
||||
$this->notify_url = $_G['siteurl'] . 'api/payment/notify/notify_qpay.php';
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function pay($order) {
|
||||
if(!$this->enable()) {
|
||||
return array('code' => 500, 'message' => 'This payment method is not open yet.');
|
||||
}
|
||||
return $this->qpay_unifiedorder_pay($order);
|
||||
}
|
||||
|
||||
public function status($out_biz_no) {
|
||||
if(!$this->enable()) {
|
||||
return array('code' => 500, 'message' => 'This payment method is not open yet.');
|
||||
}
|
||||
return $this->qpay_order_query($out_biz_no);
|
||||
}
|
||||
|
||||
public function refund($refund_no, $trade_no, $total_amount, $refund_amount, $refund_desc) {
|
||||
if(!$this->enable()) {
|
||||
return array('code' => 500, 'message' => 'This payment method is not open yet.');
|
||||
}
|
||||
return $this->qpay_refund($refund_no, $trade_no, $total_amount, $refund_amount, $refund_desc);
|
||||
}
|
||||
|
||||
public function refund_status($refund_no, $trade_no) {
|
||||
if(!$this->enable()) {
|
||||
return array('code' => 500, 'message' => 'This payment method is not open yet.');
|
||||
}
|
||||
return $this->qpay_refund_status($refund_no);
|
||||
}
|
||||
|
||||
public function transfer($transfer_no, $amount, $realname, $account, $title = '', $desc = '') {
|
||||
return array('code' => 500, 'message' => 'This payment method is not support this feature.');
|
||||
}
|
||||
|
||||
public function transfer_status($transfer_no) {
|
||||
return array('code' => 500, 'message' => 'This payment method is not support this feature.');
|
||||
}
|
||||
|
||||
public function pay_jsapi($order) {
|
||||
if(!$this->enable()) {
|
||||
return array('code' => 500, 'message' => 'This payment method is not open yet.');
|
||||
}
|
||||
return $this->qpay_unifiedorder_pay($order, 'JSAPI');
|
||||
}
|
||||
|
||||
public function qpay_sign_verify() {
|
||||
$xml = file_get_contents('php://input');
|
||||
$data = $this->qpay_x2o($xml);
|
||||
$sign = $this->qpay_sign($this->settings['v1_key'], $data, 1);
|
||||
if($sign != $data['sign']) {
|
||||
return array('code' => 50001, 'data' => $data);
|
||||
}
|
||||
if($data['return_code'] != 'SUCCESS') {
|
||||
return array('code' => 50002, 'data' => $data);
|
||||
}
|
||||
if($data['result_code'] != 'SUCCESS') {
|
||||
return array('code' => 50003, 'data' => $data);
|
||||
}
|
||||
return array('code' => 200, 'data' => $data);
|
||||
}
|
||||
|
||||
protected function enable() {
|
||||
return $this->settings && $this->settings['on'];
|
||||
}
|
||||
|
||||
private function qpay_unifiedorder_pay($order, $type = 'NATIVE') {
|
||||
global $_G;
|
||||
if(strtoupper($_G['charset'] != 'UTF-8')) {
|
||||
$order['subject'] = diconv($order['subject'], $_G['charset'], 'UTF-8');
|
||||
$order['description'] = diconv($order['description'], $_G['charset'], 'UTF-8');
|
||||
}
|
||||
$data = array('appid' => $this->settings['appid'], 'mch_id' => $this->settings['mch_id'], 'nonce_str' => $this->qpay_nonce(), 'body' => $order['subject'], 'attach' => $order['description'], 'out_trade_no' => $order['out_biz_no'], 'fee_type' => 'CNY', 'total_fee' => intval($order['amount']), 'spbill_create_ip' => $_G['clientip'], 'time_expire' => dgmdate(time() + 86400, 'YmdHis'), 'notify_url' => $this->notify_url, 'trade_type' => $type);
|
||||
$data['sign'] = $this->qpay_sign($this->settings['v1_key'], $data);
|
||||
$data = $this->qpay_o2x($data);
|
||||
|
||||
$api = SDK_QPAY_PAY_UNIFIEDORDER;
|
||||
$res = $this->qpay_request_xml($api, $data);
|
||||
if(strtoupper($_G['charset'] != 'UTF-8')) {
|
||||
$res = diconv($res, 'UTF-8', $_G['charset']);
|
||||
}
|
||||
$res = $this->qpay_x2o($res);
|
||||
|
||||
if($res['return_code'] != 'SUCCESS') {
|
||||
return array('code' => 500, 'message' => $res['return_msg']);
|
||||
} elseif($res['result_code'] != 'SUCCESS') {
|
||||
return array('code' => 501, 'message' => $res['err_code_des']);
|
||||
} else {
|
||||
return array('code' => 200, 'url' => isset($res['code_url']) ? $res['code_url'] : $res['prepay_id']);
|
||||
}
|
||||
}
|
||||
|
||||
private function qpay_order_query($out_biz_no) {
|
||||
global $_G;
|
||||
$data = array('appid' => $this->settings['appid'], 'mch_id' => $this->settings['mch_id'], 'out_trade_no' => $out_biz_no, 'nonce_str' => $this->qpay_nonce());
|
||||
$data['sign'] = $this->qpay_sign($this->settings['v1_key'], $data);
|
||||
$data = $this->qpay_o2x($data);
|
||||
$api = SDK_QPAY_PAY_ORDERQUERY;
|
||||
$res = $this->qpay_request_xml($api, $data);
|
||||
|
||||
if(strtoupper($_G['charset'] != 'UTF-8')) {
|
||||
$res = diconv($res, 'UTF-8', $_G['charset']);
|
||||
}
|
||||
$res = $this->qpay_x2o($res);
|
||||
if($res['return_code'] != 'SUCCESS') {
|
||||
return array('code' => 500, 'message' => $res['return_msg']);
|
||||
} elseif($res['result_code'] != 'SUCCESS') {
|
||||
return array('code' => 500, 'message' => $res['err_code_des']);
|
||||
} else{
|
||||
$pay_time = strtotime(preg_replace('/^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})$/', '$1-$2-$3 $4:$5:$6', $res['time_end']));
|
||||
return array('code' => 200, 'data' => array('trade_no' => $res['transaction_id'], 'payment_time' => $pay_time));
|
||||
}
|
||||
}
|
||||
|
||||
private function qpay_refund($refund_no, $trade_no, $total_amount, $refund_amount, $refund_desc) {
|
||||
global $_G;
|
||||
if(strtoupper($_G['charset'] != 'UTF-8')) {
|
||||
$refund_desc = diconv($refund_desc, $_G['charset'], 'UTF-8');
|
||||
}
|
||||
$data = array('appid' => $this->settings['appid'], 'mch_id' => $this->settings['mch_id'], 'nonce_str' => $this->qpay_nonce(), 'transaction_id' => $trade_no, 'out_refund_no' => $refund_no, 'refund_fee' => $refund_amount, 'op_user_id' => $this->settings['op_user_id'], 'op_user_passwd' => $this->settings['op_user_passwd']);
|
||||
$data['sign'] = $this->qpay_sign($this->settings['v1_key'], $data);
|
||||
$data = $this->qpay_o2x($data);
|
||||
$api = SDK_QPAY_PAY_REFUND;
|
||||
$res = $this->qpay_request_xml($api, $data, true);
|
||||
|
||||
if(strtoupper($_G['charset'] != 'UTF-8')) {
|
||||
$res = diconv($res, 'UTF-8', $_G['charset']);
|
||||
}
|
||||
$res = $this->qpay_x2o($res);
|
||||
if($res['return_code'] != 'SUCCESS') {
|
||||
return array('code' => 500, 'message' => $res['return_msg']);
|
||||
} elseif($res['result_code'] != 'SUCCESS') {
|
||||
return array('code' => 500, 'message' => $res['err_code_des']);
|
||||
} else {
|
||||
return array('code' => 200, 'data' => array('refund_time' => time()));
|
||||
}
|
||||
}
|
||||
|
||||
private function qpay_refund_status($refund_no) {
|
||||
global $_G;
|
||||
$data = array('appid' => $this->settings['appid'], 'mch_id' => $this->settings['mch_id'], 'nonce_str' => $this->qpay_nonce(), 'out_refund_no' => $refund_no);
|
||||
$data['sign'] = $this->qpay_sign($this->settings['v1_key'], $data);
|
||||
$data = $this->qpay_o2x($data);
|
||||
$api = SDK_QPAY_PAY_REFUNDQUERY;
|
||||
$res = $this->qpay_request_xml($api, $data);
|
||||
if(strtoupper($_G['charset'] != 'UTF-8')) {
|
||||
$res = diconv($res, 'UTF-8', $_G['charset']);
|
||||
}
|
||||
$res = $this->qpay_x2o($res);
|
||||
if($res['return_code'] != 'SUCCESS') {
|
||||
return array('code' => 500, 'message' => $res['return_msg']);
|
||||
} elseif($res['result_code'] != 'SUCCESS') {
|
||||
return array('code' => 500, 'message' => $res['err_code'] . '-' . $res['err_code_des']);
|
||||
} else {
|
||||
return array('code' => 200, 'data' => array('refund_time' => time()));
|
||||
}
|
||||
}
|
||||
|
||||
private function qpay_o2x($data) {
|
||||
$xml = '<xml>';
|
||||
foreach($data as $key => $value) {
|
||||
$xml .= "\n<{$key}>{$value}</{$key}>";
|
||||
}
|
||||
$xml .= "\n</xml>";
|
||||
return $xml;
|
||||
}
|
||||
|
||||
private function qpay_x2o($xml) {
|
||||
libxml_disable_entity_loader(true);
|
||||
$data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
|
||||
return $data;
|
||||
}
|
||||
|
||||
private function qpay_sign($token, $data, $sign = 0) {
|
||||
ksort($data);
|
||||
$signstr = '';
|
||||
foreach($data as $key => $value) {
|
||||
if(!$value || ($sign && $key == 'sign')) continue;
|
||||
$signstr .= $key . '=' . $value . '&';
|
||||
}
|
||||
$signstr .= 'key=' . $token;
|
||||
$sign = strtoupper(md5($signstr));
|
||||
return $sign;
|
||||
}
|
||||
|
||||
private function qpay_nonce() {
|
||||
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
$charactersLength = strlen($characters);
|
||||
$randomString = '';
|
||||
for($i = 0; $i < 32; $i++) {
|
||||
$randomString .= $characters[rand(0, $charactersLength - 1)];
|
||||
}
|
||||
return $randomString;
|
||||
}
|
||||
|
||||
private function qpay_request_xml($api, $xml, $cert = false) {
|
||||
$params = array(
|
||||
'url' => $api,
|
||||
'method' => 'POST',
|
||||
'rawdata' => $xml,
|
||||
'encodetype' => 'application/xml',
|
||||
);
|
||||
|
||||
if($cert) {
|
||||
if(!$this->settings['v1_cert_path'] || !file_exists(DISCUZ_ROOT . $this->settings['v1_cert_path']) || !is_file(DISCUZ_ROOT . $this->settings['v1_cert_path'])) {
|
||||
return '<xml><return_code>400</return_code><return_msg>p12 not found.</return_msg></xml>';
|
||||
}
|
||||
$params['verifypeer'] = $this->settings['v1_cert_path'];
|
||||
}
|
||||
|
||||
$client = filesock::open($params);
|
||||
$data = $client -> request();
|
||||
if(!$data) {
|
||||
$data = $client -> filesockbody;
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
}
|
585
api/payment/payment_wechat.php
Normal file
585
api/payment/payment_wechat.php
Normal file
@@ -0,0 +1,585 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* [Discuz!] (C)2001-2099 Comsenz Inc.
|
||||
* This is NOT a freeware, use is subject to license terms
|
||||
*
|
||||
* $Id: payment_wechat.php 36342 2021-05-17 14:15:31Z dplugin $
|
||||
*/
|
||||
|
||||
if(!defined('IN_DISCUZ')) {
|
||||
exit('Access Denied');
|
||||
}
|
||||
|
||||
define('SDK_WEIXIN_PAY_UNIFIEDORDER', 'https://api.mch.weixin.qq.com/pay/unifiedorder');
|
||||
define('SDK_WEIXIN_PAY_ORDERQUERY', 'https://api.mch.weixin.qq.com/pay/orderquery');
|
||||
define('SDK_WEIXIN_PAY_REFUND', 'https://api.mch.weixin.qq.com/secapi/pay/refund');
|
||||
define('SDK_WEIXIN_PAY_REFUNDQUERY', 'https://api.mch.weixin.qq.com/pay/refundquery');
|
||||
define('SDK_WEIXIN_AUTHORIZE', 'https://open.weixin.qq.com/connect/oauth2/authorize');
|
||||
define('SDK_WEIXIN_SNS_ACCESS_TOKEN', 'https://api.weixin.qq.com/sns/oauth2/access_token');
|
||||
|
||||
define('SDK_WEIXIN_PAY_V3_TRANSACTIONS_NATIVE', 'https://api.mch.weixin.qq.com/v3/pay/transactions/native');
|
||||
define('SDK_WEIXIN_PAY_V3_TRANSACTIONS_H5', 'https://api.mch.weixin.qq.com/v3/pay/transactions/h5');
|
||||
define('SDK_WEIXIN_PAY_V3_TRANSACTIONS_JSAPI', 'https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi');
|
||||
define('SDK_WEIXIN_PAY_V3_TRANSACTIONS_OUTTRADENO', 'https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/');
|
||||
define('SDK_WEIXIN_PAY_V3_REFUND_DOMESTIC_REFUNDS', 'https://api.mch.weixin.qq.com/v3/refund/domestic/refunds');
|
||||
define('SDK_WEIXIN_PAY_V3_REFUND_DOMESTIC_REFUNDS_QUERY', 'https://api.mch.weixin.qq.com/v3/refund/domestic/refunds/');
|
||||
define('SDK_WEIXIN_PAY_V3_CERTIFICATES', 'https://api.mch.weixin.qq.com/v3/certificates');
|
||||
|
||||
require DISCUZ_ROOT . './api/payment/payment_base.php';
|
||||
|
||||
class payment_wechat extends payment_base {
|
||||
|
||||
public function __construct() {
|
||||
global $_G;
|
||||
$this->settings = C::t('common_setting')->fetch_setting('ec_wechat', true);
|
||||
$this->notify_url = $_G['siteurl'] . 'api/payment/notify/notify_wechat.php';
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function pay($order) {
|
||||
if(!$this->enable()) {
|
||||
return array('code' => 500, 'message' => 'Did not open payment');
|
||||
}
|
||||
|
||||
$device = $this->wechat_device();
|
||||
if($device) {
|
||||
if($this->settings['ec_wechat_version']) {
|
||||
return $this->v3_wechat_h5_pay($order);
|
||||
} else {
|
||||
return $this->wechat_unifiedorder_pay($order, 'MWEB');
|
||||
}
|
||||
} else {
|
||||
if($this->settings['ec_wechat_version']) {
|
||||
return $this->v3_wechat_native_pay($order);
|
||||
} else {
|
||||
return $this->wechat_unifiedorder_pay($order, 'NATIVE');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function status($out_biz_no) {
|
||||
if(!$this->enable()) {
|
||||
return array('code' => 500, 'message' => 'Did not open payment');
|
||||
}
|
||||
if($this->settings['ec_wechat_version']) {
|
||||
return $this->v3_wechat_query_order($out_biz_no);
|
||||
} else {
|
||||
return $this->wechat_order_query($out_biz_no);
|
||||
}
|
||||
}
|
||||
|
||||
public function refund($refund_no, $trade_no, $total_amount, $refund_amount, $refund_desc) {
|
||||
if(!$this->enable()) {
|
||||
return array('code' => 500, 'message' => 'Did not open payment');
|
||||
}
|
||||
if($this->settings['ec_wechat_version']) {
|
||||
return $this->v3_wechat_refund($refund_no, $trade_no, $total_amount, $refund_amount, $refund_desc);
|
||||
} else {
|
||||
return $this->wechat_refund($refund_no, $trade_no, $total_amount, $refund_amount, $refund_desc);
|
||||
}
|
||||
}
|
||||
|
||||
public function refund_status($refund_no, $trade_no) {
|
||||
if(!$this->enable()) {
|
||||
return array('code' => 500, 'message' => 'Did not open payment');
|
||||
}
|
||||
if($this->settings['ec_wechat_version']) {
|
||||
return $this->v3_wechat_refund_query($refund_no);
|
||||
} else {
|
||||
return $this->wechat_refund_status($refund_no);
|
||||
}
|
||||
}
|
||||
|
||||
public function transfer($transfer_no, $amount, $realname, $account, $title = '', $desc = '') {
|
||||
return array('code' => 500, 'message' => 'not support.');
|
||||
}
|
||||
|
||||
public function transfer_status($transfer_no) {
|
||||
return array('code' => 500, 'message' => 'not support.');
|
||||
}
|
||||
|
||||
public function pay_jsapi($order, $openid) {
|
||||
if(!$this->enable()) {
|
||||
return array('code' => 500, 'message' => 'Did not open payment');
|
||||
}
|
||||
if($this->settings['ec_wechat_version']) {
|
||||
return $this->v3_wechat_h5_jsapi($order, $openid);
|
||||
} else {
|
||||
return $this->wechat_unifiedorder_pay($order, 'JSAPI', $openid);
|
||||
}
|
||||
}
|
||||
|
||||
public function wechat_jsapidata($prepay_id) {
|
||||
if($this->settings['ec_wechat_version']) {
|
||||
$jsapidata = array(
|
||||
'appId' => $this->settings['appid'],
|
||||
'timeStamp' => time() . '',
|
||||
'nonceStr' => $this->wechat_nonce(),
|
||||
'package' => 'prepay_id=' . $prepay_id,
|
||||
'signType' => 'RSA'
|
||||
);
|
||||
$jsapidata['paySign'] = $this->v3_wechat_jsapi_authorization($jsapidata);
|
||||
} else {
|
||||
$jsapidata = array('appId' => $this->settings['appid'], 'timeStamp' => time() . '', 'nonceStr' => $this->wechat_nonce(), 'package' => 'prepay_id=' . $prepay_id, 'signType' => 'MD5');
|
||||
$jsapidata['paySign'] = $this->wechat_sign($this -> settings['v1_key'], $jsapidata);
|
||||
}
|
||||
return json_encode($jsapidata);
|
||||
}
|
||||
|
||||
public function wechat_authorize($redirect_uri, $state, $scope = 'snsapi_base') {
|
||||
$appid = $this->settings['appid'];
|
||||
$redirect_uri = urlencode($redirect_uri);
|
||||
return SDK_WEIXIN_AUTHORIZE . "?appid={$appid}&redirect_uri={$redirect_uri}&response_type=code&scope={$scope}&state={$state}#wechat_redirect";
|
||||
}
|
||||
|
||||
public function wechat_access_token_by_code($code) {
|
||||
$appid = $this->settings['appid'];
|
||||
$appsecret = $this->settings['appsecret'];
|
||||
$api = SDK_WEIXIN_SNS_ACCESS_TOKEN . "?appid={$appid}&secret={$appsecret}&code=$code&grant_type=authorization_code";
|
||||
return $this->wechat_request($api);
|
||||
}
|
||||
|
||||
public function wechat_sign_verify() {
|
||||
$xml = file_get_contents('php://input');
|
||||
$data = $this->wechat_x2o($xml);
|
||||
$sign = $this->wechat_sign($this->settings['v1_key'], $data, 1);
|
||||
if($sign != $data['sign']) {
|
||||
return array('code' => 50001, 'data' => $data);
|
||||
}
|
||||
if($data['return_code'] != 'SUCCESS') {
|
||||
return array('code' => 50002, 'data' => $data);
|
||||
}
|
||||
if($data['result_code'] != 'SUCCESS') {
|
||||
return array('code' => 50003, 'data' => $data);
|
||||
}
|
||||
return array('code' => 200, 'data' => $data);
|
||||
}
|
||||
|
||||
public function v3_wechat_sign_verify() {
|
||||
$nonce = $_SERVER['HTTP_WECHATPAY_NONCE'];
|
||||
$timestamp = $_SERVER['HTTP_WECHATPAY_TIMESTAMP'];
|
||||
$serial = $_SERVER['HTTP_WECHATPAY_SERIAL'];
|
||||
$json = file_get_contents('php://input');
|
||||
$signature = $_SERVER['HTTP_WECHATPAY_SIGNATURE'];
|
||||
|
||||
$serial = strtoupper(ltrim($serial, '0'));
|
||||
$public_key = $this->settings['v3_certificates'][$serial];
|
||||
if(!$public_key) {
|
||||
return array('code' => 50001, 'data' => $json);
|
||||
}
|
||||
$signature = base64_decode($signature);
|
||||
$signstr = $timestamp . "\n" . $nonce . "\n" . $json . "\n";
|
||||
if(!openssl_verify($signstr, $signature, $public_key, 'sha256WithRSAEncryption')) {
|
||||
return array('code' => 50002, 'data' => $json);
|
||||
}
|
||||
$resource = json_decode($json, true);
|
||||
if($resource['event_type'] != 'TRANSACTION.SUCCESS') {
|
||||
return array('code' => 50003, 'data' => $resource);
|
||||
}
|
||||
$resource = $resource['resource'];
|
||||
$data = $this->v3_wechat_decrypt2string($resource['associated_data'], $resource['nonce'], $resource['ciphertext']);
|
||||
return array('code' => 200, 'data' => $data);
|
||||
}
|
||||
|
||||
public function v3_wechat_support() {
|
||||
if(function_exists('sodium_crypto_aead_aes256gcm_is_available') && sodium_crypto_aead_aes256gcm_is_available()) {
|
||||
return true;
|
||||
}
|
||||
if(PHP_VERSION_ID >= 70100 && in_array('aes-256-gcm', openssl_get_cipher_methods())) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function v3_wechat_certificates() {
|
||||
global $_G;
|
||||
$api = SDK_WEIXIN_PAY_V3_CERTIFICATES;
|
||||
$res = $this->v3_wechat_request_json($api, '', 'GET');
|
||||
$res = json_decode($res, true);
|
||||
$list = array();
|
||||
if($res['data']) {
|
||||
foreach($res['data'] as $item) {
|
||||
$serial_no = $item['serial_no'];
|
||||
$item = $item['encrypt_certificate'];
|
||||
$data = $this->v3_wechat_decrypt2string($item['associated_data'], $item['nonce'], $item['ciphertext']);
|
||||
$list[$serial_no] = $data;
|
||||
}
|
||||
}
|
||||
return array('code' => 200, 'data' => $list);
|
||||
}
|
||||
|
||||
protected function enable() {
|
||||
if($this->settings && $this->settings['on']) {
|
||||
if($this->settings['ec_wechat_version']) {
|
||||
return $this->v3_wechat_support();
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private function wechat_unifiedorder_pay($order, $type = 'NATIVE', $openid = null) {
|
||||
global $_G;
|
||||
if(strtoupper($_G['charset'] != 'UTF-8')) {
|
||||
$order['subject'] = diconv($order['subject'], $_G['charset'], 'UTF-8');
|
||||
$order['description'] = diconv($order['description'], $_G['charset'], 'UTF-8');
|
||||
}
|
||||
$data = array('appid' => $this->settings['appid'], 'mch_id' => $this->settings['mch_id'], 'nonce_str' => $this->wechat_nonce(), 'sign_type' => 'MD5', 'body' => $order['subject'], 'detail' => $order['description'], 'out_trade_no' => $order['out_biz_no'], 'total_fee' => intval($order['amount']), 'spbill_create_ip' => $_G['clientip'], 'time_expire' => dgmdate(time() + 86400, 'YmdHis'), 'notify_url' => $this->notify_url, 'trade_type' => $type,);
|
||||
if($openid) {
|
||||
$data['openid'] = $openid;
|
||||
}
|
||||
$data['sign'] = $this->wechat_sign($this->settings['v1_key'], $data);
|
||||
$data = $this->wechat_o2x($data);
|
||||
|
||||
$api = SDK_WEIXIN_PAY_UNIFIEDORDER;
|
||||
$res = $this->wechat_request_xml($api, $data);
|
||||
if(strtoupper($_G['charset'] != 'UTF-8')) {
|
||||
$res = diconv($res, 'UTF-8', $_G['charset']);
|
||||
}
|
||||
$res = $this->wechat_x2o($res);
|
||||
|
||||
if($res['return_code'] != 'SUCCESS') {
|
||||
return array('code' => 500, 'message' => $res['return_msg']);
|
||||
} elseif($res['result_code'] != 'SUCCESS') {
|
||||
return array('code' => 501, 'message' => $res['err_code_des']);
|
||||
} else {
|
||||
if($res['code_url']) {
|
||||
$url = $res['code_url'];
|
||||
} elseif($res['mweb_url']) {
|
||||
$url = $res['mweb_url'];
|
||||
} else {
|
||||
$url = $res['prepay_id'];
|
||||
}
|
||||
return array('code' => 200, 'url' => $url);
|
||||
}
|
||||
}
|
||||
|
||||
private function wechat_order_query($out_biz_no) {
|
||||
global $_G;
|
||||
$data = ['appid' => $this->settings['appid'], 'mch_id' => $this->settings['mch_id'], 'out_trade_no' => $out_biz_no, 'nonce_str' => $this->wechat_nonce(), 'sign_type' => 'MD5'];
|
||||
$data['sign'] = $this->wechat_sign($this->settings['v1_key'], $data);
|
||||
$data = $this->wechat_o2x($data);
|
||||
$api = SDK_WEIXIN_PAY_ORDERQUERY;
|
||||
$res = $this->wechat_request_xml($api, $data);
|
||||
|
||||
if(strtoupper($_G['charset'] != 'UTF-8')) {
|
||||
$res = diconv($res, 'UTF-8', $_G['charset']);
|
||||
}
|
||||
$res = $this->wechat_x2o($res);
|
||||
if($res['return_code'] != 'SUCCESS') {
|
||||
return array('code' => 500, 'message' => $res['return_msg']);
|
||||
} elseif($res['result_code'] != 'SUCCESS') {
|
||||
return array('code' => 500, 'message' => $res['err_code_des']);
|
||||
} else {
|
||||
$pay_time = strtotime(preg_replace('/^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})$/', '$1-$2-$3 $4:$5:$6', $res['time_end']));
|
||||
return array('code' => 200, 'data' => array('trade_no' => $res['transaction_id'], 'payment_time' => $pay_time));
|
||||
}
|
||||
}
|
||||
|
||||
private function wechat_refund($refund_no, $trade_no, $total_amount, $refund_amount, $refund_desc) {
|
||||
global $_G;
|
||||
if(strtoupper($_G['charset'] != 'UTF-8')) {
|
||||
$refund_desc = diconv($refund_desc, $_G['charset'], 'UTF-8');
|
||||
}
|
||||
$data = ['appid' => $this->settings['appid'], 'mch_id' => $this->settings['mch_id'], 'nonce_str' => $this->wechat_nonce(), 'sign_type' => 'MD5', 'transaction_id' => $trade_no, 'out_refund_no' => $refund_no, 'total_fee' => $total_amount, 'refund_fee' => $refund_amount, 'refund_desc' => $refund_desc];
|
||||
$data['sign'] = $this->wechat_sign($this->settings['v1_key'], $data);
|
||||
$data = $this->wechat_o2x($data);
|
||||
$api = SDK_WEIXIN_PAY_REFUND;
|
||||
$res = $this->wechat_request_xml($api, $data, true);
|
||||
|
||||
if(strtoupper($_G['charset'] != 'UTF-8')) {
|
||||
$res = diconv($res, 'UTF-8', $_G['charset']);
|
||||
}
|
||||
$res = $this->wechat_x2o($res);
|
||||
if($res['return_code'] != 'SUCCESS') {
|
||||
return array('code' => 500, 'message' => $res['return_msg']);
|
||||
} elseif($res['result_code'] != 'SUCCESS') {
|
||||
return array('code' => 500, 'message' => $res['err_code_des']);
|
||||
} else {
|
||||
return array('code' => 200, 'data' => array('refund_time' => time()));
|
||||
}
|
||||
}
|
||||
|
||||
private function wechat_refund_status($refund_no) {
|
||||
global $_G;
|
||||
$data = ['appid' => $this->settings['appid'], 'mch_id' => $this->settings['mch_id'], 'nonce_str' => $this->wechat_nonce(), 'sign_type' => 'MD5', 'out_refund_no' => $refund_no,];
|
||||
$data['sign'] = $this->wechat_sign($this->settings['v1_key'], $data);
|
||||
$data = $this->wechat_o2x($data);
|
||||
$api = SDK_WEIXIN_PAY_REFUNDQUERY;
|
||||
$res = $this->wechat_request_xml($api, $data);
|
||||
if(strtoupper($_G['charset'] != 'UTF-8')) {
|
||||
$res = diconv($res, 'UTF-8', $_G['charset']);
|
||||
}
|
||||
$res = $this->wechat_x2o($res);
|
||||
if($res['return_code'] != 'SUCCESS') {
|
||||
return array('code' => 500, 'message' => $res['return_msg']);
|
||||
} elseif($res['result_code'] != 'SUCCESS') {
|
||||
return array('code' => 500, 'message' => $res['err_code'] . '-' . $res['err_code_des']);
|
||||
} else {
|
||||
return array('code' => 200, 'data' => array('refund_time' => time()));
|
||||
}
|
||||
}
|
||||
|
||||
private function v3_wechat_native_pay($order) {
|
||||
global $_G;
|
||||
if(strtoupper($_G['charset'] != 'UTF-8')) {
|
||||
$order['subject'] = diconv($order['subject'], $_G['charset'], 'UTF-8');
|
||||
$order['description'] = diconv($order['description'], $_G['charset'], 'UTF-8');
|
||||
}
|
||||
$data = array('appid' => $this->settings['appid'], 'mchid' => $this->settings['mch_id'], 'description' => $order['subject'] . ': ' . $order['description'], 'out_trade_no' => $order['out_biz_no'], 'notify_url' => $this->notify_url, 'amount' => array('total' => intval($order['amount']), 'currency' => 'CNY'));
|
||||
|
||||
$api = SDK_WEIXIN_PAY_V3_TRANSACTIONS_NATIVE;
|
||||
$res = $this->v3_wechat_request_json($api, json_encode($data));
|
||||
$res = json_decode($res, true);
|
||||
if($res['code_url']) {
|
||||
return array('code' => 200, 'url' => $res['code_url']);
|
||||
} else {
|
||||
if(strtoupper($_G['charset'] != 'UTF-8') && $res['message']) {
|
||||
$res['message'] = diconv($res['message'], 'UTF-8', $_G['charset']);
|
||||
}
|
||||
return array('code' => $res['code'], 'message' => $res['message']);
|
||||
}
|
||||
}
|
||||
|
||||
private function v3_wechat_h5_pay($order) {
|
||||
global $_G;
|
||||
if(strtoupper($_G['charset'] != 'UTF-8')) {
|
||||
$order['subject'] = diconv($order['subject'], $_G['charset'], 'UTF-8');
|
||||
$order['description'] = diconv($order['description'], $_G['charset'], 'UTF-8');
|
||||
}
|
||||
$data = array('appid' => $this->settings['appid'], 'mchid' => $this->settings['mch_id'], 'description' => $order['subject'] . ': ' . $order['description'], 'out_trade_no' => $order['out_biz_no'], 'notify_url' => $this->notify_url, 'amount' => array('total' => intval($order['amount']), 'currency' => 'CNY'), 'scene_info' => array('payer_client_ip' => $_G['clientip'], 'h5_info' => array('type' => checkmobile())));
|
||||
|
||||
$api = SDK_WEIXIN_PAY_V3_TRANSACTIONS_H5;
|
||||
$res = $this->v3_wechat_request_json($api, json_encode($data));
|
||||
$res = json_decode($res, true);
|
||||
if($res['h5_url']) {
|
||||
return array('code' => 200, 'url' => $res['h5_url']);
|
||||
} else {
|
||||
if(strtoupper($_G['charset'] != 'UTF-8') && $res['message']) {
|
||||
$res['message'] = diconv($res['message'], 'UTF-8', $_G['charset']);
|
||||
}
|
||||
return array('code' => $res['code'], 'message' => $res['message']);
|
||||
}
|
||||
}
|
||||
|
||||
private function v3_wechat_h5_jsapi($order, $openid) {
|
||||
global $_G;
|
||||
if(strtoupper($_G['charset'] != 'UTF-8')) {
|
||||
$order['subject'] = diconv($order['subject'], $_G['charset'], 'UTF-8');
|
||||
$order['description'] = diconv($order['description'], $_G['charset'], 'UTF-8');
|
||||
}
|
||||
$data = array('appid' => $this->settings['appid'], 'mchid' => $this->settings['mch_id'], 'description' => $order['subject'] . ': ' . $order['description'], 'out_trade_no' => $order['out_biz_no'], 'notify_url' => $this->notify_url, 'amount' => array('total' => intval($order['amount']), 'currency' => 'CNY'), 'payer' => array('openid' => $openid));
|
||||
|
||||
$api = SDK_WEIXIN_PAY_V3_TRANSACTIONS_H5;
|
||||
$res = $this->v3_wechat_request_json($api, json_encode($data));
|
||||
$res = json_decode($res, true);
|
||||
if($res['prepay_id']) {
|
||||
return array('code' => 200, 'url' => $res['prepay_id']);
|
||||
} else {
|
||||
if(strtoupper($_G['charset'] != 'UTF-8') && $res['message']) {
|
||||
$res['message'] = diconv($res['message'], 'UTF-8', $_G['charset']);
|
||||
}
|
||||
return array('code' => $res['code'], 'message' => $res['message']);
|
||||
}
|
||||
}
|
||||
|
||||
private function v3_wechat_query_order($out_biz_no) {
|
||||
global $_G;
|
||||
$api = SDK_WEIXIN_PAY_V3_TRANSACTIONS_OUTTRADENO;
|
||||
$res = $this->v3_wechat_request_json($api . $out_biz_no . '?mchid=' . $this->settings['mch_id'], '', 'GET');
|
||||
$res = json_decode($res, true);
|
||||
if($res['trade_state'] && $res['trade_state'] == 'SUCCESS') {
|
||||
$pay_time = strtotime($res['success_time']);
|
||||
return array('code' => 200, 'data' => array('trade_no' => $res['transaction_id'], 'payment_time' => $pay_time));
|
||||
} elseif($res['trade_state']) {
|
||||
return array('code' => $res['trade_state'], 'message' => $res['trade_state_desc']);
|
||||
} else {
|
||||
if(strtoupper($_G['charset'] != 'UTF-8') && $res['message']) {
|
||||
$res['message'] = diconv($res['message'], 'UTF-8', $_G['charset']);
|
||||
}
|
||||
return array('code' => $res['code'], 'message' => $res['message']);
|
||||
}
|
||||
}
|
||||
|
||||
private function v3_wechat_refund($refund_no, $trade_no, $total_amount, $refund_amount, $refund_desc) {
|
||||
global $_G;
|
||||
if(strtoupper($_G['charset'] != 'UTF-8')) {
|
||||
$refund_desc = diconv($refund_desc, $_G['charset'], 'UTF-8');
|
||||
}
|
||||
$data = array('transaction_id' => $trade_no, 'out_refund_no' => $refund_no, 'reason' => $refund_desc, 'amount' => array('refund' => intval($refund_amount), 'total' => intval($total_amount), 'currency' => 'CNY'));
|
||||
|
||||
$api = SDK_WEIXIN_PAY_V3_REFUND_DOMESTIC_REFUNDS;
|
||||
$res = $this->v3_wechat_request_json($api, json_encode($data));
|
||||
$res = json_decode($res, true);
|
||||
if($res['status'] == 'SUCCESS') {
|
||||
return array('code' => 200, 'data' => array('refund_time' => strtotime($res['success_time'])));
|
||||
} elseif($res['status']) {
|
||||
return array('code' => 201, 'message' => $res['status']);
|
||||
} elseif($res['status']) {
|
||||
return array('code' => 500, 'message' => $res['status']);
|
||||
} else {
|
||||
if(strtoupper($_G['charset'] != 'UTF-8') && $res['message']) {
|
||||
$res['message'] = diconv($res['message'], 'UTF-8', $_G['charset']);
|
||||
}
|
||||
return array('code' => $res['code'], 'message' => $res['message']);
|
||||
}
|
||||
}
|
||||
|
||||
private function v3_wechat_refund_query($refund_no) {
|
||||
global $_G;
|
||||
$api = SDK_WEIXIN_PAY_V3_REFUND_DOMESTIC_REFUNDS_QUERY;
|
||||
$res = $this->v3_wechat_request_json($api . $refund_no, '', 'GET');
|
||||
$res = json_decode($res, true);
|
||||
if($res['status'] == 'SUCCESS') {
|
||||
return array('code' => 200, 'data' => array('refund_time' => strtotime($res['success_time'])));
|
||||
} elseif($res['status']) {
|
||||
return array('code' => 201, 'message' => $res['status']);
|
||||
} elseif($res['status']) {
|
||||
return array('code' => 500, 'message' => $res['status']);
|
||||
} else {
|
||||
if(strtoupper($_G['charset'] != 'UTF-8') && $res['message']) {
|
||||
$res['message'] = diconv($res['message'], 'UTF-8', $_G['charset']);
|
||||
}
|
||||
return array('code' => $res['code'], 'message' => $res['message']);
|
||||
}
|
||||
}
|
||||
|
||||
private function wechat_o2x($data) {
|
||||
$xml = '<xml>';
|
||||
foreach($data as $key => $value) {
|
||||
$xml .= "\n<{$key}>{$value}</{$key}>";
|
||||
}
|
||||
$xml .= "\n</xml>";
|
||||
return $xml;
|
||||
}
|
||||
|
||||
private function wechat_x2o($xml) {
|
||||
if(function_exists('libxml_disable_entity_loader')) {
|
||||
libxml_disable_entity_loader(true);
|
||||
}
|
||||
$data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
|
||||
return $data;
|
||||
}
|
||||
|
||||
private function wechat_sign($token, $data, $sign = 0) {
|
||||
ksort($data);
|
||||
$signstr = '';
|
||||
foreach($data as $key => $value) {
|
||||
if(!$value || ($sign && $key == 'sign')) {
|
||||
continue;
|
||||
}
|
||||
$signstr .= $key . '=' . $value . '&';
|
||||
}
|
||||
$signstr .= 'key=' . $token;
|
||||
$sign = strtoupper(md5($signstr));
|
||||
return $sign;
|
||||
}
|
||||
|
||||
private function wechat_nonce() {
|
||||
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
$charactersLength = strlen($characters);
|
||||
$randomString = '';
|
||||
for($i = 0; $i < 32; $i++) {
|
||||
$randomString .= $characters[rand(0, $charactersLength - 1)];
|
||||
}
|
||||
return $randomString;
|
||||
}
|
||||
|
||||
private function v3_wechat_jsapi_authorization($data) {
|
||||
$message = $data['appId'] . "\n" . $data['timeStamp'] . "\n" . $data['nonceStr'] . "\n" . $data['package'];
|
||||
openssl_sign($message, $sign, $this->settings['v3_private_key'], 'sha256WithRSAEncryption');
|
||||
$sign = base64_encode($sign);
|
||||
return $sign;
|
||||
}
|
||||
|
||||
private function v3_wechat_authorization($api, $method, $json) {
|
||||
$url_values = parse_url($api);
|
||||
$timestamp = time();
|
||||
$nonce = $this->wechat_nonce();
|
||||
$message = $method . "\n" . $url_values['path'] . ($url_values['query'] ? ('?' . $url_values['query']) : '') . "\n" . $timestamp . "\n" . $nonce . "\n" . $json . "\n";
|
||||
openssl_sign($message, $sign, $this->settings['v3_private_key'], 'sha256WithRSAEncryption');
|
||||
$sign = base64_encode($sign);
|
||||
$token = sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"', $this->settings['mch_id'], $nonce, $timestamp, $this->settings['v3_serial_no'], $sign);
|
||||
return $token;
|
||||
}
|
||||
|
||||
private function v3_wechat_decrypt2string($associateddata, $noncestr, $ciphertext) {
|
||||
$ciphertext = base64_decode($ciphertext);
|
||||
if(strlen($ciphertext) <= 16) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(function_exists('sodium_crypto_aead_aes256gcm_is_available') && sodium_crypto_aead_aes256gcm_is_available()) {
|
||||
return sodium_crypto_aead_aes256gcm_decrypt($ciphertext, $associateddata, $noncestr, $this->settings['v3_key']);
|
||||
}
|
||||
if(PHP_VERSION_ID >= 70100 && in_array('aes-256-gcm', openssl_get_cipher_methods())) {
|
||||
$ctext = substr($ciphertext, 0, -16);
|
||||
$authTag = substr($ciphertext, -16);
|
||||
|
||||
return openssl_decrypt($ctext, 'aes-256-gcm', $this->settings['v3_key'], OPENSSL_RAW_DATA, $noncestr, $authTag, $associateddata);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function wechat_request($api, $data = array()) {
|
||||
$client = filesock::open(array(
|
||||
'url' => $api,
|
||||
'method' => 'POST',
|
||||
'post' => $data
|
||||
));
|
||||
return $client->request();
|
||||
}
|
||||
|
||||
private function wechat_request_xml($api, $xml, $cert = false) {
|
||||
$params = array(
|
||||
'url' => $api,
|
||||
'method' => 'POST',
|
||||
'rawdata' => $xml,
|
||||
'encodetype' => 'application/xml',
|
||||
);
|
||||
|
||||
if($cert) {
|
||||
if(!$this->settings['v1_cert_path'] || !file_exists(DISCUZ_ROOT . $this->settings['v1_cert_path']) || !is_file(DISCUZ_ROOT . $this->settings['v1_cert_path'])) {
|
||||
return '<xml><return_code>400</return_code><return_msg>p12 not found.</return_msg></xml>';
|
||||
}
|
||||
$params['verifypeer'] = $this->settings['v1_cert_path'];
|
||||
}
|
||||
|
||||
$client = filesock::open($params);
|
||||
$data = $client -> request();
|
||||
if(!$data) {
|
||||
$data = $client -> filesockbody;
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
private function v3_wechat_request_json($api, $json = '', $method = 'POST') {
|
||||
$client = filesock::open(array(
|
||||
'url' => $api,
|
||||
'method' => $method,
|
||||
'rawdata' => $json,
|
||||
'encodetype' => 'JSON',
|
||||
'header' => array(
|
||||
'Accept' => 'application/json',
|
||||
'Authorization' => 'WECHATPAY2-SHA256-RSA2048 ' . $this->v3_wechat_authorization($api, $method, $json)
|
||||
)
|
||||
));
|
||||
$data = $client->request();
|
||||
if(!$data) {
|
||||
$data = $client->filesockbody;
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
private function wechat_device() {
|
||||
$useragent = $_SERVER['HTTP_USER_AGENT'];
|
||||
if(strpos($useragent, 'MicroMessenger') !== false) {
|
||||
return 'wechat';
|
||||
} else {
|
||||
return checkmobile();
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user