封装微信小程序支付
<?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开发,所以支付流程还是熟记于心的.但 ...
随机推荐
- mycat水平分表
和垂直分库不同,水平分表,是将那些io频繁,且数据量大的表进行水平切分. 基本的配置和垂直分库一样,我们需要改的就是我们的 schema.xml和rule.xml文件配置(server.xml不用做任 ...
- SVN更新无数次后仍显示Out of date
理器相集成的TortoiseSVN更是方便. 但有时候在提交修改后的文件时,却莫名其妙的出现out of date错误,导致工程无法commit,即使将新文件删了重新update,然后再在旧文件上作修 ...
- Caused by: com.rabbitmq.client.ShutdownSignalException: connection error
周五下午的时候升级了一个环境,跑了批处理sh升级脚本后,启动时报下列错误: INFO | jvm 1 | 2017/02/24 17:39:09 | java.io.IOException INFO ...
- String类的知识点(不断更新)
知识点1.String类位于java.lang包中,具有丰富的方法计算字符串的长度.比较字符串.连接字符串.提取字符串2.数组的length是属性,字符串的length()是方法3.import ja ...
- 12: nginx原理及常用配置
1.1 nginx基本介绍 1.nginx高并发原理( 多进程+epoll实现高并发 ) 1. Nginx 在启动后,会有一个 master 进程和多个相互独立的 worker 进程. 2. 每个子进 ...
- [BeiJing wc2012]冻结 题解
HYSBZ - 2662 这个题如果我们先想用平常的方法来建图,因为我们无法确定是否使用卡片,如果我们每个点每个边都建图,那么非常耗时占空间:注意到k是比较小的,所以我们可以把k拆开,把一个点分为k个 ...
- SSM集成activiti6.0错误集锦(二)
项目环境 Maven构建 数据库:Orcle12c 服务器:Tomcat9 <java.version>1.8</java.version> <activiti.vers ...
- Python3基础 list count 查询指定元素在列表中出现了多少次
Python : 3.7.0 OS : Ubuntu 18.04.1 LTS IDE : PyCharm 2018.2.4 Conda ...
- dede的应用
gbk和utf-8版本选择 gbk是国家编码,所有的内容编码,包括中文,英文,英文字符都占两个字节. utf-8是国际编码,中文三个字节,英文1个字节 现阶段,网站都用gbk编码, 一方面节省本地/网 ...
- 【做题】Codeforces Round #436 (Div. 2) F. Cities Excursions——图论+dfs
题意:给你一个有向图,多次询问从一个点到另一个点字典序最小的路径上第k个点. 考虑枚举每一个点作为汇点(记为i),计算出其他所有点到i的字典序最小的路径.(当然,枚举源点也是可行的) 首先,我们建一张 ...