基于thinkphp5.0和支付宝面对面扫码支付DEMO制作的扫码支付
今天接口申请下来,下载了官方demo对着调试了一天,终于实现想要的功能,先看图
选择支付宝支付
跳出二维码弹窗
手机支付宝进行扫码支付
支付完成,点击支付完成按钮跳转到订单列表
实现步骤:
1 支付宝接口申请,这个自行申请哦
2 下载官方扫码支付DEMO aopsdkdownload.cn-hangzhou.alipay-pub.aliyun-inc.com/demo/F2FPay…
将其中的f2fpay,aop两个文件夹复制到extend/alipay目录下.
其中的AlipayTradeService.php 我有稍作修改,到时在附件传上来.
3 点击页面的支付按钮后,异步请求二维码
//发起支付宝支付 public function alipay() { if (!request()->isAjax()) { $this->error('该操作仅支持异步操作'); } $productId = input('productId',0); $product = model('Product')->where('id',$productId)->find(); if (empty($product)) { $this->error('产品不存在'); } if ($product['status'] != 1) { $this->error('产品已下架'); } $outTradeNo = out_trade_no(); $data = [ 'notify_url' => url('api/Notify/alipay','',false,true), //回调链接 'return_url' => '', 'out_trade_no' => $outTradeNo, //订单号 'subject' => '爱站SEO '.$product['title'], //产品标题 'total_fee' => $product['cash'],//订单金额,单位为元 'body' => $product['remark'], //产品描述 ]; $alipay = new Alipay; $result = $alipay->qrpay($data); if(!$result['code']){ return $this->error($result['msg']); } //录入订单数据 $orderData = [ 'order_num' => $data['out_trade_no'], // 'prepay_id' => $prepayId, 'product_id' => $productId, 'uid' => session('uid'), 'count' => 1, 'pay_fee' => $data['total_fee'] * 100, 'create_time' => time(), 'paied_time' => 0, 'status' => 1, ]; $res = db('Order')->insert($orderData); if (!$res) { $this->error('订单未成功生成'); } //二维码生成 $qrcodeImg = make_qrcode($result['msg'],$data['out_trade_no']); return [ 'code' => 1, 'msg' => '请用支付宝支付', 'qrcodeImg' => $qrcodeImg, //二维码图片地址 'productInfo' => $product //产品信息 ]; }
先检查产品是否可用销售,然后生成订单号,调用Alipay支付请求,订单录入后,生成二维码图片,传给前端.
Alipay.php 我是放在common/pay/目录下的
<?php namespace app\common\pay; use think\Validate; use think\Log; /** * 支付宝扫码支付 */ class Alipay { public function qrpay($data = []) { $validate = new Validate([ ['out_trade_no','require|alphaNum','订单编号输入错误|订单编号输入错误'], ['total_fee','require|number|gt:0','金额输入错误|金额输入错误|金额输入错误'], ['subject','require','请输入标题'], ['body','require','请输入描述'], ['notify_url','require','异步通知地址不为空'], ]); if (!$validate->check($data)) { return ['code'=>0,'msg'=>$validate->getError()]; } // 支付超时,线下扫码交易定义为5分钟 $timeExpress = "5m"; import('alipay.f2fpay.model.builder.AlipayTradePrecreateContentBuilder', EXTEND_PATH); import('alipay.f2fpay.service.AlipayTradeService', EXTEND_PATH); // 创建请求builder,设置请求参数 $qrPayRequestBuilder = new \AlipayTradePrecreateContentBuilder(); $qrPayRequestBuilder->setOutTradeNo($data['out_trade_no']); $qrPayRequestBuilder->setTotalAmount($data['total_fee']); $qrPayRequestBuilder->setTimeExpress($timeExpress); $qrPayRequestBuilder->setSubject($data['subject']); $qrPayRequestBuilder->setBody($data['body']); // 调用qrPay方法获取当面付应答 $config = config('alipay'); if (!empty($data['notify_url'])) { $config['notify_url'] = $data['notify_url']; } $qrPay = new \AlipayTradeService($config); $qrPayResult = $qrPay->qrPay($qrPayRequestBuilder); // 根据状态值进行业务处理 switch ($qrPayResult->getTradeStatus()){ case "SUCCESS": // echo "支付宝创建订单二维码成功:"."<br>---------------------------------------<br>"; $response = $qrPayResult->getResponse(); return ['code'=>1,'msg'=>$response->qr_code]; break; case "FAILED": // echo "支付宝创建订单二维码失败!!!"."<br>--------------------------<br>"; return ['code'=>0,'msg'=>'支付宝创建订单二维码失败!!!']; break; case "UNKNOWN": // echo "系统异常,状态未知!!!"."<br>--------------------------<br>"; return ['code'=>0,'msg'=>'系统异常,状态未知!!!']; break; default: return ['code'=>0,'msg'=>'不支持的返回状态,创建订单二维码返回异常!!!']; break; } return ; } public function notify_alipay() { import('alipay.aop.AopClient'); $config = config('alipay'); $out_trade_no = input('post.out_trade_no'); $transaction_id = input('post.trade_no'); $aop = new \AopClient; $aop->appId = $config['app_id']; $aop->rsaPrivateKey = $config['merchant_private_key']; $aop->alipayrsaPublicKey = $config['alipay_public_key']; $aop->signType = $config['sign_type']; $result = $aop->rsaCheckV1($_POST,'',$config['sign_type']); if ($result) { if(input('trade_status') == 'TRADE_FINISHED' || input('trade_status') == 'TRADE_SUCCESS') { // 处理支付成功后的逻辑业务 $order = db('Order')->where(['order_num'=>$out_trade_no])->find(); if (!$order) { Log::write('order not exists'); return 'order not exists'; } //订单状态错误 1 未付款 其他状态均为已处理的状态 if ($order['status'] != 1) { Log::write('order is completed:'.$order['status']); return true; } if ($order['pay_fee'] != input('post.total_amount') * 100) { Log::write('total_amount is error:'.$order['pay_fee'].','.input('post.total_amount')); return 'total_amount is error'; } $order['transaction_id'] = $transaction_id; $order['paied_time'] = time(); $order['status'] = 2; db('Order')->update($order); //支付成功的逻辑 return 'success'; } Log::write('trade_status is error:'.input('trade_status')); return 'fail'; } Log::write('sign verify is error:'.var_export($_POST)); return 'fail'; } }
主要有qrpay二维码扫描支付的请求,notify_alipay接收异步通知的处理逻辑
这里用到的接口配置,我是放在/application/extra/alipay.php 下面
<?php return [ //签名方式,默认为RSA2(RSA2048) 'sign_type' => "RSA2", //支付宝公钥 'alipay_public_key' => "", //商户私钥 'merchant_private_key' => "", //编码格式 'charset' => "UTF-8", //支付宝网关 'gatewayUrl' => "https://openapi.alipay.com/gateway.do", //应用ID 'app_id' => "", //异步通知地址,只有扫码支付预下单可用 'notify_url' => "http://www.baidu.com", //最大查询重试次数 'MaxQueryRetry' => "10", //查询间隔 'QueryDuration' => "3", //日志文件 'log_file' => RUNTIME_PATH.'/log/'.date('Ym').'/'.date('d').'.log', ];
填写公钥,私钥,异步通知地址,我自己添加了一个日志文件,为了结合请求的日志记录write_log使用.