欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

laravel--对接微信JsApi支付

程序员文章站 2022-05-25 09:09:49
...

学习总结

" class="reference-link">1.下载微信支付sdk,放在laravel项目中的vendor目录中,并且整理目录中的文件laravel--对接微信JsApi支付

1.1把example文件夹中的以WxPay.开头的文件复制到lib文件夹中

laravel--对接微信JsApi支付

1.2把lib文件夹中的以每个文件中的require_once中的路径去掉,改为当前文件夹下调用

laravel--对接微信JsApi支付

2.更改WxPay.Config.php中的配置信息

  1. <?php
  2. /**
  3. *
  4. * example目录下为简单的支付样例,仅能用于搭建快速体验微信支付使用
  5. * 样例的作用仅限于指导如何使用sdk,在安全上面仅做了简单处理, 复制使用样例代码时请慎重
  6. * 请勿直接直接使用样例对外提供服务
  7. *
  8. **/
  9. require_once "WxPay.Config.Interface.php";
  10. /**
  11. *
  12. * 该类需要业务自己继承, 该类只是作为deamon使用
  13. * 实际部署时,请务必保管自己的商户密钥,证书等
  14. *
  15. */
  16. class WxPayConfig extends WxPayConfigInterface
  17. {
  18. //=======【基本信息设置】=====================================
  19. /**
  20. * TODO: 修改这里配置为您自己申请的商户信息
  21. * 微信公众号信息配置
  22. *
  23. * APPID:绑定支付的APPID(必须配置,开户邮件中可查看)
  24. *
  25. * MCHID:商户号(必须配置,开户邮件中可查看)
  26. *
  27. */
  28. public function GetAppId()
  29. {
  30. return 'AppId';
  31. }
  32. public function GetMerchantId()
  33. {
  34. return '微信支付商户号';
  35. }
  36. //=======【支付相关配置:支付成功回调地址/签名方式】===================================
  37. /**
  38. * TODO:支付回调url
  39. * 签名和验证签名方式, 支持md5和sha256方式
  40. **/
  41. public function GetNotifyUrl()
  42. {
  43. return "";
  44. }
  45. public function GetSignType()
  46. {
  47. return "HMAC-SHA256";
  48. }
  49. //=======【curl代理设置】===================================
  50. /**
  51. * TODO:这里设置代理机器,只有需要代理的时候才设置,不需要代理,请设置为0.0.0.0和0
  52. * 本例程通过curl使用HTTP POST方法,此处可修改代理服务器,
  53. * 默认CURL_PROXY_HOST=0.0.0.0和CURL_PROXY_PORT=0,此时不开启代理(如有需要才设置)
  54. * @var unknown_type
  55. */
  56. public function GetProxy(&$proxyHost, &$proxyPort)
  57. {
  58. $proxyHost = "0.0.0.0";
  59. $proxyPort = 0;
  60. }
  61. //=======【上报信息配置】===================================
  62. /**
  63. * TODO:接口调用上报等级,默认紧错误上报(注意:上报超时间为【1s】,上报无论成败【永不抛出异常】,
  64. * 不会影响接口调用流程),开启上报之后,方便微信监控请求调用的质量,建议至少
  65. * 开启错误上报。
  66. * 上报等级,0.关闭上报; 1.仅错误出错上报; 2.全量上报
  67. * @var int
  68. */
  69. public function GetReportLevenl()
  70. {
  71. return 1;
  72. }
  73. //=======【商户密钥信息-需要业务方继承】===================================
  74. /*
  75. * KEY:商户支付密钥,参考开户邮件设置(必须配置,登录商户平台自行设置), 请妥善保管, 避免密钥泄露
  76. * 设置地址:https://pay.weixin.qq.com/index.php/account/api_cert
  77. *
  78. * APPSECRET:公众帐号secert(仅JSAPI支付的时候需要配置, 登录公众平台,进入开发者中心可设置), 请妥善保管, 避免密钥泄露
  79. * 获取地址:https://mp.weixin.qq.com/advanced/advanced?action=dev&t=advanced/dev&token=2005451881&lang=zh_CN
  80. * @var string
  81. */
  82. public function GetKey()
  83. {
  84. return '商户支付密钥';
  85. }
  86. public function GetAppSecret()
  87. {
  88. return 'AppSecert';
  89. }
  90. //=======【证书路径设置-需要业务方继承】=====================================
  91. /**
  92. * TODO:设置商户证书路径
  93. * 证书路径,注意应该填写绝对路径(仅退款、撤销订单时需要,可登录商户平台下载,
  94. * API证书下载地址:https://pay.weixin.qq.com/index.php/account/api_cert,下载之前需要安装商户操作证书)
  95. * 注意:
  96. * 1.证书文件不能放在web服务器虚拟目录,应放在有访问权限控制的目录中,防止被他人下载;
  97. * 2.建议将证书文件名改为复杂且不容易猜测的文件名;
  98. * 3.商户服务器要做好病毒和木马防护工作,不被非法侵入者窃取证书文件。
  99. * @var path
  100. */
  101. public function GetSSLCertPath(&$sslCertPath, &$sslKeyPath)
  102. {
  103. $sslCertPath = '../cert/apiclient_cert.pem';
  104. $sslKeyPath = '../cert/apiclient_key.pem';
  105. }
  106. }

