1. 功能演示
http://pay.aoebbs.cn/shop/detail?proid=1
2. 支付宝官方设置
2.1 开通对应的支付功能
2.2 获取支付宝公钥和商户私钥
https://openhome.alipay.com/dev/workspace/key-manage
3. 商城控制器源码
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth;
class Shop extends Controller
{
//商城首页
public function index() {
$member = Auth::guard('member')->user();
$data['member'] = $member;
$data['lists'] = DB::table('product')->where('status',1)->lists();
return view('shop/index',$data);
}
// 商城列表页
public function lists() {
return view('shop/lists');
}
// 商城详情页
public function detail(Request $request) {
$member = Auth::guard('member')->user();
// echo '<pre>';
// var_dump($member);
// exit();
$proid=(int)$request->proid;
$data['item'] = DB::table('product')->where('id',$proid)->item();
$data['detail'] = DB::table('product_detail')->where('proid',$proid)->item();
$data['member'] = $member;
if(!$data['item']) {
return view('shop/page404');
}
return view('shop/detail',$data);
}
// 用户下单(微信下单)
public function create_order(Request $request) {
$member = Auth::guard('member')->user();
$pro_id = (int)$request->pro_id;
$product = DB::table('product')->where('id',$pro_id)->where('status',1)->item();
if (!$product) {
exit(json_encode(['code'=>1,'msg'=>'该商品不存在或未上架']));
}
if ($product['stock'] <= 0) {
exit(json_encode(['code'=>1,'msg'=>'库存不足']));
}
if ($product['stock'] < (int)$request->buy_count) {
exit(json_encode(['code'=>1,'msg'=>'库存不足']));
}
// 确定用户是否已经登录,自定义登录验证中间件
$data['ord_no'] = time().$member->id.rand(1,555); //订单号
$data['member_id'] = (int)$member->id; //交易商品id
$data['pro_id'] = $pro_id; //交易商品id
$data['count'] = (int)$request->buy_count; //数量
$data['money'] = $request->buy_count * $product['price']; //金额
$data['add_time'] = time(); //交易时间
// 添加订单信息
DB::table('orders')->insert($data);
// 减库存
DB::table('product')->where('id',$pro_id)->decrement('stock',$request->buy_count);
exit(json_encode(['code'=>0,'msg'=>'下单成功','ord_no'=>$data['ord_no']]));
}
// 支付(支付宝支付)
public function alipay(Request $request) {
$alipay_path = __DIR__ . '/../../../vendor/alipay/';
require_once $alipay_path.'config.php';
require_once $alipay_path.'pagepay/service/AlipayTradeService.php';
require_once $alipay_path.'pagepay/buildermodel/AlipayTradePagePayContentBuilder.php';
$ord_no = $request->ord_no;
//商户订单号,商户网站订单系统中唯一订单号,必填
$out_trade_no = $ord_no;
//订单名称,必填
$subject = '支付宝测试商品名称';
//付款金额,必填
$total_amount = '1';
//商品描述,可空
$body = '测试商品描述';
//构造参数
$payRequestBuilder = new \AlipayTradePagePayContentBuilder();
$payRequestBuilder->setBody($body);
$payRequestBuilder->setSubject($subject);
$payRequestBuilder->setTotalAmount($total_amount);
$payRequestBuilder->setOutTradeNo($out_trade_no);
$aop = new \AlipayTradeService($config);
/**
* pagePay 电脑网站支付请求
* @param $builder 业务参数,使用buildmodel中的对象生成。
* @param $return_url 同步跳转地址,公网可以访问
* @param $notify_url 异步通知地址,公网可以访问
* @return $response 支付宝返回的信息
*/
$response = $aop->pagePay($payRequestBuilder,$config['return_url'],$config['notify_url']);
//输出表单
var_dump($response);
}
// 支付(微信支付)
public function pay(Request $request) {
// 生成二维码
// echo __DIR__;
// D:\laravel\app\Http\Controllers
// exit;
$wx_pay_path = __DIR__ . '/../../../vendor/wx_pay/';
require_once $wx_pay_path . "lib/WxPay.Api.php";
require_once $wx_pay_path . "example/WxPay.NativePay.php";
// require_once 'log.php';
$notify = new \NativePay();
$input = new \WxPayUnifiedOrder();
// 获取订单号
$ord_no = $request->ord_no;
$input->SetBody("test");
$input->SetAttach("test");
$input->SetOut_trade_no($ord_no);
$input->SetTotal_fee("1");
$input->SetTime_start(date("YmdHis"));
$input->SetTime_expire(date("YmdHis", time() + 600));
$input->SetGoods_tag("test");
$input->SetNotify_url("http://pay.aoebbs.cn/shop/notify");
$input->SetTrade_type("NATIVE");
$input->SetProduct_id("123456789");
$result = $notify->GetPayUrl($input);
$data['url2'] = $result["code_url"];
$data['ord_no'] = $ord_no;
// echo '<pre>';
// var_dump($result);
return view('shop/pay',$data);
}
public function creatqrcode() {
$wx_pay_path = __DIR__ . '/../../../vendor/wx_pay/';
require_once $wx_pay_path . 'example/phpqrcode/phpqrcode.php';
$url = urldecode($_GET["data"]);
if(substr($url, 0, 6) == "weixin"){
\QRcode::png($url);
}else{
header('HTTP/1.1 404 Not Found');
}
}
// 异步通知
public function notify() {
// $xml = "aaaa";
$xml = file_get_contents('php://input');
$obj = simplexml_load_string($xml,"SimpleXMLElement", LIBXML_NOCDATA);
$arr = json_decode(json_encode($obj),true);
// 检查订单是否已付款
$order = DB::table('orders')->where('ord_no',$arr['out_trade_no'])->item();
if (!$order) {
return '<xml>
<return_code><![CDATA[SUCCESS]]></return_code>
<return_msg><![CDATA[OK]]></return_msg>
</xml>';
}
// 订单已经付款
if ($order['status'] === 1) {
return '<xml>
<return_code><![CDATA[SUCCESS]]></return_code>
<return_msg><![CDATA[OK]]></return_msg>
</xml>';
}
// 订单未付款
if ($order['status'] === 0) {
// 设置订单支付状态为已支付
DB::table('orders')->where('ord_no',$arr['out_trade_no'])->update(['status'=>1]);
DB::table('orders')->where('ord_no',$arr['out_trade_no'])->update(['trance_id'=>$arr['transaction_id']]);
return '<xml>
<return_code><![CDATA[SUCCESS]]></return_code>
<return_msg><![CDATA[OK]]></return_msg>
</xml>';
}
file_put_contents('xml.txt', $xml);
}
// 支付宝异步通知
public function alipay_notify() {
$trade_no = $_POST['trade_no']; //支付宝交易号
$out_trade_no = $_POST['out_trade_no']; //商户订单号
$TRADE_SUCCESS = isset($_POST['TRADE_SUCCESS'])?$_POST['TRADE_SUCCESS']:'';
// 检查订单是否已付款
$order = DB::table('orders')->where('ord_no',$out_trade_no)->item();
if (!$order) {
return 'success';
}
// 订单已经付款
if ($order['status'] === 1) {
return 'success';
}
// 订单未付款
if ($order['status'] === 0) {
// 设置订单支付状态为已支付
DB::table('orders')->where('ord_no',$out_trade_no)->update(['status'=>1]);
DB::table('orders')->where('ord_no',$out_trade_no)->update(['trance_id'=>$trade_no]);
return 'success';
}
}
// 检查订单支付状态
public function check_order_status(Request $request) {
$ord_no = $request->ord_no;
$order = DB::table('orders')->where('ord_no',$ord_no)->item();
if ($order['status'] >= 1) {
# code...
exit(json_encode(['code'=>0,'msg'=>'支付成功']));
}
exit(json_encode(['code'=>1,'msg'=>'not pay']));
}
// 选择支付方式
public function selectpay(Request $request) {
$data['ord_no'] = $request->ord_no;
return view('shop/selectpay',$data);
}
}
4. 商城路由
// 商城
Route::get('/shop/index','Shop@index');//商城首页
Route::get('/shop/lists','Shop@lists');//商城列表
Route::get('/shop/detail','Shop@detail');//商品详情
Route::post('/shop/create_order','Shop@create_order')->middleware('automember');//商城订单
Route::get('/shop/pay','Shop@pay')->middleware('automember');//商品微信付款二维码
Route::get('/shop/creatqrcode','Shop@creatqrcode');//生成二维码
Route::post('/shop/notify','Shop@notify');//微信异步通知
Route::get('/shop/check_order_status','Shop@check_order_status');//检查订单支付状态
Route::get('/shop/alipay','Shop@alipay')->middleware('automember');//支付宝支付
Route::post('/shop/alipay_notify','Shop@alipay_notify');//支付宝异步通知
Route::get('/shop/selectpay','Shop@selectpay')->middleware('automember');//选择支付方式
5. 商城详情页
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!-- 当前文档要用到阿里字体图标-->
<link rel="stylesheet" href="/static/font/iconfont.css">
<link rel="stylesheet" href="/static/css/shop_detail.css">
<link rel="stylesheet" href="/static/plugins/layui/css/layui.css">
<script src="/static/plugins/layui/layui.js"></script>
<title>{{$item['title']}}</title>
</head>
<body>
@include('shop/public/header')
<!--主体全部放在main元素中-->
<main>
<!-- 商城公共头部-->
@include('shop/public/header_search')
<!--为商品详情区块单独创建一个包含块,方便用网格布局-->
<div class="detail">
@csrf
<!--商城详情页上部购买组件-->
<div class="shop-detail-bug">
<!--头部面包屑导航-->
<nav>
<a href="">首页 > </a>
<a href="">图片写真 > </a>
<a href="">日本 > </a>
<a href="">颖宝宝</a>
</nav>
<article>
<input type="hidden" name="pro_id" value="{{$item['id']}}">
<!-- <input type="hidden" name="price" value="{{$item['price']}}"> -->
<span><img src="{{$item['thumb']}}" alt=""></span>
<div>
<!--商品标题-->
<h3>{{$item['title']}}</h3>
<!--商品价格-->
<div class="price">
<span>本站特惠:</span>
<span>¥{{$item['price']}}</span>
</div>
<!--基本描述-->
<div class="desc">
销量: <span>13</span> |
累积评价: <span>3</span> |
好评率: <span>199%</span>
</div>
<!-- 购买数量-->
<div class="buy-num">
<label for="num">购买数量:</label><input type="number" id="num" value="1">
</div>
<!--购买按钮-->
<div class="buy-btn">
<button onclick="buy()">立即购买</button>
<button><i class="iconfont icon-icon_tianjia"></i>加入购物车</button>
</div>
<!--售后承诺-->
<div class="promise">
<span><i class="iconfont icon-zhanghaoquanxianguanli"></i>本站保障</span>
<span><i class="iconfont icon-icon_safety"></i>企业认证</span>
<span><i class="iconfont icon-tianshenpi"></i>退款承诺</span>
<span><i class="iconfont icon-kuaisubianpai"></i>免费换货</span>
</div>
</div>
</article>
</div>
<!--商城详情页左下推荐商品列表-->
<div class="shop-detail-recommend">
<h3>推荐商品</h3>
<div>
<a href="">
<img src="/static/images/shop/shop1.jpg" alt="">
</a>
<a href="">韩国美女最新海报促销美妆写真图集</a>
<div class="hot">
<span>热销:</span><span>8976</span>
<span>价格:</span><span>¥99</span>
</div>
</div>
<div>
<a href="">
<img src="/static/images/shop/shop2.jpg" alt="">
</a>
<a href="">韩国美女最新海报促销美妆写真图集</a>
<div class="hot">
<span>热销:</span><span>324</span>
<span>价格:</span><span>¥798</span>
</div>
</div>
<div>
<a href="">
<img src="/static/images/shop/shop3.jpg" alt="">
</a>
<a href="">韩国美女最新海报促销美妆写真图集</a>
<div class="hot">
<span>热销:</span><span>678</span>
<span>价格:</span><span>¥630</span>
</div>
</div>
<div>
<a href="">
<img src="/static/images/shop/shop4.jpg" alt="">
</a>
<a href="">韩国美女最新海报促销美妆写真图集</a>
<div class="hot">
<span>热销:</span><span>12</span>
<span>价格:</span><span>¥980</span>
</div>
</div>
</div>
<!--商城详情页右下详情选项卡-->
<div class="shop-detail-tab">
<div class="tab">
<span class="active">商品详情</span>
<span>案例/演示</span>
<span>常见问题</span>
<span>累计评价</span>
<span>产品咨询</span>
</div>
<div class="content">
{!!$detail['contents']!!}
</div>
</div>
<!--评论与回复-->
<div class="public-comment-reply">
<!-- 评论区-->
<div class="comment">
<h3>我要评论</h3>
<div>
<label for="comment"><img src="/static/images/user.png" alt=""></label>
<textarea name="" id="comment"></textarea>
</div>
<button>发表评论</button>
</div>
<!-- 回复区-->
<div class="reply">
<h3>最新回复</h3>
<div>
<img src="/static/images/user.png" alt="">
<div class="detail">
<span>用户昵称</span>
<span>留言内容: php中文网,是一个有温度,有思想的学习平台</span>
<div>
<span>2019-12-12 15:34:23发表</span>
<span><i class="iconfont icon-dianzan"></i>回复</span>
</div>
</div>
</div>
<div>
<img src="/static/images/user.png" alt="">
<div class="detail">
<span>用户昵称</span>
<span>留言内容: php中文网,是一个有温度,有思想的学习平台</span>
<div>
<span>2019-12-12 15:34:23发表</span>
<span><i class="iconfont icon-dianzan"></i>回复</span>
</div>
</div>
</div>
<div>
<img src="/static/images/user.png" alt="">
<div class="detail">
<span>用户昵称</span>
<span>留言内容: php中文网,是一个有温度,有思想的学习平台</span>
<div>
<span>2019-12-12 15:34:23发表</span>
<span><i class="iconfont icon-dianzan"></i>回复</span>
</div>
</div>
</div>
<div>
<img src="/static/images/user.png" alt="">
<div class="detail">
<span>用户昵称</span>
<span>留言内容: php中文网,是一个有温度,有思想的学习平台</span>
<div>
<span>2019-12-12 15:34:23发表</span>
<span><i class="iconfont icon-dianzan"></i>回复</span>
</div>
</div>
</div>
</div>
</div>
</div>
</main>
<!--公共页脚-->
@include('shop/public/footer')
</body>
</html>
<script>
layui.use('layer', function(){
$ = layui.jquery;
var layer = layui.layer;
});
// 购买
function buy() {
var pro_id = parseInt($('input[name="pro_id"]').val());
var buy_count = parseInt($('#num').val());
if (isNaN(pro_id) || pro_id === 0) {
return layer.alert('商品参数错误',{icon:2});
}
if (isNaN(buy_count) || buy_count === 0) {
return layer.alert('购买数量错误',{icon:2});
}
// 下订单
var _token = $('input[name="_token"]').val();
// var price = $('input[name="price"]').val();
$.post('/shop/create_order',{pro_id:pro_id,_token:_token,buy_count:buy_count},function (res) {
// 未登录
if (res.code === 401) {
//iframe层
layer.open({
type: 2,
title: '用户登录',
shadeClose: true,
shade: 0.8,
area: ['400px', '300px'],
content: '/account/login' //iframe的url
});
return;
}
if (res.code > 0) {
return layer.alert(res.msg,{icon:2});
}
// 选择何种支付方式
layer.open({
type: 2,
title: '选择付款方式',
shadeClose: true,
shade: 0.2,
area: ['400px', '300px'],
content: '/shop/selectpay?ord_no='+ res.ord_no //iframe的url
});
// 跳转到支付宝
// window.location.href="/shop/alipay?ord_no=" + res.ord_no;
// 下面是微信的哦
// layer.msg(res.msg);
// layer.open({
// type: 2,
// title: '付款二维码',
// shadeClose: true,
// shade: 0.2,
// area: ['400px', '300px'],
// content: '/shop/pay?ord_no='+res.ord_no //iframe的url
// });
},'json');
}
</script>
6. 付款方式选择页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="/static/plugins/layui/css/layui.css">
<script src="/static/plugins/layui/layui.js"></script>
<title>支付方式选择</title>
<style>
body {
height: 80vh;
display: flex;
flex-flow: row nowrap;
justify-content: center;
align-items: center;
}
</style>
</head>
<body>
<button type="button" class="layui-btn" onclick="wxpay()">微信支付</button>
<button type="button" class="layui-btn layui-btn-normal" onclick="alipay()">支付宝支付</button>
</body>
</html>
<script>
// 微信支付
function wxpay() {
window.location.href="/shop/pay?ord_no=" + {{$ord_no}};
}
// <!-- 支付宝支付 -->
function alipay() {
window.open("/shop/alipay?ord_no=" + {{$ord_no}});
}
</script>
7. 效果图
8. 修改冲突
Cannot redeclare Encrypt() (previously declared in .../vendor/laravel/lumen-framework/src/helpers.php:126)
//或:
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. 总结
虽然官方的说明已经够详细了,但是真正入手去做还是有很多坑,此次对接过程中学习很多,其中尤其要注意的是因为官方的关系。