微信支付--PHP 封装

微信支付开发文档

类的使用方法

笔者阅读微信支付SDK里面的example之后,把下单,查询订单,退款,查询退款等常用操作封装在一个类里面。

使用方法如下 :

  • 引入类文件
  • 创建一个实例
  • 填充参数
  • 调用相关的方法
<?php
require_once './WeixinPay/WeixinPay.php';
$weixin = new WeixinPay();
$order_params = [
    'body' => '这是一个测试商品',
    'total_fee' => 1,
    'openid' => 'jfahfadhfuadhgahga-test',
    'notify_url' => 'http://test.com/check',
    'trade_type' => 'JSAPI',
    'out_trade_no' => 'test-'.date('YmdHis')
];
$weixin->setOrderParams($order_params);
$jsApiParameters = $weixin->getJsApiParameters();

微信授权登录

  • 由于微信公众号支付需要用到用户的openid,所以有必要了解一下微信的授权登录

  • 在网页的"微信网页授权"标签下 微信公众平台开发文档

获取用户信息的大致步骤如下 :

  1. 引导用户打开指定的页面
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect

注 : redirect_uri 为跳转链接(需要url_encode处理),可以在这个页面上获取到code参数
当scope= snsapi_base 时,通过获取到的code可以获得微信用户的基本信息。
当scope= snsapi_userinfo 时 ,通过获取到的code可以获得微信用户的基本信息。

  1. 在跳转页面中,通过code参数($_GET['code'])换取access_token

  2. 通过access_token 获取到用户的详细信息

获取微信用户的基本信息

  • 生成供跳转的链接

<?php
require_once './WeixinPay/WeixinPay.php';
$weixin  =  new WeixinPay();

$weixin->setRedirectUrl('http://test.com/user.php');

$url = $weixin->createOauthUrlForCodeOfSnsapiBase();

  • 拿到code参数后,通过接口获取到用户的基本信息

user.php


<?php
require_once './WeixinPay/WeixinPay.php';

$code =  $_GET['code'];

$weixin  = new WeixinPay();

$weixin->setCode($code);

$userData = $weixin->getUserBase();
  • 获取到的微信用户的基本信息
{
    "access_token": "ksL8nXGggLZY8tOKFFlOUWOa0PICM5-test",
    "expires_in": 7200,
    "refresh_token": "KmpJL_FJK74Q3uxGm444Y_hyEbTKlcP9ZI1cQ6ieOgeux8sMRDW1RKvRhdvxL6doT8YergsCUAZMcVOwzb3wmLx--test",
    "openid": "ydtfysayfgdasytest",
    "scope": "snsapi_base",
    "unionid": "oCqmrfsdfgghhh1hd8u1ST5AYtest"
}

获取微信用户的详细信息

  • 生成链接
require_once './WeixinPay/WeixinPay.php';
$weixin = new WeixinPay();
$weixin->setRedirectUrl('http://test.com/userinfo.php');
$url = $weixin->createOauthUrlForCodeOfSnsapiUserInfo();
  • 用户同意之后,拿到code,通过code获取到用户的详细信息

userinfo.php

<?php
require_once './WeixinPay/WeixinPay.php';
$code =  $_GET['code'];
$weixin  = new WeixinPay();
$weixin->setCode($code);
$userData = $weixin->getUserInfo();
  • 用户的详细信息
{
    "openid": "ydtfysayfgdasytest",
    "nickname": "test",
    "sex": 1,
    "language": "zh_CN",
    "city": "武汉",
    "province": "湖北",
    "country": "中国",
    "headimgurl": "http://wx.qlogo.cn/mmopen/ZR4W6lp2JvoCdw3CKqtFPdiczb9Utpjial621bnD3KI7V5WlJniaLxwLKfHqPvuLBvysaHLRgu5BjQhZ5Hibr4cq79DVOcCIRSQh/0",
    "privilege": [],
    "unionid": "oCqmrfsdfgghhh1hd8u1ST5AYtest"
}

获取用户的openid

<?php
require_once './WeixinPay/WeixinPay.php';
$code =  $_GET['code'];
$weixin  = new WeixinPay();
$weixin->setCode($code);
$openid = $weixin->getUserOpenid();

微信扫码支付

步骤 :

  • 填充支付信息参数

  • 获取可用于扫码支付的链接

  • 将获取到的链接转换成二维码

<?php
require_once './phpqrcode/phpqrcode.php';
require_once './WeixinPay/WeixinPay.php';
$weixin = new WeixinPay();
$order_params = [
    'body' => '扫码支付',
    'total_fee' => 1,
    'notify_url' => 'http://test.com/check',
    'out_trade_no' => 'test-' . date('YmdHis'),
    'product_id' => 10086
];

$weixin->setOrderParams($order_params);
$result = $weixin->qrCode();
header('Content-Type:image/png');
QRcode::png(
    $result['code_url'],
    false,
    QR_ECLEVEL_L,
    8,
    4
);

微信公众号支付

步骤 :

  • 获取微信用户的openid
  • 填充支付参数
  • 获取支付所需的字符串参数
