Larave6.0 APP 微信支付与支付宝支付

    技术2026-02-23  8

    Laravel6.x APP端对接微信支付与支付宝支付

    前言准备工作配置支付信息支付宝配置注意微信支付注意 创建表路由设置创建订单数据支付宝支付回调微信支付回调关于调试

    前言

    近来公司开发一个关于招聘的APP所需要对接到微信支付与支付宝支付,网上一番搜索,基本全是CPCP再CP的文章,无奈还得靠自己研究一番(其实不难),文章较长,有需要的请细看。 技术框架:Laravel6.x+uni-app 扩展包:yansongda/laravel-pay 2.0(github 与 文档)

    准备工作

    对接一个开通VIP的支付 安装好Laravel6.x版本的,并安装yansongda/laravel-pay包

    composer require yansongda/laravel-pay

    如出现说内存不足 可以尝试临时变更内存限制,Composer 问题

    COMPOSER_MEMORY_LIMIT=-1 composer require yansongda/laravel-pay

    运行配置文件,生成config/pay.php

    php artisan vendor:publish --provider="Yansongda\LaravelPay\PayServiceProvider" --tag=laravel-pay

    配置支付信息

    // 该配置目前是公钥证书模式 return [ 'alipay' => [ // 支付宝分配的 APPID 'app_id' => env('ALI_APP_ID', ''), // 支付宝异步通知地址 'notify_url' => env('APP_URL') . '/api/alipay/notify', // 支付成功后同步通知地址 'return_url' => env('APP_URL') . '/api/alipay/return', // 阿里公共密钥,验证签名时使用 'ali_public_key' => public_path() . '/cert/alipayCertPublicKey_RSA2.crt', // 自己的私钥,签名时使用 'private_key' => env('ALI_PRIVATE_KEY', ''), ///!!!注意!!!/// // 使用公钥证书模式,请配置下面两个参数,同时修改 ali_public_key 为以 .crt 结尾的支付宝公钥证书路径,如(./cert/alipayCertPublicKey_RSA2.crt) // 应用公钥证书路径 'app_cert_public_key' => public_path() . '/cert/appCertPublicKey.crt', // 支付宝根证书路径 'alipay_root_cert' => public_path() . '/cert/alipayRootCert.crt', // optional,默认 warning;日志路径为:sys_get_temp_dir().'/logs/yansongda.pay.log' 'log' => [ 'file' => storage_path('logs/alipay.log'), 'level' => 'info', // 建议生产环境等级调整为 info,开发环境为 debug 'type' => 'daily', // optional, 可选 daily. 'max_file' => 30, ], // optional,设置此参数,将进入沙箱模式 // 'mode' => 'dev', ], 'wechat' => [ // 公众号 APPID 'app_id' => env('WECHAT_APP_ID', ''), // 小程序 APPID 'miniapp_id' => env('WECHAT_MINIAPP_ID', ''), // APP 引用的 appid 'appid' => env('WECHAT_APPID', ''), // 微信支付分配的微信商户号 'mch_id' => env('WECHAT_MCH_ID', ''), // 微信支付异步通知地址 'notify_url' => env('APP_URL') . '/api/wechat/notify', // 微信支付签名秘钥 'key' => env('WECHAT_KEY', ''), // 客户端证书路径,退款、红包等需要用到。请填写绝对路径,linux 请确保权限问题。pem 格式。 'cert_client' => public_path() . '/cert/apiclient_cert.pem', // 客户端秘钥路径,退款、红包等需要用到。请填写绝对路径,linux 请确保权限问题。pem 格式。 'cert_key' => public_path() . '/cert/apiclient_key.pem', // optional,默认 warning;日志路径为:sys_get_temp_dir().'/logs/yansongda.pay.log' 'log' => [ 'file' => storage_path('logs/wechat.log'), 'level' => 'info', // 建议生产环境等级调整为 info,开发环境为 debug 'type' => 'daily', // optional, 可选 daily. 'max_file' => 30, ], // optional // 'dev' 时为沙箱模式 // 'hk' 时为东南亚节点 // 'mode' => 'dev', ], ];

    支付宝配置注意

    建议使用公钥证书模式(RSA2)配置,毕竟官方都大力推荐的,证书还是比普通的安全,像https与http,是吧 文档任意门 创建应用 生成秘钥 如个人对接,不涉及到转帐什么的,可直接用公钥模式(RSA),需要填写三个配置

    # 应用APPID ALI_APP_ID= # 支付宝公钥, 非应用公钥(非支付宝开放开发助手生成) ALI_PUBLIC_KEY= # 私钥(支付宝开放开发助手生成) ALI_PRIVATE_KEY=

    如涉及到转帐,打款等资金流向的操作,则需要使用公钥证书模式(RSA2),需要填写配置 上面的例子,证书放在了/public/cert/ 下,需要注意文件夹与文件的权限,一般可给644

    // config/pay.php ali_public_key=路径 app_cert_public_key=路径 alipay_root_cert=路径 // env那边则需要配置两个 # 应用APPID ALI_APP_ID= # 私钥(支付宝开放开发助手生成) ALI_PRIVATE_KEY=

    上面的区别就是 config/pay.php 里的 ali_public_key 如RSA的则是 env(‘ALI_PUBLIC_KEY’);如RSA2的则是支付宝公钥证书路径 最后附上支付宝接口加签方式的图片和前端配置的图片

    微信支付注意

    需要在微信开放平台 创建应用,并开通好微信支付,获取

    WECHAT_APP_IDWECHAT_APPIDWECHAT_MCH_IDWECHAT_KEY

    这里的调试有个比较坑的地方,目前我也不知道是什么问题,知道的大神麻烦解答下:github issues APP微信支付配置WECHAT_APPID与WECHAT_APP_ID导致支付与查询出现异常,所以上面的WECHAT_APP_ID与WECHAT_APPID我都一并填写一样的了,目前使用没发现异常。

    创建表

    先新建一个表(创建model的同时新建表)

    php artisan make:model Models/VipOrder -m

    编写好数据库字段(基本字段就可以了)

    Schema::create('vip_orders', function (Blueprint $table) { $table->bigIncrements('id'); $table->unsignedInteger('user_id')->default(0)->index()->comment('用户id'); $table->char('order_no', 22)->default('')->comment('订单号'); $table->tinyInteger('state')->default(0)->comment('订单状态 -1 已关闭 0 待付款 1 已付款'); $table->string('transid')->default('')->comment('交易单号'); $table->decimal('price')->default(0)->comment('价格'); $table->unsignedSmallInteger('numbers')->default(0)->comment('购买次数'); $table->unsignedTinyInteger('paytype')->default(0)->comment('支付方式 1 微信 2 支付宝'); $table->string('remark')->default('')->comment('订单备注'); $table->string('syremark')->default('')->comment('系统备注'); $table->timestamp('paid_at')->nullable()->comment('支付时间'); $table->softDeletes(); $table->timestamps(); }); DB::statement("alter table `vip_orders` comment 'vip订单'");

    路由设置

    route/api.php

    // 支付宝支付 Route::any('alipay/notify', 'AlipayController@notify'); Route::get('alipay/return', 'AlipayController@return'); // 微信支付 Route::any('wechat/notify', 'WechatController@notify');

    创建订单数据

    用户选择需要开通的等级后,请求此接口 route/api.php

    // 创建VIP订单 Route::post('vip/pay', 'VipOrdersController@pay');

    请求接口:

    public function pay(Request $request) { $setting = Setting::select('vip_set') ->firstOrFail(); $vip_key = request('vip_key', 0); // 用户选择的开通次数等级 $paytype = request('paytype', 0); // 用户选择的支付方式 $uid = auth('api')->userOrFail()->id; // 查询2分钟内是否已下单 if (env('APP_ENV') == 'production') { $has_order = VipOrder::where(['user_id' => $uid])->whereDate('created_at', Carbon::now()->toDateString())->where('created_at', '>', Carbon::now()->subMinutes(2))->exists(); if ($has_order) { return Responses::json(Responses::CONTINUE, '请别频繁下单'); } } // 获取相应的vip设置 $vip = isset($setting->vip_set) ? $setting->vip_set['vips'] : []; if (!isset($vip[$vip_key]) || empty($vip[$vip_key])) { return Responses::json(Responses::CONTINUE, Responses::NOT_FOUND_DATA); } // 创建no-自定义创建 $no = Helpers::createNO('VO'); // 标题-自定义 $title = '开通VIP'; if ($paytype == 1) { /// ---微信支付--- $config = config('pay.wechat'); $openid = auth('api')->user()->openid; if (empty($openid)) { return Responses::json(Responses::CONTINUE, '请先授权绑定微信'); } $order = [ 'out_trade_no' => $no, 'total_fee' => $vip[$vip_key]['price'] * 100, // **单位:分** 'body' => $title, 'openid' => $openid, ]; $pay = Pay::wechat($config)->app($order)->getContent(); } else if ($paytype == 2) { /// ---支付宝支付--- $config = config('pay.alipay'); $order = [ 'out_trade_no' => $no, 'total_amount' => $vip[$vip_key]['price'], 'subject' => $title, 'body' => $title, 'timeout_express' => '15m' ]; $pay = Pay::alipay($config)->app($order)->getContent(); } else { return Responses::json(Responses::CONTINUE, '请选择支付方式'); } $m_order = new VipOrder(); $m_order->user_id = $uid; $m_order->order_no = $no; $m_order->state = 0; $m_order->price = $vip[$vip_key]['price']; $m_order->numbers = $vip[$vip_key]['count']; $m_order->paytype = $paytype; $m_order->save(); // return $pay; // 这里根据自定义的json格式返回给前端处理就好了 return Responses::json(Responses::OK, Responses::SUCCESS, $pay); }

    支付宝支付回调

    public function notify(OrderService $orderService) { $config = config('pay.alipay'); $alipay = Pay::alipay($config); try { $data = $alipay->verify(); // 是的,验签就这么简单! // 请自行对 trade_status 进行判断及其它逻辑进行判断,在支付宝的业务通知中,只有交易通知状态为 TRADE_SUCCESS 或 TRADE_FINISHED 时,支付宝才会认定为买家付款成功。 // 1、商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号; // 2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额); // 3、校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email); // 4、验证app_id是否为该商户本身。 // 5、其它业务逻辑情况 if ($data) { $trade_status = $data->trade_status; $out_trade_no = $data->out_trade_no; // 订单号 $prefix = substr($out_trade_no, 0, 2); if (in_array($trade_status, ['TRADE_SUCCESS', 'TRADE_FINISHED'])) { // 这里我加多了一步, 查询这个订单是否已经支付成功 $order = [ 'out_trade_no' => $data->out_trade_no, ]; $result = $alipay->find($order); if ($result->code != 10000) { exit($result->msg); } $ret = [ 'out_trade_no' => $data->out_trade_no, // 订单号 'transid' => $data->trade_no, // 交易单号 'total_amount' => $data->total_amount, // 交易金额 'paid_at' => Carbon::now(), // 支付时间 'syremark' => 'Alipay notify' ]; switch ($prefix) { case 'VO': $orderService->payVipOrderSuccess($ret); break; case 'JO': $orderService->payJobOrderSuccess($ret); break; default: break; } return $alipay->success(); } else { exit($data->msg); } } else { exit('验签失败'); } } catch (\Exception $e) { $e->getMessage(); } }

    微信支付回调

    public function notify(OrderService $orderService) { $config = config('pay.wechat'); $wechat = Pay::wechat($config); try { $data = $wechat->verify(); // 是的,验签就这么简单! if ($data) { $return_code = $data->return_code; $result_code = $data->result_code; if ($return_code == 'SUCCESS' && $result_code == 'SUCCESS') { // 这里我加多了一步, 查询这个订单是否已经支付成功 $order = [ 'out_trade_no' => $data->out_trade_no, ]; $result = $wechat->find($order); if ($result->return_code == 'SUCCESS' && $result->result_code == 'SUCCESS' && $result->trade_state == 'SUCCESS') { $out_trade_no = $data->out_trade_no; // 订单号 $prefix = substr($out_trade_no, 0, 2); // ----交易支付成功处理----- $ret = [ 'out_trade_no' => $data->out_trade_no, // 订单号 'transid' => $data->transaction_id, // 交易单号 'paid_at' => Carbon::now(), // 支付时间 'syremark' => 'Wechat notify' ]; switch ($prefix) { case 'VO': $orderService->payVipOrderSuccess($ret); break; case 'JO': $orderService->payJobOrderSuccess($ret); break; default: break; } return $wechat->success(); // laravel 框架中请直接 `return $wechat->success()` } else { Log::debug('Wechat notify', [$result->return_msg]); } } else { exit($data->return_msg); } } else { echo '验签失败'; } } catch (\Exception $e) { $e->getMessage(); } }

    关于调试

    关于调试,有几点建议

    config/pay.php 里的log 设置debug支付宝可配置沙箱模式,并下载相关工具调试,可直接在电脑安装个模拟器(如逍遥模拟器),工具传送门安装Laravel 日志查看扩展,composer后再简单配置一下路由 route/web.phpcomposer require rap2hpoutre/laravel-log-viewer Route::get('logs', '\Rap2hpoutre\LaravelLogViewer\LogViewerController@index');

    如有问题,欢迎留言–我改

    Processed: 0.015, SQL: 9