近来期间比较忙, 忙完之后发现最近有挺多的东西没有整理,于是乎。就将以前用到的一些小东西整理了一下。

如果您需要前后端分离的JASPI或者APP支付 请查看:TP5 -- 微信支付整合(APP,JSAPI)

如果对您有帮助,则是我最大的幸运。

本篇主要是说了一下整合TP5的微信公众号支付。

不过由于最近TP6已经出了,小伙伴们要记得向最新的进发哦。

好了,废话不多说了。开始。

首先呢,需要引入我们封装好的类库:

同样在 extend/ 下

因为会将支付类库放在一起,于是就在extend 文件夹下创建了一个pay文件夹用来存储所有类文件。

以下内容为wxpay类的内容:

namespace pay;

class Wxpay
{
private $config =[
"appid" => "********", // 公众号ID
"mch_id" => "********", // 商户号
"notify_url" => "********", // 回调地址
"key" => "********", // 微信支付 商户秘钥KEY
];
public function index($param,$openid)
{
$order=array(
'body' => $param['body'],// 商品描述
'total_fee' => intval($param['total']*100),// 订单金额 以(分)为单位
// 'total_fee' => 1,
'out_trade_no' => $param['order_sn'],// 订单号
'trade_type' => 'JSAPI',// JSAPI公众号支付
'openid' => $openid// 获取到的openid
);
$userip = $param['userip'];
// 统一下单 获取prepay_id
$unified_order=$this->unifiedOrder($order,$userip);
// 获取当前时间戳
$time=time();
// 组合jssdk需要用到的数据
$data=array(
'appId' =>$this->config['appid'], //appid
'timeStamp' =>strval($time), //时间戳
'nonceStr' =>$unified_order['nonce_str'],// 随机字符串
'package' =>'prepay_id='.$unified_order['prepay_id'],// 预支付交易会话标识
'signType' =>'MD5' //加密方式
);
// 生成签名
$data['paySign']=$this->makeSign($data);
return $data;
}
/**
* 统一下单
* @param array $order 订单 必须包含支付所需要的参数 body(产品描述)、total_fee(订单金额)、out_trade_no(订单号)、product_id(产品id)、trade_type(类型:JSAPI,NATIVE,APP)
*/
public function unifiedOrder($order,$userip)
{
$config=array(
'appid' => $this->config['appid'], //appid
'mch_id' => $this->config['mch_id'], //商户号ID
'nonce_str' => $this->getNonceStr(),
'spbill_create_ip' => $userip, //你的IP
'notify_url' => $this->config['notify_url'],
//'notify_url' =>$url
);
// 合并配置数据和订单数据
$data=array_merge($order,$config);
// 生成签名
$sign=$this->makeSign($data);
$data['sign']=$sign;
//转换成xml
$xml=$this->toXml($data);
$url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';//接收xml数据的文件
$header[] = "Content-type: text/xml";//定义content-type为xml,注意是数组
$ch = curl_init ($url);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 兼容本地没有指定curl.cainfo路径的错误
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
$response = curl_exec($ch);
if(curl_errno($ch)){
// 显示报错信息;终止继续执行
die(curl_error($ch));
}
curl_close($ch);
//转换成数组
$result=$this->toArray($response);
//dump($result);
// 显示错误信息
if ($result['return_code']=='FAIL') {
die($result['return_msg']);
}
$result['sign']=$sign;
$result['nonce_str']=$this->getNonceStr();
return $result;
}
/**
* 生成签名
* @return 签名,本函数不覆盖sign成员变量,如要设置签名需要调用SetSign方法赋值
*/
public function makeSign($data)
{
// 去空
$data=array_filter($data);
//签名步骤一:按字典序排序参数
ksort($data);
//将数组转成url形式
$string_a=http_build_query($data);
$string_a=urldecode($string_a);
//签名步骤二:在string后加入KEY
$string_sign_temp=$string_a."&key=".$this->config['key'];
//签名步骤三:MD5加密
$sign = md5($string_sign_temp);
// 签名步骤四:所有字符转为大写
$result=strtoupper($sign);
return $result;
} /**
* 将xml转为array
* @param string $xml xml字符串
* @return array 转换得到的数组
*/
public function toArray($xml){
//禁止引用外部xml实体
libxml_disable_entity_loader(true);
$result= json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
return $result;
} /**
*
* 产生随机字符串,不长于32位
* @param int $length
* @return 产生的随机字符串
*/
public function getNonceStr($length = 32)
{
$chars = "abcdefghijklmnopqrstuvwxyz0123456789";
$str ="";
for ( $i = 0; $i < $length; $i++ ) {
$str .= substr($chars, mt_rand(0, strlen($chars)-1), 1);
}
return $str;
} /**
* 输出xml字符
* @throws WxPayException
*/
public function toXml($data){
if(!is_array($data) || count($data) <= 0){
throw new WxPayException("数组数据异常!");
}
$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;
} /**
* 验证
* @return array 返回数组格式的notify数据
*/
public function notify(){
// 获取xml
$xml=file_get_contents('php://input', 'r');
// 转成php数组
$data=$this->toArray($xml);
// 保存原sign
$data_sign=$data['sign'];
// sign不参与签名
unset($data['sign']);
$sign=$this->makeSign($data);
// 判断签名是否正确 判断支付状态
if ($sign===$data_sign && $data['return_code']=='SUCCESS' && $data['result_code']=='SUCCESS') {
$result=$data;
}else{
$result=false;
}
// 返回状态给微信服务器
if ($result) {
$str='<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
}else{
$str='<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[签名失败]]></return_msg></xml>';
}
// file_put_contents("./Public/aaa.text",$result);
// echo $str;
return $result;
} public function https_request($url, $data = null)
{
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
if (!empty($data)){
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
}
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($curl);
// var_dump($output);
curl_close($curl);
return $output;
} }

