基于thinkphp5框架实现微信小程序支付 退款 订单查询 退款查询操作


Posted in PHP onAugust 17, 2020

微信小程序或微信支付相关操作支付退款订单查询退款查询支付成功,进行回调退款成功 进行回调用到的方法

支付

/**
 * 预支付请求接口(POST)
 * @param string $openid openid
 * @param string $body 商品简单描述
 * @param string $order_sn 订单编号
 * @param string $total_fee 金额
 * @return json的数据
 */
 public function prepay()
 {
 tp_log('预支付请求数据===>' . json_encode($_POST), 'prepay', request()->controller());
 $goods_user = db('tf_goods_user')->where(array('order_no' => $_POST['order_no']))->find();
 $goods = db('tf_goods')->where(array('id' => $goods_user['goods_id']))->find();
 //判断产品的数量
 if (($goods['sales_initial'] - $goods['sales_actual']) <= 0) {
 $return['status'] = 0;
 $return['info'] = '此产品已售完';
 exit(json_encode($return));
 }

 $order_no = $_POST['order_no']; //订单号
 $is_sale = $_POST['is_sale'];
 $openid = $_POST['openid'];
 $goods_name = $_POST['goods_name'];
 $pay_price = $_POST['price'];
 $attach['is_sale'] = $_POST['is_sale'];
 $attach['sale_id'] = $_POST['sale_id'];
 $nonce_str = $this->nonce_str();//随机字符串


 $order_no_ssh = $this->get_orderssh(); //商户订单号
 //组装支付数据
 $data = [
 'appid' => config('pay.APPID'),
 'mch_id' => config('pay.MCHID'),
 'nonce_str' => $nonce_str,
 'body' => $goods_name, //商品名称组合
 'attach' => json_encode($attach),
 'out_trade_no' => $order_no_ssh,//$order_no, //订单号 商户订单号
 'total_fee' => intval($pay_price * 100),
 'spbill_create_ip' => $_SERVER['REMOTE_ADDR'],
 'notify_url' => config('pay.NOTIFY_URL'),
 'trade_type' => 'JSAPI',
 'openid' => $openid
 ];

 //订单支付表创建订单支付数据
 $p_o_data['createtime'] = time();
 $p_o_data['order_no'] = $order_no;
 $p_o_data['order_no_ssh'] = $order_no_ssh;
 $p_o_data['ready'] = json_encode($data);
 $p_o_return = db('tf_pay_order')->insert($p_o_data);
 if(!$p_o_return){
 //失败
 $return['status'] = -1;
 $return['info'] = $p_o_data;
 exit(json_encode($return));
 }

 // 获取签名
 $sign = $this->makeSign($data);
 $data['sign'] = $sign;
 $xml = $this->toXml($data);
 $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder'; //发起支付接口链接
 //发起预支付请求
 $prepay_return_reslut_xml = $this->http_request($url, $xml);
 $xml_to_arr = $this->fromXml($prepay_return_reslut_xml);
 $return_result = json_encode($xml_to_arr, true);
 tp_log('预支付请求返回数据array===>' .$return_result , 'prepay', request()->controller());
 //记录预支付返回信息
 db('tf_goods_order')->where(array('order_no' => $order_no))
 ->update(array(
 'go_pay' => $return_result,
 'updatetime' => time(),
 'updateuser' => $openid
 ));
 if($xml_to_arr['return_code'] == 'SUCCESS' && $xml_to_arr['result_code'] == 'SUCCESS'){
 //成功

 $time = time();
 //临时数组用于签名
 $tmp = [
 'appId' => config('pay.APPID'),
 'nonceStr' => $nonce_str,
 'package' => 'prepay_id='.$xml_to_arr['prepay_id'],
 'signType' => 'MD5',
 'timeStamp' => "$time",
 ];
 $data['timeStamp'] = "$time";//时间戳
 $data['nonceStr'] = $nonce_str;//随机字符串
 $data['signType'] = 'MD5';//签名算法,暂支持 MD5
 $data['package'] = 'prepay_id='.$xml_to_arr['prepay_id'];//统一下单接口返回的 prepay_id 参数值,提交格式如:prepay_id=*
 $data['paySign'] = $this->makeSign($tmp);//签名,具体签名方案参见微信公众号支付帮助文档;$data['out_trade_no'] = $out_trade_no;


 $return['status'] = 1;
 $return['info'] = $data;
 }else{
 //失败
 $return['status'] = -1;
 $return['info'] = $xml_to_arr;
 }
 exit(json_encode($return));
 }

 //curl请求
 public function http_request($url, $data = null, $headers = array())
 {
 $curl = curl_init();
 if (count($headers) >= 1) {
 curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
 }
 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);
 curl_close($curl);
 return $output;
 }