2.1AppIdAppSecert是微信公众号(服务号)申请时的,申请的微信公众号必须已经通过微信认证。

laravel--对接微信JsApi支付

2.2微信支付商户号商户密钥是在微信支付的官方申请的商户号,申请后会有一个商户密钥

laravel--对接微信JsApi支付
laravel--对接微信JsApi支付

2.3在微信支付中关联公众号

laravel--对接微信JsApi支付

2.4在微信公众号中设置接口权限,登录公众号,开发—接口权限—功能服务—网页授权

laravel--对接微信JsApi支付

2.5在接口域名处填写微信支付发起的域名

laravel--对接微信JsApi支付

3.微信支付控制器源码Pay.php

  • 注意:前期vendor中sdk文件夹下的目录调整,就是方便引用的时候目录的一致性,包含后调起支付时所用到的类前必须加 \ 代表当前文件下的类。
  1. <?php
  2. namespace App\Http\Controllers\homes;
  3. use App\Http\Controllers\Controller;
  4. use Exception;
  5. //手动验证用户名和密码
  6. use Illuminate\Support\Facades\Auth;
  7. use Illuminate\Http\Request;
  8. //引入数据库查询构造器,链式调用
  9. use Illuminate\Support\Facades\DB;
  10. //引入redis
  11. use Illuminate\Support\Facades\Redis;
  12. //用户支付控制器
  13. class Pay extends Controller
  14. {
  15. public function wxPay()
  16. {
  17. $dir = __DIR__.'\../../../../vendor/wxPay_sdk_v3.0.10/lib/';
  18. require_once $dir."WxPay.Api.php";
  19. require_once $dir."WxPay.JsApiPay.php";
  20. require_once $dir."WxPay.Config.php";
  21. //①、获取用户openid
  22. try{
  23. //计算总金额
  24. //通过Auth的自定义guard(门卫)获取当前用户登录id
  25. $memberID = Auth::guard('member')->id();
  26. //然后读取redis中该用户的所有点菜数据
  27. $orderData =json_decode(Redis::get('order'.$memberID),true);
  28. $res = [];
  29. $res['priceTotal'] = 0;
  30. if(is_array($orderData))
  31. {
  32. foreach($orderData as $key => $ordData)
  33. {
  34. $num =(int)$ordData['num'];
  35. $prices =json_decode($ordData['dish']['price'],true);
  36. $orderData[$key]['price'] = $prices[$ordData['priceKey']];
  37. $units = json_decode($ordData['dish']['unit'],true);
  38. $orderData[$key]['unit'] = $units[$ordData['priceKey']];
  39. $res['priceTotal']+=(float)$prices[$ordData['priceKey']]*$num;
  40. }
  41. }
  42. //调起微信支付jsApi接口
  43. $tools = new \JsApiPay();
  44. $openId = $tools->GetOpenid();
  45. //②、统一下单
  46. $input = new \WxPayUnifiedOrder();
  47. $input->SetBody("test");
  48. $input->SetAttach("test");
  49. $input->SetOut_trade_no("sdkphp".date("YmdHis"));
  50. $input->SetTotal_fee((string)($res['priceTotal']*100));
  51. $input->SetTime_start(date("YmdHis"));
  52. $input->SetTime_expire(date("YmdHis", time() + 600));
  53. $input->SetGoods_tag("test");
  54. $input->SetNotify_url("支付成功回调地址");
  55. $input->SetTrade_type("JSAPI");
  56. $input->SetOpenid($openId);
  57. $config = new \WxPayConfig();
  58. $order = \WxPayApi::unifiedOrder($config, $input);
  59. echo '<font color="#f00"><b>统一下单支付单信息</b></font><br/>';
  60. // $this->printf_info($order);
  61. $res['jsApiParameters'] = $tools->GetJsApiParameters($order);
  62. //获取共享收货地址js函数参数
  63. $res['editAddress'] = $tools->GetEditAddressParameters();
  64. return view('/homes/pay/wxPay',$res);
  65. }
  66. catch(Exception $e)
  67. {
  68. echo $e;
  69. exit;
  70. // Log::ERROR(json_encode($e));
  71. }
  72. }
  73. //打印输出数组信息
  74. public function printf_info($data)
  75. {
  76. foreach($data as $key=>$value){
  77. echo "<font color='#00ff55;'>$key</font> : ".htmlspecialchars($value, ENT_QUOTES)." <br/>";
  78. }
  79. }
  80. public function wxPayCallBack()
  81. {
  82. echo 'wxsuccsss';
  83. }
  84. }

