关于php:TinkPHP框架开发的CRMEB小程序商城v40二次开发集成支付宝支付

28次阅读

共计 8248 个字符,预计需要花费 21 分钟才能阅读完成。

前言

大家都晓得支付宝领取和微信支付宝都只能局限在本人的平台,微信内支付宝领取是基本就不能应用,即便是公众号领取也须要跳转到内部浏览器才能够唤起支付宝领取,并且 QQ 浏览器唤起支付宝领取还是问题很多,所以个别在微信生态内的利用个别都不思考接入支付宝,但依然有不少用户有这方面的需要,明天就给大家做个具体接入流程!

开明支付宝领取

  1. 开明过程省略, 可查看帮忙文档:http://help.crmeb.net/crmeb_z…

这是 crmeb 常识付费零碎的支付宝领取, 不过开明的流程都是一样的。

2. 下载支付宝领取 SDK

  • 下载地址: https://opendocs.alipay.com/o…
  • 阐明: 新版 SDK 可用 composer 装置, 目前应用的旧版本, 是不能应用 composer 装置

3. 创立 aliapay 领取类

创立门路:crmeb/services/AlipayService.php,
把下载好的文件解压在 vendor 目录中目录构造为: /vendor/alipay/

4. AlipayService

采纳单例设计模式, 支付宝领取的 SDK 旧版本不能用 composer 加载这就很不优雅了, 不能在类初始化的时候加载, 而且第一次载入时十分慢。

<?php
/**
 * @author: liaofei<136327134@qq.com>
 * @day: 2020/8/19
 */

namespace crmeb\services;

use think\exception\ValidateException;
use think\facade\Route as Url;
use think\facade\Log;

/**
 * Class AlipayService
 * @package crmeb\services
 */
class AlipayService
{
    /**
     * @var static
     */
    protected static $instance;

    /**
     * @var string
     */
    protected $alipayAppId;

    /**
     * @var string
     */
    protected $alipayPublicKey;

    /**
     * 支付宝
     * @var string
     */
    protected $alipayPrivateKey;

    /**
     * 同步回调地址
     * @var string
     */
    protected $returnUrl;

    /**
     * 异步回调地址
     * @var string
     */
    protected $notifyUrl;

    /**
     * 申请网关
     * @var string
     */
    protected $gatewayUrl = 'https://openapi.alipay.com/gateway.do';

    /**
     * 是否开启日志
     * @var bool
     */
    protected $isLog = false;

    /**
     * AlipayService constructor.
     */
    protected function __construct()
    {$this->initialize();
        $this->options();}

    /**
     * @param $name
     * @param $arguments
     */
    public function __call($name, $arguments)
    {if (strstr($name, 'set') !== false) {$name = ucwords(substr($name, 3, -1));
            if (in_array($name, ['returnUrl', 'isLog', 'notifyUrl', 'alipayPrivateKey', 'alipayAppId', 'alipayPublicKey'])) {$this->{$name} = $arguments[0];
            }
        } else {throw new ValidateException('拜访办法不存在');
        }
    }

    /**
     * 初始化加载阿里云 pay
     */
    protected function initialize()
    {$dir = app()->getRuntimePath() . 'alipay';
        if (!file_exists($dir)) {mkdir($dir, 0775, true);
        }
        define('AOP_SDK_WORK_DIR', $dir);
        include app()->getRootPath() . DS . 'vendor' . DS . 'alipay' . DS . 'AopSdk.php';
    }

    /**
     * 获取参数配置
     */
    protected function options()
    {$this->alipayAppId = sys_config('alipay_app_id');
        $this->alipayPublicKey = sys_config('alipay_public_key');
        $this->alipayPrivateKey = sys_config('alipay_private_key');
        $this->returnUrl = Url::buildUrl('/api/alipay/synchro')->domain(true)->build();
        $this->notifyUrl = Url::buildUrl('/api/alipay/notify')->domain(true)->build();}

    /**
     * @return static
     */
    public static function instance()
    {if (is_null(self::$instance)) {self::$instance = new static();
        }
        return self::$instance;
    }

    /**
     * 支付宝领取同步回调
     */
    public static function aliPayReturn()
    { }

    /**
     * 领取领取同步回调
     */
    public static function handleNotify()
    { }

    /**
     * 下单领取手机网站领取版本
     * @param string $outTradeNo 下单号
     * @param string $totalAmount 订单金额 单位元
     * @param string $subject 订单题目
     * @param string $passbackParams 订单备注 会原样返回通常用于回调监听函数
     * @param string $productCode 销售产品码,商家和支付宝签约的产品码
     * @param bool $isView 是否间接输入
     * @return $response 支付宝返回的信息
     */
    public function aliPayWap(string $outTradeNo, string $totalAmount, string $subject, string $passbackParams, string $productCode = 'QUICK_MSECURITY_PAY', bool $isView = true)
    { }

