微信-h5支付 时间:2018/12/16

背景:商户系统需要一个集成微信支付

这里放一个 PHP的demo,这个是在一个视频上面学到的,放在这里以后可能会用到。

Base类——实际项目继承至这里

<?php


class Base
{
    //key只能从商户后台获取
    const KEY = '0D0352B99D829E9427446A9360D27108'; //密钥
    const CODEURL = 'https://open.weixin.qq.com/connect/oauth2/authorize?';//获取openid
    const OPENIDURL = 'https://api.weixin.qq.com/sns/oauth2/access_token?';//获取openid
    const APPID = 'wx252bfdb5af9f6a78';
    const SECRET = 'be76a8345a964ef3bbcde5fe221da455';
    const MCHID = '1517459461';//商户号
    const UNURL = 'https://api.mch.weixin.qq.com/pay/unifiedorder';//微信支付请求的地址

    //生成签名
    public function getSign($arr){
        //去除空值
        $arr = array_filter($arr);
        //剔除sign
        if(isset($arr['sign'])){
            unset($arr['sign']);
        }
        //按照键名顺序排序
        ksort($arr);
        //生成url格式的字符串
       $str = $this->arrToUrl($arr) . 'key=' . self::KEY;
       return strtoupper(md5($str));
    }
    //获取带签名的数组
    public function setSign($arr){
        $arr['sign'] = $this->getSign($arr);;
        return $arr;
    }
    public function arrToUrl($arr){
        $stringA = '';
        foreach($arr as $k => $v) {
                $stringA .= $k . '=' . $v . '&';
        }
        return $stringA;
    }
    //验证签名
    public function chekSign($arr){
        $sign = $this->getSign($arr);
        if($sign == $arr['sign']){
            return true;
        }else{
            return false;
        }
    }
    //获取用户id
    public function getOpenId(){
        if(isset($_SESSION['openid'])){
            return $_SESSION['openid'];
        }else{
            //1.用户访问一个地址 先获取到code
           
            if(!isset($_GET['code'])){
                //print_r($_SERVER);
                $redurl = $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
                // $url = self::CODEURL . "appid=" .self::APPID ."&redirect_uri={$redurl}&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect";
				$url = self::CODEURL . "appid=" .self::APPID ."&redirect_uri=http://yueche.linfenshiyaoshenjiaxiao.cn/paytest/index.php&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect";
                //构建跳转地址 跳转
                header("location:{$url}");
            }else{
                //2.根据code获取到openid
                //调用接口获取openid
                $openidurl = self::OPENIDURL . "appid=" . self::APPID . "&secret=".self::SECRET . "&code=" . $_GET['code'] . "&grant_type=authorization_code";
                $data = file_get_contents($openidurl);
                $arr = json_decode($data,true);
                $_SESSION['openid'] = $arr['openid'];                
                return $_SESSION['openid'];
            }
        }
    }
    //调用”统一下单“api接口,传递订单号
    public function unifiedOrder($oid){
        
         // 1.构建原始数据
         // 2.加入签名
         // 3.将数据转换为XML
         // 4.发送XML格式的数据到接口地址
         
        $params = [
            'appid'=> self::APPID,
            'mch_id'=> self::MCHID,
            //随机数组为当前加密时间戳
            'nonce_str'=>md5(time()),
            //驾校服务支付测试
            'body'=>'4444',
            //内部订单号
            'out_trade_no'=>$oid,
            //总价
            'total_fee'=> 2,
            //客户端ip
            'spbill_create_ip'=>$_SERVER['REMOTE_ADDR'],
            //支付通知地址
            'notify_url'=> 'https://609laolu.sc2yun.com/paytest/notify.php',
            //支付类型为公众号支付,选择jsapi
            'trade_type'=>'JSAPI',
            //产品id
            'product_id'=>$oid,
            //获取到的openid
            'openid'=> $this->getOpenId()
        ];
       //加入签名
       $params = $this->setSign($params);
       //转xml格式数据
       $xmldata = $this->ArrToXml($params);
       //存储数据到log下
       $this->logs('log.txt', $xmldata);
       $resdata = $this->postXml(self::UNURL, $xmldata);
       $arr = $this->XmlToArr($resdata);
       return $arr;
    }
    //获取预支付id,传递订单号
    public function getPrepayId($oid){
        $arr = $this->unifiedOrder($oid);
        return $arr['prepay_id'];
    }
    //获取公众号支付所需要的js格式的数据
    public function getJsParams($prepay_id){
        $params = [
            'appId' => self::APPID,
            'timeStamp' => (string)time(),
            'nonceStr' => md5(time()),
            'package' =>'prepay_id=' . $prepay_id,     
            'signType' =>'MD5',
            //'paySign' => $this->getSign($params)。 数组还未定义完成,放到外面写
        ];
        $params['paySign'] = $this->getSign($params);
        echo "<pre>";
        var_dump($params);
        return json_encode($params);
    }


