可能是我用过的最优雅的 Alipay 和 WeChat 的支付 SDK 了


开发了多次支付宝与微信支付后,很自然产生一种反感,惰性又来了,想在网上找相关的轮子,可是一直没有找到一款自己觉得逞心如意的,要么使用起来太难理解,要么文件结构太杂乱,只有自己撸起袖子干了。

github: https://github.com/yansongda/pay
gitee: https://gitee.com/yansongda/pay

欢迎 Star,欢迎 PR!

潜水了这么久,自己学习了很多,是时候回馈社区了!

晚些时候将开发 laravel 适配包!
laravel 适配包 在这里

特点

  • 命名不那么乱七八糟
  • 隐藏开发者不需要关注的细节
  • 根据支付宝、微信最新 API 开发而成
  • 高度抽象的类,免去各种拼json与xml的痛苦
  • 符合 PSR 标准,你可以各种方便的与你的框架集成
  • 文件结构清晰易理解,可以随心所欲添加本项目中没有的支付网关
  • 方法使用更优雅,不必再去研究那些奇怪的的方法名或者类名是做啥用的

以上部分引用了@overtrue 的部分说明,在此感谢!:satisfied:

运行环境

  • PHP 5.6+
  • composer

支持的支付网关

由于各支付网关参差不齐,所以我们抽象了两个方法 driver()gateway()

两个方法的作用如下:

driver() : 确定支付平台,如 alipay,wechat;

gateway(): 确定支付网关。通过此方法,确定支付平台下的支付网关。例如,支付宝下有 「电脑网站支付」,「手机网站支付」,「APP 支付」三种支付网关,通过传入 web,wap,app 确定。

详细思路可以查看源代码。

1、支付宝

  • 电脑支付
  • 手机网站支付
  • APP 支付

SDK 中对应的 driver 和 gateway 如下表所示:

| driver | gateway | 描述 |
| :----: | :-----: | :-------: |
| alipay | web | 电脑支付 |
| alipay | wap | 手机网站支付 |
| alipay | app | APP 支付 |


2、微信

  • 公众号支付
  • 小程序支付
  • H5 支付
  • 扫码支付
  • 刷卡支付

SDK 中对应的 driver 和 gateway 如下表所示:

| driver | gateway | 描述 |
| :----: | :-----: | :-------: |
| wechat | mp | 公众号支付 |
| wechat | miniapp | 小程序支付 |
| wechat | wap | H5 支付 |
| wechat | scan | 扫码支付 |
| wechat | pos | 刷卡支付 |

支持的方法

所有网关均支持以下方法

  • pay(array $config_biz)

    说明:支付接口

    参数:数组类型,订单业务配置项,包含 订单号,订单金额等

    返回:mixed 详情请看「支付网关配置说明与返回值」一节。

  • refund(array|string $config_biz, $refund_amount = null)

    说明:退款接口

    参数:$config_biz 为字符串类型仅对支付宝支付有效,此时代表订单号,第二个参数为退款金额。

    返回:mixed 退款成功,返回 服务器返回的数组;否则返回 false;

  • close(array|string $config_biz)

    说明:关闭订单接口

    参数:$config_biz 为字符串类型时代表订单号,如果为数组,则为关闭订单业务配置项,配置项内容请参考各个支付网关官方文档。

    返回:mixed 关闭订单成功,返回 服务器返回的数组;否则返回 false;

  • find(string $out_trade_no)

    说明:查找订单接口

    参数:$out_trade_no 为订单号。

    返回:mixed 查找订单成功,返回 服务器返回的数组;否则返回 false;

  • verify($data, $sign = null)

    说明:验证服务器返回消息是否合法

    参数:$data 为服务器接收到的原始内容,$sign 为签名信息,当其为空时,系统将自动转化 $data 为数组,然后取 $data['sign']

    返回:mixed 验证成功,返回 服务器返回的数组;否则返回 false;


安装

composer require yansongda/pay

使用说明

0、一个完整的例子:

<?php

namespace App\Http\Controllers;

use Yansongda\Pay\Pay;
use Illuminate\Http\Request;

