微信小程序调微信支付

今天写小程序的支付接口,参照的当然是微信支付API了。(结尾附上第二步全部代码php版)

另外,我也参照了简书上的这篇文章,浅显易懂:https://www.jianshu.com/p/72f5c1e3f8a5

其实小程序中唤起微信支付不外乎以下几个步骤:

1.获取openid

小程序获取openid是分两个步骤的

首先小程序前端通过wx.login获取code,然后用这个code通过后台接口内部访问微信官方API获取openidsession_key

https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=CODE&grant_type=authorization_code

红字为所需参数,appid和secret手动配置(开发者平台申请),code就是小程序前端获取的code了

2.获取prepay_idpaySign

拿着刚才的openid和订单号(自定义订单号)、订单金额(手动输入金额)以及其他平台参数拼接成一个xml文件作为请求体

通过后台接口内部访问微信API接口:https://api.mch.weixin.qq.com/pay/unifiedorder

如果参数无误,将如期返回prepay_idpaySign

3.前端拉起支付

拿到了所需参数,前端就可以发起:wx.requestPayment 来拉起支付了。

            wx.requestPayment({
                          ‘timeStamp‘:timeStamp,
                          ‘nonceStr‘: nonceStr,
                          ‘package‘: ‘prepay_id=‘+res.data.prepay_id,
                          ‘signType‘: ‘MD5‘,
                          ‘paySign‘: res.data._paySignjs,
                          ‘success‘:function(res){
                              console.log(res);
                          },
                          ‘fail‘:function(res){
                              console.log(‘fail:‘+JSON.stringify(res));
                          }
                   })

如此就完成了小程序的支付,下面就要说一下今天踩的坑了。

1.appid问题

前期前端用的appid是用的他个人的appid,要知道小程序用户授权小程序所生成的openid,是需要用appid来参与验签

的,这直接导致,后期将appid更换为线上appid后,所有的测试用户openid(这个openid在用户授权之后直接存到数据

库了,所以实际上我们省略了第一步,直接从数据库拿当前用户的数据库存储的openid)走如上第二步的时候,都会报

openid和appid不匹配的错误,将前期用户数据删除,并更正appid以及其他参数,重新授权后的openid就不会产生不匹

配的错误了。

第二步获取prepay_idpaySign代码(php版本):

<?php

if (!defined(‘BASEPATH‘)) exit(‘No direct script access allowed‘);

define(APPID, ‘wx74bmn4nbf81f1593e‘);
define(MCHID, ‘1510771171‘);
define(KEY, ‘WlUprCqVM53L4MnI6Dz2Nmz7f44‘);
define(APPSECRET, ‘3b8e3202c39c67712879f6724fc8b42‘);
define(NOTIFY_URL, SITE_URL.‘web/dayrui/controllers/return_url.php‘);

require_once FCPATH . ‘branch/fqb/D_Wxapp.php‘;
require ‘WxPay.class.php‘;  

class Wxapp extends D_Wxapp {
...

  //支付,红字参数依次是openid、订单号、订单说明、订单金额
    public function pay(){
        $pay = $this->req;
        $weixinpay = new WxPay(APPID, $pay[‘openid‘], MCHID, KEY, $pay[‘out_trade_no‘], $pay[‘body‘], $pay[‘total_fee‘]);
        exit_json(1, $weixinpay->pay());
    }

}
WxPay.class.php可以直接用,只是注意get_ip()函数是用来获取客户端ip的,这里稍加封装了一下,会在后面给出封装函数代码
//WxPay.class.php

<?php
class WxPay {

    protected $appid;
    protected $mch_id;
    protected $key;
    protected $openid;
    protected $out_trade_no;
    protected $body;
    protected $total_fee;

    function  __construct ($appid, $openid, $mch_id, $key, $out_trade_no, $body,$total_fee){
        $this->appid = $appid;
        $this->openid = $openid;
        $this->mch_id = $mch_id;
        $this->key = $key;
        $this->out_trade_no = $out_trade_no;
        $this->body = $body;
        $this->total_fee = $total_fee;
    }

