Blogger Information
Blog 62
fans 7
comment 2
visits 58201
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
laravel 商城微信支付对接
我是郭富城
Original
1357 people have browsed it

1. 功能演示

http://pay.aoebbs.cn/shop/detail?proid=1

2. 微信官方设置

2.1 微信支付,开通对应的支付功能


2.2 微信公众号添加ip白名单

3. 商城控制器源码

  1. <?php
  2. namespace App\Http\Controllers;
  3. use Illuminate\Http\Request;
  4. use Illuminate\Support\Facades\DB;
  5. use Illuminate\Support\Facades\Auth;
  6. class Shop extends Controller
  7. {
  8. //商城首页
  9. public function index() {
  10. $member = Auth::guard('member')->user();
  11. $data['member'] = $member;
  12. $data['lists'] = DB::table('product')->where('status',1)->lists();
  13. return view('shop/index',$data);
  14. }
  15. // 商城列表页
  16. public function lists() {
  17. return view('shop/lists');
  18. }
  19. // 商城详情页
  20. public function detail(Request $request) {
  21. $member = Auth::guard('member')->user();
  22. // echo '<pre>';
  23. // var_dump($member);
  24. // exit();
  25. $proid=(int)$request->proid;
  26. $data['item'] = DB::table('product')->where('id',$proid)->item();
  27. $data['detail'] = DB::table('product_detail')->where('proid',$proid)->item();
  28. $data['member'] = $member;
  29. if(!$data['item']) {
  30. return view('shop/page404');
  31. }
  32. return view('shop/detail',$data);
  33. }
  34. // 用户下单
  35. public function create_order(Request $request) {
  36. $member = Auth::guard('member')->user();
  37. $pro_id = (int)$request->pro_id;
  38. $product = DB::table('product')->where('id',$pro_id)->where('status',1)->item();
  39. if (!$product) {
  40. exit(json_encode(['code'=>1,'msg'=>'该商品不存在或未上架']));
  41. }
  42. if ($product['stock'] <= 0) {
  43. exit(json_encode(['code'=>1,'msg'=>'库存不足']));
  44. }
  45. if ($product['stock'] < (int)$request->buy_count) {
  46. exit(json_encode(['code'=>1,'msg'=>'库存不足']));
  47. }
  48. // 确定用户是否已经登录,自定义登录验证中间件
  49. $data['ord_no'] = time().$member->id.rand(1,555); //订单号
  50. $data['member_id'] = (int)$member->id; //交易商品id
  51. $data['pro_id'] = $pro_id; //交易商品id
  52. $data['count'] = (int)$request->buy_count; //数量
  53. $data['money'] = $request->buy_count * $product['price']; //金额
  54. $data['add_time'] = time(); //交易时间
  55. // 添加订单信息
  56. DB::table('orders')->insert($data);
  57. // 减库存
  58. DB::table('product')->where('id',$pro_id)->decrement('stock',$request->buy_count);
  59. exit(json_encode(['code'=>0,'msg'=>'下单成功','ord_no'=>$data['ord_no']]));
  60. }
  61. // 支付
  62. public function pay(Request $request) {
  63. // 生成二维码
  64. // echo __DIR__;
  65. // D:\laravel\app\Http\Controllers
  66. // exit;
  67. $wx_pay_path = __DIR__ . '/../../../vendor/wx_pay/';
  68. require_once $wx_pay_path . "lib/WxPay.Api.php";
  69. require_once $wx_pay_path . "example/WxPay.NativePay.php";
  70. // require_once 'log.php';
  71. $notify = new \NativePay();
  72. $input = new \WxPayUnifiedOrder();
  73. // 获取订单号
  74. $ord_no = $request->ord_no;
  75. $input->SetBody("test");
  76. $input->SetAttach("test");
  77. $input->SetOut_trade_no($ord_no);
  78. $input->SetTotal_fee("1");
  79. $input->SetTime_start(date("YmdHis"));
  80. $input->SetTime_expire(date("YmdHis", time() + 600));
  81. $input->SetGoods_tag("test");
  82. $input->SetNotify_url("http://pay.aoebbs.cn/shop/notify");
  83. $input->SetTrade_type("NATIVE");
  84. $input->SetProduct_id("123456789");
  85. $result = $notify->GetPayUrl($input);
  86. $data['url2'] = $result["code_url"];
  87. $data['ord_no'] = $ord_no;
  88. // echo '<pre>';
  89. // var_dump($result);
  90. return view('shop/pay',$data);
  91. }
  92. public function creatqrcode() {
  93. $wx_pay_path = __DIR__ . '/../../../vendor/wx_pay/';
  94. require_once $wx_pay_path . 'example/phpqrcode/phpqrcode.php';
  95. $url = urldecode($_GET["data"]);
  96. if(substr($url, 0, 6) == "weixin"){
  97. \QRcode::png($url);
  98. }else{
  99. header('HTTP/1.1 404 Not Found');
  100. }
  101. }
  102. // 异步通知
  103. public function notify() {
  104. // $xml = "aaaa";
  105. $xml = file_get_contents('php://input');
  106. $obj = simplexml_load_string($xml,"SimpleXMLElement", LIBXML_NOCDATA);
  107. $arr = json_decode(json_encode($obj),true);
  108. // 检查订单是否已付款
  109. $order = DB::table('orders')->where('ord_no',$arr['out_trade_no'])->item();
  110. if (!$order) {
  111. return '<xml>
  112. <return_code><![CDATA[SUCCESS]]></return_code>
  113. <return_msg><![CDATA[OK]]></return_msg>
  114. </xml>';
  115. }
  116. // 订单已经付款
  117. if ($order['status'] === 1) {
  118. return '<xml>
  119. <return_code><![CDATA[SUCCESS]]></return_code>
  120. <return_msg><![CDATA[OK]]></return_msg>
  121. </xml>';
  122. }
  123. // 订单未付款
  124. if ($order['status'] === 0) {
  125. // 设置订单支付状态为已支付
  126. DB::table('orders')->where('ord_no',$arr['out_trade_no'])->update(['status'=>1]);
  127. DB::table('orders')->where('ord_no',$arr['out_trade_no'])->update(['trance_id'=>$arr['transaction_id']]);
  128. return '<xml>
  129. <return_code><![CDATA[SUCCESS]]></return_code>
  130. <return_msg><![CDATA[OK]]></return_msg>
  131. </xml>';
  132. }
  133. file_put_contents('xml.txt', $xml);
  134. }
  135. // 检查订单支付状态
  136. public function check_order_status(Request $request) {
  137. $ord_no = $request->ord_no;
  138. $order = DB::table('orders')->where('ord_no',$ord_no)->item();
  139. if ($order['status'] >= 1) {
  140. # code...
  141. exit(json_encode(['code'=>0,'msg'=>'支付成功']));
  142. }
  143. exit(json_encode(['code'=>1,'msg'=>'not pay']));
  144. }
  145. }