<?php
require_once './WeixinPay/WeixinPay.php';
$weixin = new WeixinPay();
$order_params = [
    'body' => '这是一个测试商品',
    'total_fee' => 1,
    'openid' => 'jfahfadhfuadhgahga-test',
    'notify_url' => 'http://test.com/check',
    'trade_type' => 'JSAPI',
    'out_trade_no' => 'test-'.date('YmdHis')
];
$weixin->setOrderParams($order_params);
$jsApiParameters = $weixin->getJsApiParameters();
  • 支付页面的html代码
<html>
<head>
    <meta http-equiv="content-type" content="text/html;charset=utf-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1"/>
    <title>微信支付样例-支付</title>
    <script type="text/javascript">
        callpay();
        function jsApiCall()
        {
            WeixinJSBridge.invoke(
                'getBrandWCPayRequest',
                <?php echo $jsApiParameters; ?>,
                function(res){
                    WeixinJSBridge.log(res.err_msg);
                    alert(res.err_code+res.err_desc+res.err_msg);
                }
            );
        }

        function callpay()
        {
            if (typeof WeixinJSBridge == "undefined"){
                if( document.addEventListener ){
                    document.addEventListener('WeixinJSBridgeReady', jsApiCall, false);
                }else if (document.attachEvent){
                    document.attachEvent('WeixinJSBridgeReady', jsApiCall);
                    document.attachEvent('onWeixinJSBridgeReady', jsApiCall);
                }
            }else{
                jsApiCall();
            }
        }
    </script>

</head>
<body>
<br/>
<font color="#9ACD32"><b>该笔订单支付金额为<span style="color:#f00;font-size:50px">1分</span>钱</b></font><br/><br/>
<div align="center">
    <button style="width:210px; height:50px; border-radius: 15px;background-color:#FE6714; border:0px #FE6714 solid; cursor: pointer;  color:white;  font-size:16px;" type="button" onclick="callpay()" >立即支付</button>
</div>
</body>
</html>

app支付

<?php
require_once './WeixinPay/WeixinPay.php';
$weixin = new WeixinPay();
$order_params = [
    'body' => '这是一个测试商品',
    'total_fee' => 1,
    'notify_url' => 'http://test.com/check',
    'trade_type' => 'APP',
    'out_trade_no' => 'test-' . date('YmdHis')
];
$weixin->setOrderParams($order_params);
$data = $weixin->getAppParameters();

查询订单

步骤 :

  • 填充参数
  • 调用查询订单方法
<?php
require_once './WeixinPay/WeixinPay.php';
$weixin = new WeixinPay();
$params = [
    'out_trade_no' => 'test'
];
$weixin->setOrderParams($params);
$result = $weixin->orderQuery();

关闭订单

  • 填充参数
<?php
require_once './WeixinPay/WeixinPay.php';
$weixin = new WeixinPay();
$params = [
    'out_trade_no' => 'test'
];
$weixin->setOrderParams($params);
$result = $weixin->closeOrder();

退款

<?php
require_once './WeixinPay/WeixinPay.php';
$weixin = new WeixinPay();
$params = [
    'out_trade_no' => 'test'
];
$weixin->setOrderParams($params);
$result = $weixin->refund();

退款查询

<?php
require_once './WeixinPay/WeixinPay.php';
$weixin = new WeixinPay();
$params = [
    'out_trade_no' => 'test'
];
$weixin->setOrderParams($params);
$result = $weixin->refundQuery();

验证回调结果

  • 代码
<?php
require_once './WeixinPay/WeixinPay.php';
$weixin = new WeixinPay();
$result = $weixin->checkSign();
if ($result['status'] === 'SUCCESS') {
    $data = $result['data'];
    echo $result['response'];
} else {
    echo $result['response'];
}

$data 中包含有订单号,金额等订单信息

  • 验签结果正确的时候
<xml>
  <return_code><![CDATA[SUCCESS]]></return_code>
  <return_msg><![CDATA[OK]]></return_msg>
</xml>
  • 验签结果错误的时候返回
<xml>
  <return_code><![CDATA[FAIL]]></return_code>
  <return_msg><![CDATA[OK]]></return_msg>
</xml>
  • 在lib/WxPay.Api.php 后面增加的代码(用于验证支付回调结果)
有时使用 $GLOBALS['HTTP_RAW_POST_DATA'] 获取不到回调数据, 可以尝试使用 file_get_contents('php://input')获取
    public function checkSing()
    {
        $xml = $GLOBALS['HTTP_RAW_POST_DATA'];
        $weixin = new WxPayDataBase();
        $result = $weixin->FromXml($xml);
        $sign = $result['sign'];
        $correctResponse = ['return_code' => 'SUCCESS', 'return_msg' => 'OK'];
        $errorResponse = ['return_code' => 'FAIL', 'return_msg' => 'OK'];
    
        if ($sign === $weixin->MakeSign()) {
        
            return ['status' => 'SUCCESS', 'response' => $this->arrayToXml($correctResponse),'data' => $result];
        } else {
            return ['status' => 'FAIL', 'response' => $this->arrayToXml($errorResponse)];
        }
    }


    /**
     * 数组转换成xml
     * @param $data
     * @return string
     */
    public function arrayToXml($data)
    {
        $xml = "<xml>";
        foreach ($data as $key => $val) {
            if (is_numeric($val)) {
                $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
            } else {
                $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
            }
        }
        $xml .= "</xml>";
        return $xml;
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容