支付宝支付接入流程

支付宝支付需要签约,并有商家号,但是测试环境中,我们可以使用支付宝提供的沙箱环境,在这个后台中进行配置,接通后,可以进行模拟支付。正式开发时,需要到开发者中心创建应用,并选择要使用的功能,以及签约。

框架:ThinkPHP 5.0

演示的支付接口:支付宝电脑网站支付(手机网站支付操作一样)

下载官方 Demo

进入支付宝开放平台,选择文档中心,在选择电脑网站支付,找到 demo 进行下载。下载解压后,将目录名修改为 “AlipayTradePagePay”,由于是手动下载的第三方类库,所以放置到框架的 extend 目录下,如下图:

附功能说明图:

完善配置项

demo 中有个 config.php 文件,我们为了方便,将这个文件中的配置项先复制下来,到 application/extra 目录下,创建名为 alipay.php 配置文件,并将刚复制的配置项放置在这里。extra 目录下是放置扩展配置文件的,完成后效果如下:

application/extra/alipay.php

<?php
    return [
        //应用ID,您的APPID。
        'app_id' => "",

        //商户私钥,也就是支付宝开发助手上生成的应用私钥
        'merchant_private_key' => "",

        //异步通知地址
        'notify_url' => "http://zhifu.acier.cn/index/index/notify_url",

        //同步跳转
        'return_url' => "http://zhifu.acier.cn/index/index/return_url",

        //编码格式
        'charset' => "UTF-8",

        //签名方式
        'sign_type'=>"RSA2",

        //支付宝网关,沙箱环境和正式环境不一样,这里使用沙箱环境
        'gatewayUrl' => "https://openapi.alipaydev.com/gateway.do",

        //支付宝公钥,查看地址:https://openhome.alipay.com/platform/keyManage.htm 对应APPID下的支付宝公钥。
        'alipay_public_key' => "",
    ];

完善上述配置,打开支付宝沙箱环境页面,在“必看部分”可以看到 APPID ,支付宝网关的信息,然后设置 RSA2(SHA256)密钥,这部分内容和之前写过支付宝第三方登录获取公钥私钥是一样的,首先需要下载“支付宝开放平台开发助手”这个工具,打开工具,选择下图所示选项,然后点击 “生成密钥” 按钮,就生成了应用私钥和应用公钥了。

在沙箱环境的“RSA2(SHA256)密钥”选项处点击“设置/查看”按钮,将应用公钥复制到弹出的框内:

保存设置,然后就能生成支付宝公钥,如下图:

将商户私钥(应用私钥)和支付宝公钥粘贴到配置文件中,notify_url 和 return_url 自己设定。

访问:域名/index/index/index

控制器代码:

<?php
namespace app\index\controller;

class Index
{
    public function index()
    {
        dump(config('alipay'));
    }
}

访问后,确保刚配置的信息可以正常打印出来。

创建函数文件

位置:application/index/common.php,内容如下:

<?php