退款

/**
 * 申请退款API
 * @param $transaction_id
 * @param double $total_fee 账单总金额
 * @param double $refund_fee 退款金额
 * @return bool
 * @throws BaseException
 */
 public function refund()
 {

 $transaction_id = '4200000712202007274705432240';
 $total_fee = '0.01';
 $refund_fee = '0.01';
 // 当前时间
 $time = time();
 // 生成随机字符串
 $nonceStr = md5($time . $transaction_id . $total_fee . $refund_fee);
 // API参数
 $params = [
 'appid' => config('pay.APPID'),
 'mch_id' => config('pay.MCHID'),
 'nonce_str' => $nonceStr,
 'transaction_id' => $transaction_id,
 'out_refund_no' => $time,
 'total_fee' => $total_fee * 100,
 'refund_fee' => $refund_fee * 100,
 'notify_url' => config('pay.NOTIFY_URL_REFUND'),//退款回调地址
 ];
 // 生成签名
 $params['sign'] = $this->makeSign($params);

 tp_log('退款请求数据===>' . json_encode($params), 'refund', request()->controller());

 // 请求API
 $url = 'https://api.mch.weixin.qq.com/secapi/pay/refund';
 $result = $this->post($url, $this->toXml($params), true, $this->getCertPem());
 $prepay = $this->fromXml($result);
 // 请求失败
 if (empty($result)) {
 throw new BaseException(['msg' => '微信退款api请求失败']);
 }
 // 格式化返回结果
 $prepay = $this->fromXml($result);
 tp_log('退款返回数据===>' . json_encode($prepay), 'refund', request()->controller());
 // 请求失败
// if ($prepay['return_code'] === 'FAIL') {
// throw new BaseException(['msg' => 'return_msg: ' . $prepay['return_msg']]);
// }
// if ($prepay['result_code'] === 'FAIL') {
// throw new BaseException(['msg' => 'err_code_des: ' . $prepay['err_code_des']]);
// }
 return true;
 }
 /**
 * 模拟POST请求
 * @param $url
 * @param array $data
 * @param bool $useCert
 * @param array $sslCert
 * @return mixed
 */
 public function post($url, $data = [], $useCert = false, $sslCert = [])
 {
 $header = [
 'Content-type: application/json;'
 ];
 $curl = curl_init();
 //如果有配置代理这里就设置代理
// if(WxPayConfig::CURL_PROXY_HOST != "0.0.0.0"
// && WxPayConfig::CURL_PROXY_PORT != 0){
// curl_setopt($ch,CURLOPT_PROXY, WxPayConfig::CURL_PROXY_HOST);
// curl_setopt($ch,CURLOPT_PROXYPORT, WxPayConfig::CURL_PROXY_PORT);
// }

 curl_setopt($curl, CURLOPT_URL, $url);
 curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
 curl_setopt($curl, CURLOPT_HEADER, false);
 curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
 curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
 curl_setopt($curl, CURLOPT_POST, TRUE);
 curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
 if ($useCert == true) {
 // 设置证书:cert 与 key 分别属于两个.pem文件
 curl_setopt($curl, CURLOPT_SSLCERTTYPE, 'PEM');
 curl_setopt($curl, CURLOPT_SSLCERT, $sslCert['certPem']);
 curl_setopt($curl, CURLOPT_SSLKEYTYPE, 'PEM');
 curl_setopt($curl, CURLOPT_SSLKEY, $sslCert['keyPem']);
 }
 $result = curl_exec($curl);
 curl_close($curl);
 return $result;
 }