    /**
     * 对立收单交易退款接口
     * @param string $outTradeNo 下单订单号
     * @param string $tradeNo 支付宝订单号
     * @param string $refundAmount 退款金额
     * @param string $refundReason 退款阐明
     * @param string $passbackParams 备注
     * @return $response 支付宝返回的信息
     */
    public function aliPayRefund(string $outTradeNo, string $tradeNo, string $refundAmount, string $refundReason, string $passbackParams)
    { }
    
    /**
     * 设置业务参数
     * @param array $biz_content
     * @return string
     */
    protected function setBizContent(array $bizContent = [])
    {if (isset($bizContent['passback_params'])) $bizContent['passback_params'] = urlencode($bizContent['passback_params']);
        if (isset($bizContent['trade_no']) && empty($bizContent['trade_no'])) unset($bizContent['trade_no']);
        $bizContent = json_encode($bizContent);
        // 打印业务参数
        $this->isLog && $this->writeLog($bizContent);
        return $bizContent;
    }

    /**
     * 写入日志
     * @param $content string | array | object
     * @return Log
     */
    protected function writeLog($content)
    {if (is_array($content)) $content = 'response:' . var_export($content, true);
        if (is_object($content)) $content = 'response:' . var_export($content, true);
        return Log::write(date('Y-m-d H:i:s', time()) . ' ' . $content);
    }


}

首先要把从数据库中获取到的参数放入领取配置里

创立 aopclientRequestExecute() 办法把 options()办法获取到的参数赋值给支付宝此办法会输入或者间接返回 HTML 的文本, 前后端拆散可间接用返回提交数据.

    /**
     * 初始化参数
     * @param $request
     * @param bool $isView
     * @return mixed|\SimpleXMLElement|string|\ 提交表单 HTML 文本
     * @throws \Exception
     */
    protected function aopclientRequestExecute(\AlipayTradeWapPayRequest $request, bool $isView = false)
    {$aop = new \AopClient();
        // 网管地址
        $aop->gatewayUrl = $this->gatewayUrl;
        //appid
        $aop->appId = $this->alipayAppId;
        // 私钥
        $aop->rsaPrivateKey = $this->alipayPrivateKey;
        // 公钥
        $aop->alipayrsaPublicKey = $this->alipayPublicKey;
        // 版本
        $aop->apiVersion = "1.0";
        // 编码格局
        $aop->postCharset = 'UTF-8';
        // 内容格局
        $aop->format = 'JSON';
        // 加密形式
        $aop->signType = 'RSA2';
        // 开启页面信息输入
        $aop->debugInfo = false;
        if ($isView) {$result = $aop->pageExecute($request, "post");
            echo $result;
        } else {$result = $aop->Execute($request);
        }
        // 关上后,将报文写入 log 文件
        $this->isLog && $this->writeLog($result);
        return $result;
    }

创立订单

下面曾经创立好 aliPayWap() 办法, 接下来咱们来实现它,aliPayWap()办法的逻辑也十分的简略, 只须要传入订单号, 领取金额, 订单题目, 订单备注. 订单备注个别会原样返回的, 这样能够利用订单备注来让异步回调执行对应的办法
例如有用户下单领取和用户充值回调回调办法为一个, 为一个回调办法解决的逻辑就比拟凌乱。

    /**
     * 下单领取手机网站领取版本
     * @param string $outTradeNo 下单号
     * @param string $totalAmount 订单金额 单位元
     * @param string $subject 订单题目
     * @param string $passbackParams 订单备注 会原样返回通常用于回调监听函数
     * @param string $productCode 销售产品码,商家和支付宝签约的产品码
     * @param bool $isView 是否间接输入
     * @return $response 支付宝返回的信息
     */
    public function aliPayWap(string $outTradeNo, string $totalAmount, string $subject, string $passbackParams, string $productCode = 'QUICK_MSECURITY_PAY', bool $isView = true)
    {$request = new \AlipayTradeWapPayRequest();
        // 设置异步回调地址
        $request->setNotifyUrl($this->notifyUrl);
        // 设置同步回调地址
        $request->setReturnUrl($this->returnUrl);
        // 用内置办法格式化参数
        $content = $this->setBizContent([
            'out_trade_no' => $outTradeNo,
            'total_amount' => $totalAmount,
            'subject' => $subject,
            'passback_params' => $passbackParams,
            'product_code' => $productCode,
        ]);
        // 设置下单参数
        $request->setBizContent($content);
        // 执行申请进行下单, 返回对应的领取参数
        return $this->aopclientRequestExecute($request, $isView);
    }