class PayController extends Controller
{
    protected $config = [
        'alipay' => [
            'app_id' => '2016082000295641',
            'notify_url' => 'http://yansongda.cn/alipay_notify.php',
            'return_url' => 'http://yansongda.cn/return.php',
            'ali_public_key' => 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuWJKrQ6SWvS6niI+4vEVZiYfjkCfLQfoFI2nCp9ZLDS42QtiL4Ccyx8scgc3nhVwmVRte8f57TFvGhvJD0upT4O5O/lRxmTjechXAorirVdAODpOu0mFfQV9y/T9o9hHnU+VmO5spoVb3umqpq6D/Pt8p25Yk852/w01VTIczrXC4QlrbOEe3sr1E9auoC7rgYjjCO6lZUIDjX/oBmNXZxhRDrYx4Yf5X7y8FRBFvygIE2FgxV4Yw+SL3QAa2m5MLcbusJpxOml9YVQfP8iSurx41PvvXUMo49JG3BDVernaCYXQCoUJv9fJwbnfZd7J5YByC+5KM4sblJTq7bXZWQIDAQAB',
            'private_key' => 'MIIEpAIBAAKCAQEAs6+F2leOgOrvj9jTeDhb5q46GewOjqLBlGSs/bVL4Z3fMr3p+Q1Tux/6uogeVi/eHd84xvQdfpZ87A1SfoWnEGH5z15yorccxSOwWUI+q8gz51IWqjgZxhWKe31BxNZ+prnQpyeMBtE25fXp5nQZ/pftgePyUUvUZRcAUisswntobDQKbwx28VCXw5XB2A+lvYEvxmMv/QexYjwKK4M54j435TuC3UctZbnuynSPpOmCu45ZhEYXd4YMsGMdZE5/077ZU1aU7wx/gk07PiHImEOCDkzqsFo0Buc/knGcdOiUDvm2hn2y1XvwjyFOThsqCsQYi4JmwZdRa8kvOf57nwIDAQABAoIBAQCw5QCqln4VTrTvcW+msB1ReX57nJgsNfDLbV2dG8mLYQemBa9833DqDK6iynTLNq69y88ylose33o2TVtEccGp8Dqluv6yUAED14G6LexS43KtrXPgugAtsXE253ZDGUNwUggnN1i0MW2RcMqHdQ9ORDWvJUCeZj/AEafgPN8AyiLrZeL07jJz/uaRfAuNqkImCVIarKUX3HBCjl9TpuoMjcMhz/MsOmQ0agtCatO1eoH1sqv5Odvxb1i59c8Hvq/mGEXyRuoiDo05SE6IyXYXr84/Nf2xvVNHNQA6kTckj8shSi+HGM4mO1Y4Pbb7XcnxNkT0Inn6oJMSiy56P+CpAoGBAO1O+5FE1ZuVGuLb48cY+0lHCD+nhSBd66B5FrxgPYCkFOQWR7pWyfNDBlmO3SSooQ8TQXA25blrkDxzOAEGX57EPiipXr/hy5e+WNoukpy09rsO1TMsvC+v0FXLvZ+TIAkqfnYBgaT56ku7yZ8aFGMwdCPL7WJYAwUIcZX8wZ3dAoGBAMHWplAqhe4bfkGOEEpfs6VvEQxCqYMYVyR65K0rI1LiDZn6Ij8fdVtwMjGKFSZZTspmsqnbbuCE/VTyDzF4NpAxdm3cBtZACv1Lpu2Om+aTzhK2PI6WTDVTKAJBYegXaahBCqVbSxieR62IWtmOMjggTtAKWZ1P5LQcRwdkaB2rAoGAWnAPT318Kp7YcDx8whOzMGnxqtCc24jvk2iSUZgb2Dqv+3zCOTF6JUsV0Guxu5bISoZ8GdfSFKf5gBAo97sGFeuUBMsHYPkcLehM1FmLZk1Q+ljcx3P1A/ds3kWXLolTXCrlpvNMBSN5NwOKAyhdPK/qkvnUrfX8sJ5XK2H4J8ECgYAGIZ0HIiE0Y+g9eJnpUFelXvsCEUW9YNK4065SD/BBGedmPHRC3OLgbo8X5A9BNEf6vP7fwpIiRfKhcjqqzOuk6fueA/yvYD04v+Da2MzzoS8+hkcqF3T3pta4I4tORRdRfCUzD80zTSZlRc/h286Y2eTETd+By1onnFFe2X01mwKBgQDaxo4PBcLL2OyVT5DoXiIdTCJ8KNZL9+kV1aiBuOWxnRgkDjPngslzNa1bK+klGgJNYDbQqohKNn1HeFX3mYNfCUpuSnD2Yag53Dd/1DLO+NxzwvTu4D6DCUnMMMBVaF42ig31Bs0jI3JQZVqeeFzSET8fkoFopJf3G6UXlrIEAQ==',
        ],
    ];