然后就是调用方法了:

namespace app\index\controller;

use pay\Wxpay;

class Index extends Base
{
/**
*调用支付接口
*
*/
public function getorder()
{ $param = input('get.');
$pays = model('pay')->where('id',$id)->find();
$wxpay = [
'order_sn' => $pays['pay_sn'], //支付订单号
'total' => $pays['money'], //支付总额
'body' => $pays['body'], //支付说明
'userip' => $pays['userip'], //用户IP
]; $openid = $this->_user['openid']; $pay = new Wxpay();
$data = $pay->index($wxpay,$openid); $logUrl = "********"; //支付完成跳转地址 $this->assign([
'data'=>json_encode($data),
'logUrl'=>$logUrl,
]);
return $this->fetch();
} }

其次是对应的调用空白页面:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>订单提交成功</title> <style>
.info{
text-align: center;
margin-top: 40px;
}
</style>
</head> <body>
<div class="info">支付进行中,请稍候...</div>
<script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
<script type="text/javascript">
//调用微信JS api 支付
function onBridgeReady(){
var data = {$data};
WeixinJSBridge.invoke(
'getBrandWCPayRequest', data,
function(res){
if(res.err_msg == "get_brand_wcpay_request:ok" ) {
// 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回 ok,但并不保证它绝对可靠。
window.location.href="{$logUrl}";
}else{
alert('支付失败');
// alert(res.err_code+res.err_desc+res.err_msg); // 显示错误信息
}
}
);
} 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> </body>
</html>

最后就是回调了(拿到回调在此控制器汇中进行数据库操作):

namespace app\index\controller;

use Think\Controller;
/**
* 支付回调 -- 接收并处理调整数据库
*/
class ClassName extends AnotherClass
{
private $config =[
"key" => "*******", //微信支付 商户秘钥KEY
]; /**
* notify_url接收页面
*/
public function wxpaynotify()
{
$result=$this->notify();
if ($result)
{//以下为处理数据库操作等 操作完成后输出success
echo "SUCCESS";
}
}
/**
* 一下验证类 活获取 token 等可写入至 common 公告类中
* 验证
* @return array 返回数组格式的notify数据
*/
public function notify(){
// 获取xml
$xml=file_get_contents('php://input', 'r');
// 转成php数组
$data=$this->toArray($xml);
// 保存原sign
$data_sign=$data['sign'];
// sign不参与签名
unset($data['sign']);
$sign=$this->makeSign($data);
// 判断签名是否正确 判断支付状态
if ($sign===$data_sign && $data['return_code']=='SUCCESS' && $data['result_code']=='SUCCESS') {
$result=$data;
}else{
$result=false;
}
// 返回状态给微信服务器
if ($result) {
$str='<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
}else{
$str='<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[签名失败]]></return_msg></xml>';
}
// file_put_contents("./Public/aaa.text",$result);
// echo $str;
return $result;
}
/**
* 将xml转为array
* @param string $xml xml字符串
* @return array 转换得到的数组
*/
public function toArray($xml){
//禁止引用外部xml实体
libxml_disable_entity_loader(true);
$result= json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
return $result;
}
/**
* 生成签名
* @return 签名,本函数不覆盖sign成员变量,如要设置签名需要调用SetSign方法赋值
*/
public function makeSign($data)
{
// 去空
$data=array_filter($data);
//签名步骤一:按字典序排序参数
ksort($data);
//将数组转成url形式
$string_a=http_build_query($data);
$string_a=urldecode($string_a);
//签名步骤二:在string后加入KEY
$string_sign_temp=$string_a."&key=".$this->config['key'];
//签名步骤三:MD5加密
$sign = md5($string_sign_temp);
// 签名步骤四:所有字符转为大写
$result=strtoupper($sign);
return $result;
} }

以上就是微信公众号支付的全部内容。

如有疑问,请评论或留言。

感谢您的查看。

2019年05月31日

