评论

【新手必看】微信支付V2之傻瓜式1秒接入

傻瓜式介入微信支付,这你还不会的话,来找我,看我怎么揍你🤪

微信支付之前也对接过几次,因为时隔久远,每次对接都要挠头一番,可怜了发际线了,我的宝你在哪里,你再不来我头发掉光了😭


这次决定记录下来,以后对接方便新人也方便自己,说真,其实我是看上官方的拉杆箱了🥰


欲练神功,必先挠头,快快乐乐吃西瓜,清清凉凉一夏天👻


如果你是第一次对接支付:

1.你得申请一个服务号,并通过微信认证

2.获取参数看图:往下看 ⬇️

3.注册微信商户平台并配置API密钥


第一式:随便起个文件名,最好要有特色


//命名为:wwxpay-mini.php  扔到你的微信支付授权目录,就这一个文件已经实现了jsapi支付,无需下载其他sdk


第二式:调试工具

微信公众平台支付接口调试工具:https://pay.weixin.qq.com/wiki/tools/signverify/ (调试错误的时候可以用得上,新手暂时略过)


第三式:上代码

操作方法:将此文件备注位置-【商户参数】/【订单信息】两处的参数,改为你自己的即可,其中订单参数可以为动态获取,如果你只有一个商品那就写死吧


<?php
/*下单参数:
公众账号ID	字段: appid
商户号	    字段: mch_id
随机字符串	字段: nonce_str
签名	   字段: sign
签名类型	字段: sign_type  "MD5"
商品描述	字段: body
商户订单号	字段: out_trade_no
标价金额	字段: total_fee
终端IP	   字段: spbill_create_ip
通知地址	字段: notify_url
交易类型	字段: trade_type	"JSAPI"


转化为以下格式:


<xml>
   <appid>wx2421b1c4370ec43b</appid>
   <attach>支付测试</attach>
   <body>JSAPI支付测试</body>
   <mch_id>10000100</mch_id>
   <detail><![CDATA[{ "goods_detail":[ { "goods_id":"iphone6s_16G", "wxpay_goods_id":"1001", "goods_name":"iPhone6s 16G", "quantity":1, "price":528800, "goods_category":"123456", "body":"苹果手机" }, { "goods_id":"iphone6s_32G", "wxpay_goods_id":"1002", "goods_name":"iPhone6s 32G", "quantity":1, "price":608800, "goods_category":"123789", "body":"苹果手机" } ] }]]></detail>
   <nonce_str>1add1a30ac87aa2db72f57a2375d8fec</nonce_str>
   <notify_url>https://wxpay.wxutil.com/pub_v2/pay/notify.v2.php</notify_url>
   <openid>oUpF8uMuAJO_M2pxb1Q9zNjWeS6o</openid>
   <out_trade_no>1415659990</out_trade_no>
   <spbill_create_ip>14.23.150.211</spbill_create_ip>
   <total_fee>1</total_fee>
   <trade_type>JSAPI</trade_type>
   <sign>0CB01533B8C1EF103065174F50BCA001</sign>
</xml>


返回值:
返回状态码	字段: return_code	返回值:  SUCCESS/FAIL
返回信息	字段: return_msg	返回值: OK


成功的话,在return_code为SUCCESS的时候有返回:
公众账号ID	字段: appid
商户号	字段: mch_id
签名	字段: sign
业务结果	字段: result_code
错误代码	字段: err_code  返回值: SUCCESS/FAIL(错误的时候返回)


错误码解析:


INVALID_REQUEST	参数错误	参数格式有误或者未按规则上传	订单重入时,要求参数值与原请求一致,请确认参数问题
NOAUTH	商户无此接口权限	商户未开通此接口权限	请商户前往申请此接口权限
NOTENOUGH	余额不足	用户账号余额不足	用户账号余额不足,请用户充值或更换支付卡后再支付
ORDERPAID	商户订单已支付	商户订单已支付,无需重复操作	商户订单已支付,无需更多操作
ORDERCLOSED	订单已关闭	当前订单已关闭,无法支付	当前订单已关闭,请重新下单
SYSTEMERROR	系统错误	系统超时	系统异常,请用相同参数重新调用
APPID_NOT_EXIST	APPID不存在	参数中缺少APPID	请检查APPID是否正确
MCHID_NOT_EXIST	MCHID不存在	参数中缺少MCHID	请检查MCHID是否正确
APPID_MCHID_NOT_MATCH	appid和mch_id不匹配	appid和mch_id不匹配	请确认appid和mch_id是否匹配
LACK_PARAMS	缺少参数	缺少必要的请求参数	请检查参数是否齐全
OUT_TRADE_NO_USED	商户订单号重复	同一笔交易不能多次提交	请核实商户订单号是否重复提交
SIGNERROR	签名错误	参数签名结果不正确	请检查签名参数和方法是否都符合签名算法要求
XML_FORMAT_ERROR	XML格式错误	XML格式错误	请检查XML参数格式是否正确
REQUIRE_POST_METHOD	请使用post方法	未使用post传递参数 	请检查请求参数是否通过post方法提交
POST_DATA_EMPTY	post数据为空	post数据不能为空	请检查post数据是否为空
NOT_UTF8	编码格式错误	未使用指定编码格式	请使用UTF-8编码格式


接口地址:https://api.mch.weixin.qq.com/pay/unifiedorder
*/
header('Content-type:text/html; Charset=utf-8');//设置网页编码
ini_set('date.timezone', 'Asia/Shanghai');