    public function index()
    {
        $config_biz = [
            'out_trade_no' => time(),
            'total_amount' => '1',
            'subject'      => 'test subject',
        ];

        $pay = new Pay($this->config);

        return $pay->driver('alipay')->gateway()->pay($config_biz);
    }

    public function return(Request $request)
    {
        $pay = new Pay($this->config);

        return $pay->driver('alipay')->gateway()->verify($request->all());
    }

    public function notify(Request $request)
    {
        $pay = new Pay($this->config);

        if ($pay->driver('alipay')->gateway()->verify($request->all())) {
            file_put_contents(storage_path('notify.txt'), "收到来自支付宝的异步通知\r\n", FILE_APPEND);
            file_put_contents(storage_path('notify.txt'), '订单号:' . $request->out_trade_no . "\r\n", FILE_APPEND);
            file_put_contents(storage_path('notify.txt'), '订单金额:' . $request->total_amount . "\r\n\r\n", FILE_APPEND);
        } else {
            file_put_contents(storage_path('notify.txt'), "收到异步通知\r\n", FILE_APPEND);
        }

        echo "success";
    }
}
<?php

namespace App\Http\Controllers;

use Yansongda\Pay\Pay;
use Illuminate\Http\Request;

class PayController extends Controller
{
    protected $config = [
        'wechat' => [
            'app_id' => 'wxb3f6d0xxxxxxxd',
            'mch_id' => '1457768302',
            'notify_url' => 'http://yansongda.cn/wechat_notify.php',
            'key' => 'mF2suE9sU6Mkxxxxxxx5645645',
            'cert_client' => './apiclient_cert.pem',
            'cert_key' => './apiclient_key.pem',
        ],
    ];

    public function index()
    {
        $config_biz = [
            'out_trade_no' => 'e2',
            'total_fee' => '0.01',
            'body' => 'test body',
            'spbill_create_ip' => '14.213.156.207',
            'openid' => 'onkVf1FjWS5SBIihS-123456_abc',
        ];

        $pay = new Pay($this->config);

        return $pay->driver('wechat')->gateway('mp')->pay($config_biz);
    }

    public function notify(Request $request)
    {
        $pay = new Pay($this->config);
        $verify = $p->driver('wechat')->gateway('mp')->verify($request->getContent());

        if ($verify) {
            file_put_contents('notify.txt', "收到来自微信的异步通知\r\n", FILE_APPEND);
            file_put_contents('notify.txt', '订单号:' . $verify['out_trade_no'] . "\r\n", FILE_APPEND);
            file_put_contents('notify.txt', '订单金额:' . $verify['total_fee'] . "\r\n\r\n", FILE_APPEND);
        } else {
            file_put_contents(storage_path('notify.txt'), "收到异步通知\r\n", FILE_APPEND);
        }

        echo "success";
    }
}

1、准备配置参数

$config = [
    'alipay' => [
        'app_id' => '',             // 支付宝提供的 APP_ID
        'ali_public_key' => '',     // 支付宝公钥,1行填写
        'private_key' => '',        // 自己的私钥,1行填写
    ],
];
$config_biz = [
    'out_trade_no' => '12',                 // 订单号
    'total_amount' => '13',                 // 订单金额,单位:元
    'subject' => 'test subject',   // 订单商品标题
];

2、在代码中使用

$pay = new Pay($config);
return $pay->dirver('alipay')->gateway('web')->pay($config_biz);

错误

使用非跳转接口(如, refund 接口,close 接口)时,如果在调用相关支付网关 API 时有错误产生,会抛出 GatewayException 错误,可以通过 $e->getMessage() 查看,同时,也可通过 $e->raw 查看调用 API 后返回的原始数据,该值为数组格式。

支付网关配置说明与返回值

由于支付网关不同,每家参数参差不齐,为了方便,我们抽象定义了两个参数:$config,$config_biz,分别为全局参数,业务参数。但是,所有配置参数均为官方标准参数,无任何差别。

「业务参数」为订单相关的参数,「全局参数」为除订单相关参数以外的全局性参数。

具体参数列表请查看每个支付网关的使用说明。

请传送至github,查看详细内容

代码贡献

由于测试及使用环境的限制,本项目中只开发了「支付宝」和「微信支付」的相关支付网关。

如果您有其它支付网关的需求,或者发现本项目中需要改进的代码,欢迎 Fork 并提交 PR!

感谢大家支持!

LICENSE

MIT


点赞 取消点赞 收藏 取消收藏

<< 上一篇: 如何做到 Laravel 配置可以通过网站后台设置实现

>> 下一篇: Code 好事开源