    public function  pay (){
        //统一下单接口  

        $return=$this->weixinapp ();
        return $return;
    }

    //微信小程序接口
    private function  weixinapp (){
        //统一下单接口
        $unifiedorder=$this->unifiedorder ();
        $parameters=array (‘appId‘=>$this->appid ,//小程序ID
        ‘timeStamp‘=>‘‘.time().‘‘,//时间戳
        ‘nonceStr‘=>$this->createNoncestr (),//随机串
        ‘package‘=>‘prepay_id=‘.$unifiedorder[‘prepay_id‘],//数据包
        ‘signType‘=>‘MD5‘//签名方式
        );
        $parameters[‘paySign‘]=$this->getSign ($parameters);
        return $parameters;
    }

    //统一下单接口
    private function  unifiedorder (){
        $url=‘https://api.mch.weixin.qq.com/pay/unifiedorder‘;
        $parameters=array (
            ‘appid‘=>$this->appid ,
            ‘mch_id‘=>$this->mch_id ,
            ‘nonce_str‘=>$this->createNoncestr(),
            ‘body‘=>$this->body,
            ‘out_trade_no‘=>$this->out_trade_no ,
            ‘total_fee‘=>$this->total_fee,
            ‘spbill_create_ip‘=>get_ip(),
            ‘notify_url‘=> NOTIFY_URL,
            ‘openid‘=>$this->openid,
            ‘trade_type‘=>‘JSAPI‘
        );
        //统一下单签名
        //pre($parameters);
        $parameters[‘sign‘]=$this->getSign ($parameters);
        $xmlData=$this->arrayToXml ($parameters);
        $return=$this->xmlToArray ($this->postXmlCurl ($xmlData,$url,60));
        return $return;
    }

    private static function  postXmlCurl ($xml,$url,$second=30){
        $ch=curl_init();
        //设置超时
        curl_setopt($ch,CURLOPT_TIMEOUT ,$second);
        curl_setopt($ch,CURLOPT_URL ,$url);
        curl_setopt($ch,CURLOPT_SSL_VERIFYPEER ,FALSE);
        curl_setopt($ch,CURLOPT_SSL_VERIFYHOST ,FALSE);
        //严格校验
        //设置header
        curl_setopt($ch,CURLOPT_HEADER ,FALSE);
        //要求结果为字符串且输出到屏幕上
        curl_setopt($ch,CURLOPT_RETURNTRANSFER ,TRUE);
        //post提交方式
        curl_setopt($ch,CURLOPT_POST ,TRUE);
        curl_setopt($ch,CURLOPT_POSTFIELDS ,$xml);
        curl_setopt($ch,CURLOPT_CONNECTTIMEOUT ,20);
        curl_setopt($ch,CURLOPT_TIMEOUT ,40);
        set_time_limit(0);
        //运行curl
        $data=curl_exec($ch);
        //返回结果
        if ($data){
            curl_close($ch);
            return $data;
        }else {
            $error=curl_errno($ch);
            curl_close($ch);
            throw new WxPayException("curl出错,错误码:$error");
        }
    }
    //数组转换成xml
    private function  arrayToXml ($arr){
        $xml="<root>";
        foreach ($arr as $key=>$val){
            if (is_array($val)){
                $xml.="<".$key.">".arrayToXml ($val)."</".$key.">";
            }else {
                $xml.="<".$key.">".$val."</".$key.">";
            }
        }
        $xml.="</root>";
        return $xml;
    }

    //xml转换成数组
    private function  xmlToArray ($xml){
        //禁止引用外部xml实体
        libxml_disable_entity_loader(true);
        $xmlstring=simplexml_load_string($xml,‘SimpleXMLElement‘,LIBXML_NOCDATA );
        $val=json_decode(json_encode($xmlstring),true);
        return $val;
    }

