经验分享为热心网友提供,用于有能力的用户学习使用,不保证源码存在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文件,这个文件增加后,后台刷新应该就有配置入口了。代码内容如下:
<?phpnamespace 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 );// 返回最后的Locationcurl_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 代码如下:
<?phpnamespace 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 ); // 关闭资源类型}}?>