    //数组转xml
    public function ArrToXml($arr)
    {
            if(!is_array($arr) || count($arr) == 0) return '';

            $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; 
    }


    //xml转数组
    public function XmlToArr($xml)
    {	
        if($xml == '') return '';
        libxml_disable_entity_loader(true);
        $arr = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);		
        return $arr;
    }
    

    //存储文件的方法(blogs)
    public function logs($filename,$data){
        file_put_contents('./logs/' . $filename, $data);
    }


    //上传信息的方法(blogs)
    public function postXml($url,$postfields){
       
        $ch = curl_init();
        $params[CURLOPT_URL] = $url;    //请求url地址
        $params[CURLOPT_HEADER] = false; //是否返回响应头信息
        $params[CURLOPT_RETURNTRANSFER] = true; //是否将结果返回
        $params[CURLOPT_FOLLOWLOCATION] = true; //是否重定向
        $params[CURLOPT_POST] = true;
        $params[CURLOPT_POSTFIELDS] = $postfields;
        //禁用证书验证
        $params[CURLOPT_SSL_VERIFYPEER] = false;
	$params[CURLOPT_SSL_VERIFYHOST] = false;
        curl_setopt_array($ch, $params); //传入curl参数
        $content = curl_exec($ch); //执行
        curl_close($ch); //关闭连接
        return $content;
    }
    //获取post过来的数据
    public function getPost(){
        return file_get_contents('php://input');
    }
}

测试类——项目从这里开始

<?php 
	session_start();
	include './Base.php';

	class WeiXinPay extends Base
	{
	    public function __construct() {
	    }   
	}
	$obj = new WeiXinPay();
	$prepay_id = $obj->getPrepayId(time().rand(11,99));
	//echo $prepay_id;
	$json = $obj->getJsParams($prepay_id);
?>
<script>
function onBridgeReady(){
   WeixinJSBridge.invoke(
       'getBrandWCPayRequest', <?php echo $json;?>,
       function(res){     
           if(res.err_msg == "get_brand_wcpay_request:ok" ) {}     // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回    ok,但并不保证它绝对可靠。 
       }
   ); 
}
if (typeof WeixinJSBridge == "undefined"){
   if( document.addEventListener){
       document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
   }else if (document.attachEvent){
       document.attachEvent('WeixinJSBridgeReady', onBridgeReady); 
       document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
   }
}else{
   onBridgeReady();
}
</script>

还有一个支付成功后微信请求我们服务器的一个页面

<?php
include './Base.php';


    //1.获取通知数据 ->转换为数组
    //2.验证签名 (使用以前的方法)
    //3.验证业务结果 (return_code 和 result_code)
    //4.验证订单号和金额 (out_trade_no total_fee)
    //5.记录日志 修改订单状态 给用户发货
 

class Notify extends Base
{
    public function __construct() {
        $xmlData = $this->getPost();
        $arr = $this->XmlToArr($xmlData);
        if($this->chekSign($arr)){
            if($arr['return_code'] == 'SUCCESS' && $arr['result_code'] == 'SUCCESS'){
                //生产环境需要根据订单号来查询价格
                if($arr['total_fee'] == 2){
                    $this->logs('stat.txt', '交易成功!'); //更改订单状态
                    $returnParams = [
                        'return_code' => 'SUCCESS',
                        'return_msg'  => 'OK'
                    ];
                    echo $this->ArrToXml($returnParams);
                }else{
                    $this->logs('stat.txt', '金额有误!');
                }
            }else{
                $this->logs('stat.txt', '业务结果不正确!');
            }
        }else{
            $this->logs('stat.txt', '签名失败!');
        }
    }
}
$obj = new Notify();

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值