4. 商城路由

  1. // 商城
  2. Route::get('/shop/index','Shop@index');//商城首页
  3. Route::get('/shop/lists','Shop@lists');//商城列表
  4. Route::get('/shop/detail','Shop@detail');//商品详情
  5. Route::post('/shop/create_order','Shop@create_order')->middleware('automember');//商城订单
  6. Route::get('/shop/pay','Shop@pay')->middleware('automember');//商品微信付款二维码
  7. Route::get('/shop/creatqrcode','Shop@creatqrcode');//生成二维码
  8. Route::post('/shop/notify','Shop@notify');//微信异步通知
  9. Route::get('/shop/check_order_status','Shop@check_order_status');//检查订单支付状态

5. 商城详情页

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <!-- 当前文档要用到阿里字体图标-->
  6. <link rel="stylesheet" href="/static/font/iconfont.css">
  7. <link rel="stylesheet" href="/static/css/shop_detail.css">
  8. <link rel="stylesheet" href="/static/plugins/layui/css/layui.css">
  9. <script src="/static/plugins/layui/layui.js"></script>
  10. <title>{{$item['title']}}</title>
  11. </head>
  12. <body>
  13. @include('shop/public/header')
  14. <!--主体全部放在main元素中-->
  15. <main>
  16. <!-- 商城公共头部-->
  17. @include('shop/public/header_search')
  18. <!--为商品详情区块单独创建一个包含块,方便用网格布局-->
  19. <div class="detail">
  20. @csrf
  21. <!--商城详情页上部购买组件-->
  22. <div class="shop-detail-bug">
  23. <!--头部面包屑导航-->
  24. <nav>
  25. <a href="">首页&nbsp;&gt;&nbsp;</a>
  26. <a href="">图片写真&nbsp;&gt;&nbsp;</a>
  27. <a href="">日本&nbsp;&gt;&nbsp;</a>
  28. <a href="">颖宝宝</a>
  29. </nav>
  30. <article>
  31. <input type="hidden" name="pro_id" value="{{$item['id']}}">
  32. <!-- <input type="hidden" name="price" value="{{$item['price']}}"> -->
  33. <span><img src="{{$item['thumb']}}" alt=""></span>
  34. <div>
  35. <!--商品标题-->
  36. <h3>{{$item['title']}}</h3>
  37. <!--商品价格-->
  38. <div class="price">
  39. <span>本站特惠:</span>
  40. <span>&yen;{{$item['price']}}</span>
  41. </div>
  42. <!--基本描述-->
  43. <div class="desc">
  44. 销量: <span>13</span>&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;
  45. 累积评价: <span>3</span>&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;
  46. 好评率: <span>199%</span>
  47. </div>
  48. <!-- 购买数量-->
  49. <div class="buy-num">
  50. <label for="num">购买数量:</label><input type="number" id="num" value="1">
  51. </div>
  52. <!--购买按钮-->
  53. <div class="buy-btn">
  54. <button onclick="buy()">立即购买</button>
  55. <button><i class="iconfont icon-icon_tianjia"></i>加入购物车</button>
  56. </div>
  57. <!--售后承诺-->
  58. <div class="promise">
  59. <span><i class="iconfont icon-zhanghaoquanxianguanli"></i>本站保障</span>
  60. <span><i class="iconfont icon-icon_safety"></i>企业认证</span>
  61. <span><i class="iconfont icon-tianshenpi"></i>退款承诺</span>
  62. <span><i class="iconfont icon-kuaisubianpai"></i>免费换货</span>
  63. </div>
  64. </div>
  65. </article>
  66. </div>
  67. <!--商城详情页左下推荐商品列表-->
  68. <div class="shop-detail-recommend">
  69. <h3>推荐商品</h3>
  70. <div>
  71. <a href="">
  72. <img src="/static/images/shop/shop1.jpg" alt="">
  73. </a>
  74. <a href="">韩国美女最新海报促销美妆写真图集</a>
  75. <div class="hot">
  76. <span>热销:</span><span>8976</span>
  77. <span>价格:</span><span>&yen;99</span>
  78. </div>
  79. </div>
  80. <div>
  81. <a href="">
  82. <img src="/static/images/shop/shop2.jpg" alt="">
  83. </a>
  84. <a href="">韩国美女最新海报促销美妆写真图集</a>
  85. <div class="hot">
  86. <span>热销:</span><span>324</span>
  87. <span>价格:</span><span>&yen;798</span>
  88. </div>
  89. </div>
  90. <div>
  91. <a href="">
  92. <img src="/static/images/shop/shop3.jpg" alt="">
  93. </a>
  94. <a href="">韩国美女最新海报促销美妆写真图集</a>
  95. <div class="hot">
  96. <span>热销:</span><span>678</span>
  97. <span>价格:</span><span>&yen;630</span>
  98. </div>
  99. </div>
  100. <div>
  101. <a href="">
  102. <img src="/static/images/shop/shop4.jpg" alt="">
  103. </a>
  104. <a href="">韩国美女最新海报促销美妆写真图集</a>
  105. <div class="hot">
  106. <span>热销:</span><span>12</span>
  107. <span>价格:</span><span>&yen;980</span>
  108. </div>
  109. </div>
  110. </div>
  111. <!--商城详情页右下详情选项卡-->
  112. <div class="shop-detail-tab">
  113. <div class="tab">
  114. <span class="active">商品详情</span>
  115. <span>案例/演示</span>
  116. <span>常见问题</span>
  117. <span>累计评价</span>
  118. <span>产品咨询</span>
  119. </div>
  120. <div class="content">
  121. {!!$detail['contents']!!}
  122. </div>
  123. </div>
  124. <!--评论与回复-->
  125. <div class="public-comment-reply">
  126. <!-- 评论区-->
  127. <div class="comment">
  128. <h3>我要评论</h3>
  129. <div>
  130. <label for="comment"><img src="/static/images/user.png" alt=""></label>
  131. <textarea name="" id="comment"></textarea>
  132. </div>
  133. <button>发表评论</button>
  134. </div>
  135. <!-- 回复区-->
  136. <div class="reply">
  137. <h3>最新回复</h3>
  138. <div>
  139. <img src="/static/images/user.png" alt="">
  140. <div class="detail">
  141. <span>用户昵称</span>
  142. <span>留言内容: php中文网,是一个有温度,有思想的学习平台</span>
  143. <div>
  144. <span>2019-12-12 15:34:23发表</span>
  145. <span><i class="iconfont icon-dianzan"></i>回复</span>
  146. </div>
  147. </div>
  148. </div>
  149. <div>
  150. <img src="/static/images/user.png" alt="">
  151. <div class="detail">
  152. <span>用户昵称</span>
  153. <span>留言内容: php中文网,是一个有温度,有思想的学习平台</span>
  154. <div>
  155. <span>2019-12-12 15:34:23发表</span>
  156. <span><i class="iconfont icon-dianzan"></i>回复</span>
  157. </div>
  158. </div>
  159. </div>
  160. <div>
  161. <img src="/static/images/user.png" alt="">
  162. <div class="detail">
  163. <span>用户昵称</span>
  164. <span>留言内容: php中文网,是一个有温度,有思想的学习平台</span>
  165. <div>
  166. <span>2019-12-12 15:34:23发表</span>
  167. <span><i class="iconfont icon-dianzan"></i>回复</span>
  168. </div>
  169. </div>
  170. </div>
  171. <div>
  172. <img src="/static/images/user.png" alt="">
  173. <div class="detail">
  174. <span>用户昵称</span>
  175. <span>留言内容: php中文网,是一个有温度,有思想的学习平台</span>
  176. <div>
  177. <span>2019-12-12 15:34:23发表</span>
  178. <span><i class="iconfont icon-dianzan"></i>回复</span>
  179. </div>
  180. </div>
  181. </div>
  182. </div>
  183. </div>
  184. </div>
  185. </main>
  186. <!--公共页脚-->
  187. @include('shop/public/footer')
  188. </body>
  189. </html>
  190. <script>
  191. layui.use('layer', function(){
  192. $ = layui.jquery;
  193. var layer = layui.layer;
  194. });
  195. // 购买
  196. function buy() {
  197. var pro_id = parseInt($('input[name="pro_id"]').val());
  198. var buy_count = parseInt($('#num').val());
  199. if (isNaN(pro_id) || pro_id === 0) {
  200. return layer.alert('商品参数错误',{icon:2});
  201. }
  202. if (isNaN(buy_count) || buy_count === 0) {
  203. return layer.alert('购买数量错误',{icon:2});
  204. }
  205. // 下订单
  206. var _token = $('input[name="_token"]').val();
  207. // var price = $('input[name="price"]').val();
  208. $.post('/shop/create_order',{pro_id:pro_id,_token:_token,buy_count:buy_count},function (res) {
  209. // 未登录
  210. if (res.code === 401) {
  211. //iframe层
  212. layer.open({
  213. type: 2,
  214. title: '用户登录',
  215. shadeClose: true,
  216. shade: 0.8,
  217. area: ['400px', '300px'],
  218. content: '/account/login' //iframe的url
  219. });
  220. return;
  221. }
  222. if (res.code > 0) {
  223. return layer.alert(res.msg,{icon:2});
  224. }
  225. layer.msg(res.msg);
  226. layer.open({
  227. type: 2,
  228. title: '付款二维码',
  229. shadeClose: true,
  230. shade: 0.2,
  231. area: ['400px', '300px'],
  232. content: '/shop/pay?ord_no='+res.ord_no //iframe的url
  233. });
  234. },'json');
  235. }
  236. </script>