订单查询

/**
 * 订单查询
 * @param $out_trade_no
 * @return mixed
 * @throws BaseException
 */
 public function orderquery()
 {
 $transaction_id = '4200000712202007274705432240';//微信订单号
 // 当前时间
 $time = time();
 // 生成随机字符串
 $nonce_str = md5($time . mt_rand(00000,99999));
 //API参数
 $params = [
 'appid' => config('pay.APPID'), //公众号ID
 'mch_id' => config('pay.MCHID'), //商户号
 'transaction_id' => $transaction_id, //商户订单号
 'nonce_str' => $nonce_str, // 随机字符串
 ];
 //生成签名
 $params['sign'] = $this->makeSign($params);
 //请求API
 $url = 'https://api.mch.weixin.qq.com/pay/orderquery';
 $result = $this->post($url, $this->toXml($params));
 $prepay = $this->fromXml($result);
 // 请求失败
 if ($prepay['return_code'] === 'FAIL') {
 throw new BaseException(['msg' => $prepay['return_msg'], 'code' => 0]);
 }
 if ($prepay['result_code'] === 'FAIL') {
 throw new BaseException(['msg' => $prepay['err_code_des'], 'code' => 0]);
 }
 return $prepay;
 }

退款查询

/**
 * 退款查询
 * @param $out_trade_no
 * @return mixed
 * @throws BaseException
 */
 public function refundquery()
 {
 $transaction_id = '4200000712202007274705432240';//微信订单号
 // 当前时间
 $time = time();
 // 生成随机字符串
 $nonce_str = md5($time . mt_rand(00000,99999));
 //API参数
 $params = [
 'appid' => config('pay.APPID'), //公众号ID
 'mch_id' => config('pay.MCHID'), //商户号
 'transaction_id' => $transaction_id, //商户订单号
 'nonce_str' => $nonce_str, // 随机字符串
 ];
 //生成签名
 $params['sign'] = $this->makeSign($params);
 //请求API
 $url = 'https://api.mch.weixin.qq.com/pay/refundquery';
 $result = $this->post($url, $this->toXml($params));
 $prepay = $this->fromXml($result);
 dump($prepay);die;
 // 请求失败
 if ($prepay['return_code'] === 'FAIL') {
 throw new BaseException(['msg' => $prepay['return_msg'], 'code' => 0]);
 }
 if ($prepay['result_code'] === 'FAIL') {
 throw new BaseException(['msg' => $prepay['err_code_des'], 'code' => 0]);
 }
 return $prepay;
 }

支付成功,进行回调

public function index()
 {
 $data = file_get_contents('php://input');
 $data = $this->FromXml($data);
 tp_log('支付回调数据===>' . json_encode($data), 'index', request()->controller());
 // 保存微信服务器返回的签名sign
 $data_sign = $data['sign'];
 // sign不参与签名算法
 unset($data['sign']);
 $sign = $this->makeSign($data);//回调验证签名

 $str_success = '<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
 $str_error = '<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[签名失败]]></return_msg></xml>';

 if (($sign === $data_sign) && ($data['return_code'] == 'SUCCESS') && ($data['result_code'] == 'SUCCESS')) {
 // 支付成功 进行你的逻辑处理
 }
echo $str_success;//str_error 告知微信 你已的逻辑处理完毕 不用再推送或再次推送你结果
 }

退款成功 进行回调

