<?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);
}

封装微信小程序支付的更多相关文章

  1. 微信小程序支付及退款流程详解

    微信小程序的支付和退款流程 近期在做微信小程序时,涉及到了小程序的支付和退款流程,所以也大概的将这方面的东西看了一个遍,就在这篇博客里总结一下. 首先说明一下,微信小程序支付的主要逻辑集中在后端,前端 ...

  2. php对接微信小程序支付

    前言:这里我就假装你已经注册了微信小程序,并且基本的配置都已经好了.注: 个人注册小程序不支持微信支付,所以我还是假装你是企业或者个体工商户的微信小程序,其他的商户号注册,二者绑定,授权,支付开通,就 ...

  3. 微信小程序支付接入注意点

    一.微信支付后台服务器部署 服务器采用ubuntu16.04 + php7.0 + apache2.0. 微信支付后台服务使用了curl 和 samplexml ,因此php.ini配置中必须开启这两 ...

  4. 微信小程序支付开发之申请退款

    微信小程序支付跟微信公众号支付类似,这里不另做记录,如果没有开发过支付,可以查看我关于微信支付的文章 重点记录微信小程序申请退款开发过程中遇到一些坑. 退款接口比支付接口接口多了一个 双向证书 证书介 ...

  5. 微信小程序支付接入实战

    1. 微信小程序支付接入实战 1.1. 需求   最近接到一个小程序微信支付的需求,需要我写后台支持,本着能不自己写就不自己写的cv原则,在网上找到了些第三方程序,经过尝试后,最后决定了这不要脸作者的 ...

  6. Java实现微信小程序支付(完整版)

    在开发微信小程序支付的功能前,我们先熟悉下微信小程序支付的业务流程图: 不熟悉流程的建议还是仔细阅读微信官方的开发者文档. 一,准备工作 事先需要申请企业版小程序,并开通“微信支付”(即商户功能).并 ...

  7. php 微信小程序支付

    php 微信小程序支付 直接贴代码: 前端测试按钮wxml: <view class="container"> <text class="name&qu ...

  8. .Net后台实现微信小程序支付

    最近一直再研究微信支付和支付宝支付,官方支付文档中一直在讲与第三方支付打交道的原理,却没有介绍我们自己项目中的APP与后台该怎么交互(哈哈,人家也没必要介绍这一块).拜读了官方文档和前辈们的佳作,自己 ...

  9. 微信小程序支付步骤

    http://blog.csdn.net/wangsf789/article/details/53419781 最近开发微信小程序进入到支付阶段,一直以来从事App开发,所以支付流程还是熟记于心的.但 ...

随机推荐

  1. 一线互联网常见的 14 个 Java 面试题,你颤抖了吗程序员

    跳槽不算频繁,但参加过不少面试(电话面试.face to face 面试),面过大 / 小公司.互联网 / 传统软件公司,面糊过(眼高手低,缺乏实战经验,挂掉),也面过人,所幸未因失败而气馁,在此过程 ...

  2. 获取select被选中的option的值

    <select id="select">      <option>绥江</option>      <option>西江</ ...

  3. 通过数组和枚举简化GPIO操作编码(转)

    源: 通过数组和枚举简化GPIO操作编码

  4. Python调用大漠插件

    Python版本要用32位的?我去官网下载,太慢了,就在腾讯软件里面下载了一个,结果实验成功 import win32com.client dm = win32com.client.Dispatch( ...

  5. 阿里云Maven settings.xml文件

    <?xml version="1.0" encoding="UTF-8"?> <!-- Licensed to the Apache Soft ...

  6. 框架frame

    使用框架切分网页 效果: 代码: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"& ...

  7. 做了 3 年企业级 SaaS,我收获的 10 点心得(转)

    关于中国企业级服务的总结不少,本土派和海外派都有出色的文章出来,VC 和创业者站在各自角度也有很多不错的总结.本文基于 Ping++ 近三年的创业历程而来,有弯路,有教训,有醒悟,也有心得.盛景 B2 ...

  8. 火车时刻表WebApp

    关键词 :Ajax 跨域访问 php 同源策略 JQueryMobile 前言 在面试的过程中,兄弟连的徐老师提出要求我用JQuery Mobile(前端框架)来实现一个具有“火车时刻表”功能的Web ...

  9. 04: nginx部署vue

    1.1 基本配置 server { listen 9000; server_name 1.1.1.3; #access_log logs/access_example.log main; root / ...

  10. Kali linux 2018安装后全屏乱码解决

    安装的时候选择了中文, 后来安装成功后成了全部乱码的. 原因是,系统没有中文字体显示安装包, 下载一个 sudo apt-get install ttf-wqy-zenhei 重启解决!