    //作用:产生随机字符串,不长于32位
    private function  createNoncestr ($length=32){
        $chars="abcdefghijklmnopqrstuvwxyz0123456789";
        $str="";
        for ($i=0;
        $i<$length;
        $i++){
            $str.=substr($chars,mt_rand(0,strlen($chars)-1),1);
        }
        return $str;
    }
    //作用:生成签名
    private function  getSign ($Obj){
        foreach ($Obj as $k=>$v){
            $Parameters[$k]=$v;
        }
        //签名步骤一:按字典序排序参数
        ksort($Parameters);
        $String=$this->formatBizQueryParaMap ($Parameters,false);
        //签名步骤二:在string后加入KEY
        $String=$String."&key=".$this->key ;
        //签名步骤三:MD5加密
        $String=md5($String);
        //签名步骤四:所有字符转为大写
        $result_=strtoupper($String);
        return $result_;
    }
    ///作用:格式化参数,签名过程需要使用
    private function  formatBizQueryParaMap ($paraMap,$urlencode){
        $buff="";
        ksort($paraMap);
        foreach ($paraMap as $k=>$v){
            if ($urlencode){
                $v=urlencode($v);
            }
            $buff.=$k."=".$v."&";
        }
        $reqPar;
        if (strlen($buff)>0){
            $reqPar=substr($buff,0,strlen($buff)-1);
        }
        return $reqPar;
    }
}

get_ip():

function get_ip(){
    //判断服务器是否允许$_SERVER
    if(isset($_SERVER)){
        if(isset($_SERVER[HTTP_X_FORWARDED_FOR])){
            $realip = $_SERVER[HTTP_X_FORWARDED_FOR];
        }elseif(isset($_SERVER[HTTP_CLIENT_IP])) {
            $realip = $_SERVER[HTTP_CLIENT_IP];
        }else{
            $realip = $_SERVER[REMOTE_ADDR];
        }
    }else{
        //不允许就使用getenv获取
        if(getenv("HTTP_X_FORWARDED_FOR")){
              $realip = getenv( "HTTP_X_FORWARDED_FOR");
        }elseif(getenv("HTTP_CLIENT_IP")) {
              $realip = getenv("HTTP_CLIENT_IP");
        }else{
              $realip = getenv("REMOTE_ADDR");
        }
    }
    return $realip;
}      

原文地址:https://www.cnblogs.com/eco-just/p/9399151.html

时间: 2024-08-03 21:03:40

微信小程序调微信支付的相关文章

【转】微信小程序实现微信支付功能(可用)

原博: https://blog.csdn.net/fredrik/article/details/79697963 微信小程序实现微信支付功能 直接把里面的参数替换成你的就可以了,前提是你要开通的有微信支付功能,需要商户号,appid,appsecret,openid, //小程序端代码: pay:function(){ var that=this wx.getStorage({ key: 'openid', success: function(res) { wx.request({ //这里

微信小程序(原名微信应用号)开发工具0.9版安装教程

微信小程序全称微信公众平台·小程序,原名微信公众平台·应用号(简称微信应用号) 声明 微信小程序开发工具类似于一个轻量级的IDE集成开发环境,目前仅开放给了少部分受微信官方邀请的人士(据说仅200个名额)进行内测,因此目前未受到邀请的人士只能使用破解版: 本破解版资源来自于网上,与本人无关,仅供技术开发人员研究之用: 由于尚属内测阶段,因此迭代更新非常快,后续很可能由于升级而导致暂时无法使用.   特别注意 由于目前发布的0.9版本必须验证才能登录(估计是为了验证是否为内测人士),因此必须先下载

微信小程序_微信小程序开发,小程序源码、案例、教程

原文地址:http://whosmall.com/?post=448 本文标签: 微信小程序 小程序源码案例 小程序项目 小程序源码 微信小程序教程 什么是微信小程序? 微信小程序是微信基于微信平台的一个应用发布平台,微信小程序app开发属于原生app组件提供js接口的开发方式,比混合是app的用户体验更好,仅次于原生应用. 不过微信小程序定位于小,要符合轻量易用无需下载,所以从体积上也是有限制,整个小程序应用体积不能超过1M. 微信小程序的应用场景? 微信小程序的应用场景适用于轻量应用,非强交