/*
 * 小程序 退款结果通知
 */
 public function refund(){

 $data = file_get_contents('php://input');
 $data = $this->FromXml($data);
 tp_log('退款回调数据===>' . json_encode($data), 'refund', request()->controller());

 //对加密的字符串解密
 $req_info_xml = openssl_decrypt(base64_decode($data['req_info']), 'aes-256-ecb', md5(config('pay.KEY')),OPENSSL_RAW_DATA);
 $req_info = $this->FromXml($req_info_xml);

// // 保存微信服务器返回的签名sign
// $data_sign = $data['sign'];
// // sign不参与签名算法
// unset($data['sign']);
// $sign = $this->makeSign($data);//回调验证签名
//
// $str_success = '<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
// $str_error = '<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[签名失败]]></return_msg></xml>';
//
//
//
// if (($sign === $data_sign) && ($data['return_code'] == 'SUCCESS') && ($data['result_code'] == 'SUCCESS')) {
// tp_log('退款成功===>', 'refund', request()->controller());
// //去修改订单的状态 和支付回调的一样 修改成功 告知微信 不在推送
// }
 }

用到的方法

/**
 * 生成签名
 * @param $values
 * @return string 本函数不覆盖sign成员变量,如要设置签名需要调用SetSign方法赋值
 */
 private function makeSign($values)
 {
 //签名步骤一:按字典序排序参数
 ksort($values);
 $string = $this->toUrlParams($values);
 //签名步骤二:在string后加入KEY
 $string = $string . '&key=' . config('pay.KEY');
 //签名步骤三:MD5加密
 $string = md5($string);
 //签名步骤四:所有字符转为大写
 $result = strtoupper($string);
 return $result;
 }
 private function ToUrlParams($array)
 {
 $buff = "";
 foreach ($array as $k => $v) {
 if ($k != "sign" && $v != "" && !is_array($v)) {
 $buff .= $k . "=" . $v . "&";
 }
 }
 $buff = trim($buff, "&");
 return $buff;
 }

 /**
 * 输出xml字符
 * @param $values
 * @return bool|string
 */
 private function toXml($values)
 {
 if (!is_array($values)
 || count($values) <= 0
 ) {
 return false;
 }
 $xml = "<xml>";
 foreach ($values as $key => $val) {
 if (is_numeric($val)) {
 $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
 } else {
 $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
 }
 }
 $xml .= "</xml>";
 return $xml;
 }

 /**
 * 将xml转为array
 * @param $xml
 * @return mixed
 */
 private function fromXml($xml)
 {
 // 禁止引用外部xml实体
 libxml_disable_entity_loader(true);
 return json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
 }

 /**
 * 获取cert证书文件
 * @return array
 * @throws BaseException
 */
 private function getCertPem()
 {
// if (empty($this->config['cert_pem']) || empty($this->config['key_pem'])) {
// throw new BaseException(['msg' => '请先到后台小程序设置填写微信支付证书文件']);
// }
 // cert目录
 $filePath = EXTEND_PATH.'wxpay/cert/';
 return [
 'certPem' => $filePath . 'apiclient_cert.pem',
 'keyPem' => $filePath . 'apiclient_key.pem'
 ];
 }
/**
 * 生成商户订单号
 */
 public function get_orderssh()
 {
 return date("YmdHis") . mt_rand(10000000, 99999999);
 }

证书路径

基于thinkphp5框架实现微信小程序支付 退款 订单查询 退款查询操作

config配置

基于thinkphp5框架实现微信小程序支付 退款 订单查询 退款查询操作

总结

到此这篇关于基于thinkphp5框架实现微信小程序支付 退款 订单查询 退款查询的文章就介绍到这了,更多相关微信小程序支付 退款 订单查询 退款查询内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