6. 前端付款二维码

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>微信支付二维码</title>
  6. <link rel="stylesheet" href="/static/plugins/layui/css/layui.css">
  7. <link rel="stylesheet" href="/static/css/index.css">
  8. <script src="/static/plugins/layui/layui.js"></script>
  9. </head>
  10. <body>
  11. <input type="hidden" name="ord_no" value="{{$ord_no}}">
  12. <div class="wx_pay">
  13. <img alt="扫码支付" src="/shop/creatqrcode?data=<?php echo urlencode($url2);?>" />
  14. </div>
  15. </body>
  16. </html>
  17. <script>
  18. layui.use(['layer'],function(){
  19. var layer = layui.layer;
  20. $ = layui.jquery;
  21. // 检查订单状态,定时器
  22. setInterval(function(){
  23. check_order_status();
  24. },2000);
  25. });
  26. function check_order_status() {
  27. var ord_no = $('input[name="ord_no"]').val();
  28. $.get('/shop/check_order_status',{ord_no:ord_no},function(res) {
  29. if (res.code > 0) {
  30. return;
  31. }
  32. layer.msg(res.msg);
  33. setTimeout(function(){
  34. parent.window.location.reload();
  35. },1500);
  36. },'json');
  37. }
  38. </script>

7. 效果图


8. 总结

扫码支付,同步回调地址在微信商户平台中设置,异步通知地址在统一下单接口的请求参数中设置;其中扫码支付主要用于电脑端;同步回调地址是作为微信后台跟商户进行页面跳转的渠道,因此同步回调地址是至关重要的,如果不填写,则可能导致支付完成后无法做页面跳转。

Correcting teacher:GuanhuiGuanhui

Correction status:qualified

Teacher's comments:可以,写的不错!
Statement of this Website
The copyright of this blog article belongs to the blogger. Please specify the address when reprinting! If there is any infringement or violation of the law, please contact admin@php.cn Report processing!
All comments Speak rationally on civilized internet, please comply with News Comment Service Agreement
0 comments
Author's latest blog post