在支付宝开放平台的文档中心点击”网页&移动应用”链接, 进入开发文档.
点击”开放能力”页签, 依次选择”电脑网站支付/支付能力/快速接入/电脑网站支付 SDK & Demo”, 下载PHP版本的资源包, 解压到laravel项目的/vendor
目录下(假设重命名为/vendor/alipay
).
其中的/vendor/alipay/pagepay/pagepay.php
就是生成支付页面(有支付二维码)的脚本, 拷贝其中的PHP代码, 粘贴到一个控制器方法中(假设是\admin\front\Shop@ali_pay
). 调整各种require
的文件路径.
// 连通支付宝支付
public function ali_pay(Request $req)
{
// 订单号
$ord_no = $req->ord_no;
// 用相对路径导航到alipay根目录
$alipayPath = __DIR__ . "/../../../../vendor/alipay/";
require_once $alipayPath . 'config.php';
require_once $alipayPath . 'pagepay/service/AlipayTradeService.php';
require_once $alipayPath . 'pagepay/buildermodel/AlipayTradePagePayContentBuilder.php';
//商户订单号,商户网站订单系统中唯一订单号,必填
$out_trade_no = $ord_no; //trim($_POST['WIDout_trade_no']);
//订单名称,必填
$subject = '测试商品名称';//trim($_POST['WIDsubject']);
//付款金额,必填(假设为1分钱)
$total_amount = 0.01;//trim($_POST['WIDtotal_amount']);
//商品描述,可空
$body = '';//trim($_POST['WIDbody']);
//构造参数
$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);
}
把申请到的APPID, 商户私钥, 商户公钥填到/vendor/alipay/config.php
中的对应位置.
在/vendor/alipay/
目录下新建文件夹tmp
, 并把/vendor/alipay/AopSdk.php
的第18行改为: define("AOP_SDK_WORK_DIR", dirname(__FILE__) . "/tmp/");
;
因为支付宝SDK的加密/解密方法跟laravel的加密/解密方法同名, 导致系统报错: “Cannot redeclare Decrypt()”, 所以把支付宝的加密/解密方法重命名(或删除, 逻辑是相同的. 直接用laravel提供的同名加密/解密方法即可). 重命名涉及下面3个文件, 在这3个文件中查找, 把encrypt/decrypt
替换成alipayEncrypt/alipayDecrypt
.
/vendor/alipay/aop/AopEncrypt.php
/vendor/alipay/aop/AopClient.php
/vendor/alipay/lotusphp_runtime/Cookie/Cookie.php
因为PHP7+ 不再支持each()
循环, 所以需要把/vendor/alipay/aop/AopClient.php
的413行的while (list ($key, $val) = each ($para_temp))
改为foreach($para_temp as $key => $val)
至此, 订单创建完成后, 就能跳转到支付宝的收银台了.
下单成功后, 页面请求\admin\front\Shop@ali_pay
控制器方法, 跳转到支付宝收银台.
编写一个控制器方法, 作为支付完成后, 支付宝轮询发送含有支付结果信息的post
请求的目标回调方法, 处理站点支付完成后的业务逻辑(假设是: \admin\front\Shop@alipay_notify
). 该回调方法处理完成后, 必须返回”success”字符串, 否则支付宝会一直轮询发送请求, 直到24小时22分后不再发送.
/**
* 支付完成后, 支付宝发送的post请求的目标回调处理方法, 支付宝需要回调处理方法在24小时22分钟内返回'success'字符串, 否则它也会各一段时间请求一次
*/
public function alipay_notify() {
// 支付宝生成的交易号
$trade_no = $_POST['trade_no'];
// 站点订单号
$out_trade_no = $_POST['out_trade_no'];
// 支付结果, 若值为"TRADE_SUCCESS"表示支付成功.
$trade_status = $_POST['trade_status'];
// 支付不成功, 则执行站点支付不成功的业务逻辑, 然后返回"success"字符串给支付宝, 通知其停止轮询发送请求
if($trade_status != "TRADE_SUCCESS") {
// 支付不成功时的业务逻辑....
return 'success';
}
$order = DB::table('orders')->where('ord_no', $out_trade_no)->getFirst();
// 找不到订单, 则认为是无效信息, 直接返回
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, 'trance_id' => $trade_no]);
// 发送优惠券, 积分等
// 发送短信通知客户等
// 通知支付宝已成功处理, 不要再发送支付结果的处理请求了
return 'success';
}
}
配置/vendor/alipay/config.php
中的notify_url
和return_url
配置项, 前者是上一步创建的回调方法, 后者是给支付宝自动跳转的站点页面路由地址, 如用户订单列表等页面.