4.视图页源码wxPay.blade.php

  • 注意:控制器传来的数据jsApiParameterseditAddress是json数据,必须解析后使用,否则无法调起支付
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  7. <link rel="stylesheet" href="/static/plugins/layui/css/layui.css">
  8. <script src="/static/plugins/layui/layui.js"></script>
  9. <title>微信支付</title>
  10. <script type="text/javascript">
  11. layui.use(['layer'],function(){
  12. $ = layui.jquery;
  13. });
  14. //调用微信JS api 支付
  15. function jsApiCall()
  16. {
  17. var jsApiPar =JSON.parse($('input[name="jsApiPar"]').val());
  18. WeixinJSBridge.invoke(
  19. 'getBrandWCPayRequest',
  20. jsApiPar,
  21. function(res){
  22. WeixinJSBridge.log(res.err_msg);
  23. alert(res.err_code+res.err_desc+res.err_msg);
  24. }
  25. );
  26. }
  27. function callpay()
  28. {
  29. if (typeof WeixinJSBridge == "undefined"){
  30. if( document.addEventListener ){
  31. document.addEventListener('WeixinJSBridgeReady', jsApiCall, false);
  32. }else if (document.attachEvent){
  33. document.attachEvent('WeixinJSBridgeReady', jsApiCall);
  34. document.attachEvent('onWeixinJSBridgeReady', jsApiCall);
  35. }
  36. }else{
  37. jsApiCall();
  38. }
  39. }
  40. </script>
  41. <script type="text/javascript">
  42. //获取共享地址
  43. function editAddress()
  44. {
  45. var editAdd =JSON.parse($('input[name="editAdd"]').val());
  46. WeixinJSBridge.invoke(
  47. 'editAddress',
  48. editAdd,
  49. function(res){
  50. $('div[name="test"]').text(JSON.parse(res));
  51. var value1 = res.proviceFirstStageName;
  52. var value2 = res.addressCitySecondStageName;
  53. var value3 = res.addressCountiesThirdStageName;
  54. var value4 = res.addressDetailInfo;
  55. var tel = res.telNumber;
  56. alert(value1 + value2 + value3 + value4 + ":" + tel);
  57. }
  58. );
  59. }
  60. window.onload = function(){
  61. if (typeof WeixinJSBridge == "undefined"){
  62. if( document.addEventListener ){
  63. document.addEventListener('WeixinJSBridgeReady', editAddress, false);
  64. }else if (document.attachEvent){
  65. document.attachEvent('WeixinJSBridgeReady', editAddress);
  66. document.attachEvent('onWeixinJSBridgeReady', editAddress);
  67. }
  68. }else{
  69. editAddress();
  70. }
  71. };
  72. </script>
  73. </head>
  74. <body>
  75. <br/>
  76. <font color="#9ACD32"><b>该笔订单支付金额为<span style="color:#f00;font-size:50px">{{$priceTotal}}</span></b></font><br/><br/>
  77. <div align="center">
  78. <button style="width:210px; height:50px; border-radius: 15px;background-color:#FE6714; border:0px #FE6714 solid; cursor: pointer; color:white; font-size:16px;" type="button" onclick="callpay()" >立即支付</button>
  79. <input type="hidden" name="jsApiPar" value="{{$jsApiParameters}}">
  80. <input type="hidden" name="editAdd" value="{{$editAddress}}">
  81. </div>
  82. </body>
  83. </html>