//生成唯一订单号
function build_order_no(){
    return date('Ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
}
/**
 * 支付宝 电脑网站支付
 * @auhor hongweizhiyuan
 * @param $out_trade_no     商户订单号
 * @param $subject          订单名称
 * @param $total_amount     订单金额
 * @param $body             商品描述
 * @example alipayPagepay('201791711599526','商品标题','0.01','商品描述');
 */
function alipayPagepay($out_trade_no,$subject,$total_amount,$body)
{
    //step1:获取配置
    import('AlipayTradePagePay.pagepay.service.AlipayTradeService',EXTEND_PATH,'.php');// 加载交易服务类
    $config=config('alipay');
    $aop=new AlipayTradeService($config);

    //step2:加载表单,构造参数
    import('AlipayTradePagePay.pagepay.buildermodel.AlipayTradePagePayContentBuilder',EXTEND_PATH,'.php');  // 支付宝电脑网站支付
    $payRequestBuilder = new AlipayTradePagePayContentBuilder();
    $payRequestBuilder->setBody($body);
    $payRequestBuilder->setSubject($subject);
    $payRequestBuilder->setTotalAmount($total_amount);
    $payRequestBuilder->setOutTradeNo($out_trade_no);

    //step3:创建支付
    $response = $aop->pagePay($payRequestBuilder,$config['return_url'],$config['notify_url']);

    //输出表单
    var_dump($response);

}

/**
 * 支付宝 电脑网站 交易查询
 * @param $WIDTQout_trade_no     商户订单号,商户网站订单系统中唯一订单号(请二选一设置)
 * @param $WIDTQtrade_no         支付宝交易号(请二选一设置)
 */
function alipayQuery($WIDTQout_trade_no,$WIDTQtrade_no)
{
    //step1:获取配置
    import('AlipayTradePagePay.pagepay.service.AlipayTradeService',EXTEND_PATH,'.php');// 加载交易服务类
    $config=config('alipay');
    $aop = new AlipayTradeService($config);

    //step2:加载表单,构造参数
    import('AlipayTradePagePay.pagepay.buildermodel.AlipayTradeQueryContentBuilder',EXTEND_PATH,'.php');  // 支付宝电脑网站支付查询接口
    $RequestBuilder = new AlipayTradeQueryContentBuilder();
    $RequestBuilder->setOutTradeNo($WIDTQout_trade_no);
    $RequestBuilder->setTradeNo($WIDTQtrade_no);

    /**
     * alipay.trade.query (统一收单线下交易查询)
     * @param $builder 业务参数,使用buildmodel中的对象生成。
     * @return $response 支付宝返回的信息
     */
    $response = $aop->Query($RequestBuilder);
    var_dump($response);
}

/**
 * 支付宝 电脑网站 退款
 * @param $out_trade_no     商户订单号,商户网站订单系统中唯一订单号(请二选一设置)
 * @param $trade_no         支付宝交易号(请二选一设置)
 * @param $refund_amount    需要退款的金额,该金额不能大于订单金额,必填
 * @param $refund_reason    退款的原因说明
 * @param $out_request_no   标识一次退款请求,同一笔交易多次退款需要保证唯一,如需部分退款,则此参数必传
 */
function alipayRefund($out_trade_no,$trade_no,$refund_amount,$refund_reason,$out_request_no)
{
    //step1:获取配置
    import('AlipayTradePagePay.pagepay.service.AlipayTradeService',EXTEND_PATH,'.php');// 加载交易服务类
    $config=config('alipay');
    $aop = new AlipayTradeService($config);

    //step2:加载表单,构造参数
    import('AlipayTradePagePay.pagepay.buildermodel.AlipayTradeRefundContentBuilder',EXTEND_PATH,'.php');  // 支付宝电脑网站支付退款接口
    $RequestBuilder=new AlipayTradeRefundContentBuilder();
    $RequestBuilder->setOutTradeNo($out_trade_no);
    $RequestBuilder->setTradeNo($trade_no);
    $RequestBuilder->setRefundAmount($refund_amount);
    $RequestBuilder->setOutRequestNo($out_request_no);
    $RequestBuilder->setRefundReason($refund_reason);

    /**
     * alipay.trade.refund (统一收单交易退款接口)
     * @param $builder 业务参数,使用buildmodel中的对象生成。
     * @return $response 支付宝返回的信息
     */
    $response = $aop->Refund($RequestBuilder);
    var_dump($response);;
}

/**
 * 支付宝 电脑网站 退款查询
 * @param $out_trade_no         商户订单号,商户网站订单系统中唯一订单号(请二选一设置)
 * @param $trade_no             支付宝交易号(请二选一设置)
 * @param $out_request_no       请求退款接口时,传入的退款请求号,如果在退款请求时未传入,则该值为创建交易时的外部交易号,必填
 */
function alipayRefundQuery($out_trade_no,$trade_no,$out_request_no)
{
    //step1:获取配置
    import('AlipayTradePagePay.pagepay.service.AlipayTradeService',EXTEND_PATH,'.php');// 加载交易服务类
    $config=config('alipay');
    $aop = new AlipayTradeService($config);

    //step2:加载表单,构造参数
    import('AlipayTradePagePay.pagepay.buildermodel.AlipayTradeFastpayRefundQueryContentBuilder',EXTEND_PATH,'.php');  // 支付宝电脑网站 统一收单交易退款查询
    $RequestBuilder=new AlipayTradeFastpayRefundQueryContentBuilder();
    $RequestBuilder->setOutTradeNo($out_trade_no);
    $RequestBuilder->setTradeNo($trade_no);
    $RequestBuilder->setOutRequestNo($out_request_no);

    /**
     * 退款查询   alipay.trade.fastpay.refund.query (统一收单交易退款查询)
     * @param $builder 业务参数,使用buildmodel中的对象生成。
     * @return $response 支付宝返回的信息
     */
    $response = $aop->refundQuery($RequestBuilder);
    var_dump($response);
}

/**
 * 支付宝 电脑网站 交易关闭
 * @param $out_trade_no     商户订单号,商户网站订单系统中唯一订单号(请二选一设置)
 * @param $trade_no         支付宝交易号(请二选一设置)
 */
function alipayClose($out_trade_no,$trade_no)
{
    //step1:获取配置
    import('AlipayTradePagePay.pagepay.service.AlipayTradeService',EXTEND_PATH,'.php');// 加载交易服务类
    $config=C('ALIPAY_CONFIG');
    $aop = new AlipayTradeService($config);

    //step2:加载表单,构造参数
    import('AlipayTradePagePay.pagepay.buildermodel.AlipayTradeCloseContentBuilder',EXTEND_PATH,'.php');  // 支付宝电脑网站 统一收单交易关闭接口
    $RequestBuilder=new AlipayTradeCloseContentBuilder();
    $RequestBuilder->setOutTradeNo($out_trade_no);
    $RequestBuilder->setTradeNo($trade_no);

    /**
     * alipay.trade.close (统一收单交易关闭接口)
     * @param $builder 业务参数,使用buildmodel中的对象生成。
     * @return $response 支付宝返回的信息
     */
    $response = $aop->Close($RequestBuilder);
    var_dump($response);
}

开始使用

本功能官方文档:https://opendocs.alipay.com/apis/api_1/alipay.trade.page.pay

设置 demo 中 log.txt 权限为 777。

访问:域名/index/index/pagepayTest

方法代码:

public function pagepayTest()
{
    alipayPagepay(build_order_no(),'商品标题','666','商品描述');
}

访问后,如果使用 PHP 7.2 版本,会发现有报错。打开框架配置文件 applica/config.php ,开启调试模式和应用Trace,可以看到错误提示:

发现是 each() 这个函数已经废弃了,并且框架把错误的代码也贴出来了。将鼠标放在错误提示上,即可看到错误位置的具体路径:

根据提示,查找到 /extend/AlipayTradePagePay/aop/AopClient.php 这个文件的413行,将:

while (list ($key, $val) = each ($para_temp)) {

替换为:

foreach ($para_temp as $key => $val) {

发现可以正常访问了。若出现以下情况:

可以通过尝试更换浏览器解决。正常情况是可以扫码支付了。

这里不能用我们自己的支付宝扫码支付,需要下载沙箱环境专用的支付宝APP来进行支付,在沙箱应用中有下载地址。

支付后的回调

刚在支付宝配置文件中我们设置了 同步跳转 和 异步通知地址,简单来说,同步跳转 是当用户支付完成后,页面要跳到的地址,使用户能够回到项目中继续其他操作。而 异步通知 是支付后用来处理业务逻辑信息的,例如修改数据库中该件商品的支付状态,减库存等等。

支付后,同步跳转 return_url() 方法会接收到如下参数:

out_trade_no:商户订单号

total_amount:交易金额

trade_no:支付宝交易号

seller_id:收款支付宝账号对应的支付宝唯一用户号

在 demo 中,已经集成了 return_url.php 和 notify_url.php 两个文件,分别对应这两种回调类型,可以参考。

最后再说一下,异步通知中,因为是支付宝主动发送,cookie 和 session 会失效。若支付后,参数 trade_status 有两种值,TRADE_FINISHEDTRADE_SUCCESS ,前者是交易完结了,后续不会有其它操作了,如退款。后者仅代表本次交易成功,后续可能会有退款,若没有,三个月后,会再次发送过来 TRADE_FINISHED 值。数据库设计中,应确保有这两个字段。即时到账普通版接口没有退款,高级版有退款。

还有最重要一点,异步通知程序执行完后,一定要打印输出 “success” 这七个字符,否则支付宝服务器会不断重发通知,直到超过24小时22分钟。在25小时内完成6~10次通知(通知频率:5s,2m,10m,15m,1h,2h,6h,15h)。

其他接口,例如订单查询,退款等,都在 common.php 中已经写好,组织好参数调用即可。

手机网站支付

手机网页上使用支付宝支付,需要下载手机网站支付 demo ,下载后使用方式和电脑支付一样,只是载入的类名不一样,配置文件和电脑支付都是一样的,可以共用。同样,这里我们也封装在函数里,下面演示一下:

/**
 * 支付宝 手机网站支付
 * @auhor hongweizhiyuan
 * @param $out_trade_no     商户订单号
 * @param $subject          订单名称
 * @param $total_amount     订单金额
 * @param $body             商品描述
 * @example alipayPagepay('201791711599526','商品标题','0.01','商品描述');
 */
function alipayWappay($out_trade_no,$subject,$total_amount,$body)
{
    //step1:获取配置
    import('AlipayTradeWapPay.wappay.service.AlipayTradeService',EXTEND_PATH,'.php');// 加载交易服务类
    $config=config('alipay');
    $aop=new AlipayTradeService($config);

    //超时时间
    $timeout_express="1m";

    //step2:加载表单,构造参数
    import('AlipayTradeWapPay.wappay.buildermodel.AlipayTradeWapPayContentBuilder',EXTEND_PATH,'.php');  // 支付宝电脑网站支付
    $payRequestBuilder = new AlipayTradeWapPayContentBuilder();
    $payRequestBuilder->setBody($body);
    $payRequestBuilder->setSubject($subject);
    $payRequestBuilder->setTotalAmount($total_amount);
    $payRequestBuilder->setOutTradeNo($out_trade_no);
    $payRequestBuilder->setTimeExpress($timeout_express);

    //step3:创建支付
    $response = $aop->wapPay($payRequestBuilder,$config['return_url'],$config['notify_url']);

    //输出表单
    var_dump($response);
}

发表评论

发表回复

沙发空缺中,还不快抢~