订单退款

aliPayRefund()办法负责退款解决, 须要参数下单订单号, 支付宝订单号, 退款金额, 退款阐明, 备注. 支付宝订单号须要在异步领取回调中或者同步回调中获取更新在数据库中, 不便退款解决。

/**
     * 对立收单交易退款接口
     * @param string $outTradeNo 下单订单号
     * @param string $tradeNo 支付宝订单号
     * @param string $refundAmount 退款金额
     * @param string $refundReason 退款阐明
     * @param string $passbackParams 备注
     * @return $response 支付宝返回的信息
     */
    public function aliPayRefund(string $outTradeNo, string $tradeNo, string $refundAmount, string $refundReason, string $passbackParams)
    {$request = new \AlipayTradeRefundRequest();
        $content = $this->setBizContent([
            'out_trade_no' => $outTradeNo,
            'trade_no' => $tradeNo,
            'refund_amount' => $refundAmount,
            'passback_params' => $passbackParams,
            'refund_reason' => $refundReason,
            'product_code' => $passbackParams,
        ]);
        $request->setBizContent($content);
        return $this->aopclientRequestExecute($request);
    }

回调验签

次要给异步和同步回调验证签名和数据处理不便调用

    /**
     * 验签办法
     * @param array $post 验签支付宝返回的信息,应用支付宝公钥。* @return boolean
     */
    protected function aliPaycheck(array $post)
    {$aop = new \AopClient();
        $aop->alipayrsaPublicKey = $this->alipayPublicKey;
        return $aop->rsaCheckV1($post, $this->alipayPrivateKey, 'RSA2');
    }

异步回调

创立异步回调路由, 批改文件:app/api/route/v1.php, 在顶部中减少以下代码, 别忘了创立对应的 AlipayController 文件

Route::any('alipay/notify', 'v1.alipay.AlipayController/notify');// 支付宝领取回调

首先须要解决领取包异步返回来的数据, 新增 aliPayNotify()办法来解析解决异步回调返回的参数。

    /**
     * 支付宝异步回调
     * @param callable $notifyFn 闭包函数 参数 1, 回调返回的参数, 回调后果
     * @return bool
     */
    protected function aliPayNotify(callable $notifyFn)
    {$post = app()->request->post();
        $result = $this->aliPaycheck($post);
        if ($result) {
            // 商户订单号
            $post['out_trade_no'] = isset($post['out_trade_no']) ? $post['out_trade_no'] : '';
            // 支付宝交易号
            $post['trade_no'] = isset($post['trade_no']) ? $post['trade_no'] : '';
            // 交易状态
            $post['trade_status'] = isset($post['trade_status']) ? $post['trade_status'] : '';
            // 备注
            $post['attach'] = isset($post['passback_params']) ? urldecode($post['passback_params']) : '';
            // 异步回调胜利执行
            try {if (is_callable($notifyFn)) $notifyFn((object)$post, $result);
            } catch (\Exception $e) {$this->isLog && $this->writeLog('支付宝领取胜利, 订单号为:' . $post['out_trade_no'] . '. 回调报错:' . $e->getMessage());
            }
            echo 'success';
        } else {echo 'fail';}
        $this->isLog && $this->writeLog($result);
        return true;

    }

执行 instance() 办法实例本类调用 aliPayNotify()办法

    /**
     * 支付宝领取同步回调
     */
    public static function aliPayReturn()
    {self::instance()->aliPayNotify(function ($data, $result) {
            //$data 为支付宝回调返回通过解析后重组的数据
            //$result 为验签后果
            // 这里要写异步回调的逻辑
            // 可依据 $data->attach 来判断须要执行的逻辑
            // 能够调用 TP6 中的事件来执行对应的业务逻辑
            //event($data->attach,$data)
        });
    }

同步回调

同步回调应用在领取胜利后跳转回去的页面一遍验证下返回的数据是否失常, 记录下支付宝订单号, 或者其余逻辑

    /**
     * 领取领取同步回调
     */
    public static function handleNotify()
    {
        // 获取返回参数
        $get = app()->request->get();
        // 验签胜利与否
        $result = self::instance()->aliPaycheck($get);
        // 记录日志
        self::instance()->isLog && self::instance()->writeLog(compact('result', 'get'));
        return compact('result', 'get');
    }

其余的业务逻辑可依据本身需要编写, 以上就是支付宝领取的下单, 退款, 异步同步回调
记得进入后盾减少对应的支付宝配置。

正文完
 0