PHP 相关文章推荐
通过对php一些服务器端特性的配置加强php的安全
Oct 09 PHP
php部分常见问题总结
Mar 27 PHP
PHP中$_SERVER的详细参数与说明
Jul 29 PHP
PHP中的socket_read和socket_recv区别详解
Feb 09 PHP
CentOS 安装 PHP5.5+Redis+XDebug+Nginx+MySQL全纪录
Mar 25 PHP
php数组指针操作详解
Feb 14 PHP
PHP实现双链表删除与插入节点的方法示例
Nov 11 PHP
PHP检测接口Traversable用法详解
Dec 29 PHP
Laravel Validator 实现两个或多个字段联合索引唯一
May 08 PHP
Laravel+Intervention实现上传图片功能示例
Jul 09 PHP
PHP getID3类的使用方法学习笔记【附getID3源码下载】
Oct 18 PHP
PHP 对接美团大众点评团购券(门票)的开发步骤
Apr 03 PHP
PhpStorm2020.1 安装 debug - Postman 调用的详细教程
Aug 17 #PHP
php开发最强大的IDE编辑的phpstorm 2020.2配置Xdebug调试的详细教程
Aug 17 #PHP
PHP unset函数原理及使用方法解析
Aug 14 #PHP
PHP常量及变量区别原理详解
Aug 14 #PHP
PHP获取当前时间不准确问题解决方案
Aug 14 #PHP
PHP语言对接抖音快手小红书视频/图片去水印API接口源码
Aug 11 #PHP
php实现微信和支付宝支付的示例代码
Aug 11 #PHP
You might like
真正的ZIP文件操作类(php)
2007/07/21 PHP
PHP 日志缩略名的创建函数代码
2010/05/26 PHP
Php获取金书网的书名的实现代码
2010/06/11 PHP
javascript同步Import,同步调用外部js的方法
2008/07/08 Javascript
JQuery 动画卷页 返回顶部 动画特效(兼容Chrome)
2010/02/15 Javascript
JS定时刷新页面及跳转页面的方法
2013/07/04 Javascript
js中如何把字符串转化为对象、数组示例代码
2013/07/17 Javascript
Javascript仿PHP $_GET获取URL中的参数
2014/05/12 Javascript
解决js下referer兼容各大浏览器的方法
2014/11/03 Javascript
js脚本实现数据去重
2014/11/27 Javascript
JS实现固定在右下角可展开收缩DIV层的方法
2015/02/13 Javascript
JavaScript通过元素索引号删除数组中对应元素的方法
2015/03/18 Javascript
jQuery找出网页上最高元素的方法
2015/03/20 Javascript
对于jQuery性能的一些优化建议
2015/08/13 Javascript
JavaScript开发者必备的10个Sublime Text插件
2016/02/27 Javascript
JS学习之表格的排序简单实例
2016/05/16 Javascript
js获取浏览器高度 窗口高度 元素尺寸 偏移属性的方法
2016/11/21 Javascript
EasyUI学习之DataGird分页显示数据
2016/12/29 Javascript
js图片轮播手动切换特效
2017/01/12 Javascript
原JS实现banner图的常用功能
2017/06/12 Javascript
小程序图片长按识别功能的实现方法
2018/08/30 Javascript
Vue基础学习之项目整合及优化
2019/06/02 Javascript
教你30秒发布一个TypeScript包到NPM的方法步骤
2019/07/22 Javascript
vue 弹出遮罩层样式实例
2020/07/22 Javascript
如何HttpServletRequest文件对象并储存
2020/08/14 Javascript
解决removeEventListener 无法清除监听的问题
2020/10/30 Javascript
python网络编程示例(客户端与服务端)
2014/04/24 Python
python脚本实现查找webshell的方法
2014/07/31 Python
Python中模块(Module)和包(Package)的区别详解
2019/08/07 Python
flask/django 动态查询表结构相同表名不同数据的Model实现方法
2019/08/29 Python
Python使用Pandas库常见操作详解
2020/01/16 Python
BONIA波尼亚新加坡官网:皮革手袋,鞋类和配件
2016/08/25 全球购物
LN-CC英国:伦敦时尚生活的缩影
2019/09/01 全球购物
房产委托公证书
2014/04/08 职场文书
Mysql 设置boolean类型的操作
2021/06/04 MySQL
Mysql数据库group by原理详解
2022/07/07 MySQL