封装微信小程序支付
<?php
/**
* User: Eden
* Date: 2019/3/21
* 共有内容
*/
namespace Common\Service;
use Think\Exception;
use Vendor\Func\Http;
class WxPayService extends CommonService {
public static function unifiedOrder($openid,$order_num,$total_fee,$products_name,$notify_url = ''){
$trade_no = $order_num;
$url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
$data = [
'appid' => C('APPID'),
'mch_id' => C('MCHID'),
'nonce_str' => self::createNonceStr(),
'sign_type' => 'MD5',
'body' => $products_name, //商品名称组合
'attach' => C('APP_NAME').'-附加信息',
'out_trade_no' => $trade_no, //订单号
'fee_type' => 'CNY',
'total_fee' => $total_fee,
'spbill_create_ip' => $_SERVER['REMOTE_ADDR'],
'goods_tag' => C('APP_NAME').'-商品标记',
'notify_url' => $notify_url ?:C('NOTIFY_URL'),
'trade_type' => 'JSAPI',
'openid' => $openid
];
$sign = self::MakeSign($data);
$data['sign'] = $sign;
$xml = self::ToXml($data);
$result = self::FromXml(Http::postXmlCurl($url,$xml));
// 加工数据
$data = [
'appId' => $result['appid'] ?: C('APPID'),
'timeStamp' => time(),
'nonceStr' => self::createNonceStr(),
'package' => 'prepay_id=' . $result['prepay_id'],
'signType' => 'MD5'
];
$sign = self::MakeSign($data);
$data['sign'] = $sign;
return $data;
}
public static function FromXml($xml)
{
if(!$xml){
throw new Exception("xml数据异常!");
}
//将XML转为array
//禁止引用外部xml实体
libxml_disable_entity_loader(true);
$values = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
return $values;
}
public static function ToXml($array){
if(!is_array($array)|| count($array) <= 0){
return ;
}
$xml = '<xml version="1.0">';
foreach ($array as $key=>$val){
if (is_numeric($val)){
$xml.="<".$key.">".$val."</".$key.">";
}else{
$xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
}
}
$xml.="</xml>";
return $xml;
}
public static function createNonceStr($length = 16) {
$chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
$str = '';
for ( $i = 0; $i < $length; $i++ ) {
$str .= substr($chars, mt_rand(0, strlen($chars)-1), 1);
}
return $str;
}
public static function MakeSign($data)
{
//签名步骤一:按字典序排序参数
ksort($data);
$string = self::ToUrlParams($data);
//签名步骤二:在string后加入KEY
$string = $string . "&key=".C('WEIXIN_PAY_KEY');
//签名步骤三:MD5加密
$string = md5($string);
//签名步骤四:所有字符转为大写
$result = strtoupper($string);
return $result;
}
public static function ToUrlParams($array)
{
$buff = "";
foreach ($array as $k => $v)
{
if($k != "sign" && $v != "" && !is_array($v)){
$buff .= $k . "=" . $v . "&";
}
}
$buff = trim($buff, "&");
return $buff;
}
}
/***
* 发起捐赠
*/
public function pay()
{
if (!$openid = trim($_POST['openid'])) {
$this->json->setErr(10001, '缺少参数');
$this->json->Send();
}
if (!$donate_id = $_POST['donate_id']) {
$this->json->setErr(10001, '缺少参数donate_id');
$this->json->Send();
}
$amount = (float)$_POST['amount']; // 实际支付金额
if ($amount <= 0) {
$this->json->setErr(10002, '支付金额不可为0或负数');
$this->json->Send();
}
$donate = M('donate');
$donate_info = $donate->where(array('id' => $donate_id, 'status' => 1, 'is_show' => 1))->find();
if (!$donate_info) {
$this->json->setErr(10002, '捐赠内容不存在');
$this->json->Send();
}
// 判断当前是否可以捐赠
$now = time();
if ($now < (int)$donate_info['start_time']) {
$this->json->setErr(10003, '捐赠未开始');
$this->json->Send();
}
if ($now > (int)$donate_info['end_time']) {
$this->json->setErr(10004, '捐赠已结束');
$this->json->Send();
}
$money = $donate_info['money']; // 已有捐赠金额
$user = M('user');
$user_info = $user->where(array('openid' => $openid))->find();
if (!$user_info) {
$this->json->setErr(10001, '用户信息不存在');
$this->json->Send();
}
$uid = $user_info['id'];
// step1 生成订单
$order_info = $this->makeOrder($uid, $donate_id, $amount, $money);
$order_num = $order_info['order_num'];
$products_name = $order_info['products_name'];
// step2 unifiedOrder
$unifiedorder = WxPayService::unifiedOrder($openid, $order_num, $amount * 100, $products_name);
// step3 将数据package下放到小程序中
$this->json->setAttr('data', $unifiedorder);
$this->json->Send();
}
/***
* 生成捐赠订单
* @param $uid
* @param $donate_id
* @param $amount
* @param $money
* @return mixed
*/
private function makeOrder($uid, $donate_id, $amount, $money)
{
$donate_order = M('donate_order');
$now = time();
$order_num = 'do' . $uid . substr($now, 3) . rand(1000, 9999);
$order_add_data = [
'donate_id' => $donate_id,
'order_num' => $order_num,
'amount' => $amount, //订单价格
'money' => $money + $amount,
'uid' => $uid,
'status' => 1, //未到账
'create_time' => $now, //订单生成时间
];
$order_add_flag = $donate_order->add($order_add_data);
if (!$order_add_flag) {
$this->json->setErr(10003, '生成订单失败');
$this->json->Send();
}
$return_data['order_num'] = $order_num;
$return_data['products_name'] = '捐赠';
return $return_data;
}
//微信支付回调
public function order_notice()
{
$xml = $GLOBALS['HTTP_RAW_POST_DATA'];
$data = WxPayService::FromXml($xml);
// 保存微信服务器返回的签名sign
$data_sign = $data['sign'];
// sign不参与签名算法
unset($data['sign']);
$sign = WxPayService::MakeSign($data);
Clog::setLog($data, 'order_notice 回调数据');
// 判断签名是否正确 判断支付状态
if (($sign === $data_sign) && ($data['return_code'] == 'SUCCESS') && ($data['result_code'] == 'SUCCESS')) {
//获取服务器返回的数据
$order_num = $data['out_trade_no']; //订单单号
$openid = $data['openid']; //付款人openID
$total_fee = $data['total_fee']; //付款金额
$transaction_id = $data['transaction_id']; //微信支付流水号
$user = M('user');
$user_info = $user->where(array('openid' => $openid))->find();
$total_payed_price = $total_fee / 100;
$save_data = array(
'total_payed_price' => $total_payed_price, //实际到帐金额
'transaction_id' => $transaction_id,
'pay_time' => time(),
'status' => 2,
);
// 开启事务
M()->startTrans();
$error_count = 0;
// step 1 修改充值订单数据
$donate_order = M('donate_order');
$donate_order_info = $donate_order->where(array('order_num' => $order_num, 'uid' => $user_info['id']))->find();
$donate_amount = $donate_order_info['amount'];
$save_flag = $donate_order->where(array('order_num' => $order_num, 'uid' => $user_info['id']))->save($save_data);
if (!$save_flag) {
$error_count++;
Clog::setLog('修改订单失败', 'order_notice 订单数据');
}
// step 2 修改捐赠总数
$donate = M('donate');
$donate_info = $donate->where(['id' => $donate_order_info['donate_id']])->find();
$save_donate_data = [
'money' => $donate_info['money'] + $donate_amount
];
$money_save_flag = $donate->where(['id' => $donate_order_info['donate_id']])->save($save_donate_data);
if (!$money_save_flag) {
$error_count++;
Clog::setLog('修改捐赠总数失败', 'order_notice 捐款数据');
}
// step 3 处理configs中的统计信息
$configService = new ConfigService();
$key = ['key' => ['in', ['total_donate', 'total_help', 'total_join']]];
$total_data = $configService->queryKey($key);
$edit_donate = $configService->updateOneKey('total_donate',$total_data['total_donate']+$total_payed_price);
if (!$edit_donate && $edit_donate !== 0) {
$error_count ++;
}
if ((float)$donate_info['money'] === 0.00) {
// 第一次被帮助
$edit_help = $configService->updateOneKey('total_help',$total_data['total_help']+1);
if (!$edit_help && $edit_help !== 0) {
$error_count ++;
}
}
$save_join = $configService->updateOneKey('total_join',$total_data['total_join']+1);
if (!$save_join && $save_join !== 0) {
$error_count ++;
}
if ($error_count > 0) {
Clog::setLog('回滚了', 'order_notice');
M()->rollback();
$result = -2;
} else {
Clog::setLog('commit了', 'order_notice');
M()->commit();
$result = 0;
}
} else {
Clog::setLog('签名有误', 'order_notice');
$result = -1;
}
Clog::setLog($result, 'order_notice');
// 返回状态给微信服务器
$str = '';
if ($result === 0) { // 成功之后不会再回调
$str = '<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
} elseif ($result === -1) { // 失败后会继续发送几次回调
$str = '<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[签名失败]]></return_msg></xml>';
} elseif ($result === -2) { // 失败后会继续发送几次回调
$str = '<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[操作失败]]></return_msg></xml>';
}
exit($str);
}
封装微信小程序支付的更多相关文章
- 微信小程序支付及退款流程详解
微信小程序的支付和退款流程 近期在做微信小程序时,涉及到了小程序的支付和退款流程,所以也大概的将这方面的东西看了一个遍,就在这篇博客里总结一下. 首先说明一下,微信小程序支付的主要逻辑集中在后端,前端 ...
- php对接微信小程序支付
前言:这里我就假装你已经注册了微信小程序,并且基本的配置都已经好了.注: 个人注册小程序不支持微信支付,所以我还是假装你是企业或者个体工商户的微信小程序,其他的商户号注册,二者绑定,授权,支付开通,就 ...
- 微信小程序支付接入注意点
一.微信支付后台服务器部署 服务器采用ubuntu16.04 + php7.0 + apache2.0. 微信支付后台服务使用了curl 和 samplexml ,因此php.ini配置中必须开启这两 ...
- 微信小程序支付开发之申请退款
微信小程序支付跟微信公众号支付类似,这里不另做记录,如果没有开发过支付,可以查看我关于微信支付的文章 重点记录微信小程序申请退款开发过程中遇到一些坑. 退款接口比支付接口接口多了一个 双向证书 证书介 ...
- 微信小程序支付接入实战
1. 微信小程序支付接入实战 1.1. 需求 最近接到一个小程序微信支付的需求,需要我写后台支持,本着能不自己写就不自己写的cv原则,在网上找到了些第三方程序,经过尝试后,最后决定了这不要脸作者的 ...
- Java实现微信小程序支付(完整版)
在开发微信小程序支付的功能前,我们先熟悉下微信小程序支付的业务流程图: 不熟悉流程的建议还是仔细阅读微信官方的开发者文档. 一,准备工作 事先需要申请企业版小程序,并开通“微信支付”(即商户功能).并 ...
- php 微信小程序支付
php 微信小程序支付 直接贴代码: 前端测试按钮wxml: <view class="container"> <text class="name&qu ...
- .Net后台实现微信小程序支付
最近一直再研究微信支付和支付宝支付,官方支付文档中一直在讲与第三方支付打交道的原理,却没有介绍我们自己项目中的APP与后台该怎么交互(哈哈,人家也没必要介绍这一块).拜读了官方文档和前辈们的佳作,自己 ...
- 微信小程序支付步骤
http://blog.csdn.net/wangsf789/article/details/53419781 最近开发微信小程序进入到支付阶段,一直以来从事App开发,所以支付流程还是熟记于心的.但 ...
随机推荐
- 从源码层面聊聊面试问烂了的 Spring AOP与SpringMVC
Spring AOP ,SpringMVC ,这两个应该是国内面试必问题,网上有很多答案,其实背背就可以.但今天笔者带大家一起深入浅出源码,看看他的原理.以期让印象更加深刻,面试的时候游刃有余. Sp ...
- 用Java实现MVPtree——MVPtree核心算法代码的搭建
项目需要,需要把MVPtree这种冷门的数据结构写入Java,然网上没有成形的Java实现,虽说C++看惯了不过对C++实现复杂结构也是看得蒙蔽,幸好客户给了个github上job什么的人用Java写 ...
- tar 压缩指令基本用法
压缩:tar -cjvf aaa.tar.bz2 www.test.com/ --exclude *.log(-j是用bz2压缩,-exclude是排除.log后缀的文件) c-创建 j-bzip ...
- 20145308 《网络对抗》 注入shellcode+Return-to-libc攻击 学习总结
20145308 <网络对抗> 逆向及BOF进阶实践 注入shellcode+Return-to-libc攻击 学习总结 实践目的 注入shellcode 实现Return-to-libc ...
- Ymodem协议(参考STM32)
相信很多人都希望,不开盖就可以对固件进行升级吧,就像手机那些.下文中的bootload就来实现这样的功能. 前段时间有项目关于Bootload设计.所以就仔细的去了研究了一翻.以前都是用的stm32官 ...
- UML状态机图【图3】--☆
UML状态机图 基本概述 状态机图描述的是围绕某一事物状态变化的图.它也是三大流程分析利器之一.它和活动图的区别在于,活动图是描述事物发生的流程,是多个角色参与的,而状态机描述的是事物的状态变化 ...
- bzoj 2733 永无乡 - 并查集 - 线段树
永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达另一个岛. ...
- jsoup对 HTML 文档的解析和操作
本文手动转载自http://www.cnblogs.com/chenying99/archive/2013/01/04/2844615.html,仅根据个人需要对实用部分进行转载,详细请阅读原文. j ...
- 建立TCP连接过程
1.服务器实例化一个ServerSocket 对象, 表示通过服务器上的端口通信. ServerSocket serverSocket = new ServerSocket(port); 2.服务器调 ...
- 解决Tax discount configure 报出异常
If your tax calculation is based on a problematic configuration, the following warnings appear: Warn ...