经验分享为热心网友提供,用于有能力的用户学习使用,不保证源码存在bug等问题
阿帕云Zkeys自定义支付说明:https://www.apayun.com/doc/614.html
分享者QQ:2448066128(代码主要部分);1005265250(手机端支付部分)
整理说明:根据阿帕云官网的自定义支付说明开发的,以下分享的是支付宝的支付方式,我只测试过PC端的支付,手机端的没有对接。(我已经把支付方式参数对接到配置中了,其实也可以理解是加了一种)。
备注: 支付方式的图标放在 public/template/user/Zkeys/PC/static/css/ucModule/finance/img/ 下面,图标名字为支付方式名和创建的对应php文件类名一样,也就是上传个ZhifufmAlipay.png 就可以了。
其他支付方式增加类似,举例增加微信支付,文件复制后修改如下地方:
- 文件名修改。发起部分如:ZhifufmAlipay.class.php 修改为 ZhifufmWepay.class.php;回调部分文件名字如:ZhifufmAlipayNotifyController.class.php 修改为 ZhifufmWepayNotifyController.class.php
- 类名修改。如:ZhifufmAlipay.class.php文件内:class ZhifufmAlipay implements Ipay 修改为 class ZhifufmWepay implements Ipay;ZhifufmAlipayNotifyController.class.php文件内:class ZhifufmAlipayNotifyController extends PaymentNotifyController 修改为 class ZhifufmWepayNotifyController extends PaymentNotifyController
- 发起部分的回调路径修改。发起部分如:ZhifufmAlipay.class.php 中/ApiNotify/ZhifufmAlipayNotify/notify 修改为 /ApiNotify/ZhifufmWepayNotify/notify
- 根据自己喜好上次支付方式的图标。如:ZhifufmWepayNotify.png
后台以及支付发起部分
在libs/Niaoyun/Payment 目录下新建要接入的支付方式ZhifufmAlipay.class.php文件,这个文件增加后,后台刷新应该就有配置入口了。代码内容如下:
<?php
namespace Niaoyun\Payment;
use Niaoyun\Payment\PayInterface\Ipay;
class ZhifufmAlipay implements Ipay{
private $payment_method;
private $config=[
'zhifu_merchant'=>'',
'zhifu_key' => '',
'zhifu_apiurl' => '',
'zhifu_paytype' => ''
];
private $configAdmin=[
'zhifu_merchant' =>['name'=>'商户号','show'=>true],
'zhifu_key' =>['name'=>'接入密钥','show'=>true],
'zhifu_apiurl' =>['name'=>'接口地址','show'=>true],
'zhifu_paytype' =>['name'=>'支付方式传值','show'=>true]
];
public function __construct(){
foreach ($this->configAdmin as $k => $v){
$this->config[$k] = C('recharge')[substr(__CLASS__, strrpos(__CLASS__,'\\') + 1).$k];
}
}
public function getPayName(){
return '支付FM';
}
//获取接口配置项,并展示与【平台后台】-【系统】-【全局设置】-【充值】中
public function getConfigAdmin(){
return $this->configAdmin;
}
public function getConfig(){
return $this->config;
}
public function pay($params){
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
//$params array(3) { ["total_fee"]=> string(1) "1" ["out_trade_no"]=> string(18) "800000008" ["body"]=> string(39) "充值款,会员ID:11111" }
$config = $this->config;
// php form表单page方式自动跳转
// 开发手册:http://docs.nephalem.cn/read/zhifufm/step
$amount = $params ['total_fee']; // 获取充值金额
$orderNo = $params['out_trade_no']; // 自己创建的本地订单号
$merchantNum = $config['zhifu_merchant']; // 商户号, 商户后台的用户中心页面查看
$secret = $config['zhifu_key']; // 商户密钥, 商户后台的用户中心页面查看
$api_url = $config['zhifu_apiurl']; // 付款请求接口, 商户后台的用户中心页面查看
$payType = $config['zhifu_paytype'];//'alipay';修改为前端传入的支付方式值,这样就可以自己控制了或者随时调整支付方式,查看支付接口文档说明payType的取值
$notifyUrl = $protocol.$_SERVER['HTTP_HOST'].'/ApiNotify/ZhifufmAlipayNotify/notify'; // XXXX修改为您自己用来接收支付成功的公网地址
$returnUrl = $protocol.$_SERVER['HTTP_HOST'].'/user/payment/record.html'; # 支付成功您想让页面跳转的地址
$returnType = "json"; // 接口返回方式 page为直接跳转到支付页面,不传返回json
$sign = md5 ( join ( '', array (
$merchantNum,
$orderNo,
$amount,
$notifyUrl,
$secret
) ));
$native = array (
"merchantNum" => $merchantNum,
"payType" => $payType,
"amount" => $amount,
"orderNo" => $orderNo,
"notifyUrl" => $notifyUrl,
"returnUrl" => $returnUrl,
"sign" => $sign,
"returnType" => $returnType
);
$param = http_build_query ( $native );
$return = $this->http_request ( $api_url, $param, 'application/x-www-form-urlencoded;charset=utf-8' );
if (strpos ( $return, '{' ) === 0) {
$return = json_decode ( $return, true );
if ($return ['success']) {
// json方式展示支付链接有如下几种
return [
'code'=>200, //200表示成功,201 表示失败
'html_text'=>$return ['data'] ['payUrl'], //返回的是跳转链接则用html_text字段,用于新窗口打开的页面
'msg'=>'success' //成功success,失败fail
];
} else {
return [
'code'=>201, //200表示成功,201 表示失败
'html_text'=>'', //返回的是跳转链接则用html_text字段,用于新窗口打开的页面
'msg'=>$return ['msg'] //成功success,失败fail
];
exit($return ['msg']);
}
} else {
return [
'code'=>201, //200表示成功,201 表示失败
'html_text'=>'', //返回的是跳转链接则用html_text字段,用于新窗口打开的页面
'msg'=>'请求异常' //成功success,失败fail
];
exit( "请求异常");
}
// $html = '<html>
// <head><title>redirect...</title></head>
// <body>
// <form id="post_data" action="' . $api_url . '" method="post">
// <input type="hidden" name="merchantNum" value="' . $merchantNum . '"/>
// <input type="hidden" name="payType" value="' . $payType . '"/>
// <input type="hidden" name="amount" value="' . $amount . '"/>
// <input type="hidden" name="orderNo" value="' . $orderNo . '"/>
// <input type="hidden" name="notifyUrl" value="' . $notifyUrl . '"/>
// <input type="hidden" name="returnUrl" value="' . $returnUrl . '"/>
// <input type="hidden" name="sign" value="' . $sign . '"/>
// <input type="hidden" name="returnType" value="' . $returnType . '"/>
// </form>
// <script>document.getElementById("post_data").submit();</script>
// </body>
// </html>';
// return [
// 'code'=>200, //200表示成功,400 表示失败
// 'type'=> 'html', //固定类型,表示返回的是html页面
// 'html'=>$html,//支付方式返回的是一个新的html自动跳转页面
// 'msg'=>'success' //成功success,失败fail
// ];
}
public function wapPay($params){
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
//$params array(3) { ["total_fee"]=> string(1) "1" ["out_trade_no"]=> string(18) "800000008" ["body"]=> string(39) "充值款,会员ID:11111" }
$config = $this->config;
// php form表单page方式自动跳转
// 开发手册:http://docs.nephalem.cn/read/zhifufm/step
$amount = $params ['total_fee']; // 获取充值金额
$orderNo = $params['out_trade_no']; // 自己创建的本地订单号
$merchantNum = $config['zhifu_merchant']; // 商户号, 商户后台的用户中心页面查看
$secret = $config['zhifu_key']; // 商户密钥, 商户后台的用户中心页面查看
$api_url = $config['zhifu_apiurl']; // 付款请求接口, 商户后台的用户中心页面查看
$payType = $config['zhifu_paytype'];//'alipay';修改为前端传入的支付方式值,这样就可以自己控制了或者随时调整支付方式,查看支付接口文档说明payType的取值
$notifyUrl = $protocol.$_SERVER['HTTP_HOST'].'/ApiNotify/ZhifufmAlipayNotify/notify'; // XXXX修改为您自己用来接收支付成功的公网地址
$returnUrl = $protocol.$_SERVER['HTTP_HOST'].'/user/payment/record.html'; # 支付成功您想让页面跳转的地址
$returnType = "json"; // 接口返回方式 page为直接跳转到支付页面,不传返回json
$sign = md5 ( join ( '', array (
$merchantNum,
$orderNo,
$amount,
$notifyUrl,
$secret
) ));
$native = array (
"merchantNum" => $merchantNum,
"payType" => $payType,
"amount" => $amount,
"orderNo" => $orderNo,
"notifyUrl" => $notifyUrl,
"returnUrl" => $returnUrl,
"sign" => $sign,
"returnType" => $returnType
);
$param = http_build_query ( $native );
$return = $this->http_request ( $api_url, $param, 'application/x-www-form-urlencoded;charset=utf-8' );
if (strpos ( $return, '{' ) === 0) {
$return = json_decode ( $return, true );
if ($return ['success']) {
// json方式展示支付链接有如下几种
return [
'code'=>200, //200表示成功,400 表示失败
'type'=>'redirect',
'url'=> $return ['data'] ['payUrl'], //返回的是即将跳转的RUL地址
'msg'=>'success' //成功success,失败fail
];
} else {
return [
'code'=>201, //200表示成功,201 表示失败
'msg'=>$return ['msg'] //成功success,失败fail
];
exit($return ['msg']);
}
} else {
return [
'code'=>201, //200表示成功,201 表示失败
'msg'=>'请求异常' //成功success,失败fail
];
exit( "请求异常");
}
}
// 发送请求
function http_request($url, $post_data = array(), $header = 'Content-Type: application/json') {
$ch = curl_init ();
curl_setopt ( $ch, CURLOPT_URL, $url );
curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, 1 );
// 返回最后的Location
curl_setopt ( $ch, CURLOPT_FOLLOWLOCATION, 1 );
curl_setopt ( $ch, CURLOPT_POST, 1 );
curl_setopt ( $ch, CURLOPT_POSTFIELDS, $post_data );
curl_setopt ( $ch, CURLOPT_CONNECTTIMEOUT, 60 );
curl_setopt ( $ch, CURLOPT_SSL_VERIFYPEER, FALSE );
curl_setopt ( $ch, CURLOPT_SSL_VERIFYHOST, FALSE );
curl_setopt ( $ch, CURLOPT_HTTPHEADER, array (
$header,
'Content-Length: ' . strlen ( $post_data )
) );
$contents = curl_exec ( $ch );
curl_close ( $ch );
return $contents;
}
}
?>
支付回调
在 app\ApiNotify\Controller\ 下创建回调php文件ZhifufmAlipayNotifyController.class.php 代码如下:
<?php
namespace ApiNotify\Controller;
class ZhifufmAlipayNotifyController extends PaymentNotifyController{
private $payConfig = [];
function _initialize(){
parent::_initialize();
$className = substr(__CLASS__, strrpos(__CLASS__,'\\')+1,-16);
$class = new \ReflectionClass("\Niaoyun\Payment\\$className");
$obj = $class->newInstance();
$this->payConfig = $obj->getConfig();
}
//验证签名
public function checkSign($params){
// $this->write_log("checkSign");
// $this->write_log($params);
$data_arr = array (
$params ['state'],
$this->payConfig['zhifu_merchant'],
$params ['orderNo'],
$params ['amount'],
$this->payConfig['zhifu_key'],
) ;
$sign = md5 ( join ( '', $data_arr ) );
if($sign==$params['sign']){
echo "success";
return true;
}else{
return false;
}
}
//回调状态
public function getPayStatus($params){
//$this->write_log($params);
if($params['state']=='1'){
$this->orderNo = $params['orderNo'];
$this->trade_no = $params['platformOrderNo'];
$this->total_fee = $params['amount'];
// $this->payAccount = $params['mh_oid'];
echo "success";
return true;
}else{
return false;
}
}
/**
* write_log 写入日志,调试或者记录用,上线后可以删除也可以按需保留部分
* Class中调用方式 $this->write_log(...)
* @param [type] $data [写入的数据]
* @return [type] [description]
*/
function write_log($data) {
$years = date ( 'Y-m' );
// 设置路径目录信息
$url = './zhifufm/' . $years . '/' . date ( 'Ymd' ) . '_request_log.log';
$dir_name = dirname ( $url );
// 目录不存在就创建
if (! file_exists ( $dir_name )) {
// iconv防止中文名乱码
$res = mkdir ( iconv ( "UTF-8", "GBK", $dir_name ), 0777, true );
}
$fp = fopen ( $url, "a" ); // 打开文件资源类型 不存在则自动创建
fwrite ( $fp, date ( "[Y-m-d H:i:s] " ) . var_export ( $data, true ) . "\r\n" ); // 写入文件
fclose ( $fp ); // 关闭资源类型
}
}
?>