ci微信支付,微信分账

配置文件application\config\config.php

<?php
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* 微信分账支付配置
*/
$config['wxpay_profitsharing'] = [
    'mch_id'=>'商户号', 
    'appid'=>'商户APPID',
    'AppSecret'=> '密钥',
    'key'=>'key',
    'sandbox'=> false,  //沙盒环境
    'notify_url'=> '回调跳地址',
    "usecert" => [
        "cert"  => "apiclient_cert.pem",
        "key"   => "apiclient_key.pem"
    ]
];

模型application\models\Wxpay_model.php

<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class Wxpay_model extends CI_Model
{
    public $unifiedorderUrl;
    public $profitsharingaddreceiverUrl;
    public $profitsharingremovereceiverUrl;
    public $profitsharingUrl;
    public $conf;
    public function __construct()
    {
        parent::__construct();
        //自动判断是否用沙盒环境
        $this->conf = $this->config->item('wxpay_profitsharing');
        if($this->conf['sandbox'] == true){
            $baseUrl = "https://api.mch.weixin.qq.com/sandboxnew/pay/";
        }else{
            $baseUrl = "https://api.mch.weixin.qq.com/pay/";
        }
        $this->unifiedorderUrl = $baseUrl."unifiedorder"; //统一下单
        $this->profitsharingaddreceiverUrl = $baseUrl."profitsharingaddreceiver"; //添加分账接收方
        $this->profitsharingremovereceiverUrl = $baseUrl."profitsharingremovereceiver"; //添加分账接收方
        $this->profitsharingUrl = "https://api.mch.weixin.qq.com/secapi/pay/profitsharing"; //请求单次分账
    }
    /**
     * 创建支付
     * @param $param
     * @return false|string
     */
    public function createPay($param){
        $param['appid'] = $this->conf['appid'];
        $param['mch_id'] = $this->conf['mch_id'];
        $param['nonce_str'] = $this->noncestr();
        $param['spbill_create_ip'] = $this->input->ip_address();
        $param['notify_url'] = $this->conf['notify_url'];
        $param['trade_type'] = 'JSAPI';
        $param['sign'] = $this->sign($param, $this->getSignKey());//签名;
        $postXml = $this->arrayToXml($param); //转换成xml
        $resp = $this->httpRequest($this->unifiedorderUrl, $postXml);
        $xml = simplexml_load_string($resp);
        if((string)$xml->return_code != "SUCCESS" || (string)$xml->result_code != "SUCCESS"){
            log_message('error',$xml);
            return json_encode(['code'=>-1,'msg'=>(string)$xml->return_msg], JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
        }
        $payParam = array(
            'appId'         => $param['appid'],
            'package'       => "prepay_id=".(string)$xml->prepay_id,
            'nonceStr'      => $param['nonce_str'],
            'timeStamp'     => time(),
            'signType'      => 'MD5',
        );
        $signNew = $this->sign($payParam, $this->getSignKey());//生产js用的签名;
        $payParam['paySign'] = $signNew;
        return json_encode(['code'=>0,'msg'=>'ok','data'=>$payParam],JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
    }
    /**
     * 获取openid和其他参数
     * @param $arr  url参数
     * @return array|void
     */
    public function getOpenidAndState($arr){
        $appid = $this->conf['appid'];
        $secret = $this->conf['AppSecret'];
        $code = $this->input->get('code');
        $state2 = urldecode($this->input->get('state'));
        if(empty($code) && empty($state2)){ //没获取到code
            $redirectUri = urlencode("回调地址");
            $state1 = urlencode(json_encode($arr));
            $url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={$appid}&redirect_uri={$redirectUri}&response_type=code&scope=snsapi_base&state={$state1}#wechat_redirect";
            header("Location: {$url}");
            return;
        }else{ //已经获取code
            $accessToken = redis()->get('h5_access_token');
            redis()->close();
            if(empty($accessToken)) {
                $url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid={$appid}&secret={$secret}&code={$code}&grant_type=authorization_code";
                $resJson = $this->httpGet($url);
                $resArr = json_decode($resJson,true);
                $refresh_token = $resArr['refresh_token'];
                redis()->set('h5_access_token', $resJson, 7199);
                redis()->close();
            }else{
                $accessTokenArr =  json_decode($accessToken,true);
                $refresh_token = $accessTokenArr['refresh_token'];
            }
            $url2 = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid={$appid}&grant_type=refresh_token&refresh_token=$refresh_token";
            $res2 = $this->httpGet($url2);
            $openid = json_decode($res2,true)['openid'];
            return ['openid'=>$openid, 'state'=>json_decode($state2,true)];
        }
    }
    /**
     * 获取验签秘钥
     * @return bool|string
     */
    public function getSignKey(){
        if($this->conf['sandbox'] == true){ //沙盒环境
            $arr = [
                'mch_id'=>$this->conf['mch_id'],
                'nonce_str'=>$this->noncestr()
            ];
            $sign = $this->sign($arr, $this->conf['key']);
            $postXml = "<xml>
               <mch_id>{$arr['mch_id']}</mch_id>
               <nonce_str>{$arr['nonce_str']}</nonce_str>
               <sign>{$sign}</sign>
            </xml>";
            $resp = $this->httpRequest("https://api.mch.weixin.qq.com/sandboxnew/pay/getsignkey", $postXml);
            $xml = simplexml_load_string($resp);
            if((string)$xml->return_code=="SUCCESS"){
                return (string)$xml->sandbox_signkey;
            }else{
                return $resp;
            }
        }else{ //生产环境
            return $this->config->item('wxpay_profitsharing')['key'];
        }
    }
    /**
     * 添加分账接收方
     * @param $param
     * @return false|string
     */
    public function addreceiver($param){
        $param['appid'] = $this->conf['appid'];
        $param['mch_id'] = $this->conf['mch_id'];
        $param['nonce_str'] = $this->noncestr();
        $param['sign_type'] = 'HMAC-SHA256';
        $param['sign'] = $this->signSHA256($param, $this->getSignKey());//签名
        $postXml = $this->arrayToXml($param); //转换成xml
        $resp = $this->httpRequest($this->profitsharingaddreceiverUrl, $postXml);
        $xml = simplexml_load_string($resp);
        if((string)$xml->return_code != "SUCCESS" || (string)$xml->result_code != "SUCCESS"){
            log_message('error',$xml);
            return json_encode(['code'=>-1,'msg'=>(string)$xml->err_code_des], JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
        }
        $receiver = json_decode($param['receiver'], true);
        return json_encode(['code'=>0,'msg'=>'ok', 'data'=>$receiver],JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
    }
    /**
     * 申请单次分账
     * @param $param
     * @return false|string
     */
    public function applyProfitshare($param){
        $param['appid'] = $this->conf['appid'];
        $param['mch_id'] = $this->conf['mch_id'];
        $param['nonce_str'] = $this->noncestr();
        $param['sign_type'] = 'HMAC-SHA256';
        $param['sign'] = $this->signSHA256($param, $this->getSignKey());//签名
        $postXml = $this->arrayToXml($param); //转换成xml
        $resp = $this->httpRequest($this->profitsharingUrl, $postXml, true);
        $xml = simplexml_load_string($resp);
        if((string)$xml->return_code != "SUCCESS" || (string)$xml->result_code != "SUCCESS"){
            log_message('error',$xml);
            return json_encode(['code'=>-1,'msg'=>(string)$xml->err_code_des], JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
        }
        $receivers = json_decode($param['receivers'], true);
        return json_encode(['code'=>0,'msg'=>'ok', 'data'=>$receivers],JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
    }
    /**
     * 随机32位字符串
     * @return string
     */
    public function noncestr(){
        $result = '';
        $str = 'QWERTYUIOPASDFGHJKLZXVBNMqwertyuioplkjhgfdsamnbvcxz';
        for ($i=0;$i<32;$i++){
            $result .= $str[rand(0,48)];
        }
        return $result;
    }
    /**
     * MD5签名方式 $arr要先排好顺序  https://pay.weixin.qq.com/wiki/doc/api/jsapi_sl.php?chapter=4_3
     * 但是凡是调用接口的签名, 在StringA按ASCII码拼接完请求参数之后,都需要在结尾加上key值
     * @param $arr
     * @param $key  签名key
     * @return string
     */
    public function sign($arr, $key=null){
        $stringSign = '';
        ksort($arr);
        foreach ($arr as $k=>$v){
            $stringSign .= $k.'='.$v.'&';
        }
        $stringSign = trim($stringSign,"&");
        if($key){
            $stringSign .= "&key=".$key;
        }
        return strtoupper(md5($stringSign));
    }
    /**
     * HMAC-SHA256签名方式 $arr要先排好顺序  https://pay.weixin.qq.com/wiki/doc/api/jsapi_sl.php?chapter=4_3
     * @param $arr
     * @param null $key
     * @return string
     */
    public function signSHA256($arr, $key=null){
        $stringSign = '';
        ksort($arr);
        foreach ($arr as $k=>$v){
            $stringSign .= $k.'='.$v.'&';
        }
        $stringSign = trim($stringSign,"&");
        if($key){
            $stringSign .= "&key=".$key;
        }
        return  strtoupper(hash_hmac('sha256', $stringSign, $key));
    }
    /**
     * curl post请求
     * @param $url
     * @param array $data
     * @param array $headers
     * @param bool $useCert
     * @return bool|string
     */
    public function httpRequest($url,$data = null,$useCert=false,$headers=array())
    {
        $curl = curl_init();
        if( count($headers) >= 1 ){
            curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
        }
        curl_setopt($curl, CURLOPT_URL, $url);
        if($useCert == true){
            //使用证书:cert 与 key 分别属于两个.pem文件
            curl_setopt($curl,CURLOPT_SSLCERTTYPE,'PEM');
            curl_setopt($curl,CURLOPT_SSLCERT, $this->conf['usecert']['cert']);
            curl_setopt($curl,CURLOPT_SSLKEYTYPE,'PEM');
            curl_setopt($curl,CURLOPT_SSLKEY, $this->conf['usecert']['key']);
        }
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
        if (!empty($data)){
            curl_setopt($curl, CURLOPT_POST, 1);
            curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
        }
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        $output = curl_exec($curl);
        curl_close($curl);
        return $output;
    }
    /**
     * curl get请求
     * @param $url
     * @return bool|string
     */
    public function httpGet($url){
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL,$url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        $result = curl_exec($ch);
        curl_close ($ch);
        return $result;
    }
    /**
     * 将xml转为array
     * param string $xml
     */
    public function xmlToArray($xml)
    {
        if(!$xml){
            log_message('error',"支付xml数据异常!");
        }
        //将XML转为array
        //禁止引用外部xml实体
        libxml_disable_entity_loader(true);
        $values = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
        return $values;
    }
    /**
     * 数组转换xml
     * param array $arr
     */
    public function arrayToXml($arr){
        if(!is_array($arr) || count($arr) <= 0){
            log_message('error',"数组数据异常!");
        }
        $xml = "<xml>";
        foreach ($arr as $key=>$val){
            if (is_numeric($val)){
                $xml.="<".$key.">".$val."</".$key.">";
            }else{
                $xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
            }
        }
        $xml.="</xml>";
        return $xml;
    }
}

控制器application\controllers\Pay.php

<?php
defined('BASEPATH') OR exit('No direct script access allowed');
header("Access-Control-Allow-Credentials","true");
header("Access-Control-Allow-Origin: * ");
class Test extends CI_Controller
{
    public function __construct()
    {
        parent::__construct();
        $this->load->model('Wxpay_model');
    }
    //html显示页
    public function merchantWxpay(){
        //获取参数
        $merchantId = $this->input->get('mid');
        $param = [ 'mid'=>$merchantId ];
        //获取用户openid
        $resArr  = $this->Wxpay_model->getOpenidAndState($param);
        $item = [
            'title'=>'店铺名',
            'desc'=>'店铺描述',
            'openid'=>$resArr['openid'],
            'mid'=>$resArr['state']['mid'] //商户id
        ];
        $this->load->view("wxpay", $item);
    }
    //发起输入密码请求
    public function merchantReceipt(){
        $openid = $this->input->post('openid');
        $mid = $this->input->post('mid');
        $money = $this->input->post('money');
        /**
         * todo   下单前动作
         */
        $param['openid'] = $openid;
        $param['out_trade_no'] = orderSn($mid); //生产订单号
        $param['sub_mch_id'] = '商户号';  //特约商户列表里的商户号
        $param['total_fee'] = $money * 100;
        $param['body'] = 'JSAPI_Test';
        $param['profit_sharing'] = "Y"; //开启分账
        $res = $this->Wxpay_model->createPay($param);
        echo $res;
    }
    //回调地址
    public function notifyProfitsharing(){
        $xml = file_get_contents('php://input');
        log_message('error',$xml);
        $param = $this->Wxpay_model->xmlToArray($xml);
        $sign = $param['sign'];
        unset($param['sign']);
        $signSelf = $this->Wxpay_model->sign($param, $this->Wxpay_model->getSignKey());//生签名
        //校验签名
        if($sign == $signSelf){
            if($param['return_code'] == 'SUCCESS' && $param['result_code'] == 'SUCCESS'){
                $out_trade_no = $param['out_trade_no'];
                $transaction_id = $param['transaction_id']; //微信返回
                /**
                 * todo   处理回调动作
                 */
                //https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=9_7&index=7
                echo "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[{$param['OK']}]]></return_msg></xml>";
            }else{
                logMessage($param);
                echo "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[{$param['err_code_des']}]]></return_msg></xml>";
            }
        }else{
            log_message('error','校验签名失败: '.$sign .'=='. $signSelf);
            echo "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[校验签名失败]]></return_msg></xml>";
        }
    }
    //添加分账接收方
    public function merchantAddreceiver(){
        /**
         * todo   添加前的处理
         */
        $item = [
            'type'=>'MERCHANT_ID',
            'account'=>'商户号',
            'name'=>'商户全称',
            'relation_type'=>'SERVICE_PROVIDER'
        ];
        $receiverJson = json_encode($item,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
        $param['receiver'] = $receiverJson;
        $param['sub_mch_id'] = '1567643641';
        $res = $this->Wxpay_model->addreceiver($param);
        var_dump($res);
    }
    //申请分账
    public function applyProfitsharing(){
        //服务商最多可控制的分账资金是(订单金额-手续费)*该比例。如需修改,请联系特约商户。 (0.6%)
        $items = [
            [
                'type'=>'MERCHANT_ID',
                'account'=>'商户号',
                'amount'=>0.03 * 100,
                'description'=>'分账描述'
            ],
            [
                'type'=>'PERSONAL_WECHATID',
                'account'=>'个人微信号',
                'amount'=>0.01 * 100,
                'description'=>'分账描述'
            ],
        ];
        $receiverJson = json_encode($items,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
        $param['receivers'] = $receiverJson;
        $param['sub_mch_id'] = '1567643641';
        $param['transaction_id'] = '4200000449201912198210883714';
        $param['out_order_no'] = 'ljsy2019121917080610000000148681';
        $res = $this->Wxpay_model->applyProfitshare($param);
        var_dump($res);
    }
}

站帮html页面application\views\wxpay.php

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1, user-scalable=no">
    <title>向商家付款</title>
    <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" href="__ROOT__/statics/bbshop/news/css/basic.css">
    <link rel="stylesheet" href="__ROOT__/statics/bbshop/news/js/font-awesome/css/font-awesome.min.css">
    <style>
        .a{height:65px;line-height:65px;text-align:center;border:1px solid #ccc;background-color:white}
        .up{border-top:none}
        .left{border-left:none}
        .b{height:195px;padding:65px 0;background-color:deepskyblue}
        .b a{height:195px;display:block;font-size:20px;color:white}
        .b a:hover{text-decoration:none}
        .container-fluid{overflow:hidden;position:fixed;bottom:0;height:260px;color:#666;width:100%;font-size:30px;background-color:#ffffff}
        .form-group{margin:15px auto;width:90%}
        .form-group span{padding:5px 10px 0 0;float:right;font-size:15px;color:#999}
        .form-group .input-group input{height:60px;text-align:right;color:#333333;font-size:38px}
        .footer{overflow:hidden;position:fixed;bottom:280px;margin:0 auto;text-align:center;width:100%;color:#999;font-size:14px}
        .pay_logo{margin:0 auto;width:260px;height:100px}
        .pay_logo img{float:left;width:80px;height:80px}
        .pay_logo h1{font-size:26px;font-weight:normal;padding:15px 0 0 95px}
        .pay_logo p{padding:0 0 0 115px}
        .header{margin:15px auto;width:100%}
        body{background-color:#FFFFFF}
        .imgs{z-index:999;position:relative;top:-52px}
        *{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}
    </style>
</head>
<script>
    $(document).ready(function(){
        $("#input-money").focus(function(){
            document.activeElement.blur();
        });
    });
</script>
<body>
<div class="header">
    <div class="pay_logo">
        <img src="__ROOT__/statics/bbshop/images/seller_logo.png" alt="">
        <h1><?php echo $title;?></h1>
        <!--<p>评分:4.9分</p>-->
    </div>
</div>
<form class="form-horizontal" action="" method="post" enctype="multipart/form-data" name="pay">
    <div class="form-group">
        <div class="input-group">
            <div class="input-group-addon" style="font-size: 30px;">¥</div>
            <input type="tel" name="money" value="1.01" id="input-money"  class="form-control" />
            <input type="hidden" name="mid" id="mid" value="<?php echo $mid;?>" />
            <input type="hidden" name="openid" id="openid" value="<?php echo $openid;?>" />
        </div>
        <span class="imgs"><img src="__ROOT__/statics/bbshop/images/cursor.gif" alt=""></span>
        <span><?php echo $desc;?></span>
    </div>
</form>
<!--<div class="footer">由 XXX 提供技术支持</div>-->
<div class="container-fluid">
    <div class="row">
        <div class="col-xs-3 a" ontouchend="pay_money(this,1)">1</div>
        <div class="col-xs-3 a left" ontouchend="pay_money(this,1)">2</div>
        <div class="col-xs-3 a left" ontouchend="pay_money(this,1)">3</div>
        <div class="col-xs-3 a left" ontouchend="pay_money(this,3)"><i class="fa fa-remove"></i></div>
    </div>
    <div class="row">
        <div class="col-xs-9">
            <div class="row">
                <div class="col-xs-4 a up" ontouchend="pay_money(this,1)">4</div>
                <div class="col-xs-4 a up left" ontouchend="pay_money(this,1)">5</div>
                <div class="col-xs-4 a up left" ontouchend="pay_money(this,1)">6</div>
            </div>
            <div class="row">
                <div class="col-xs-4 a up" ontouchend="pay_money(this,1)">7</div>
                <div class="col-xs-4 a up left" ontouchend="pay_money(this,1)">8</div>
                <div class="col-xs-4 a up left" ontouchend="pay_money(this,1)">9</div>
            </div>
            <div class="row">
                <div class="col-xs-8 a up" ontouchend="pay_money(this,1)">0</div>
                <div class="col-xs-4 a up left" ontouchend="pay_money(this,1)">.</div>
            </div>
        </div>
        <div class="col-xs-3 b left" align="center">
            <a href="###" class="text" id="pay">确定
支付</a>
        </div>
    </div>
</div>
<script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script>
    var fm = document.pay;
    function pay_money(obj,tip){
        if(tip==1){
            var con=document.getElementById('input-money').value;
            var num = con + obj.innerHTML;
            if(num == '.'){
                num = '0.';
            }
            if(num>0){
                $(".b").css('background','deepskyblue');
            }
            if(num>=1){
                num = num.replace(/\b(0+)/gi,"");
            }            
            if(num<=99999.99 && num.toString().length<=8){
                if(num.indexOf(".")>0){
                    num = num.replace(/\b(0+)/gi,"0");
                    if(num.toString().split(".")[1].length<=2){
                        document.getElementById('input-money').value = num;
                    }
                }else {
                    document.getElementById('input-money').value = num;
                }
            }
        }else if(tip==2){
            document.getElementById('input-money').value="";
        }else if(tip==3){
            var con = document.getElementById('input-money').value;
            var num = con.slice(0,-1);
            if(num < 0.01){
                $(".b").css('background','lightblue');
            }
            document.getElementById('input-money').value = num;
        }
    }
    $('#pay').on('click',function () {
        var money = fm.money.value;
        var openid = fm.openid.value;
        var mid = fm.mid.value;
        $.post("https://xxxx/pay/merchantreceipt",
            {'mid':mid,'openid':openid,'money':money},
            function(resdata){
                //console.log("resdata",resdata);
                var payInfo = JSON.parse(resdata);
                if(payInfo.code==0){
                    //https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7
                    WeixinJSBridge.invoke(
                        'getBrandWCPayRequest',{
                            "appId" : payInfo.data.appId, //公众号名称,由商户传入
                            "timeStamp": payInfo.data.timeStamp, //戳,自1970 年以来的秒数
                            "nonceStr" : payInfo.data.nonceStr, //随机串
                            "package" : payInfo.data.package,
                            "signType" : payInfo.data.signType, //微信签名方式:
                            "paySign" : payInfo.data.paySign  //微信签名,
                        },function(res){
                            //https://mp.weixin.qq.com/s/JEQnD_NmqNvYnCi5hCKW9g
                            if(res.err_msg == "get_brand_wcpay_request:ok" ) {
                                console.log("充值成功!");
                            }
                        }
                    );
                }
            }
        );
    });
</script>
</body>
</html>

 

发布了6 篇原创文章 · 获赞 0 · 访问量 445
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览