博客列表 >laravel 商城支付宝支付对接

laravel 商城支付宝支付对接

我是郭富城
我是郭富城原创
2020年07月07日 13:28:071556浏览

1. 功能演示

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

2. 支付宝官方设置

2.1 开通对应的支付功能

2.2 获取支付宝公钥和商户私钥

https://openhome.alipay.com/dev/workspace/key-manage

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 alipay(Request $request) {
  63. $alipay_path = __DIR__ . '/../../../vendor/alipay/';
  64. require_once $alipay_path.'config.php';
  65. require_once $alipay_path.'pagepay/service/AlipayTradeService.php';
  66. require_once $alipay_path.'pagepay/buildermodel/AlipayTradePagePayContentBuilder.php';
  67. $ord_no = $request->ord_no;
  68. //商户订单号,商户网站订单系统中唯一订单号,必填
  69. $out_trade_no = $ord_no;
  70. //订单名称,必填
  71. $subject = '支付宝测试商品名称';
  72. //付款金额,必填
  73. $total_amount = '1';
  74. //商品描述,可空
  75. $body = '测试商品描述';
  76. //构造参数
  77. $payRequestBuilder = new \AlipayTradePagePayContentBuilder();
  78. $payRequestBuilder->setBody($body);
  79. $payRequestBuilder->setSubject($subject);
  80. $payRequestBuilder->setTotalAmount($total_amount);
  81. $payRequestBuilder->setOutTradeNo($out_trade_no);
  82. $aop = new \AlipayTradeService($config);
  83. /**
  84. * pagePay 电脑网站支付请求
  85. * @param $builder 业务参数,使用buildmodel中的对象生成。
  86. * @param $return_url 同步跳转地址,公网可以访问
  87. * @param $notify_url 异步通知地址,公网可以访问
  88. * @return $response 支付宝返回的信息
  89. */
  90. $response = $aop->pagePay($payRequestBuilder,$config['return_url'],$config['notify_url']);
  91. //输出表单
  92. var_dump($response);
  93. }
  94. // 支付(微信支付)
  95. public function pay(Request $request) {
  96. // 生成二维码
  97. // echo __DIR__;
  98. // D:\laravel\app\Http\Controllers
  99. // exit;
  100. $wx_pay_path = __DIR__ . '/../../../vendor/wx_pay/';
  101. require_once $wx_pay_path . "lib/WxPay.Api.php";
  102. require_once $wx_pay_path . "example/WxPay.NativePay.php";
  103. // require_once 'log.php';
  104. $notify = new \NativePay();
  105. $input = new \WxPayUnifiedOrder();
  106. // 获取订单号
  107. $ord_no = $request->ord_no;
  108. $input->SetBody("test");
  109. $input->SetAttach("test");
  110. $input->SetOut_trade_no($ord_no);
  111. $input->SetTotal_fee("1");
  112. $input->SetTime_start(date("YmdHis"));
  113. $input->SetTime_expire(date("YmdHis", time() + 600));
  114. $input->SetGoods_tag("test");
  115. $input->SetNotify_url("http://pay.aoebbs.cn/shop/notify");
  116. $input->SetTrade_type("NATIVE");
  117. $input->SetProduct_id("123456789");
  118. $result = $notify->GetPayUrl($input);
  119. $data['url2'] = $result["code_url"];
  120. $data['ord_no'] = $ord_no;
  121. // echo '<pre>';
  122. // var_dump($result);
  123. return view('shop/pay',$data);
  124. }
  125. public function creatqrcode() {
  126. $wx_pay_path = __DIR__ . '/../../../vendor/wx_pay/';
  127. require_once $wx_pay_path . 'example/phpqrcode/phpqrcode.php';
  128. $url = urldecode($_GET["data"]);
  129. if(substr($url, 0, 6) == "weixin"){
  130. \QRcode::png($url);
  131. }else{
  132. header('HTTP/1.1 404 Not Found');
  133. }
  134. }
  135. // 异步通知
  136. public function notify() {
  137. // $xml = "aaaa";
  138. $xml = file_get_contents('php://input');
  139. $obj = simplexml_load_string($xml,"SimpleXMLElement", LIBXML_NOCDATA);
  140. $arr = json_decode(json_encode($obj),true);
  141. // 检查订单是否已付款
  142. $order = DB::table('orders')->where('ord_no',$arr['out_trade_no'])->item();
  143. if (!$order) {
  144. return '<xml>
  145. <return_code><![CDATA[SUCCESS]]></return_code>
  146. <return_msg><![CDATA[OK]]></return_msg>
  147. </xml>';
  148. }
  149. // 订单已经付款
  150. if ($order['status'] === 1) {
  151. return '<xml>
  152. <return_code><![CDATA[SUCCESS]]></return_code>
  153. <return_msg><![CDATA[OK]]></return_msg>
  154. </xml>';
  155. }
  156. // 订单未付款
  157. if ($order['status'] === 0) {
  158. // 设置订单支付状态为已支付
  159. DB::table('orders')->where('ord_no',$arr['out_trade_no'])->update(['status'=>1]);
  160. DB::table('orders')->where('ord_no',$arr['out_trade_no'])->update(['trance_id'=>$arr['transaction_id']]);
  161. return '<xml>
  162. <return_code><![CDATA[SUCCESS]]></return_code>
  163. <return_msg><![CDATA[OK]]></return_msg>
  164. </xml>';
  165. }
  166. file_put_contents('xml.txt', $xml);
  167. }
  168. // 支付宝异步通知
  169. public function alipay_notify() {
  170. $trade_no = $_POST['trade_no']; //支付宝交易号
  171. $out_trade_no = $_POST['out_trade_no']; //商户订单号
  172. $TRADE_SUCCESS = isset($_POST['TRADE_SUCCESS'])?$_POST['TRADE_SUCCESS']:'';
  173. // 检查订单是否已付款
  174. $order = DB::table('orders')->where('ord_no',$out_trade_no)->item();
  175. if (!$order) {
  176. return 'success';
  177. }
  178. // 订单已经付款
  179. if ($order['status'] === 1) {
  180. return 'success';
  181. }
  182. // 订单未付款
  183. if ($order['status'] === 0) {
  184. // 设置订单支付状态为已支付
  185. DB::table('orders')->where('ord_no',$out_trade_no)->update(['status'=>1]);
  186. DB::table('orders')->where('ord_no',$out_trade_no)->update(['trance_id'=>$trade_no]);
  187. return 'success';
  188. }
  189. }
  190. // 检查订单支付状态
  191. public function check_order_status(Request $request) {
  192. $ord_no = $request->ord_no;
  193. $order = DB::table('orders')->where('ord_no',$ord_no)->item();
  194. if ($order['status'] >= 1) {
  195. # code...
  196. exit(json_encode(['code'=>0,'msg'=>'支付成功']));
  197. }
  198. exit(json_encode(['code'=>1,'msg'=>'not pay']));
  199. }
  200. // 选择支付方式
  201. public function selectpay(Request $request) {
  202. $data['ord_no'] = $request->ord_no;
  203. return view('shop/selectpay',$data);
  204. }
  205. }

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');//检查订单支付状态
  10. Route::get('/shop/alipay','Shop@alipay')->middleware('automember');//支付宝支付
  11. Route::post('/shop/alipay_notify','Shop@alipay_notify');//支付宝异步通知
  12. Route::get('/shop/selectpay','Shop@selectpay')->middleware('automember');//选择支付方式

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. // 选择何种支付方式
  226. layer.open({
  227. type: 2,
  228. title: '选择付款方式',
  229. shadeClose: true,
  230. shade: 0.2,
  231. area: ['400px', '300px'],
  232. content: '/shop/selectpay?ord_no='+ res.ord_no //iframe的url
  233. });
  234. // 跳转到支付宝
  235. // window.location.href="/shop/alipay?ord_no=" + res.ord_no;
  236. // 下面是微信的哦
  237. // layer.msg(res.msg);
  238. // layer.open({
  239. // type: 2,
  240. // title: '付款二维码',
  241. // shadeClose: true,
  242. // shade: 0.2,
  243. // area: ['400px', '300px'],
  244. // content: '/shop/pay?ord_no='+res.ord_no //iframe的url
  245. // });
  246. },'json');
  247. }
  248. </script>

