PHP 第三方支付

来源:互联网 发布:域名举报 编辑:程序博客网 时间:2024/05/21 22:25

支付的逻辑需要三步:

(1)去合作的第三方拿到  商家号和秘钥 。

(2)自己项目中集成第三方的SDK,完成支付。

(3)第三方的异步通知,自己接收通知,修改订单状态。

 

知道RSA加密的可以忽略:

秘钥:RSA加密,需要生成,公钥publicKey 和私钥originKey

规则: 私钥加密,公钥解密。 知道双方的公钥和私钥,就互相验证了。

代码逻辑 【加密方式自己查看SDK,我们用的是RSA加密,所以就以它为例子】:

 (1)页面写好提交的方法,然后准备提交。

复制代码
 //js获取页面数据,然后submit  建议:最好表单去提交function sub(){        var pay_money = $("#pay_money").val();        var bank_code = $("input[name='bank']:checked").val();        $.ajax({            url:'/recharge/pay_data',            type:'post',            data:{'pay_money':pay_money,'bank_code':bank_code},            dataType:'json',            async: false,            success:function(e){                document.getElementById('order_no_number').value= e.order_no;                if(e.sign !='' && e.sign_type !=''){                    //js动态创建表单,然后提交                    var form = $("<form method='post' id='myform'></form>");                    form.attr({"action":"跳转地址"});                    form.attr({"target":"_blank"});                    for (arg in e)                    {                        var input = $("<input type='hidden'>");                        input.attr({"name":arg});                        input.val(e[arg]);                        form.append(input);                    }                    $("#form_hidden").append(form);                    $("#myform").submit();                }            }        })}
复制代码

(2)服务端,得按照SDK所需参数,配置好各种必须的参数,提供页面数据提交的参数。

