小程序微信支付开发指引:https://pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter2_8_2.shtml
流程图:

<?php
namespace app\api\controller;use \think\Cache;
use \think\Controller;
use think\Loader;
use think\Db;
use \think\Cookie;
use \think\Session;
use \think\Request;
use app\api\controller\Base;// class Pay extends Base
class Pay extends Controller
{// private $apiV3key =config('wx_key');//微信解密https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_2.shtmlprivate $aesKey;const KEY_LENGTH_BYTE = 32;const AUTH_TAG_LENGTH_BYTE = 16;public function _empty(){//把所有城市的操作解析到city方法echo "迷路了!";}//微信支付调用接口,可根据情况调整//所需字段 $price   $cost_type  $product_id//产品idpublic function payPrice(){//随机生产的订单号,可根据情况资讯修改$out_trade_no=time().session("userinfo.id");if(empty($out_trade_no)) return json(['code'=>0,'msg'=>'缺少参数order_sn']);        //价格$price=(float)input('post.price');$product_id=(string)input('post.product_id');//JSAPI下单官方说明,请求参数,返回参数//https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_5_1.shtml// 官方提供网址$url = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi";$urlarr = parse_url($url); //拆解为:[scheme=>https,host=>api.mch.weixin.qq.com,path=>/v3/pay/transactions/native]$time = (string)time(); //时间戳$noncestr = $this->getNonceStr();$appid = config('appid');//appID$mchid = config('mch_id');//商户ID$xlid  = config('xlid');//证书序列号$data  = array();$data['appid'] = $appid;$data['mchid'] = $mchid;$data['description'] = '商品描述'$data['out_trade_no'] = $out_trade_no;//订单编号,订单号在微信支付里是唯一的$data['notify_url'] = config('notify_url');//异步接收微信支付结果通知的回调地址,需根据自己的情况修改回调接口,也可以为空$data['amount']['total'] = $price*100;//金额 单位 分$data['scene_info']['payer_client_ip'] = $_SERVER["REMOTE_ADDR"];;//场景ip//用户在直连商户appid下的唯一标识openid$data['payer']['openid']=session("userinfo.open_id"); //openid//var_dump($data);// var_dump(session('userinfo'));// exit();//json加密成json对象$data = json_encode($data);$http_method = 'POST';//微信支付API v3通过验证签名来保证请求的真实性和数据的完整性,所有向微信支付发送请求之前都要先进行签名,所有微信支付返回的信息都要进行验签,涉及都 php rsa 加密解密,参考地址:https://blog.csdn.net/wkj001/article/details/129093672?spm=1001.2014.3001.5501//微信支付签名生成:https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_0.shtml//微信签名,包含了$data数据、微信指定地址、随机数和时间$key = $this->getSign($http_method,$data,$urlarr['path'],$noncestr,$time);// echo $key;// exit();$token = sprintf('mchid="%s",serial_no="%s",nonce_str="%s",timestamp="%d",signature="%s"',$mchid,$xlid,$noncestr,$time,$key);//微信支付商户API v3要求请求通过HTTP Authorization头来传递签名。 Authorization由认证类型和签名信息两个部分组成。//头部信息$header  = array('Accept: application/json','Content-Type: application/json','User-Agent:*/*','Authorization: WECHATPAY2-SHA256-RSA2048 '.$token);// var_dump($data);// exit();//向微信接口地址提交json格式的$data和header的头部信息,得到返回值$res = $this->curl_post_https($url,$data,$header);// var_dump($res);// exit();$prepay_id=json_decode($res,true)['prepay_id'];//通过JSAPI下单接口获取到发起支付的必要参数prepay_id,然后使用微信支付提供的前端JS方法调起公众号支付//计算调起支付的签名$paySign=$this->getWechartSign($appid,$time,$noncestr,'prepay_id='.$prepay_id);$payData=['timeStamp'=>$time,'nonceStr'=>$noncestr,'package'=>'prepay_id='.$prepay_id,'signType'=>'RSA','paySign'=>$paySign];return json(['code'=>1,'msg'=>'ok','data'=>$payData]);}//获取随机字符串public function getNonceStr(){$strs="QWERTYUIOPASDFGHJKLZXCVBNM1234567890";$name=substr(str_shuffle($strs),mt_rand(0,strlen($strs)-11),32);return $name;}//微信支付签名function getSign($method,$data=array(),$url,$randstr,$time){$str = $method."\n".$url."\n".$time."\n".$randstr."\n".$data."\n";$key = file_get_contents('../cert/apiclient_key.pem');//在商户平台下载的秘钥,读取到变量$str = $this->getSha256WithRSA($str,$key);return $str;}//调起支付的签名function getWechartSign($appid,$timeStamp,$noncestr,$prepay_id){//JSAPI调起支付的参数需要按照签名规则进行签名加密://https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_4.shtml#menu1$str = $appid."\n".$timeStamp."\n".$noncestr."\n".$prepay_id."\n";$key = file_get_contents('../cert/apiclient_key.pem');//在商户平台下载的秘钥,读取到变量$str = $this->getSha256WithRSA($str,$key);return $str;}//加密public function getSha256WithRSA($content, $privateKey){$binary_signature = "";$algo = "SHA256";openssl_sign($content, $binary_signature, $privateKey, $algo);$sign = base64_encode($binary_signature);return $sign;}/* PHP CURL HTTPS POST */function curl_post_https($url,$data,$header){ // 模拟提交数据函数$curl = curl_init(); // 启动一个CURL会话curl_setopt($curl, CURLOPT_URL, $url); // 要访问的地址curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); // 对认证证书来源的检查curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0); // 从证书中检查SSL加密算法是否存在,如果出错则修改为0,默认为1curl_setopt($curl, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); // 模拟用户使用的浏览器curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); // 使用自动跳转curl_setopt($curl, CURLOPT_AUTOREFERER, 1); // 自动设置Referercurl_setopt($curl, CURLOPT_POST, 1); // 发送一个常规的Post请求curl_setopt($curl, CURLOPT_POSTFIELDS, $data); // Post提交的数据包curl_setopt($curl, CURLOPT_TIMEOUT, 30); // 设置超时限制防止死循环curl_setopt($curl, CURLOPT_HEADER, 0); // 显示返回的Header区域内容curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // 获取的信息以文件流的形式返回curl_setopt($curl, CURLOPT_HTTPHEADER, $header);$tmpInfo = curl_exec($curl); // 执行操作if (curl_errno($curl)) {echo 'Errno'.curl_error($curl);//捕抓异常}curl_close($curl); // 关闭CURL会话return $tmpInfo; // 返回数据,json格式}/* PHP CURL HTTPS POST */function curl_get_https($url,$header){ // 模拟提交数据函数$curl = curl_init(); // 启动一个CURL会话curl_setopt($curl, CURLOPT_URL, $url); // 要访问的地址curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); // 对认证证书来源的检查curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0); // 从证书中检查SSL加密算法是否存在,如果出错则修改为0,默认为1curl_setopt($curl, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); // 模拟用户使用的浏览器curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); // 使用自动跳转curl_setopt($curl, CURLOPT_AUTOREFERER, 1); // 自动设置Referercurl_setopt($curl, CURLOPT_TIMEOUT, 30); // 设置超时限制防止死循环curl_setopt($curl, CURLOPT_HEADER, 0); // 显示返回的Header区域内容curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // 获取的信息以文件流的形式返回curl_setopt($curl, CURLOPT_HTTPHEADER, $header);$tmpInfo = curl_exec($curl); // 执行操作if (curl_errno($curl)) {echo 'Errno'.curl_error($curl);//捕抓异常}curl_close($curl); // 关闭CURL会话return $tmpInfo; // 返回数据,json格式}//什么是平台证书//https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay3_1.shtml#part-2//获取微信支付平台证书序列,解密后是平台公钥 回调验证签名要用到//如何获取平台证书 https://pay.weixin.qq.com/wiki/doc/apiv3/apis/wechatpay5_1.shtmlpublic function get_cert(){$url = 'https://api.mch.weixin.qq.com/v3/certificates';$url_parts = parse_url($url);$http_method = 'GET';$timestamp = (string)time();$appid = config('appid');//appID$mchid = config('mch_id');//商户ID$xlid  = config('xlid');//证书序列号//        $nonce = md5(time() . $out_trade_no);$noncestr = $this->getNonceStr();//生成随机字符串$body = '';$canonical_url = ($url_parts['path'] . (!empty($url_parts['query']) ? "?${url_parts['query']}" : ""));//给微信支付发送请求前,先签名,包含了$data数据、微信指定地址、随机数和时间$key = $this->getSign($http_method,$body,$canonical_url,$noncestr,$timestamp);//$sign = $this->wechat_sign($message);//签名 和统一下单 调起支付签名一样$token = sprintf('mchid="%s",serial_no="%s",nonce_str="%s",timestamp="%d",signature="%s"',$mchid,$xlid,$noncestr,$timestamp,$key);//头部信息$header  = array('Accept: application/json','Content-Type: application/json','User-Agent:*/*','Authorization: WECHATPAY2-SHA256-RSA2048 '.$token);//GET 获取平台证书列表$res = $this->curl_get_https($url,$header);//$res=json_decode($res,true);// var_dump($res);// exit();
//         //$rs = $this->wechat_req($nonce, $timestamp, $sign, $url, $http_method, '');
//         //保存
// //        $path = APPPATH . '/Wechat/wxp_cert.pem';//平台证书序列
// //        file_put_contents($path, json_encode($rs));return $res;}//微信支付成功后的回调信息public function wx_notify(){//file_put_contents("hd.txt", '微信回调');//https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_5_5.shtml//支付成功结果通知数据回调  $header =Request::instance()->header();$response_body = file_get_contents('php://input');// // file_put_contents("head.txt", $header);// // file_put_contents("body.txt", $response_body);//微信签名验证//微信支付发来的信息要进行验签//https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_1.shtml$res=$this->verify_wechatnotify($header, $response_body);file_put_contents("yq.txt", $res);if(!$res){return json(['code'=>0,'msg'=>'签名验证失败']);exit();}//验签通过后,进行内容解密$data = file_get_contents('php://input');//json解密成数组$data = json_decode($data, true);//$data['resource'] 通知数据//随机串$nonceStr = $data['resource']['nonce'];//附加数据$associatedData = $data['resource']['associated_data'];//数据密文Base64编码$ciphertext = $data['resource']['ciphertext'];$ciphertext = base64_decode($ciphertext);//php>7.1,为了使用这个扩展,你必须将extension=php_sodium.dll添加到php.iniif (function_exists('\sodium_crypto_aead_aes256gcm_is_available') && \sodium_crypto_aead_aes256gcm_is_available()) {//$APIv3_KEY就是在商户平台后端设置是APIv3秘钥$orderData = \sodium_crypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, config('wx_key'));file_put_contents("jieguo.txt", $orderData.PHP_EOL,FILE_APPEND);     $orderData = json_decode($orderData, true);// $str12=print_r($orderData,true);// file_put_contents("yewu12.txt", $str12.PHP_EOL,FILE_APPEND); if ($orderData['trade_state']=='SUCCESS'){// file_put_contents("SUCCESS.txt", $orderData['attach'].PHP_EOL,FILE_APPEND);$order_sn=$orderData['out_trade_no']; //商户订单号$transaction_id=$orderData['transaction_id']; //微信订单号$open_id=$orderData['payer']['openid'];$str13=print_r($orderData,true);file_put_contents("yewu13.txt", $str13.PHP_EOL,FILE_APPEND);   // file_put_contents("test.txt", $orderData['attach'].PHP_EOL,FILE_APPEND);file_put_contents("yewu14.txt", (string)$orderData['attach']); //如果附加数据不为空$attach=explode("*",(string)$orderData['attach']);$cost_type=$attach['0']?$attach['0']:'';$product_id=$attach['1']?$attach['1']:'';file_put_contents("cost_type.txt", $cost_type.PHP_EOL,FILE_APPEND);file_put_contents("product_id.txt", $product_id.PHP_EOL,FILE_APPEND);// 启动事务Db::startTrans();try{/*业务处理*/$str1=print_r($orderData,true);file_put_contents("yewu.txt", $str1.PHP_EOL,FILE_APPEND); //业务1$re['t1']=Db::name('user')->insertGetId($id);//业务2$re['t2']=Db::name('product')->insertGetId($id);//业务3$re['t2']=Db::name('order')->insertGetId($id);//任意一个表写入失败都会抛出异常:if (in_array('0', $re)) {        throw new Exception('意不意外?');}//最后提交事务       Db::commit();//应答微信支付已处理该订单的通知return json(['code' => 'SUCCESS', 'message' =>'ok']);} catch (\Exception $e) {// 回滚事务Db::rollback();return json(['code' => 'ERROR', 'message' =>'no']);}}}}//微信验证签名public function verify_wechatnotify($header, $response_body)
//      public function verify_wechatnotify(){// var_dump( $header);
// exit();//$header 回调头部信息 //$response_body回调主体//获取平台证书$plat = $this->get_cert();//平台证书返回为json格式,json_decode转为数组格式$plat=json_decode($plat,true);// $string = print_r($plat, true);// file_put_contents("plat1.txt", $string);// $string2 = print_r($header, true);// file_put_contents("header1.txt", $string2);//serial_no平台证书序列号 //跟商户证书序列号不一样 不要搞混了$serial_no = $plat['data'][0]['serial_no'];//验证回调头部信息中的平台证书序列号跟平台证书序列号是否一致if ($header['wechatpay-serial'] != $serial_no) {return $data=['code'=>'0','msg'=> '平台证书序列号不一致,签名验证不通过'];}//解密平台证书序列获取公钥// var_dump($plat);// exit();$associatedData = $plat['data'][0]['encrypt_certificate']['associated_data'];$nonceStr = $plat['data'][0]['encrypt_certificate']['nonce'];$ciphertext = $plat['data'][0]['encrypt_certificate']['ciphertext'];//官方解密文档 https://wechatpay-api.gitbook.io/wechatpay-api-v3/qian-ming-zhi-nan-1/zheng-shu-he-hui-tiao-bao-wen-jie-mi//平台证书解密后即获取公钥$plat_cert_decrtpt = $this->decryptToString($associatedData, $nonceStr, $ciphertext);// var_dump($plat_cert_decrtpt);// exit();//这个解密方法看官方文档https://wechatpay-api.gitbook.io/wechatpay-api-v3/qian-ming-zhi-nan-1/zheng-shu-he-hui-tiao-bao-wen-jie-mi//$pub_path = 'XX/Wechat/wxp_pub.pem';
//        file_put_contents($pub_path, $plat_cert_decrtpt);//平台公钥 //保存平台公钥 回调验签要用//$plat_cert_decrtpt = file_get_contents($pub_path);//提取平台公钥$pub_key = openssl_pkey_get_public($plat_cert_decrtpt);// var_dump($pub_key);// exit();//组装验签名串【未加密数据】$message = $header['wechatpay-timestamp'] . "\n" . $header['wechatpay-nonce'] . "\n" . $response_body . "\n";//对 Wechatpay-Signature的字段值使用Base64进行解码,得到应答签名。【加密数据】$Signature = $header['wechatpay-signature'];$sign = base64_decode($Signature);//进行验证签名:使用微信支付平台公钥对验签名串和签名进行SHA256 with RSA签名验证$ok = openssl_verify($message, $sign, $pub_key, OPENSSL_ALGO_SHA256);//回调验签if ($ok == 1) {//            return $this->error('1', '回调签名验证成功');return true;} else {return false;}}//微信支付解密字符串//https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_2.shtmlpublic function decryptToString($associatedData, $nonceStr, $ciphertext,$aesKey = '') {if (empty($aesKey)) {$this-> aesKey =config('wx_key'); //微信商户平台 api安全中设置获取}else{$this-> aesKey=$aesKey;}$ciphertext = \base64_decode($ciphertext);if (strlen($ciphertext) <= self::AUTH_TAG_LENGTH_BYTE) {return false;}// ext-sodium (default installed on >= PHP 7.2)if (function_exists('\sodium_crypto_aead_aes256gcm_is_available') && \sodium_crypto_aead_aes256gcm_is_available()) {return \sodium_crypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, $this-> aesKey);}// ext-libsodium (need install libsodium-php 1.x via pecl)if (function_exists('\Sodium\crypto_aead_aes256gcm_is_available') && \Sodium\crypto_aead_aes256gcm_is_available()) {return \Sodium\crypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, $this-> aesKey);}// openssl (PHP >= 7.1 support AEAD)if (PHP_VERSION_ID >= 70100 && in_array('aes-256-gcm', \openssl_get_cipher_methods())) {$ctext = substr($ciphertext, 0, -self::AUTH_TAG_LENGTH_BYTE);$authTag = substr($ciphertext, -self::AUTH_TAG_LENGTH_BYTE);return \openssl_decrypt($ctext, 'aes-256-gcm', $this-> aesKey, \OPENSSL_RAW_DATA, $nonceStr,$authTag, $associatedData);}throw new \RuntimeException('AEAD_AES_256_GCM需要PHP 7.1以上或者安装libsodium-php');}}

tp小程序微信支付部分代码相关推荐