6. 付款方式选择页面

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <link rel="stylesheet" href="/static/plugins/layui/css/layui.css">
  6. <script src="/static/plugins/layui/layui.js"></script>
  7. <title>支付方式选择</title>
  8. <style>
  9. body {
  10. height: 80vh;
  11. display: flex;
  12. flex-flow: row nowrap;
  13. justify-content: center;
  14. align-items: center;
  15. }
  16. </style>
  17. </head>
  18. <body>
  19. <button type="button" class="layui-btn" onclick="wxpay()">微信支付</button>
  20. <button type="button" class="layui-btn layui-btn-normal" onclick="alipay()">支付宝支付</button>
  21. </body>
  22. </html>
  23. <script>
  24. // 微信支付
  25. function wxpay() {
  26. window.location.href="/shop/pay?ord_no=" + {{$ord_no}};
  27. }
  28. // <!-- 支付宝支付 -->
  29. function alipay() {
  30. window.open("/shop/alipay?ord_no=" + {{$ord_no}});
  31. }
  32. </script>

7. 效果图

8. 修改冲突

  1. Cannot redeclare Encrypt() (previously declared in .../vendor/laravel/lumen-framework/src/helpers.php:126)
  2. //或:
  3. Cannot redeclare Decrypt() (previously declared in .../vendor/laravel/lumen-framework/src/helpers.php:126)

这是因为Laravel 5使用Alipay SDK时,Laravel内带的加密解密函数Encrypt()/Decrypt()函数和Alipay SDK中的加密解密函数Encrypt()/Decrypt()函数命名冲突

解决方法:只需修改Alipay SDK中定义的函数名称,修改引用的函数名称。

9. 总结

虽然官方的说明已经够详细了,但是真正入手去做还是有很多坑,此次对接过程中学习很多,其中尤其要注意的是因为官方的关系。

声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议