tp5 -- 微信公众号支付的更多相关文章

  1. 微信公众号支付之坑:调用支付jsapi缺少参数 timeStamp等错误解决方法

    这段时间一直比较忙,一忙起来真感觉自己就只是一台挣钱的机器了(说的好像能挣到多少钱似的,呵呵):这会儿难得有点儿空闲时间,想把前段时间开发微信公众号支付遇到问题及解决方法跟大家分享下,这些“暗坑”能不 ...

  2. 使用开源库MAGICODES.WECHAT.SDK进行微信公众号支付开发

    概要 博客使用Word发博,发布后,排版会出现很多问题,敬请谅解.可加群获取原始文档. 本篇主要讲解微信支付的开发流程,相关业务基于MAGICODES.WECHAT.SDK实现.通过本篇教程,您可以很 ...

  3. ASP.NET MVC 微信公众号支付,微信公众平台配置

    微信公众号支付,首先要登录微信公众号进行配置: 第一步:配置网页授权域名

  4. 微信公众号支付流程(Node实现)

    前言 花费了一天时间,调通了微信公众号支付.作下记录,方便以后再次填坑.先声明,微信公众号支付,不同于微信H5支付,这点在本文结束时再详细说明. 微信配置 设置测试目录 在微信公众平台设置,栏目见下图 ...

  5. 微信公众号支付开发全过程 --JAVA

    按照惯例,开头总得写点感想 ------------------------------------------------------------------ 业务流程 这个微信官网说的还是很详细的 ...

  6. 到处是坑的微信公众号支付开发(java)

    之前公司项目开发中支付是用阿里的支付做的,那叫一个简单,随意:悲催的是,现在公司开发了微信公众号,所以我步入了全是坑的微信支付开发中... ------------------------------ ...

  7. 微信公众号支付|微信H5支付|微信扫码支付|小程序支付|APP微信支付解决方案总结

    最近负责的一些项目开发,都用到了微信支付(微信公众号支付.微信H5支付.微信扫码支付.APP微信支付).在开发的过程中,在调试支付的过程中,或多或少都遇到了一些问题,今天总结下,分享,留存. 先说注意 ...

  8. 微信公众号支付JSAPI网页,total_fee错误不正确,header重定向参数丢失,无法获取订单号和金额解决

    微信公众号支付官方demo错误, 公众号支付只能用在微信里,也就是微信内部浏览器. 1.到WxPayHubHelper.php文件 JsApi_pub()类下createOauthUrlForCode ...

  9. 微信公众号支付提示mch_id参数格式错误

    背景: .Net MVC微信公众号支付功能 问题: 今天在做网站微信支付的时候,一直提示“微信公众号支付提示mch_id参数格式错误” ! 解决方法: 其实这个问题一般并不是说你配置有错,首先它提示你 ...

随机推荐

  1. CString和CStringA之间的转换

    使用UNICODE字符集编程时,总是需要使用那些不支持UNICODE的库,例如sqlite3,Lua等必须使用char*类型的.这个时候用CStringA是最好的. 另外CStringA与CStrin ...

  2. Lightoj1014【基础题】

    题意: 有C个人,安排了P个吃的,每个人会吃Q个吃的,最后留下L个吃的:求所有可能的Q,从小到大输出,要保证Q>L; 思路: 其实就是求出P-L的所有数的约数,然后这个约数>L的话就满足: ...

  3. laravel 安装配置前准备

    Laravel 框架使用 Composer 来管理其依赖性.所以,在你使用 Laravel 之前,你必须在你电脑上是否安装了 Composer.最简单的获取Composer的方式就是百度之,百度关键字 ...

  4. P4443 [COCI2017-2018#3] Dojave(线段树)

    传送门 设\(lim=2^n-1\),对于一个区间\([l,r]\)来说,如果\(sum\neq lim\)且能换出\(x\)并换进\(y\)来,使得\(sum\bigoplus a_x\bigopl ...

  5. hyperledger fabric 1.0.5 分布式部署 (三)

    本篇博客主要是向读者介绍 fabric 在部署时的一些细节,还有作者自己学习过程中的心得. 初始化相关密钥的程序,实际上是一个shell脚本,并且结构特别简单 generateArtifacts.sh ...

  6. Faster_Rcnn在windows下运行踩坑总结

    Faster_Rcnn在windows下运行踩坑总结  20190524 今天又是元气满满的一天! 1.代码下载 2.编译 3.下载数据集 4.下载pre-train Model 5.运行train ...

  7. android webview.goback 问题

    重写 shouldOverrideUrlLoading 不需要实现 view.loadUrl(url);直接return false;即可 如果实现了,则使用window.location.repla ...

  8. redis集群模式

    1 弊端和优势 弊端:相比单机模式,集群模式会在节点之间同步数据,会降低20%-30%的性能,同时增加架构复杂性,提高硬件成本和学习成本. 优势:增加冗余,避免单点故障.单机模式如果要重启,必然会丢失 ...

  9. morphia(2)-添加

    1.简单 @Test public void add() throws Exception { final Employee em = new Employee("遥远2",500 ...

  10. 使用express+mongoDB搭建多人博客 学习(5)权限控制

    修改index.js如下: var express = require('express'); var router = express.Router(); var crypto=require('c ...