复制代码
 public function pay_data(){        //银行代码和充值金额        $bank_code = $_POST['bank_code'];        $pay_money = $_POST['pay_money'];        //充值数据        $uid = $this->session->userdata('uid');        if(!empty($uid) && !empty($bank_code) && !empty($pay_money)){            $hkd = $pay_money; //港币(测试完成,放开)            $hk_rate = $this->comm_func->getHkRate();//汇率,港币兑人民币            $order_amount = $pay_money * $hk_rate; //人民币 = 港币 * 汇率            $data['merchant_code'] = $this->config->item('merchant_code'); //配置中获取-商户号            $data['service_type'] = 'direct_pay';            $data['interface_version'] = 'V3.0';            $data['input_charset'] = 'UTF-8';            $data['notify_url'] = $this->config->item('web_notify_url');  //配置中获取-异步通知地址            $data['return_url'] = $this->config->item('web_return_url');  //配置中获取-支付完成后的跳转地址            $data['client_ip'] = $_SERVER["REMOTE_ADDR"];            $data['order_no']   = self::get_orderno($uid);            $data['order_time'] = date('Y-m-d H:i:s');            $data['order_amount']  = sprintf('%01.2f',$order_amount);            $data['product_name']  = '港币充值testpay';            $data['bank_code'] = $bank_code;            $sign_type ="RSA-S";            $sign_str = $this->doSign($data,$this->config->item('origPriKey'));//配置中获取-RSA加密的私钥            $pay_type = 1;            //插入订单记录            $sql = "INSERT INTO tb_pay (`uid`,`order_no`,`order_time`,`order_amount`,`hkd`,`rate`,`pay_type`,`bank_code`) VALUES('{$uid}','{$data['order_no']}','{$data['order_time']}','{$data['order_amount']}','{$hkd}','{$hk_rate}','{$pay_type}','{$data['bank_code']}')";            try {                $this->db->query($sql);                if ($this->db->affected_rows() <=0) {                    self::write_log('sql未起效:'.$sql,'web_pay_err');                }            } catch (Exception $e) {                self::write_log('sql报错:'.$e,'web_pay_err');            }            //支付请求日志            self::write_log('返回数据:uid='.$uid.' data='.json_encode($data)."sign_str=".$sign_str,'web_get_paydata');            $data['sign'] = $sign_str;            $data['sign_type'] = $sign_type;            echo json_encode($data);        }    }
复制代码

(3)服务端,处理异步通知--这个是重点,做好各种处理措施。

复制代码
/*     * 服务器通知notify_url     */    public function notify_url(){        $notifyStr = json_encode($_POST);        self::write_log($notifyStr,'web_notify_pay');//记录日志        $signArr = $_POST;        unset($signArr['sign'],$signArr['sign_type']);        $dinpaySign = base64_decode($_POST["sign"]);        $sign = $this->CheckSign($signArr,$dinpaySign,$this->config->item('PublicPriKey'));   //获取验证的公钥        if(isset($_POST['order_no']) && isset($_POST['sign']) && $sign)        {            $DB_LOCK = $this->load->database('lock_tb', TRUE);            $order_no = isset($_POST['order_no'])?$_POST['order_no']:'';            $trade_no = isset($_POST['trade_no'])?$_POST['trade_no']:'';            $trade_time = isset($_POST['trade_time'])?$_POST['trade_time']:'';            $trade_status = isset($_POST['trade_status'])?$_POST['trade_status']:'';            //$bank_code = isset($_POST['bank_code'])?$_POST['bank_code']:'';            $bank_seq_no = isset($_POST['bank_seq_no'])?$_POST['bank_seq_no']:'';            $trade_amount = isset($_POST['order_amount'])?$_POST['order_amount']:'';                        //-----开启事物处理            $DB_LOCK->trans_start();              //mysql行级锁,处理完成,释放锁            $query  = $DB_LOCK->query("SELECT * FROM `tb_pay` WHERE order_no = '{$_POST['order_no']}' FOR UPDATE");            $row = $query->row_array();            if (isset($row) && !empty($row))            {                //有且还未返回状态 更新                if (isset($row['trade_status']) && $row['trade_status']==0)                {                    $trade_status_field = ($trade_status == 'SUCCESS')?1:2;                    $upSql = "UPDATE tb_pay SET `trade_time` = '{$trade_time}',`trade_no` = '{$trade_no}',`trade_amount` = '{$trade_amount}',`trade_status`='{$trade_status_field}',`bank_seq_no`='{$bank_seq_no}',`back_time`='".date('Y-m-d H:i:s')."' WHERE `order_no` = '{$order_no}'";                                        try {                        $DB_LOCK->query($upSql);                                                if ($DB_LOCK->affected_rows() <=0) {                            self::write_log('sql未起效:'.$upSql,'web_pay_err');                        }else{                            $this->update_money($row['uid'],$row['hkd']);                        }                    } catch (Exception $e) {                        self::write_log('sql报错:'.$e,'web_pay_err');                    }                }                //已有返回状态                if (isset($row['trade_status']) && $row['trade_status']!=0)                {                    $trade_status_field = ($trade_status == 'SUCCESS')?1:2;                    if ($trade_status_field == $row['trade_status'] && $trade_amount == $row['trade_amount'])                    {                        //重复发送                        self::write_log('重复异步通知:'.$notifyStr,'web_pay_err');                    }else {                        //两次数据不一致                        self::write_log('重要bug:与已有数据冲突:'.$notifyStr,'web_pay_err');                    }                }            }else {                //无此记录                self::write_log('订单库中无此记录:'.$notifyStr,'web_pay_err');            }            $DB_LOCK->trans_complete();            //----事物结束,处理失败,回滚业务                       echo 'SUCCESS';  //没有问题,打印success,处理成功        }else {            //验签失败            self::write_log('验签失败:'.$notifyStr.'sign:'.$sign,'web_pay_err');        }    }
复制代码

代码所用的一些方法:

复制代码
     /*生成订单号     * @uid     */    public static function get_orderno($id)    {        $rand = date('ymd').substr(time(),-5).substr(microtime(),2,7);        $fix = substr(md5($id),0,7);        return $rand.$fix;    }    /**     * sign     * */    public function doSign($inA,$origPriKey)    {        if(empty($inA))            return false;        $signStr = $this->doSort($inA);        $priKey = openssl_get_privatekey($origPriKey);        openssl_sign($signStr,$sign_info,$priKey,OPENSSL_ALGO_MD5);        $sign = base64_encode($sign_info);        return $sign;    }    /*     * sort     */    private function doSort($param)    {        $signStr = '';        ksort($param);        foreach($param as $k => $v){            $signStr .= $k."=".$v."&";        }        $signStr = rtrim($signStr,'&');        self::write_log("web_send_signStr::".$signStr,'web_send_pay_signStr');        return $signStr;    }    /*     * 验证notify中的签名     */    public function CheckSign($inA,$dinpaySign,$pubKey){        if(empty($inA))            return false;        $param = $inA;        $signStr = '';        ksort($param);        foreach($param as $k => $v){            $signStr .= $k."=".$v."&";        }        $signStr = rtrim($signStr,'&');              $priKey = openssl_get_publickey($pubKey);        $sign = openssl_verify($signStr,$dinpaySign,$priKey,OPENSSL_ALGO_MD5);        if($sign){            return true;        }else{            return false;        }    }

原创粉丝点击