//商户参数
$appKey = 'xxxxxxxxxxxxxxxxxx';//公众号的APPKey
$config = array(
    'mch_id' => 'xxxxxxxxxx',//微信支付平台商户号
    'appid' => 'xxxxxxxxxxxxxxx',//公众号平台的APPID
    'key' => 'xxxxxxxxxxxxxxxxxxxxxxx' //https://pay.weixin.qq.com 帐户设置-安全设置-API安全-API密钥V2-设置API密钥
);
//订单信息
$unified = array(
    'appid' => $config['appid'],//公众账号ID
    'attach' => '饭团',//附加数据
    'body' => "饭团子",//商品描述
    'mch_id' => $config['mch_id'],//商户号
    'nonce_str' => NoStr(),//随机字符串
    'notify_url' => "http://pay.xxxxxx.com/wxpay/api/returns.php",//通知地址
        'openid' => GetOpenid($config),
    'out_trade_no' => strval(date("YmdH").time()),//商户订单号
    'spbill_create_ip' => $_SERVER['REMOTE_ADDR'],//终端IP
    'total_fee' => intval(0.01*100), //微信会自己减去两位数*100补回,标价金额
    'trade_type' => 'JSAPI',//交易类型
);
$unified['sign'] = getSign($unified, $config['key']);//获取签名
// echo "<pre>";print_r($unified);echo "</pre>";die;
// die(arrayToXml($unified));
$responseXml = curlPost('https://api.mch.weixin.qq.com/pay/unifiedorder', arrayToXml($unified));//转换为xml并发送
$unifiedOrder = simplexml_load_string($responseXml, 'SimpleXMLElement', LIBXML_NOCDATA);//解析XML为对象
if ($unifiedOrder === false) {
    die('parse xml error');//解析错误
}
if ($unifiedOrder->return_code != 'SUCCESS') {
    die($unifiedOrder->return_msg);//返回成功结果
}
if ($unifiedOrder->result_code != 'SUCCESS') {
    die($unifiedOrder->err_code->des);//返回失败结果
}


$arr = array(
    "appId" => $config['appid'],//公众账号ID
    "timeStamp" => strval(time()),//这里是字符串的时间戳
    "nonceStr" => NoStr(),//随机字符串
    "package" => "prepay_id=" . $unifiedOrder->prepay_id,//订单详情扩展字符串
    "signType" => 'MD5',//声明加密类型
);
$arr['paySign'] = getSign($arr, $config['key']);//获取调起支付的签名
$jsApiParameters=json_encode($arr);


?>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1"/>
    <title>FT-收银台</title>
    <script type="text/javascript">
/*
JSAPI调起支付


公众号id	appId
时间戳	timeStamp
随机字符串	nonceStr	String(32)	5K8264ILTKCH16CQ2502SI8ZNMTM67VS	随机字符串,32位。推荐随机数生成算法
订单详情扩展字符串	package	String(128)	prepay_id=123456789	统一下单接口返回的prepay_id参数值,提交格式如:prepay_id=***
签名方式	signType	MD5	签名类型,默认为MD5,支持HMAC-SHA256和MD5。注意此处需与统一下单的签名类型一致
签名	paySign	是	String(64)	C380BEC2BFD727A4B6845133519F3AD6	签名,详见签名生成算法:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_3
*/ 
        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">0.01元</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>


<?php
//所有的函数都在这里了