  1. 微信小程序 微信支付代码实现流程

    微信小程序 微信支付是一个很简单的流程  微信开发文档 地址:wx.requestPayment(Object object) | 微信开放文档 微信公众平台申请支付功能 百度一大堆例举代码 官方文档 ...

  2. 调用支付jsapi缺少参数appid_服务商模式下的小程序微信支付

    最近,要做一个小程序商城的项目,需要在小程序中用到分账功能,也就是顾客购买商品支付的钱要给各个店铺,这就需要用到服务商模式. 在谈服务商模式下小程序微信支付之前,我们先要有一个服务商的商户号,这个商户 ...

  3. PHP实现小程序微信支付V2获取prepay_id

    PS:本文旨在简单获取prepay_id,只是简单的介绍一下流程,并非完整的订单支付流程 小程序端JS代码: getxml(){var test = thiswx.getStorage({ //从缓存 ...

  4. nodejs实现小程序微信支付

    最近做小程序时用到了微信支付很是开心,因为之前支付一直都没有做过,终于又可以学点东西了.于是很开心的去看了下微信小程序的支付接口,没想到,事情基本都是后端做的,前端只要调用wx.requestPaym ...

  5. 移动支付开发:小程序微信支付开发测试

    小程序推出邀请测试已经有一个多月,终于申请到一个内部账号,尝试了一把小程序上的微信支付.小程序虽然叫"小",但是个人感觉他的门槛并不低.(/www.zhaoweb.cn) 教育小程 ...

  6. 微信退款返回58 linux,小程序微信支付申请退款返回cUrl错误,错误码:58

    2019-04-03 15:15:29 如何看待微信公开课小程序热门讨论「小程序微信支付申请退款返回cUrl错误,错误码:58」 摘要:小程序微信支付申请退款返回cUrl错误,错误码:58 展开:调用 ...

  7. 微信小程序-微信支付退款

    微信小程序-微信支付退款 官方接口文档及相关附件 申请退款 SDK 错误集锦 调用该https://api.mch.weixin.qq.com/secapi/pay/refund接口需要应程序安装AP ...

  8. 微信小程序支付返回签名错误_java 微信小程序微信支付统一下订单及数字签名错误问题(后端)...

    今天来分享一下之前做微信小程序微信支付遇到的一些坑,博主这里是微信小程序支付功能,因此选择的微信支付方式是JSAPI支付方式(温馨提示左下角有音乐哦). 首先我们肯定是要在小程序后台绑定一个商户号的, ...

  9. PHP实现小程序微信支付v3版本退款,以及对退款订单进行查询

    PS:本篇文章仅用作对小程序微信支付v3版本的退款流程以及对退款订单进行查询的流程展示,如要用于实际,还请自行修改代码 文章中调用的API_Connect.php 与API_v3Connect.php ...

最新文章

  1. 大咖云集!Kubernetes and Cloud Native Meetup 深圳站开始报名!
  2. 【杂谈】AI工业界都有哪些值得参加的比赛?
  3. ultra96-v2通过网线连接PC传输文件
  4. kafka 怎么样连接图形化界面_图形化编程有多简单,点亮LED不到一分钟
  5. python代码300行程序_python小工具,15行代码秒出工资条
  6. Python内置数据结构——字符串string
  7. java 多线程 最优_Java多线程与并发系列从0到1全部合集,强烈建议收藏!
  8. 23.6. Functions
  9. Captaris WorkFlow的开发和部署
  10. JavaEE Tutorials (9) - 运行持久化示例
  11. 在不受支持的 Mac 上安装 macOS Monterey 12(OpenCore Patcher)
  12. 完整版第四方Oreo易支付源码+28K易支付源码
  13. Office/Wps日常操作小技巧
  14. 脸型测试软件在线测试,脸型测试软件最新版
  15. 第五(模块、包说明)
  16. Inventory文件扩展
  17. 谢谢 留下几个 那个有关于C++既QQ群吖
  18. PHP税前税后,请问下大家 怎么根据税后工资1万元推算出税前工资是多少
  19. 信捷plc c 语言全局变量,三菱PLC编程中,跳转指令CJ、子程序调用CALL和中断指令有什么区别?...
  20. SSO(single sign on)模式 单点登录

热门文章

  1. 请你说说看,为什么电影类app先选座位后付款,飞机先付款后选座位?
  2. vs2015配置python_安装 VS2017 并卸载 VS2015 之后 Python 出现严重兼容性问题
  3. 放弃FastDFS,拥抱MinIO的7大理由
  4. Unity3D之塔防游戏的制作(一)
  5. valgrind 内存泄漏分析
  6. Observer Node [SBN-READ] 原理及实现分析
  7. 实体零售,为什么干不过电商?
  8. VBA的3种错误处理方式 on error goto 0 /-1 , on error resume next , on error goto index,是抛出异常,还是忽略报错,还是进行错误捕捉?
  9. mysql的ace什么概念,饭圈ace是什么意思 全能ace多用于团体详细含义揭秘
  10. python引用turtle画烟花_代码也浪漫:用Python放一场烟花秀!