微信小程序(微信应用号)开发ide安装解决方法

这两天整个技术圈都炸锅了,微信小程序(微信应用号)发布内测,首批200家收到邀请,但是没受邀请的同学,也不用担心,下面介绍一下解决方法. 首先需要下载ide,昨天只需要下载0.9版本的编辑器并替换文件就行了,但是可能微信那边修复了,导致不可用.现在我们要准备两个版本:0.7盒0.9的版本,我测试过了,可以使用,正常的界面如下图: 首先准备好两个安装文件,先安装0.7的版本.安装成功后,打开,微信扫描,确认登陆. 两个文件在QQ微信应用号群(390289365)里有共享. 然后安装0.9的版本,安

微信小程序与微信公众号同一用户登录问题

最近在做微信小程序与微信公众号登录合并的接口.整理相关资料以及个人认识的心得写了这篇文章与大家一起分享. 首先,简单说下我遇到的问题是我们的程序调用微信小程序得到openid,然后通过openID得到用户的唯一标识,用户得以登录,然而,当我们调用微信公众号也同样的到openid,同一以用户两个不同的openid,不能区分是否为同一用户,然后发现无论调用微信小程序还是微信公众号同一个用户的到unionid是相同的,所以我们就用unionid来区分是否为同一用户. UnionID机制说明: 如果开发

微信小程序、微信公众号、H5之间相互跳转

转自慕课网 一.小程序和公众号 答案是:可以相互关联. 在微信公众号里可以添加小程序. 图片有点小,我把文字打出来吧: 可关联已有的小程序或快速创建小程序.已关联的小程序可被使用在自定义菜单和模版消息等场景中. 公众号可关联同主体的10个小程序及不同主体的3个小程序.同一个小程序可关联最多50个公众号. 1.公众号跳小程序 比如说 "丰巢快递柜" 公众号关联的小程序:丰巢寄快递. 2.小程序跳公众号 打开"丰巢寄快递",点击右上角的菜单选项,然后点击"关于

[转]微信小程序、微信公众号、H5之间相互跳转

本文转自:https://www.cnblogs.com/colorful-paopao1/p/8608609.html 转自慕课网 一.小程序和公众号 答案是:可以相互关联. 在微信公众号里可以添加小程序. 图片有点小,我把文字打出来吧: 可关联已有的小程序或快速创建小程序.已关联的小程序可被使用在自定义菜单和模版消息等场景中. 公众号可关联同主体的10个小程序及不同主体的3个小程序.同一个小程序可关联最多50个公众号. 1.公众号跳小程序 比如说 “丰巢快递柜” 公众号关联的小程序:丰巢寄快

微信小程序之微信登陆 —— 微信小程序教程系列(20)

简介: 微信登陆,在新建一个微信小程序Hello World项目的时候,就可以看到项目中出现了我们的微信头像,其实这个Hello World项目,就有一个简化版的微信登陆.只不过是,还没有写入到咱们自家的后台中而已. 新建一个Hello World项目,找到app.js文件打开,代码如下: app.js: App({ onLaunch: function () { //调用API从本地缓存中获取数据 var logs = wx.getStorageSync('logs') || [] logs.

使用Appium 测试微信小程序和微信公众号方法

由于腾讯系QQ.微信等都是基于腾讯自研X5内核,不是google原生webview,需要打开TBS内核Inspector调试功能才能用Chrome浏览器查看页面元素,并实现Appium自动化测试微信小程序和微信公众号. 前提条件Appium环境搭建,这里不多说了,可查阅Appium环境搭建文章. 因夜神等模拟器是intel的X86架构,很多app安装不了,比如微信.qq等(虽然说可以通过安装arm解释器来解决该问题,但是进行X5内核调试的话也会出现问题),建议最好是一台真实的手机来做. webv