function GetOpenid(array $config){
    //通过code获得openid
    if (!isset($_GET['code'])){
        //触发微信返回code码
        $scheme = $_SERVER['HTTPS']=='on' ? 'https://' : 'http://';
        $baseUrl = urlencode($scheme.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'].$_SERVER['QUERY_STRING']);
        $url = __CreateOauthUrlForCode($baseUrl,$config);
        Header("Location: $url");
        exit();
    } else {
        //获取code码,以获取openid
        $code = $_GET['code'];
        $openid = GetOpenidFromMp($code,$config);
        return $openid;
    }
}
function GetOpenidFromMp($code,array $config){
    $url = __CreateOauthUrlForOpenid($code,$config);
    $res = curlGet($url);
    //取出openid
    $data = json_decode($res,true);
    // $this->data = $data;
    $openid = $data['openid'];
    return $openid;
}
function __CreateOauthUrlForOpenid($code,array $config){
    $urlObj["appid"] = $config['appid'];
    $urlObj["secret"] = $GLOBALS['appKey'];
    $urlObj["code"] = $code;
    $urlObj["grant_type"] = "authorization_code";
    $bizString = toparams2($urlObj);
    return "https://api.weixin.qq.com/sns/oauth2/access_token?".$bizString;
}


/**
 * 构造获取code的url连接
 * @param string $redirectUrl 微信服务器回跳的url,需要url编码
 * @return 返回构造好的url
 */
function __CreateOauthUrlForCode($redirectUrl,array $config){
    $urlObj["appid"] = $config['appid'];
    $urlObj["redirect_uri"] = "$redirectUrl";
    $urlObj["response_type"] = "code";
    $urlObj["scope"] = "snsapi_base";
    $urlObj["state"] = "STATE"."#wechat_redirect";
    $bizString = toparams2($urlObj);
    return "https://open.weixin.qq.com/connect/oauth2/authorize?".$bizString;
}
function getSign($params, $key){
    //生成签名
    ksort($params, SORT_STRING);//把值作为字符串来排序
    $unSignParaString = toparams1($params, false);
    $signStr = strtoupper(md5($unSignParaString . "&key=" . $key));//拼接字符并转换为大写
    return $signStr;
}
function arrayToXml($arr)
    {
        $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;
    }
function toparams1($paraMap, $urlEncode = false){
    //签名数组排序并拼接
    $buff = "";
    ksort($paraMap);//对数组进行排序:ABCDEFG……
    foreach ($paraMap as $k => $v) {
        if (null != $v && "null" != $v) {
            if ($urlEncode) {
                $v = urlencode($v);
            }
            $buff .= $k . "=" . $v . "&";
        }
    }
    $reqPar = false;
    if (strlen($buff) > 0) {
        $reqPar = substr($buff, 0, strlen($buff) - 1);//移除多余的&
    }
    return $reqPar;
}


function toparams2($urlObj){
    //把数组转成URL参数:appid=123456&sign=xxxxxxxxxxxxxxxxx
    $buff = "";
    foreach ($urlObj as $k => $v)
    {
        if($k != "sign") $buff .= $k . "=" . $v . "&";
    }
    $buff = trim($buff, "&");//移除多余的&
    return $buff;
}


function curlGet($url = '', $options = array()){
    //get访问
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_TIMEOUT, 30);
    if (!empty($options)) {
        curl_setopt_array($ch, $options);
    }
    //https请求 不验证证书和host
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    $data = curl_exec($ch);
    curl_close($ch);
    return $data;
}
function curlPost($url = '', $postData = '', $options = array()){
    //post访问
    if (is_array($postData)) {
        $postData = http_build_query($postData);//把数组转成URL参数:appid=123456&sign=xxxxxxxxxxxxxxxxx
    }
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
    curl_setopt($ch, CURLOPT_TIMEOUT, 30); //设置cURL超时为30秒
    if (!empty($options)) {
        curl_setopt_array($ch, $options);
    }
    //https请求 不验证证书和host
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    $data = curl_exec($ch);
    curl_close($ch);
    return $data;
}
function NoStr($length = 16){
    //随机字符串默认16位
    $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
    $str = '';
    for ($i = 0; $i < $length; $i++) {
        $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
    }
    return $str;
}


?>


我喜欢面向过程emm,别笑话我🤣


别问为啥这么多备注,因为怕你笨🤣


总结:

1. 申请服务号,注册微信商户平台,获取:Appid Key Api密钥 商户号

2. 创建wxpay-mini.php【名称随意,但是一定放到授权目录】

3.【商户参数】/【订单信息】两处的参数,改为你自己的参数

4.运行支付测试结果


这你还不会的话,来找我,看我怎么揍你🤪


我还没对象,拉杆箱可以不要,官方给我介绍个对象呗,别说给我New一个😭


还没有用过微信云托管的朋友可以看我另一篇教程:https://developers.weixin.qq.com/community/minihome/article/doc/000068648fcae81db5fd0f17e58413

暂时就写这么多,再熬天就要亮了😇

最后一次编辑于  2022-05-27  
点赞 3
收藏
评论

3 个评论

  • 广东真热啊
    广东真热啊
    2022-05-27

    忘了说运行环境了,我的是:Nginx+PHP8.1 如果你们的环境有问题请尝试升级PHP,或留言

    2022-05-27
    赞同
    回复
  • 广东真热啊
    广东真热啊
    2022-05-27

    采用了的小朋友,反手给我一个赞

    2022-05-27
    赞同
    回复
  • 广东真热啊
    广东真热啊
    2022-05-27

    向官方反馈一个小问题,修改编辑文章的时候编辑器会自己修改文章内容,应该是哪个过滤机制在捣鬼

    2022-05-27
    赞同
    回复
登录 后发表内容