├── .gitignore
├── src
├── CacertFile
│ ├── old_alipay_public_key.pem
│ └── wx_cacert.pem
├── Common
│ ├── PayException.php
│ ├── BaseStrategy.php
│ ├── Cmb
│ │ └── Data
│ │ │ ├── PubKeyData.php
│ │ │ ├── BindCardData.php
│ │ │ ├── Query
│ │ │ ├── ChargeQueryData.php
│ │ │ └── RefundQueryData.php
│ │ │ ├── RefundData.php
│ │ │ ├── CmbBaseData.php
│ │ │ └── Charge
│ │ │ └── ChargeData.php
│ ├── Weixin
│ │ ├── Data
│ │ │ ├── BackPubChargeData.php
│ │ │ ├── BackAppChargeData.php
│ │ │ ├── Query
│ │ │ │ ├── TransferQueryData.php
│ │ │ │ ├── ChargeQueryData.php
│ │ │ │ └── RefundQueryData.php
│ │ │ ├── WxBaseData.php
│ │ │ ├── Charge
│ │ │ │ ├── AppChargeData.php
│ │ │ │ ├── BarChargeData.php
│ │ │ │ ├── WapChargeData.php
│ │ │ │ ├── ChargeBaseData.php
│ │ │ │ ├── QrChargeData.php
│ │ │ │ └── PubChargeData.php
│ │ │ └── TransferData.php
│ │ └── WechatHelper.php
│ ├── Ali
│ │ └── Data
│ │ │ ├── Query
│ │ │ ├── TransferQueryData.php
│ │ │ ├── ChargeQueryData.php
│ │ │ └── RefundQueryData.php
│ │ │ ├── Charge
│ │ │ ├── AppChargeData.php
│ │ │ ├── QrChargeData.php
│ │ │ ├── WapChargeData.php
│ │ │ ├── WebChargeData.php
│ │ │ ├── ChargeBaseData.php
│ │ │ └── BarChargeData.php
│ │ │ ├── RefundData.php
│ │ │ ├── TransData.php
│ │ │ └── AliBaseData.php
│ └── ConfigInterface.php
├── Notify
│ ├── PayNotifyInterface.php
│ └── NotifyStrategy.php
├── Helper
│ └── Cmb
│ │ ├── BindCardHelper.php
│ │ └── PubKeyHelper.php
├── Charge
│ ├── Cmb
│ │ └── CmbCharge.php
│ ├── Wx
│ │ ├── WxQrCharge.php
│ │ ├── WxWapCharge.php
│ │ ├── WxBarCharge.php
│ │ ├── WxAppCharge.php
│ │ └── WxPubCharge.php
│ └── Ali
│ │ ├── AliAppCharge.php
│ │ ├── AliWapCharge.php
│ │ ├── AliQrCharge.php
│ │ ├── AliWebCharge.php
│ │ └── AliBarCharge.php
├── Utils
│ ├── Rc4Encrypt.php
│ ├── DataParser.php
│ ├── StrUtil.php
│ ├── RsaEncrypt.php
│ ├── Rsa2Encrypt.php
│ └── ArrayUtil.php
├── HelperContext.php
├── Client
│ ├── Refund.php
│ ├── Helper.php
│ ├── Transfer.php
│ ├── Query.php
│ ├── Charge.php
│ └── Notify.php
├── Query
│ ├── Cmb
│ │ ├── CmbRefundQuery.php
│ │ └── CmbChargeQuery.php
│ ├── Ali
│ │ ├── AliRefundQuery.php
│ │ ├── AliTransferQuery.php
│ │ └── AliChargeQuery.php
│ └── Wx
│ │ ├── WxChargeQuery.php
│ │ └── WxTransferQuery.php
├── TransferContext.php
├── Refund
│ ├── CmbRefund.php
│ ├── AliRefund.php
│ └── WxRefund.php
├── Trans
│ ├── AliTransfer.php
│ └── WxTransfer.php
├── RefundContext.php
├── NotifyContext.php
├── Config.php
└── QueryContext.php
├── examples
├── index.html
├── cmb
│ ├── index.html
│ ├── queryPubKey.php
│ ├── queryOrder.php
│ ├── queryRefund.php
│ ├── refund.php
│ ├── bindCard.php
│ └── charge.php
├── wx
│ ├── queryTransfer.php
│ ├── queryOrder.php
│ ├── queryRefund.php
│ ├── transfer.php
│ ├── refund.php
│ ├── index.html
│ ├── appCharge.php
│ ├── liteCharge.php
│ ├── qrCharge.php
│ ├── barCharge.php
│ ├── pubCharge.php
│ └── wapCharge.php
├── ali
│ ├── queryOrder.php
│ ├── queryTransfer.php
│ ├── queryRefund.php
│ ├── refund.php
│ ├── transfer.php
│ ├── index.html
│ ├── appCharge.php
│ ├── qrCharge.php
│ ├── wapCharge.php
│ ├── webCharge.php
│ └── barCharge.php
├── testNotify.php
├── cmbconfig.php
├── wxconfig.php
├── notify.php
└── aliconfig.php
├── autoload.php
├── composer.json
├── LICENSE
├── SUPPORT.md
└── CONTRIBUTING.md
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | .DS_Store
3 | /codecept.phar
4 | /examples/test.php
5 | /examples/wx/pem
6 | /vendor/
7 | /examples_bak/
8 | /composer.lock
9 | /examples/wxconfig-bak.php
10 | /examples/wx/pem/
11 |
--------------------------------------------------------------------------------
/src/CacertFile/old_alipay_public_key.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN PUBLIC KEY-----
2 | MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCnxj/9qwVfgoUh/y2W89L6BkRA
3 | FljhNhgPdyPuBV64bfQNN1PjbCzkIM6qRdKBoLPXmKKMiFYnkd6rAoprih3/PrQE
4 | B/VsW8OoM8fxn67UDYuyBTqA23MML9q1+ilIZwBC2AQ2UBVOrFXfFl75p6/B5Ksi
5 | NG9zpgmLCUYuLkxpLQIDAQAB
6 | -----END PUBLIC KEY-----
--------------------------------------------------------------------------------
/examples/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 支付演示demo
6 |
7 |
8 |
13 |
14 |
--------------------------------------------------------------------------------
/autoload.php:
--------------------------------------------------------------------------------
1 | getMessage();
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/Notify/PayNotifyInterface.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 招商一网通支付demo
6 |
7 |
8 |
13 |
14 |
18 |
19 |
22 |
23 |
--------------------------------------------------------------------------------
/examples/cmb/queryPubKey.php:
--------------------------------------------------------------------------------
1 | errorMessage();
25 | exit;
26 | }
27 |
28 | echo json_encode($ret, JSON_UNESCAPED_UNICODE);
29 |
--------------------------------------------------------------------------------
/examples/wx/queryTransfer.php:
--------------------------------------------------------------------------------
1 | '1489852933',
22 | ];
23 |
24 | try {
25 | $ret = Query::run(Config::WX_CHARGE, $wxConfig, $data);
26 | } catch (PayException $e) {
27 | echo $e->errorMessage();
28 | exit;
29 | }
30 |
31 | echo json_encode($ret, JSON_UNESCAPED_UNICODE);
--------------------------------------------------------------------------------
/src/Common/Cmb/Data/PubKeyData.php:
--------------------------------------------------------------------------------
1 | $this->dateTime,
25 | 'branchNo' => $this->branchNo,
26 | 'merchantNo' => $this->merchantNo,
27 | 'txCode' => CmbConfig::TRADE_CODE,
28 | ];
29 |
30 | // 这里不能进行过滤空值,招商的空值也要加入签名中
31 | return $reqData;
32 | }
33 | }
--------------------------------------------------------------------------------
/examples/wx/queryOrder.php:
--------------------------------------------------------------------------------
1 | '14935505602169',
22 | 'transaction_id' => '20170430190922203640695',
23 | ];
24 |
25 | try {
26 | $ret = Query::run(Config::WX_CHARGE, $wxConfig, $data);
27 | } catch (PayException $e) {
28 | echo $e->errorMessage();
29 | exit;
30 | }
31 |
32 | echo json_encode($ret, JSON_UNESCAPED_UNICODE);
--------------------------------------------------------------------------------
/examples/cmb/queryOrder.php:
--------------------------------------------------------------------------------
1 | '9336161758',
20 | 'date' => '20170428',
21 | 'transaction_id' => '17242823500000000010',
22 | ];
23 |
24 | try {
25 | $ret = Query::run(Config::CMB_CHARGE, $cmbConfig, $data);
26 | } catch (PayException $e) {
27 | echo $e->errorMessage();
28 | exit;
29 | }
30 |
31 | echo json_encode($ret, JSON_UNESCAPED_UNICODE);
--------------------------------------------------------------------------------
/src/Helper/Cmb/BindCardHelper.php:
--------------------------------------------------------------------------------
1 | config->getewayUrl = 'https://mobile.cmbchina.com/mobilehtml/DebitCard/M_NetPay/OneNetRegister/NP_BindCard.aspx';
19 | if ($this->config->useSandbox) {// 测试
20 | $this->config->getewayUrl = 'http://121.15.180.66:801/mobilehtml/DebitCard/M_NetPay/OneNetRegister/NP_BindCard.aspx';
21 | }
22 |
23 | return BindCardData::class;
24 | }
25 | }
--------------------------------------------------------------------------------
/examples/ali/queryOrder.php:
--------------------------------------------------------------------------------
1 | '15043337047336',
22 | //'trade_no' => '2017090221001004350200242476',
23 | ];
24 |
25 | try {
26 | $ret = Query::run(Config::ALI_CHARGE, $aliConfig, $data);
27 | } catch (PayException $e) {
28 | echo $e->errorMessage();
29 | exit;
30 | }
31 |
32 | echo json_encode($ret, JSON_UNESCAPED_UNICODE);
--------------------------------------------------------------------------------
/examples/ali/queryTransfer.php:
--------------------------------------------------------------------------------
1 | '15043431341',
22 | 'transaction_id' => '201709021100700015026800000163021',
23 | ];
24 |
25 | try {
26 | $ret = Query::run(Config::ALI_TRANSFER, $aliConfig, $data);
27 | } catch (PayException $e) {
28 | echo $e->errorMessage();
29 | exit;
30 | }
31 |
32 | echo json_encode($ret, JSON_UNESCAPED_UNICODE);
--------------------------------------------------------------------------------
/examples/ali/queryRefund.php:
--------------------------------------------------------------------------------
1 | '15043296209218',
21 | 'trade_no' => '2017090221001004350200242476',
22 | 'refund_no' => '15043420895504',
23 | ];
24 |
25 | try {
26 | $ret = Query::run(Config::ALI_REFUND, $aliConfig, $data);
27 | } catch (PayException $e) {
28 | echo $e->errorMessage();
29 | exit;
30 | }
31 |
32 | echo json_encode($ret, JSON_UNESCAPED_UNICODE);
--------------------------------------------------------------------------------
/examples/cmb/queryRefund.php:
--------------------------------------------------------------------------------
1 | '9354737499',
20 | 'refund_no' => '',// 商户退款流水号,长度不超过20位
21 | 'date' => '20170430',
22 | 'refund_id' => '',// 银行退款流水号,长度不超过20位
23 | ];
24 |
25 | try {
26 | $ret = Query::run(Config::CMB_REFUND, $cmbConfig, $data);
27 | } catch (PayException $e) {
28 | echo $e->errorMessage();
29 | exit;
30 | }
31 |
32 | echo json_encode($ret, JSON_UNESCAPED_UNICODE);
--------------------------------------------------------------------------------
/src/Charge/Cmb/CmbCharge.php:
--------------------------------------------------------------------------------
1 | config->getewayUrl = 'https://netpay.cmbchina.com/netpayment/BaseHttp.dll?MB_EUserPay';
23 | if ($this->config->useSandbox) {// 测试
24 | $this->config->getewayUrl = 'http://121.15.180.66:801/NetPayment/BaseHttp.dll?MB_EUserPay';
25 | }
26 |
27 | return ChargeData::class;
28 | }
29 | }
--------------------------------------------------------------------------------
/examples/testNotify.php:
--------------------------------------------------------------------------------
1 | '14935385689468',
22 | 'refund_no' => '14935506214648',
23 | 'transaction_id' => '12345678920170430191024123337865',
24 | 'refund_id' => '1234567892017043019102412333',
25 | ];
26 |
27 | try {
28 | $ret = Query::run(Config::WX_REFUND, $wxConfig, $data);
29 | } catch (PayException $e) {
30 | echo $e->errorMessage();
31 | exit;
32 | }
33 |
34 | echo json_encode($ret, JSON_UNESCAPED_UNICODE);
--------------------------------------------------------------------------------
/examples/ali/refund.php:
--------------------------------------------------------------------------------
1 | '15043296209218',
23 | 'trade_no' => '',// 支付宝交易号, 与 out_trade_no 必须二选一
24 | 'refund_fee' => '0.01',
25 | 'reason' => '我要退款',
26 | 'refund_no' => $refundNo,
27 | ];
28 |
29 | try {
30 | $ret = Refund::run(Config::ALI_REFUND, $aliConfig, $data);
31 | } catch (PayException $e) {
32 | echo $e->errorMessage();
33 | exit;
34 | }
35 |
36 | echo json_encode($ret, JSON_UNESCAPED_UNICODE);
--------------------------------------------------------------------------------
/examples/cmb/refund.php:
--------------------------------------------------------------------------------
1 | '9354737499',
22 | 'date' => '20170430',
23 | 'refund_no' => $refundNo,
24 | 'refund_fee' => 0.01,
25 | 'reason' => '测试帐号退款',
26 | 'operator_id' => '9999',
27 | ];
28 |
29 | try {
30 | $ret = Refund::run(Config::CMB_REFUND, $cmbConfig, $data);
31 | } catch (PayException $e) {
32 | echo $e->errorMessage();
33 | exit;
34 | }
35 |
36 | echo json_encode($ret, JSON_UNESCAPED_UNICODE);
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "riverslei/payment",
3 | "type": "library",
4 | "description": "支付宝支付、微信支付、招商一网通支付php SDK。方便快速接入,最完整的开源支付 php sdk",
5 | "keywords": ["alipay", "weixin", "支付宝支付", "微信支付", "集成支付接口SDK", "招商一网通", "一网通"],
6 | "homepage": "https://helei112g.github.io/categories/payment-3/",
7 | "license": "MIT",
8 | "authors": [
9 | {
10 | "name": "helei",
11 | "email": "dayugog@gmail.com",
12 | "homepage": "https://helei112g.github.io/categories/payment-3/"
13 | }
14 | ],
15 | "require": {
16 | "php": ">=5.6",
17 | "ext-bcmath": "*",
18 | "ext-mbstring": "*",
19 | "guzzlehttp/guzzle": "~6.0"
20 | },
21 | "require-dev": {
22 | "endroid/qrcode": "~1.9",
23 | "codeception/codeception": "*"
24 | },
25 | "autoload": {
26 | "psr-4": {"Payment\\": "src/"}
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/examples/ali/transfer.php:
--------------------------------------------------------------------------------
1 | time(),
21 | 'payee_type' => 'ALIPAY_LOGONID',
22 | 'payee_account' => 'aaqlmq0729@sandbox.com',// ALIPAY_USERID: 2088102169940354 ALIPAY_LOGONID:aaqlmq0729@sandbox.com
23 | 'amount' => '1000',
24 | 'remark' => '转账拉,有钱了',
25 | 'payer_show_name' => '一个未来的富豪',
26 | ];
27 |
28 | try {
29 | $ret = Transfer::run(Config::ALI_TRANSFER, $aliConfig, $data);
30 | } catch (PayException $e) {
31 | echo $e->errorMessage();
32 | exit;
33 | }
34 |
35 | echo json_encode($ret, JSON_UNESCAPED_UNICODE);
--------------------------------------------------------------------------------
/examples/wx/transfer.php:
--------------------------------------------------------------------------------
1 | time(),
20 | 'openid' => 'o-e_mwTXTaxEhBM8xDoj1ui1f950',
21 | 'check_name' => 'NO_CHECK',// NO_CHECK:不校验真实姓名 FORCE_CHECK:强校验真实姓名 OPTION_CHECK:针对已实名认证的用户才校验真实姓名
22 | 'payer_real_name' => '何磊',
23 | 'amount' => '1',
24 | 'desc' => '测试转账',
25 | 'spbill_create_ip' => '127.0.0.1',
26 | ];
27 |
28 | try {
29 | $ret = Transfer::run(Config::WX_TRANSFER, $wxConfig, $data);
30 | } catch (PayException $e) {
31 | echo $e->errorMessage();
32 | exit;
33 | }
34 |
35 | echo json_encode($ret, JSON_UNESCAPED_UNICODE);
--------------------------------------------------------------------------------
/src/Common/Weixin/Data/BackPubChargeData.php:
--------------------------------------------------------------------------------
1 | retData = [
26 | 'appId' => $this->appId,
27 | 'timeStamp' => time() . '',
28 | 'nonceStr' => $this->nonceStr,
29 | 'package' => 'prepay_id=' . $this->prepay_id,
30 | 'signType' => 'MD5',// 签名算法,暂支持MD5
31 | ];
32 | }
33 |
34 | protected function checkDataParam()
35 | {
36 | // 不进行检查
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/examples/wx/refund.php:
--------------------------------------------------------------------------------
1 | '14935385689468',
23 | 'total_fee' => '3.01',
24 | 'refund_fee' => '3.01',
25 | 'refund_no' => $refundNo,
26 | 'refund_account' => WxConfig::REFUND_RECHARGE,// REFUND_RECHARGE:可用余额退款 REFUND_UNSETTLED:未结算资金退款(默认)
27 | ];
28 |
29 | try {
30 | $ret = Refund::run(Config::WX_REFUND, $wxConfig, $data);
31 | } catch (PayException $e) {
32 | echo $e->errorMessage();
33 | exit;
34 | }
35 |
36 | echo json_encode($ret, JSON_UNESCAPED_UNICODE);
--------------------------------------------------------------------------------
/src/Charge/Wx/WxQrCharge.php:
--------------------------------------------------------------------------------
1 | config->tradeType = 'NATIVE';// 微信文档这里写错了
19 | return QrChargeData::class;
20 | }
21 |
22 | /**
23 | * 处理扫码支付的返回值
24 | * @param array $ret
25 | * @return string 可生产二维码的uri
26 | * @author helei
27 | */
28 | protected function retData(array $ret)
29 | {
30 | if ($this->config->returnRaw) {
31 | return $ret;
32 | }
33 |
34 | // 扫码支付,返回链接
35 | return $ret['code_url'];
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/examples/cmbconfig.php:
--------------------------------------------------------------------------------
1 | true,// 是否使用 招商测试系统
12 |
13 | 'branch_no' => 'xxx', // 商户分行号,4位数字
14 | 'merchant_no' => 'xxxx',// 商户号,6位数字
15 | 'mer_key' => 'xxxxxx',// 秘钥16位,包含大小写字母 数字
16 |
17 | // 招商的公钥,建议每天凌晨2:15发起查询招行公钥请求更新公钥。
18 | 'cmb_pub_key' => 'xxxxx',
19 |
20 | 'op_pwd' => 'xxxxx',// 操作员登录密码。
21 | 'sign_type' => 'SHA-256',// 签名算法,固定为“SHA-256”
22 | 'limit_pay' => [
23 | //'A',
24 | ],// 允许支付的卡类型,默认对支付卡种不做限制,储蓄卡和信用卡均可支付 A:储蓄卡支付,即禁止信用卡支付
25 |
26 | 'notify_url' => 'http://114.215.86.31/__readme/phpinfo.php',// 支付成功的回调
27 |
28 | 'sign_notify_url' => 'http://114.215.86.31/__readme/phpinfo.php',// 成功签约结果通知地址
29 |
30 | 'return_url' => 'https://helei112g.github.io/',// 如果是h5支付,可以设置该值,返回到指定页面
31 |
32 | 'return_raw' => false,// 在处理回调时,是否直接返回原始数据,默认为true
33 | ];
--------------------------------------------------------------------------------
/src/Common/Weixin/Data/BackAppChargeData.php:
--------------------------------------------------------------------------------
1 | retData = [
25 | 'appid' => $this->appId,
26 | 'partnerid' => $this->mchId,
27 | 'prepayid' => $this->prepay_id,
28 | 'package' => 'Sign=WXPay',
29 | 'noncestr' => StrUtil::getNonceStr(),
30 | 'timestamp' => time(),
31 | ];
32 | }
33 |
34 | protected function checkDataParam()
35 | {
36 | // 对于返回数据不做检查检查
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/examples/wx/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 微信支付demo
6 |
7 |
8 |
16 |
17 |
22 |
23 |
27 |
28 |
--------------------------------------------------------------------------------
/src/Common/Ali/Data/Query/TransferQueryData.php:
--------------------------------------------------------------------------------
1 | $this->trans_no,
23 | 'order_id' => $this->transaction_id,
24 | ];
25 |
26 | return $content;
27 | }
28 |
29 | protected function checkDataParam()
30 | {
31 | $transNo = $this->trans_no;
32 | $transactionId = $this->transaction_id;
33 |
34 | // 二者不能同时为空
35 | if (empty($transactionId) && empty($transNo)) {
36 | throw new PayException('必须提供支付宝转账单据号或者商户转账单号');
37 | }
38 | }
39 | }
--------------------------------------------------------------------------------
/examples/wx/appCharge.php:
--------------------------------------------------------------------------------
1 | 'test body',
23 | 'subject' => 'test subject',
24 | 'order_no' => $orderNo,
25 | 'timeout_express' => time() + 600,// 表示必须 600s 内付款
26 | 'amount' => '3.01',// 微信沙箱模式,需要金额固定为3.01
27 | 'return_param' => '123',
28 | 'client_ip' => isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '127.0.0.1',// 客户地址
29 | ];
30 |
31 | try {
32 | $ret = Charge::run(Config::WX_CHANNEL_APP, $wxConfig, $payData);
33 | } catch (PayException $e) {
34 | echo $e->errorMessage();
35 | exit;
36 | }
37 |
38 | echo json_encode($ret, JSON_UNESCAPED_UNICODE);
--------------------------------------------------------------------------------
/src/Charge/Wx/WxWapCharge.php:
--------------------------------------------------------------------------------
1 | config->tradeType = 'MWEB';
20 | return WapChargeData::class;
21 | }
22 |
23 | /**
24 | * 这里由于
25 | * @param array $ret
26 | * @return mixed
27 | */
28 | protected function retData(array $ret)
29 | {
30 | if ($this->config->returnRaw) {
31 | return $ret;
32 | }
33 |
34 | $wabUrl = $ret['mweb_url'];
35 | if ($this->config->returnUrl) {
36 | $wabUrl .= '&redirect_url=' . urlencode($this->config->returnUrl);
37 | }
38 |
39 | return $wabUrl;
40 | }
41 | }
--------------------------------------------------------------------------------
/examples/ali/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 支付宝支付demo
6 |
7 |
8 |
15 |
16 |
21 |
22 |
26 |
27 |
30 |
31 |
--------------------------------------------------------------------------------
/examples/wxconfig.php:
--------------------------------------------------------------------------------
1 | true,// 是否使用 微信支付仿真测试系统
10 |
11 | 'app_id' => 'wxxxxxx', // 公众账号ID
12 | 'mch_id' => 'xxxxx',// 商户id
13 | 'md5_key' => 'xxxxxxx',// md5 秘钥
14 | 'app_cert_pem' => dirname(__FILE__) . DIRECTORY_SEPARATOR . 'wx' . DIRECTORY_SEPARATOR . 'pem' . DIRECTORY_SEPARATOR . 'weixin_app_cert.pem',
15 | 'app_key_pem' => dirname(__FILE__) . DIRECTORY_SEPARATOR . 'wx' . DIRECTORY_SEPARATOR . 'pem' . DIRECTORY_SEPARATOR . 'weixin_app_key.pem',
16 | 'sign_type' => 'MD5',// MD5 HMAC-SHA256
17 | 'limit_pay' => [
18 | //'no_credit',
19 | ],// 指定不能使用信用卡支付 不传入,则均可使用
20 | 'fee_type' => 'CNY',// 货币类型 当前仅支持该字段
21 |
22 | 'notify_url' => 'https://helei112g.github.io/v1/notify/wx',
23 |
24 | 'redirect_url' => 'https://helei112g.github.io/',// 如果是h5支付,可以设置该值,返回到指定页面
25 |
26 | 'return_raw' => false,// 在处理回调时,是否直接返回原始数据,默认为true
27 | ];
--------------------------------------------------------------------------------
/src/Charge/Wx/WxBarCharge.php:
--------------------------------------------------------------------------------
1 | config->returnRaw) {
35 | return $ret;
36 | }
37 |
38 | return $ret;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2016-2017 Daniele Alessandri
2 |
3 | Permission is hereby granted, free of charge, to any person
4 | obtaining a copy of this software and associated documentation
5 | files (the "Software"), to deal in the Software without
6 | restriction, including without limitation the rights to use,
7 | copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the
9 | Software is furnished to do so, subject to the following
10 | conditions:
11 |
12 | The above copyright notice and this permission notice shall be
13 | included in all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/src/Charge/Ali/AliAppCharge.php:
--------------------------------------------------------------------------------
1 | config->method = $this->method;
27 | // 以下两种方式任选一种
28 | return AppChargeData::class;
29 | }
30 |
31 | /**
32 | * 组装返回的数据格式
33 | * @param array $data
34 | * @return string
35 | */
36 | protected function retData(array $data)
37 | {
38 | $data = parent::retData($data);
39 |
40 | // 组装成 key=value&key=value 形式返回
41 | return http_build_query($data);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/Charge/Ali/AliWapCharge.php:
--------------------------------------------------------------------------------
1 | config->method = $this->method;
27 | // 以下两种方式任选一种
28 | return WapChargeData::class;
29 | }
30 |
31 | /**
32 | * 返回可发起h5支付的请求
33 | * @param array $data
34 | * @return array|string
35 | */
36 | protected function retData(array $data)
37 | {
38 | $data = parent::retData($data);
39 |
40 | return $this->config->getewayUrl . '?' . http_build_query($data);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/examples/ali/appCharge.php:
--------------------------------------------------------------------------------
1 | 'ali qr pay',
23 | 'subject' => '测试支付宝扫码支付',
24 | 'order_no' => $orderNo,
25 | 'timeout_express' => time() + 600,// 表示必须 600s 内付款
26 | 'amount' => '0.01',// 单位为元 ,最小为0.01
27 | 'return_param' => '123123',
28 | // 'client_ip' => isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '127.0.0.1',// 客户地址
29 | 'goods_type' => '1',// 0—虚拟类商品,1—实物类商品
30 | 'store_id' => '',
31 | ];
32 |
33 | try {
34 | $str = Charge::run(Config::ALI_CHANNEL_APP, $aliConfig, $payData);
35 | } catch (PayException $e) {
36 | echo $e->errorMessage();
37 | exit;
38 | }
39 |
40 | echo $str;// 这里如果直接输出到页面,¬ 会被转义,请注意
--------------------------------------------------------------------------------
/examples/wx/liteCharge.php:
--------------------------------------------------------------------------------
1 | 'test body',
25 | 'subject' => 'test subject',
26 | 'order_no' => $orderNo,
27 | 'timeout_express' => time() + 600,// 表示必须 600s 内付款
28 | 'amount' => '3.01',// 微信沙箱模式,需要金额固定为3.01
29 | 'return_param' => '123',
30 | 'client_ip' => isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '127.0.0.1',// 客户地址
31 | 'openid' => 'ottkCuO1PW1Dnh6PWFffNk-2MPbY',
32 | 'product_id' => '123',
33 | ];
34 |
35 | try {
36 | $ret = Charge::run(Config::WX_CHANNEL_LITE, $wxConfig, $payData);
37 | } catch (PayException $e) {
38 | echo $e->errorMessage();
39 | exit;
40 | }
41 |
42 | echo json_encode($ret, JSON_UNESCAPED_UNICODE);
--------------------------------------------------------------------------------
/src/CacertFile/wx_cacert.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV
3 | UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy
4 | dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1
5 | MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx
6 | dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B
7 | AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f
8 | BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A
9 | cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC
10 | AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ
11 | MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm
12 | aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw
13 | ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj
14 | IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF
15 | MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA
16 | A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y
17 | 7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh
18 | 1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4
19 | -----END CERTIFICATE-----
--------------------------------------------------------------------------------
/examples/ali/qrCharge.php:
--------------------------------------------------------------------------------
1 | 'ali qr pay',
23 | 'subject' => '测试支付宝扫码支付',
24 | 'order_no' => $orderNo,
25 | 'timeout_express' => time() + 600,// 表示必须 600s 内付款
26 | 'amount' => '0.01',// 单位为元 ,最小为0.01
27 | 'return_param' => '123123',
28 | // 'client_ip' => isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '127.0.0.1',// 客户地址
29 | 'goods_type' => '1',// 0—虚拟类商品,1—实物类商品
30 | 'store_id' => '',
31 |
32 | 'operator_id' => '',
33 | 'terminal_id' => '',// 终端设备号(门店号或收银设备ID) 默认值 web
34 | ];
35 |
36 |
37 | try {
38 | $url = Charge::run(Config::ALI_CHANNEL_QR, $aliConfig, $payData);
39 | } catch (PayException $e) {
40 | echo $e->errorMessage();
41 | exit;
42 | }
43 |
44 | echo $url;
45 |
--------------------------------------------------------------------------------
/examples/ali/wapCharge.php:
--------------------------------------------------------------------------------
1 | 'ali wap pay',
23 | 'subject' => '测试支付宝手机网站支付',
24 | 'order_no' => $orderNo,
25 | 'timeout_express' => time() + 600,// 表示必须 600s 内付款
26 | 'amount' => '0.01',// 单位为元 ,最小为0.01
27 | 'return_param' => 'tata',// 一定不要传入汉字,只能是 字母 数字组合
28 | // 'client_ip' => isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '127.0.0.1',// 客户地址
29 | 'goods_type' => '1',// 0—虚拟类商品,1—实物类商品
30 | 'store_id' => '',
31 | 'quit_url' => 'http://helei112g.github.io', // 收银台的返回按钮(用户打断支付操作时返回的地址,4.0.3版本新增)
32 | ];
33 |
34 | try {
35 | $url = Charge::run(Config::ALI_CHANNEL_WAP, $aliConfig, $payData);
36 | } catch (PayException $e) {
37 | echo $e->errorMessage();
38 | exit;
39 | }
40 |
41 | header('Location:' . $url);
--------------------------------------------------------------------------------
/examples/wx/qrCharge.php:
--------------------------------------------------------------------------------
1 | 'test body',
24 | 'subject' => 'test subject',
25 | 'order_no' => $orderNo,
26 | 'timeout_express' => time() + 600,// 表示必须 600s 内付款
27 | 'amount' => '3.01',// 微信沙箱模式,需要金额固定为3.01
28 | 'return_param' => '123',
29 | 'client_ip' => isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '127.0.0.1',// 客户地址
30 | 'openid' => 'ohQeiwnNrAsfdsdf9VvmGFIhba--k',
31 | 'product_id' => '123',
32 |
33 | // 如果是服务商,请提供以下参数
34 | 'sub_appid' => '',//微信分配的子商户公众账号ID
35 | 'sub_mch_id' => '',// 微信支付分配的子商户号
36 | ];
37 |
38 | try {
39 | $ret = Charge::run(Config::WX_CHANNEL_QR, $wxConfig, $payData);
40 | } catch (PayException $e) {
41 | echo $e->errorMessage();
42 | exit;
43 | }
44 |
45 | echo $ret;
--------------------------------------------------------------------------------
/src/Common/Weixin/Data/Query/TransferQueryData.php:
--------------------------------------------------------------------------------
1 | retData = [
30 | 'appid' => $this->appId,
31 | 'mch_id' => $this->mchId,
32 | 'nonce_str' => $this->nonceStr,
33 | //'sign_type' => $this->signType,// 转账查询,不能加入该数据
34 |
35 | 'partner_trade_no' => $this->trans_no,
36 | ];
37 |
38 | $this->retData = ArrayUtil::paraFilter($this->retData);
39 | }
40 |
41 | protected function checkDataParam()
42 | {
43 | $transNo = $this->trans_no;
44 | if (empty($transNo)) {
45 | throw new PayException('请提供商户调用企业付款API时使用的商户订单号');
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/src/Charge/Ali/AliQrCharge.php:
--------------------------------------------------------------------------------
1 | config->method = $this->method;
25 | return QrChargeData::class;
26 | }
27 |
28 | /**
29 | * 处理扫码支付的返回值
30 | * @param array $ret
31 | *
32 | * @throws PayException
33 | * @return string 可生产二维码的uri
34 | * @author helei
35 | */
36 | protected function retData(array $ret)
37 | {
38 | $url = parent::retData($ret);
39 |
40 | // 发起网络请求
41 | try {
42 | $data = $this->sendReq($url);
43 | } catch (PayException $e) {
44 | throw $e;
45 | }
46 |
47 | return $data['qr_code'];
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/Charge/Ali/AliWebCharge.php:
--------------------------------------------------------------------------------
1 | config->method = $this->method;
30 | // 以下两种方式均可以
31 | return WebChargeData::class;
32 | //return 'Payment\Common\Ali\Data\Charge\WebChargeData';
33 | }
34 |
35 | /**
36 | * 返回可发起h5支付的请求
37 | * @param array $data
38 | * @return array|string
39 | */
40 | protected function retData(array $data)
41 | {
42 | $data = parent::retData($data);
43 |
44 | return $this->config->getewayUrl . '?' . http_build_query($data);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/examples/ali/webCharge.php:
--------------------------------------------------------------------------------
1 | 'ali web pay',
24 | 'subject' => '测试支付宝电脑网站支付',
25 | 'order_no' => $orderNo,
26 | 'timeout_express' => time() + 600,// 表示必须 600s 内付款
27 | 'amount' => '0.01',// 单位为元 ,最小为0.01
28 | 'return_param' => '123123',
29 | // 'client_ip' => isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '127.0.0.1',// 客户地址
30 | 'goods_type' => '1',// 0—虚拟类商品,1—实物类商品
31 | 'store_id' => '',
32 |
33 | // 说明地址:https://doc.open.alipay.com/doc2/detail.htm?treeId=270&articleId=105901&docType=1
34 | // 建议什么也不填
35 | 'qr_mod' => '',
36 | ];
37 |
38 | try {
39 | $url = Charge::run(Config::ALI_CHANNEL_WEB, $aliConfig, $payData);
40 | } catch (PayException $e) {
41 | echo $e->errorMessage();
42 | exit;
43 | }
44 |
45 | header('Location:' . $url);
--------------------------------------------------------------------------------
/examples/wx/barCharge.php:
--------------------------------------------------------------------------------
1 | 'test body',
24 | 'subject' => 'test subject',
25 | 'order_no' => $orderNo,
26 | 'timeout_express' => time() + 600,// 表示必须 600s 内付款
27 | 'amount' => '0.01',// 微信沙箱模式,需要金额固定为0.01
28 | 'return_param' => '123',
29 | 'client_ip' => isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '127.0.0.1',// 客户地址
30 | 'terminal_id' => 'web',// 终端设备号(门店号或收银设备ID) 默认值 web
31 | 'auth_code' => '1231212232323123123',
32 |
33 | // 如果是服务商,请提供以下参数
34 | 'sub_appid' => '',//微信分配的子商户公众账号ID
35 | 'sub_mch_id' => '',// 微信支付分配的子商户号
36 | ];
37 |
38 | try {
39 | $ret = Charge::run(Config::WX_CHANNEL_BAR, $wxConfig, $payData);
40 | } catch (PayException $e) {
41 | echo $e->errorMessage();
42 | exit;
43 | }
44 |
45 | echo json_encode($ret, JSON_UNESCAPED_UNICODE);
--------------------------------------------------------------------------------
/src/Common/ConfigInterface.php:
--------------------------------------------------------------------------------
1 | initConfig($config);
45 | } catch (PayException $e) {
46 | throw $e;
47 | }
48 | }
49 |
50 | /**
51 | * 配置文件初始化具体实现
52 | * @param array $config
53 | */
54 | abstract protected function initConfig(array $config);
55 | }
56 |
--------------------------------------------------------------------------------
/examples/ali/barCharge.php:
--------------------------------------------------------------------------------
1 | 'ali bar pay',
23 | 'subject' => '测试支付宝条码支付',
24 | 'order_no' => $orderNo,
25 | 'timeout_express' => time() + 600,// 表示必须 600s 内付款
26 | 'amount' => '0.01',// 单位为元 ,最小为0.01
27 | 'return_param' => '123123',
28 | // 'client_ip' => isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '127.0.0.1',// 客户地址
29 | 'goods_type' => '1',// 0—虚拟类商品,1—实物类商品
30 | 'store_id' => '',
31 |
32 | 'operator_id' => '',
33 | 'terminal_id' => '',// 终端设备号(门店号或收银设备ID) 默认值 web
34 | 'scene' => 'bar_code',// 条码支付:bar_code 声波支付:wave_code
35 | 'auth_code' => '12312313123',
36 | ];
37 |
38 | try {
39 | $ret = Charge::run(Config::ALI_CHANNEL_BAR, $aliConfig, $payData);
40 | } catch (PayException $e) {
41 | echo $e->errorMessage();
42 | exit;
43 | }
44 |
45 | var_dump($ret);
--------------------------------------------------------------------------------
/examples/wx/pubCharge.php:
--------------------------------------------------------------------------------
1 | 'test body',
25 | 'subject' => 'test subject',
26 | 'order_no' => $orderNo,
27 | 'timeout_express' => time() + 600,// 表示必须 600s 内付款
28 | 'amount' => '3.01',// 微信沙箱模式,需要金额固定为3.01
29 | 'return_param' => '123',
30 | 'client_ip' => isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '127.0.0.1',// 客户地址
31 | 'openid' => 'ottkCuO1PW1Dnh6PWFffNk-2MPbY',
32 | 'product_id' => '123',
33 |
34 | // 如果是服务商,请提供以下参数
35 | 'sub_appid' => '',//微信分配的子商户公众账号ID
36 | 'sub_mch_id' => '',// 微信支付分配的子商户号
37 | 'sub_openid' => '',// 用户在子商户appid下的唯一标识
38 | ];
39 |
40 | try {
41 | $ret = Charge::run(Config::WX_CHANNEL_PUB, $wxConfig, $payData);
42 | } catch (PayException $e) {
43 | echo $e->errorMessage();
44 | exit;
45 | }
46 |
47 | echo json_encode($ret, JSON_UNESCAPED_UNICODE);
--------------------------------------------------------------------------------
/examples/wx/wapCharge.php:
--------------------------------------------------------------------------------
1 | 'test body',
24 | 'subject' => 'test subject',
25 | 'order_no' => $orderNo,
26 | 'timeout_express' => time() + 600,// 表示必须 600s 内付款
27 | 'amount' => '3.01',// 微信沙箱模式,需要金额固定为3.01
28 | 'return_param' => '123',
29 | 'client_ip' => isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '127.0.0.1',// 客户地址
30 |
31 | //{"h5_info": {"type":"Wap","wap_url": "https://pay.qq.com","wap_name": "腾讯充值"}}
32 | 'scene_info' => [
33 | 'type' => 'Wap',// IOS Android Wap 腾讯建议 IOS ANDROID 采用app支付
34 | 'wap_url' => 'https://helei112g.github.io/',//自己的 wap 地址
35 | 'wap_name' => '测试充值',
36 | ],
37 | ];
38 |
39 | try {
40 | $url = Charge::run(Config::WX_CHANNEL_WAP, $wxConfig, $payData);
41 | } catch (PayException $e) {
42 | echo $e->errorMessage();
43 | exit;
44 | }
45 |
46 | echo $url;
--------------------------------------------------------------------------------
/src/Common/Ali/Data/Query/ChargeQueryData.php:
--------------------------------------------------------------------------------
1 | $this->out_trade_no,
30 | 'trade_no' => $this->trade_no,
31 | ];
32 |
33 | return $content;
34 | }
35 |
36 | /**
37 | * 检查参数
38 | * @author helei
39 | */
40 | protected function checkDataParam()
41 | {
42 | $tradeNo = $this->trade_no;// 支付宝交易号,查询效率高
43 | $outTradeNo = $this->out_trade_no;// 商户订单号,查询效率低,不建议使用
44 |
45 | // 二者不能同时为空
46 | if (empty($outTradeNo) && empty($tradeNo)) {
47 | throw new PayException('必须提供支付宝交易号或者商户网站唯一订单号。建议使用支付宝交易号');
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/Common/Ali/Data/Query/RefundQueryData.php:
--------------------------------------------------------------------------------
1 | $this->out_trade_no,
24 | 'trade_no' => $this->trade_no,
25 | 'out_request_no' => $this->refund_no,
26 | ];
27 |
28 | return $content;
29 | }
30 |
31 | protected function checkDataParam()
32 | {
33 | $tradeNo = $this->trade_no;// 支付宝交易号,查询效率高
34 | $outTradeNo = $this->out_trade_no;// 商户订单号,查询效率低,不建议使用
35 |
36 | // 二者不能同时为空
37 | if (empty($outTradeNo) && empty($tradeNo)) {
38 | throw new PayException('必须提供支付宝交易号或者商户网站唯一订单号。建议使用支付宝交易号');
39 | }
40 |
41 | $refundNo = $this->refund_no;
42 | if (empty($refundNo)) {
43 | throw new PayException('支付宝查询退款,必须传入提款的请求号。如果在退款请求时未传入,则该值为创建交易时的外部交易号');
44 | }
45 | }
46 | }
--------------------------------------------------------------------------------
/src/Charge/Wx/WxAppCharge.php:
--------------------------------------------------------------------------------
1 | config->tradeType = 'APP';
20 | return AppChargeData::class;
21 | }
22 |
23 | /**
24 | * 处理APP支付的返回值。直接返回与微信文档对应的字段
25 | * @param array $ret
26 | *
27 | * @return array $data
28 | *
29 | * ```php
30 | * $data = [
31 | * 'appid' => '', // 应用ID
32 | * 'partnerid' => '', // 商户号
33 | * 'prepayid' => '', // 预支付交易会话ID
34 | * 'package' => '', // 扩展字段 固定值:Sign=WXPay
35 | * 'noncestr' => '', // 随机字符串
36 | * 'timestamp' => '', // 时间戳
37 | * 'sign' => '', // 签名
38 | * ];
39 | * ```
40 | * @author helei
41 | */
42 | protected function retData(array $ret)
43 | {
44 | $back = new BackAppChargeData($this->config, $ret);
45 |
46 | $back->setSign();
47 | $backData = $back->getData();
48 |
49 | return $backData;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/SUPPORT.md:
--------------------------------------------------------------------------------
1 | **打赏名单**
2 |
3 | 名字 | 金额 | 留言 | 时间
4 | ---|---|---|---
5 | 未留名 | 20.00 | 感谢无私 | 2017-09-2
6 | 未留名 | 8.88 | 感谢 | 2017-09-19
7 | ** | 16.80 | 严重支持开源(我想问为什么是严重?) | 2017-08-22
8 | *滔 | 16.80 | 谢谢帮助 | 2017-08-09
9 | 鑫* | 10.00 | 来自支付宝 | 2017-08-01
10 | 来自微信(付款) | 10.00 | 加油,很棒! | 2017-07-25
11 | 一掠而过 | 10.00 | 一点心意 | 2017-07-14
12 | 北国之雪 | 30.00 | Payment好用 | 2017-05-04
13 | 里暮色中 | 50.00 | Payment越来越好(感谢发现一个bug issue#39) | 2017-05-01
14 | lobtao | 8.88 | 你的内裤非常好用 | 2017-04-26
15 | 182xxxx | 10.00 | 支持 | 2017-04-19
16 | 来自简单 | 200.00 | 支付宝服务商模式咨询 | 2017-04-16
17 | 刘华 | 50.00 | 微信支付咨询 | 2017-04-14
18 | 靖 | 88.00 | 感谢开源 | 2017-03-19
19 | 李 | 150.00 | 打赏支持 | 2017-03-14
20 | Alex.Ma | 6.66 | 支持 | 2017-03-13
21 | 阿笨 | 10.00 | 打算使用,先感谢一下 | 2017-03-10
22 | 彦 | 88.00 | 感觉还不错,特打赏88元,略表感谢。 | 2017-02-28
23 | 汤明洋 | 66.66 | 支持一下 | 2017-02-19
24 | 李仕建同学 | 18.88 | 新春快乐 | 2017-02-09
25 | 凡额 | 50.00 | 帮助调试,谢谢了 | 2017-01-18
26 | Thans秦 | 66.66 | 商业使用 | 2017-01-08
27 | John | 10.00 | 设计很棒 | 2017-01-06
28 | Davidw | 699.00 | 支持开发2.0 | 2016-12-15
29 | 宁静致远 | 10.00 | 鼓励你,加油额 | 2016-12-13
30 | k7 | 8.00 | 批量付款,一次成功 | 2016-11-24
31 | 洋 | 50.00 | 资助开源 | 2016-11-23
32 | 张仲东 | 50.00 | 接口封装的不错 | 2016-11-17
33 | 放下...快乐 | 1000.00 | 支付宝即时到帐处理 | 2016-11-15
34 | Robin Core Animation | 50.00 | 解决微信支付问题 | 2016-11-04
35 | 5Z4 | 20.00 | 解决回调问题 | 2016-10-31
36 | 哈罗Joe | 1.00 | 加油~~ | 2016-8-23
37 | 小兵~招UI前端 | 50.00 | 继续努力,喝杯水吧:-) | 2016-8-14
38 | 尊称韦爵爷 | 1.00 | 赶紧出个yii的扩展 | 2016-7-22
39 | 一米市集 | 1000.00 | 希望提供技术长期合作 | 2016-7-20
40 | 张松 | 15.00 | 不错,已用到项目中 | 2016-6-17
--------------------------------------------------------------------------------
/src/Helper/Cmb/PubKeyHelper.php:
--------------------------------------------------------------------------------
1 | config->getewayUrl = 'https://b2b.cmbchina.com/CmbBank_B2B/UI/NetPay/DoBusiness.ashx';
20 | if ($this->config->useSandbox) {// 测试
21 | $this->config->getewayUrl = 'http://121.15.180.72/CmbBank_B2B/UI/NetPay/DoBusiness.ashx';
22 | }
23 |
24 | return PubKeyData::class;
25 | }
26 |
27 | protected function retData(array $ret)
28 | {
29 | $json = json_encode($ret, JSON_UNESCAPED_UNICODE);
30 |
31 | $postData = CmbConfig::REQ_FILED_NAME . '=' . $json;
32 | $retData = $this->sendReq($postData);
33 |
34 | if ($this->config->returnRaw) {
35 | $retData['channel'] = Config::CMB_PUB_KEY;
36 | return $retData;
37 | }
38 |
39 | // 正确情况
40 | $rData = [
41 | 'is_success' => 'T',
42 | 'response' => [
43 | 'pub_key' => $retData['fbPubKey'],
44 | 'channel' => Config::CMB_PUB_KEY,
45 | 'time' => date('Y-m-d H:i:s', strtotime($retData['dateTime'])),// Y-m-d H:i:s,
46 | ],
47 | ];
48 |
49 | return $rData;
50 | }
51 | }
--------------------------------------------------------------------------------
/src/Charge/Wx/WxPubCharge.php:
--------------------------------------------------------------------------------
1 | config->tradeType = 'JSAPI';
20 | return PubChargeData::class;
21 | }
22 |
23 | /**
24 | * 处理公众号支付的返回值。直接返回与微信文档对应的字段
25 | * @param array $ret
26 | *
27 | * @return string $data 包含以下键
28 | *
29 | * ```php
30 | * $data = [
31 | * 'appId' => '', // 公众号id
32 | * 'package' => '', // 订单详情扩展字符串 统一下单接口返回的prepay_id参数值,提交格式如:prepay_id=***
33 | * 'nonceStr' => '', // 随机字符串
34 | * 'timeStamp' => '', // 时间戳
35 | * 'signType' => '', // 签名算法,暂支持MD5
36 | * 'paySign' => '', // 签名
37 | * ];
38 | * ```
39 | * @author helei
40 | */
41 | protected function retData(array $ret)
42 | {
43 | $back = new BackPubChargeData($this->config, $ret);
44 |
45 | $back->setSign();
46 | $backData = $back->getData();
47 |
48 | $backData['paySign'] = $backData['sign'];
49 | // 移除sign
50 | unset($backData['sign']);
51 |
52 | // 公众号支付返回数组结构
53 | return $backData;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/Common/Weixin/Data/Query/ChargeQueryData.php:
--------------------------------------------------------------------------------
1 | retData = [
30 | 'appid' => $this->appId,
31 | 'mch_id' => $this->mchId,
32 | 'nonce_str' => $this->nonceStr,
33 | 'sign_type' => $this->signType,
34 |
35 | 'transaction_id' => $this->transaction_id,
36 | 'out_trade_no' => $this->out_trade_no,
37 |
38 | // 服务商
39 | 'sub_appid' => $this->sub_appid,
40 | 'sub_mch_id' => $this->sub_mch_id,
41 | ];
42 |
43 | $this->retData = ArrayUtil::paraFilter($this->retData);
44 | }
45 |
46 | protected function checkDataParam()
47 | {
48 | $transaction_id = $this->transaction_id;// 微信交易号,查询效率高
49 | $order_no = $this->out_trade_no;// 商户订单号,查询效率低,不建议使用
50 |
51 | // 二者不能同时为空
52 | if (empty($transaction_id) && empty($order_no)) {
53 | throw new PayException('必须提供微信交易号或商户网站唯一订单号。建议使用微信交易号');
54 | }
55 | }
56 | }
--------------------------------------------------------------------------------
/src/Common/Ali/Data/Charge/AppChargeData.php:
--------------------------------------------------------------------------------
1 | strval($this->body),
23 | 'subject' => strval($this->subject),
24 | 'out_trade_no' => strval($this->order_no),
25 | 'total_amount' => strval($this->amount),
26 |
27 | // 销售产品码,商家和支付宝签约的产品码,为固定值QUICK_MSECURITY_PAY
28 | 'product_code' => 'QUICK_MSECURITY_PAY',
29 | 'goods_type' => $this->goods_type,
30 | 'passback_params' => $this->return_param,
31 | // TODO 优惠信息待支持 业务扩展参数,待支持
32 | // 'promo_params' => '',
33 | // 'extend_params => '',
34 | 'disable_pay_channels' => $this->limitPay,
35 | 'store_id' => $this->store_id,
36 | ];
37 |
38 | $timeExpire = $this->timeout_express;
39 | if (! empty($timeExpire)) {
40 | $express = floor(($timeExpire - strtotime($this->timestamp)) / 60);
41 | ($express > 0) && $content['timeout_express'] = $express . 'm';// 超时时间 统一使用分钟计算
42 | }
43 |
44 | return $content;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/Common/Ali/Data/Charge/QrChargeData.php:
--------------------------------------------------------------------------------
1 | strval($this->order_no),
25 | // TODO 卖家支付宝id
26 | // 'seller_id' => '',
27 | 'total_amount' => strval($this->amount),
28 | // TODO 折扣金额
29 | // 'discountable_amount' => '',
30 | // TODO 业务扩展参数 订单商品列表信息,待支持
31 | // 'extend_params => '',
32 | // 'goods_detail' => '',
33 | 'subject' => strval($this->subject),
34 | 'body' => strval($this->body),
35 |
36 | 'operator_id' => $this->operator_id,
37 | 'store_id' => $this->store_id,
38 | 'terminal_id' => $this->terminal_id,
39 | ];
40 |
41 | $timeExpire = $this->timeout_express;
42 | if (! empty($timeExpire)) {
43 | $express = floor(($timeExpire - strtotime($this->timestamp)) / 60);
44 | ($express > 0) && $content['timeout_express'] = $express . 'm';// 超时时间 统一使用分钟计算
45 | }
46 |
47 | return $content;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/Common/Ali/Data/Charge/WapChargeData.php:
--------------------------------------------------------------------------------
1 | strval($this->body),
25 | 'subject' => strval($this->subject),
26 | 'out_trade_no' => strval($this->order_no),
27 | 'total_amount' => strval($this->amount),
28 |
29 | // 销售产品码,商家和支付宝签约的产品码,为固定值QUICK_WAP_PAY
30 | 'product_code' => 'QUICK_WAP_PAY',
31 | 'goods_type' => $this->goods_type,
32 | 'passback_params' => $this->return_param,
33 | // TODO 优惠信息待支持 业务扩展参数,待支持
34 | // 'promo_params' => '',
35 | // 'extend_params => '',
36 | 'disable_pay_channels' => $this->limitPay,
37 | 'store_id' => $this->store_id,
38 | // TODO 在收银台出现返回按钮
39 | 'quit_url' => $this->quit_url,
40 | ];
41 |
42 | $timeExpire = $this->timeout_express;
43 | if (! empty($timeExpire)) {
44 | $express = floor(($timeExpire - strtotime($this->timestamp)) / 60);
45 | ($express > 0) && $content['timeout_express'] = $express . 'm';// 超时时间 统一使用分钟计算
46 | }
47 |
48 | return $content;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/Utils/Rc4Encrypt.php:
--------------------------------------------------------------------------------
1 | key = $key;
18 | }
19 |
20 | /**
21 | * 设置key
22 | * @param $key
23 | * @author helei
24 | */
25 | public function setKey($key)
26 | {
27 | $this->key = $key;
28 | }
29 |
30 | /**
31 | * rc4加密算法
32 | * @param $data
33 | * @return string
34 | * @throws \Exception
35 | */
36 | public function encrypt($data)
37 | {
38 | $cipher = $box[] = $key[] = '';
39 |
40 | $pwd_length = strlen($this->key);
41 | $data_length = strlen($data);
42 |
43 | for ($i = 0; $i < 256; $i++) {
44 | $key[$i] = ord($this->key[$i % $pwd_length]);
45 | $box[$i] = $i;
46 | }
47 |
48 | for ($j = $i = 0; $i < 256; $i++) {
49 | $j = ($j + $box[$i] + $key[$i]) % 256;
50 | $tmp = $box[$i];
51 | $box[$i] = $box[$j];
52 | $box[$j] = $tmp;
53 | }
54 |
55 | for ($a = $j = $i = 0; $i < $data_length; $i++) {
56 | $a = ($a + 1) % 256;
57 | $j = ($j + $box[$a]) % 256;
58 |
59 | $tmp = $box[$a];
60 | $box[$a] = $box[$j];
61 | $box[$j] = $tmp;
62 |
63 | $k = $box[(($box[$a] + $box[$j]) % 256)];
64 | $cipher .= chr(ord($data[$i]) ^ $k);
65 | }
66 |
67 | return strtoupper(StrUtil::String2Hex($cipher));
68 | }
69 | }
--------------------------------------------------------------------------------
/src/Common/Cmb/Data/BindCardData.php:
--------------------------------------------------------------------------------
1 | agr_no;
30 | if (empty($agrNo) || mb_strlen($agrNo) > 30 || ! is_numeric($agrNo)) {
31 | throw new PayException('客户协议号。必须为纯数字串,不超过30位');
32 | }
33 | }
34 |
35 | protected function getReqData()
36 | {
37 | $reqData = [
38 | 'dateTime' => $this->dateTime,
39 | 'merchantSerialNo' => $this->serial_no ? $this->serial_no : '',
40 | 'agrNo' => $this->agr_no,
41 | 'branchNo' => $this->branchNo,
42 | 'merchantNo' => $this->merchantNo,
43 | 'userID' => $this->user_id ? $this->user_id : '',
44 | 'mobile' => $this->mobile ? $this->mobile : '',
45 | 'lon' => $this->lon ? $this->lon : '',
46 | 'lat' => $this->lat ? $this->lat : '',
47 | 'riskLevel' => $this->risk_level ? $this->risk_level : '',
48 | 'noticeUrl' => $this->signNoticeUrl ? $this->signNoticeUrl : '',
49 | 'noticePara' => $this->return_param ? $this->return_param : '',
50 | 'returnUrl' => $this->returnUrl ? $this->returnUrl : '',
51 | ];
52 |
53 | // 这里不能进行过滤空值,招商的空值也要加入签名中
54 | return $reqData;
55 | }
56 | }
--------------------------------------------------------------------------------
/src/HelperContext.php:
--------------------------------------------------------------------------------
1 | helper = new BindCardHelper($config);
37 | break;
38 | case Config::CMB_PUB_KEY:
39 | $this->helper = new PubKeyHelper($config);
40 | break;
41 | default:
42 | throw new PayException('当前仅支持:CMB_BIND CMB_PUB_KEY 操作');
43 | }
44 | } catch (PayException $e) {
45 | throw $e;
46 | }
47 | }
48 |
49 | /**
50 | * 获取帮助操作
51 | *
52 | * @param array $data
53 | *
54 | * @return array
55 | * @throws PayException
56 | * @author helei
57 | */
58 | public function helper(array $data)
59 | {
60 | if (! $this->helper instanceof BaseStrategy) {
61 | throw new PayException('请检查初始化是否正确');
62 | }
63 |
64 | try {
65 | return $this->helper->handle($data);
66 | } catch (PayException $e) {
67 | throw $e;
68 | }
69 | }
70 | }
--------------------------------------------------------------------------------
/src/Client/Refund.php:
--------------------------------------------------------------------------------
1 | initRefund($channel, $config);
47 | } catch (PayException $e) {
48 | throw $e;
49 | }
50 |
51 | return static::$instance;
52 | }
53 |
54 | public static function run($channel, $config, $refundData)
55 | {
56 | if (! in_array($channel, self::$supportChannel)) {
57 | throw new PayException('sdk当前不支持该退款渠道,当前仅支持:' . implode(',', self::$supportChannel));
58 | }
59 |
60 | try {
61 | $instance = self::getInstance($channel, $config);
62 |
63 | $ret = $instance->refund($refundData);
64 | } catch (PayException $e) {
65 | throw $e;
66 | }
67 |
68 | return $ret;
69 | }
70 | }
--------------------------------------------------------------------------------
/src/Common/Weixin/Data/WxBaseData.php:
--------------------------------------------------------------------------------
1 | signType) {
45 | case 'MD5':
46 | $signStr .= '&key=' . $this->md5Key;
47 | $sign = md5($signStr);
48 | break;
49 | case 'HMAC-SHA256':
50 | $sign = base64_encode(hash_hmac('sha256', $signStr, $this->md5Key));
51 | break;
52 | default:
53 | $sign = '';
54 | }
55 |
56 | return strtoupper($sign);
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/Query/Cmb/CmbRefundQuery.php:
--------------------------------------------------------------------------------
1 | config->getewayUrl = 'https://payment.ebank.cmbchina.com/NetPayment/BaseHttp.dll?QuerySettledRefund';
22 | if ($this->config->useSandbox) {// 测试
23 | $this->config->getewayUrl = 'http://121.15.180.66:801/netpayment_dl/BaseHttp.dll?QuerySettledRefund';
24 | }
25 |
26 | return RefundQueryData::class;
27 | }
28 |
29 | protected function retData(array $ret)
30 | {
31 | $json = json_encode($ret, JSON_UNESCAPED_UNICODE);
32 |
33 | $postData = CmbConfig::REQ_FILED_NAME . '=' . $json;
34 | $retData = $this->sendReq($postData);
35 |
36 | if ($this->config->returnRaw) {
37 | $retData['channel'] = Config::CMB_REFUND;
38 | return $retData;
39 | }
40 |
41 | $list = $retData['dataList'];
42 | $list = str_replace('`', '', $list);
43 | $list = explode(PHP_EOL, $list);
44 |
45 | $header = array_shift($list);
46 | $header = explode(',', $header);
47 |
48 | foreach ($list as $key => $item) {
49 | $item = explode(',', $item);
50 |
51 | $list[$key] = array_combine($header, $item);
52 | }
53 |
54 | // 正确情况
55 | $retData = [
56 | 'is_success' => 'T',
57 | 'response' => [
58 | 'channel' => Config::CMB_REFUND,
59 | 'refund_data' => $list,
60 | ],
61 | ];
62 |
63 | return $retData;
64 | }
65 | }
--------------------------------------------------------------------------------
/src/TransferContext.php:
--------------------------------------------------------------------------------
1 | transfer = new AliTransfer($config);
39 | break;
40 | case Config::WX_TRANSFER:
41 | $this->transfer = new WxTransfer($config);
42 | break;
43 | default:
44 | throw new PayException('当前仅支持:ALI WEIXIN两个常量');
45 | }
46 | } catch (PayException $e) {
47 | throw $e;
48 | }
49 | }
50 |
51 | /**
52 | * 通过环境类调用支付转款操作
53 | *
54 | * @param array $data
55 | *
56 | * @return array
57 | * @throws PayException
58 | * @author helei
59 | */
60 | public function transfer(array $data)
61 | {
62 | if (! $this->transfer instanceof BaseStrategy) {
63 | throw new PayException('请检查初始化是否正确');
64 | }
65 |
66 | try {
67 | return $this->transfer->handle($data);
68 | } catch (PayException $e) {
69 | throw $e;
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | Payment只有在大家的使用反馈中才能得到不断的完善。
2 |
3 | 我希望通过真实的项目来驱动它不断发展,在为工作带来方便的同时尽力保持它的简洁。
4 |
5 | # issue报Bug
6 | 由于Payment高度依赖第三方接口,因此第三方一个小的变动也会导致项目产生一个大版本号。当前主要有:
7 | - 2.x 应该没多少人使用了,已经放弃维护
8 | - 3.x 继续维护,只修bug,不做接口更新
9 | - 4.x 当前开发版本,均保持当前第三方的最新接口
10 |
11 | 由于版本比较多。因此报bug建议采用以下格式:
12 |
13 | [3/4.x]版本,在什么环境下(沙盒还是正式),调用了什么接口,出现了什么错误(最好有截图)。自己尝试过哪些办法去解决未达到预期效果
14 |
15 | 推荐所有的bug在提交时,先使用demo代码运行一下,看看能否通过。
16 |
17 | **只提供标题,或者没有重现步骤的,将不处理**
18 |
19 | # 贡献代码
20 | 请代码书写遵循以下规则:
21 |
22 | - [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)
23 | - 使用4个空格作为缩紧(不是tab)
24 | - 命名使用驼峰命名(不准使用拼音)
25 | - 请给类、方法、变量添加注释,注释需要包含:日期、修改人、含义
26 |
27 | ## 开发流程
28 |
29 | 1. Fork [helei112g/payment](https://github.com/helei112g/payment) 到本地
30 | 2. 创建新的分支:
31 |
32 | ```shell
33 | $ git checkout -b new_feature
34 | ```
35 |
36 | 3. 编写代码
37 | 4. Push 到你的分支:
38 |
39 | ```shell
40 | $ git push origin new_feature
41 | ```
42 |
43 | 5. 创建 Pull Request 并描述你完成的功能或者做出的修改
44 |
45 | 所提交的部分一定自己真实测试完毕,如果是新的支付功能,需要添加对应的demo以及
46 |
47 | 相关功能的文档(暂无开源文档地址,请根据功能名称,提供 `.md`的说明文档)。
48 |
49 | ## 代码说明
50 | 为了让大家快速理解代码结构,将项目相关结构图进行说明,这里从调用者的角度出发进行描述
51 | 
52 |
53 | 这张图表现的是库的一个层次。用支付宝手机wap支付为例:
54 | 调用这只需要通过
55 | ```php
56 | Charge::run()
57 | ```
58 | 这个方法即可完成所有调用。剩下的所有东西对调用者都应该是透明的
59 |
60 | 这个方法内部会首先通过
61 | ```php
62 | ChargeContext::initCharge()
63 | ```
64 | 进行上下文的初始化,完成准备工作,并返回一个具体的对应支付实例,在这里是:`AliAppCharge`
65 |
66 | 接着内部会调用
67 | ```php
68 | AliAppCharge::charge()
69 | ```
70 | 完成支付的请求,他会把结果返回给调用者
71 |
72 | 在 `AliAppCharge::charge()` 调用中完成了请求数据的组装,请求数据的签名,如果需要网络请求,会发送网络请求到支付宝网关。并把结果逐步返回。
73 |
74 | ## 核心类图
75 | 本库的所有功能,层次结构比较一致。这里以支付宝app支付为例,进行一下类图描述,方便大家以此进行类比
76 |
77 | 
78 |
79 | 如果看不清楚,可[点击下载](http://ol59nqr1i.bkt.clouddn.com/payment-uml.png)
80 |
81 | ---------
82 | **`遇到bug,90%都是秘钥相关导致的,微信可能与后台配置有关。请仔细检查。`**
--------------------------------------------------------------------------------
/src/Client/Helper.php:
--------------------------------------------------------------------------------
1 | initHelper($channel, $config);
42 | } catch (PayException $e) {
43 | throw $e;
44 | }
45 |
46 | return static::$instance;
47 | }
48 |
49 | /**
50 | * @param string $channel
51 | * @param array $config
52 | * @param array $metadata
53 | *
54 | * @return mixed
55 | * @throws PayException
56 | */
57 | public static function run($channel, $config, array $metadata = [])
58 | {
59 | if (! in_array($channel, self::$supportChannel)) {
60 | throw new PayException('sdk当前不支持该渠道,当前仅支持:' . implode(',', self::$supportChannel));
61 | }
62 |
63 | try {
64 | $instance = self::getInstance($channel, $config);
65 |
66 | $ret = $instance->helper($metadata);
67 | } catch (PayException $e) {
68 | throw $e;
69 | }
70 |
71 | return $ret;
72 | }
73 | }
--------------------------------------------------------------------------------
/src/Common/Ali/Data/Charge/WebChargeData.php:
--------------------------------------------------------------------------------
1 | strval($this->order_no),
30 | // 销售产品码,商家和支付宝签约的产品码,为固定值QUICK_WAP_PAY
31 | 'product_code' => 'FAST_INSTANT_TRADE_PAY',
32 | 'total_amount' => strval($this->amount),
33 | 'subject' => strval($this->subject),
34 | 'body' => strval($this->body),
35 | // TODO 订单包含的商品列表信息 待实现
36 | // 'goods_detail' => '',
37 | 'passback_params' => $this->return_param,
38 | // TODO 业务扩展参数,待支持
39 | // 'extend_params => '',
40 | 'goods_type' => $this->goods_type,
41 | 'disable_pay_channels' => $this->limitPay,
42 | 'store_id' => $this->store_id,
43 | 'qr_pay_mode' => $this->qr_mod,
44 | // TODO 设置二维码宽度
45 | // 'qrcode_width' => '',// qr_pay_mode = 4时有效。设置二维码宽度
46 | ];
47 |
48 | $timeExpire = $this->timeout_express;
49 | if (! empty($timeExpire)) {
50 | $express = floor(($timeExpire - strtotime($this->timestamp)) / 60);
51 | ($express > 0) && $content['timeout_express'] = $express . 'm';// 超时时间 统一使用分钟计算
52 | }
53 |
54 | return $content;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/Common/Cmb/Data/Query/ChargeQueryData.php:
--------------------------------------------------------------------------------
1 | transaction_id;
28 | $date = $this->date;
29 | $orderNo = $this->out_trade_no;
30 |
31 | if (empty($date) || mb_strlen($date) !== 8) {
32 | throw new PayException('商户订单日期必须提供,格式:yyyyMMdd');
33 | }
34 |
35 | if ($bankSerialNo && mb_strlen($bankSerialNo) === 20) {
36 | $this->type = 'A';
37 | } elseif ($orderNo && mb_strlen($bankSerialNo) <= 32) {
38 | $this->type = 'B';
39 | } else {
40 | throw new PayException('必须设置商户订单信息或者招商流水号');
41 | }
42 | }
43 |
44 | protected function getReqData()
45 | {
46 | $reqData = [
47 | 'dateTime' => $this->dateTime,
48 | 'branchNo' => $this->branchNo,
49 | 'merchantNo' => $this->merchantNo,
50 | 'type' => $this->type,
51 | 'bankSerialNo' => $this->transaction_id ? $this->transaction_id : '',
52 |
53 | 'date' => $this->date ? $this->date : '',
54 | 'orderNo' => $this->out_trade_no ? $this->out_trade_no : '',
55 | 'operatorNo' => $this->operator_no ? $this->operator_no : '',
56 | ];
57 |
58 | // 这里不能进行过滤空值,招商的空值也要加入签名中
59 | return $reqData;
60 | }
61 | }
--------------------------------------------------------------------------------
/src/Refund/CmbRefund.php:
--------------------------------------------------------------------------------
1 | config->getewayUrl = 'https://payment.ebank.cmbchina.com/NetPayment/BaseHttp.dll?DoRefund';
20 | if ($this->config->useSandbox) {// 测试
21 | $this->config->getewayUrl = 'http://121.15.180.66:801/NetPayment_dl/BaseHttp.dll?DoRefund';
22 | }
23 |
24 | return RefundData::class;
25 | }
26 |
27 | protected function retData(array $ret)
28 | {
29 | $json = json_encode($ret, JSON_UNESCAPED_UNICODE);
30 |
31 | $postData = CmbConfig::REQ_FILED_NAME . '=' . $json;
32 |
33 | $rsqData = $this->sendReq($postData);
34 |
35 | if ($this->config->returnRaw) {
36 | $rsqData['channel'] = Config::CMB_REFUND;
37 | return $rsqData;
38 | }
39 |
40 | // 正确情况
41 | $retData = [
42 | 'is_success' => 'T',
43 | 'response' => [
44 | 'transaction_id' => $rsqData['bankSerialNo'],// 银行的退款流水号
45 | 'order_no' => $ret['reqData']['orderNo'],
46 | 'date' => $ret['reqData']['date'],
47 | 'refund_no' => trim($rsqData['refundSerialNo']),//退款流水号,商户生成
48 | 'refund_id' => $rsqData['refundRefNo'],// 银行的退款参考号
49 | 'currency' => $rsqData['currency'],
50 | 'refund_fee' => $rsqData['amount'],
51 | 'channel' => Config::CMB_REFUND,
52 | 'refund_time' => date('Y-m-d H:i:s', strtotime($rsqData['bankDate'] . $rsqData['bankTime'])),
53 | ],
54 | ];
55 |
56 | return $retData;
57 | }
58 | }
--------------------------------------------------------------------------------
/src/Trans/AliTransfer.php:
--------------------------------------------------------------------------------
1 | config->method = $this->method;
21 | return TransData::class;
22 | }
23 |
24 | protected function retData(array $data)
25 | {
26 | $reqData = parent::retData($data);
27 |
28 | try {
29 | $retData = $this->sendReq($reqData);
30 | } catch (PayException $e) {
31 | throw $e;
32 | }
33 |
34 | return $this->createBackData($retData);
35 | }
36 |
37 | /**
38 | * 处理返回的数据
39 | * @param array $data
40 | * @return array
41 | * @author helei
42 | */
43 | protected function createBackData(array $data)
44 | {
45 | if ($this->config->returnRaw) {
46 | $retData['channel'] = Config::ALI_TRANSFER;
47 | return $retData;
48 | }
49 |
50 | if ($data['code'] !== '10000') {
51 | return $retData = [
52 | 'is_success' => 'F',
53 | 'error' => $data['sub_msg'],
54 | 'channel' => Config::ALI_TRANSFER,
55 | ];
56 | }
57 |
58 | $retData = [
59 | 'is_success' => 'T',
60 | 'response' => [
61 | 'trans_no' => $data['out_biz_no'],// 商户转账唯一订单号
62 | 'transaction_id' => $data['order_id'],// 支付宝转账单据号
63 | 'pay_date' => $data['pay_date'],// 支付时间
64 | 'channel' => Config::ALI_TRANSFER,
65 | ],
66 | ];
67 |
68 | return $retData;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/Charge/Ali/AliBarCharge.php:
--------------------------------------------------------------------------------
1 | config->method = $this->method;
25 | return BarChargeData::class;
26 | }
27 |
28 | /**
29 | * 处理扫码支付的返回值
30 | * @param array $ret
31 | * $data = [
32 | 'code' => 10000,
33 | 'msg' => 'Success',
34 | 'buyer_logon_id' => 'day***@gmail.com',
35 | 'buyer_pay_amount' => '0.01',
36 | 'buyer_user_id' => '2088002162809334',
37 | 'fund_bill_list' => [
38 | ['amount' => '0.01', 'fund_channel' => 'ALIPAYACCOUNT'],
39 | ],
40 | 'gmt_payment' => '2017-03-05 22:27:46',
41 | 'open_id' => '20880008025007264081318860117433',
42 | 'out_trade_no' => '14887240631516',
43 | 'point_amount' => '0.00',
44 | 'receipt_amount' => '0.01',
45 | 'total_amount' => '0.01',
46 | 'trade_no' => '2017030521001004330274482163',
47 | ];
48 | *
49 | * @throws PayException
50 | * @return string 可生产二维码的uri
51 | * @author helei
52 | */
53 | protected function retData(array $ret)
54 | {
55 | $reqData = parent::retData($ret);
56 |
57 | // 发起网络请求
58 | try {
59 | $data = $this->sendReq($reqData);
60 | } catch (PayException $e) {
61 | throw $e;
62 | }
63 |
64 | return $data;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/Common/Weixin/Data/Query/RefundQueryData.php:
--------------------------------------------------------------------------------
1 | retData = [
33 | 'appid' => $this->appId,
34 | 'mch_id' => $this->mchId,
35 | 'device_info' => $this->terminal_id,
36 | 'nonce_str' => $this->nonceStr,
37 | 'sign_type' => $this->signType,
38 |
39 | 'transaction_id' => $this->transaction_id,
40 | 'out_trade_no' => $this->out_trade_no,
41 | 'out_refund_no' => $this->refund_no,
42 | 'refund_id' => $this->refund_id,
43 |
44 | // 服务商
45 | 'sub_appid' => $this->sub_appid,
46 | 'sub_mch_id' => $this->sub_mch_id,
47 | ];
48 |
49 | $this->retData = ArrayUtil::paraFilter($this->retData);
50 | }
51 |
52 | protected function checkDataParam()
53 | {
54 | $transactionId = $this->transaction_id;// 微信交易号,查询效率高
55 | $orderNo = $this->out_trade_no;// 商户订单号,查询效率低,不建议使用
56 | $refundNo = $this->refund_no;// 商户的退款单号
57 | $refundId = $this->refund_id;// 微信的退款交易号
58 |
59 | // 四者不能同时为空
60 | if (empty($transactionId) && empty($orderNo) && empty($refundNo) && empty($refundId)) {
61 | throw new PayException('查询退款 必须提供微信交易号、商户订单号、商户退款单号、微信退款交易号中的一种');
62 | }
63 | }
64 | }
--------------------------------------------------------------------------------
/src/Client/Transfer.php:
--------------------------------------------------------------------------------
1 | initTransfer($channel, $config);
47 | } catch (PayException $e) {
48 | throw $e;
49 | }
50 |
51 | return static::$instance;
52 | }
53 |
54 | /**
55 | * @param $channel
56 | * @param $config
57 | * @param $metadata
58 | *
59 | * @return array
60 | * @throws PayException
61 | */
62 | public static function run($channel, $config, $metadata)
63 | {
64 | if (! in_array($channel, self::$supportChannel)) {
65 | throw new PayException('sdk当前不支持该退款渠道,当前仅支持:' . implode(',', self::$supportChannel));
66 | }
67 |
68 | try {
69 | $instance = self::getInstance($channel, $config);
70 |
71 | $ret = $instance->transfer($metadata);
72 | } catch (PayException $e) {
73 | throw $e;
74 | }
75 |
76 | return $ret;
77 | }
78 | }
--------------------------------------------------------------------------------
/src/Common/Weixin/WechatHelper.php:
--------------------------------------------------------------------------------
1 | setSign();
30 |
31 | $xml = DataParser::toXml($this->getData());
32 |
33 | $url = self::SANDBOX_URL;
34 |
35 | $client = new Client([
36 | 'timeout' => '10.0'
37 | ]);
38 | $options = [
39 | 'body' => $xml,
40 | 'http_errors' => false
41 | ];
42 |
43 | $response = $client->request('POST', self::SANDBOX_URL, $options);
44 |
45 | if ($response->getStatusCode() != '200') {
46 | throw new PayException('网络发生错误,请稍后再试curl返回码:' . $response->getReasonPhrase());
47 | }
48 | // 格式化为数组
49 | $retData = DataParser::toArray($response->getBody()->getContents());
50 | if (strtoupper($retData['return_code']) != 'SUCCESS') {
51 | throw new PayException('微信返回错误提示:' . $retData['return_msg']);
52 | }
53 |
54 | return $retData['sandbox_signkey'];
55 | }
56 |
57 | /**
58 | * 构建请求的数据
59 | */
60 | protected function buildData()
61 | {
62 | $this->retData = [
63 | 'mch_id' => $this->mchId,
64 | 'nonce_str' => StrUtil::getNonceStr(),
65 | ];
66 | }
67 |
68 | protected function checkDataParam()
69 | {
70 | // TODO: Implement checkDataParam() method.
71 | }
72 | }
--------------------------------------------------------------------------------
/src/Common/Ali/Data/RefundData.php:
--------------------------------------------------------------------------------
1 | trade_no;// 支付宝交易号,查询效率高
31 | $outTradeNo = $this->out_trade_no;// 商户订单号,查询效率低,不建议使用
32 | $refundAmount = $this->refund_fee;
33 |
34 | // 二者不能同时为空
35 | if (empty($outTradeNo) && empty($tradeNo)) {
36 | throw new PayException('必须提供支付宝交易号或者商户网站唯一订单号。建议使用支付宝交易号');
37 | }
38 |
39 | if (empty($refundAmount) || ! is_numeric($refundAmount)) {
40 | throw new PayException('refund_fee 退款的金额,该金额不能大于订单金额,单位为元,支持两位小数');
41 | }
42 | }
43 |
44 | /**
45 | * 业务请求参数的集合,最大长度不限,除公共参数外所有请求参数都必须放在这个参数中传递
46 | *
47 | * @return string
48 | */
49 | protected function getBizContent()
50 | {
51 | $content = [
52 | 'out_trade_no' => $this->out_trade_no,
53 | 'trade_no' => $this->trade_no,
54 | 'refund_amount' => $this->refund_fee,
55 | 'refund_reason' => $this->reason,
56 | 'out_request_no' => $this->refund_no,
57 | 'operator_id' => $this->operator_id,
58 | 'store_id' => $this->store_id,
59 | 'terminal_id' => $this->terminal_id,
60 | ];
61 |
62 | return $content;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/Common/Weixin/Data/Charge/AppChargeData.php:
--------------------------------------------------------------------------------
1 | scene_info;
18 | $sceneInfo = [];
19 | if ($info && is_array($info)) {
20 | $sceneInfo['store_info'] = $info;
21 | }
22 |
23 | $signData = [
24 | 'appid' => trim($this->appId),
25 | 'mch_id' => trim($this->mchId),
26 | 'device_info' => $this->terminal_id,
27 | 'nonce_str' => $this->nonceStr,
28 | 'sign_type' => $this->signType,
29 | 'body' => trim($this->subject),
30 | //'detail' => json_encode($this->body, JSON_UNESCAPED_UNICODE),
31 | 'attach' => trim($this->return_param),
32 | 'out_trade_no' => trim($this->order_no),
33 | 'fee_type' => $this->feeType,
34 | 'total_fee' => $this->amount,
35 | 'spbill_create_ip' => trim($this->client_ip),
36 | 'time_start' => $this->timeStart,
37 | 'time_expire' => $this->timeout_express,
38 | //'goods_tag' => '订单优惠标记',
39 | 'notify_url' => $this->notifyUrl,
40 | 'trade_type' => $this->tradeType, //设置APP支付
41 | //'product_id' => '商品id',
42 | 'limit_pay' => $this->limitPay, // 指定不使用信用卡
43 | //'openid' => '用户标识',
44 | 'scene_info' => $sceneInfo ? json_encode($sceneInfo, JSON_UNESCAPED_UNICODE) : '',
45 |
46 | // 服务商
47 | 'sub_appid' => $this->sub_appid,
48 | 'sub_mch_id' => $this->sub_mch_id,
49 | ];
50 |
51 | // 移除数组中的空值
52 | $this->retData = ArrayUtil::paraFilter($signData);
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/RefundContext.php:
--------------------------------------------------------------------------------
1 | refund = new AliRefund($config);
42 | break;
43 | case Config::WX_REFUND:
44 | $this->refund = new WxRefund($config);
45 | break;
46 | case Config::CMB_REFUND:
47 | $this->refund = new CmbRefund($config);
48 | break;
49 | default:
50 | throw new PayException('当前仅支持:ALI WEIXIN CMB');
51 | }
52 | } catch (PayException $e) {
53 | throw $e;
54 | }
55 | }
56 |
57 | /**
58 | * 通过环境类调用支付退款操作
59 | *
60 | * @param array $data
61 | *
62 | * @return array
63 | * @throws PayException
64 | * @author helei
65 | */
66 | public function refund(array $data)
67 | {
68 | if (! $this->refund instanceof BaseStrategy) {
69 | throw new PayException('请检查初始化是否正确');
70 | }
71 |
72 | try {
73 | return $this->refund->handle($data);
74 | } catch (PayException $e) {
75 | throw $e;
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/Client/Query.php:
--------------------------------------------------------------------------------
1 | initQuery($queryType, $config);
52 | } catch (PayException $e) {
53 | throw $e;
54 | }
55 |
56 | return static::$instance;
57 | }
58 |
59 | /**
60 | * @param string $queryType
61 | * @param array $config
62 | * @param array $metadata
63 | * @return array
64 | * @throws PayException
65 | */
66 | public static function run($queryType, $config, $metadata)
67 | {
68 | if (! in_array($queryType, self::$supportType)) {
69 | throw new PayException('sdk当前不支持该类型查询,当前仅支持:' . implode(',', self::$supportType) . __LINE__);
70 | }
71 |
72 | try {
73 | $instance = self::getInstance($queryType, $config);
74 |
75 | $ret = $instance->query($metadata);
76 | } catch (PayException $e) {
77 | throw $e;
78 | }
79 |
80 | return $ret;
81 | }
82 | }
--------------------------------------------------------------------------------
/src/Common/Weixin/Data/Charge/BarChargeData.php:
--------------------------------------------------------------------------------
1 | auth_code;
24 | if (empty($authCode)) {
25 | throw new PayException('扫码支付授权码,必须设置该参数.');
26 | }
27 | }
28 |
29 | /**
30 | * 生成下单的数据
31 | */
32 | protected function buildData()
33 | {
34 | $info = $this->scene_info;
35 | $sceneInfo = [];
36 | if ($info && is_array($info)) {
37 | $sceneInfo['store_info'] = $info;
38 | }
39 |
40 | $signData = [
41 | 'appid' => trim($this->appId),
42 | 'mch_id' => trim($this->mchId),
43 | 'device_info' => $this->terminal_id,
44 | 'nonce_str' => $this->nonceStr,
45 | 'sign_type' => $this->signType,
46 | 'body' => trim($this->subject),
47 | //'detail' => json_encode($this->body, JSON_UNESCAPED_UNICODE),
48 | 'attach' => trim($this->return_param),
49 | 'out_trade_no' => trim($this->order_no),
50 | 'total_fee' => $this->amount,
51 | 'fee_type' => $this->feeType,
52 | 'spbill_create_ip' => trim($this->client_ip),
53 | //'goods_tag' => '订单优惠标记',
54 | 'limit_pay' => $this->limitPay, // 指定不使用信用卡
55 | 'auth_code' => $this->auth_code,
56 | 'scene_info' => $sceneInfo ? json_encode($sceneInfo, JSON_UNESCAPED_UNICODE) : '',
57 |
58 | // 服务商
59 | 'sub_appid' => $this->sub_appid,
60 | 'sub_mch_id' => $this->sub_mch_id,
61 | ];
62 |
63 | // 移除数组中的空值
64 | $this->retData = ArrayUtil::paraFilter($signData);
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/Query/Cmb/CmbChargeQuery.php:
--------------------------------------------------------------------------------
1 | config->getewayUrl = 'https://payment.ebank.cmbchina.com/NetPayment/BaseHttp.dll?QuerySingleOrder';
22 | if ($this->config->useSandbox) {// 测试
23 | $this->config->getewayUrl = 'http://121.15.180.66:801/NetPayment_dl/BaseHttp.dll?QuerySingleOrder';
24 | }
25 |
26 | return ChargeQueryData::class;
27 | }
28 |
29 | protected function retData(array $ret)
30 | {
31 | $json = json_encode($ret, JSON_UNESCAPED_UNICODE);
32 |
33 | $postData = CmbConfig::REQ_FILED_NAME . '=' . $json;
34 | $ret = $this->sendReq($postData);
35 |
36 | if ($this->config->returnRaw) {
37 | $ret['channel'] = Config::CMB_CHARGE;
38 | return $ret;
39 | }
40 |
41 | // 正确情况
42 | $retData = [
43 | 'is_success' => 'T',
44 | 'response' => [
45 | 'amount' => $ret['orderAmount'],
46 | 'channel' => Config::CMB_CHARGE,
47 | 'order_no' => $ret['orderNo'],
48 | 'trade_state' => $this->getTradeStatus($ret['orderStatus']),
49 | 'transaction_id' => $ret['bankSerialNo'],
50 | 'time_end' => date('Y-m-d H:i:s', strtotime($ret['settleDate'] . $ret['settleTime'])),// Y-m-d H:i:s
51 | 'fee' => $ret['fee'],// 招商抽取的金额
52 | 'time_start' => date('Y-m-d H:i:s', strtotime($ret['bankDate'] . $ret['bankTime'])),
53 | 'discount_fee' => $ret['discountAmount'],// 优惠金额,格式:xxxx.xx 无优惠时返回0.00
54 | 'card_type' => $ret['cardType'],// 卡类型,02:一卡通;03:信用卡;07:他行卡
55 | 'return_param' => $ret['merchantPara'],
56 | ],
57 | ];
58 |
59 | return $retData;
60 | }
61 | }
--------------------------------------------------------------------------------
/src/NotifyContext.php:
--------------------------------------------------------------------------------
1 | notify = new AliNotify($config);
43 | break;
44 | case Config::WX_CHARGE:
45 | $this->notify = new WxNotify($config);
46 | break;
47 | case Config::CMB_CHARGE:
48 | $this->notify = new CmbNotify($config);
49 | break;
50 | default:
51 | throw new PayException('当前仅支持:ALI_CHARGE WX_CHARGE CMB_CHARGE 常量');
52 | }
53 | } catch (PayException $e) {
54 | throw $e;
55 | }
56 | }
57 |
58 | /**
59 | * 返回异步通知的数据
60 | * @return array|false
61 | */
62 | public function getNotifyData()
63 | {
64 | return $this->notify->getNotifyData();
65 | }
66 |
67 | /**
68 | * 通过环境类调用支付异步通知
69 | *
70 | * @param PayNotifyInterface $notify
71 | * @return array
72 | * @throws PayException
73 | * @author helei
74 | */
75 | public function notify(PayNotifyInterface $notify)
76 | {
77 | if (! $this->notify instanceof NotifyStrategy) {
78 | throw new PayException('请检查初始化是否正确');
79 | }
80 |
81 | return $this->notify->handle($notify);
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/examples/notify.php:
--------------------------------------------------------------------------------
1 | errorMessage();
44 | exit;
45 | }
46 |
47 | var_dump($ret);
48 | exit;
49 |
--------------------------------------------------------------------------------
/src/Common/Cmb/Data/Query/RefundQueryData.php:
--------------------------------------------------------------------------------
1 | out_trade_no;
34 | $date = $this->date;
35 | $refundId = $this->refund_id;// 微信的退款交易号
36 | $refundNo = $this->refund_no;// 商户的退款单号
37 |
38 | if (empty($date)) {
39 | throw new PayException('商户退款日期,格式:yyyyMMdd');
40 | }
41 |
42 | if (! empty($refundId)) {// 按银行退款流水号查单笔
43 | $this->out_trade_no = '';
44 | $this->refund_no = '';
45 | $this->type = 'A';
46 | } elseif (! empty($orderNo) && ! empty($refundNo)) {// 按商户订单号+商户退款流水号查单笔
47 | $this->refund_id = '';
48 | $this->type = 'B';
49 | } elseif (! empty($orderNo)) {// 按商户订单号查退款
50 | $this->refund_id = '';
51 | $this->refund_no = '';
52 | $this->type = 'C';
53 | } else {
54 | throw new PayException('请设置需要查询的商户订单号');
55 | }
56 | }
57 |
58 | protected function getReqData()
59 | {
60 | $reqData = [
61 | 'dateTime' => $this->dateTime,
62 | 'branchNo' => $this->branchNo,
63 | 'merchantNo' => $this->merchantNo,
64 | 'type' => $this->type,
65 | 'orderNo' => $this->out_trade_no ? $this->out_trade_no : '',
66 | 'date' => $this->date,
67 | 'merchantSerialNo' => $this->refund_no ? $this->refund_no : '',
68 | 'bankSerialNo' => $this->refund_id ? $this->refund_id : '',
69 | ];
70 |
71 | // 这里不能进行过滤空值,招商的空值也要加入签名中
72 | return $reqData;
73 | }
74 | }
--------------------------------------------------------------------------------
/src/Common/Ali/Data/Charge/ChargeBaseData.php:
--------------------------------------------------------------------------------
1 | subject;
45 | $orderNo = $this->order_no;
46 | $amount = $this->amount;
47 | $goodsType = $this->goods_type;
48 | $passBack = $this->return_param;
49 |
50 | // 检查 商品名称 与 商品描述
51 | if (empty($subject)) {
52 | throw new PayException('必须提供 商品的标题/交易标题/订单标题/订单关键字 等');
53 | }
54 |
55 | // 检查订单号是否合法
56 | if (empty($orderNo) || mb_strlen($orderNo) > 64) {
57 | throw new PayException('订单号不能为空,并且长度不能超过64位');
58 | }
59 |
60 | // 检查金额不能低于0.01
61 | if (bccomp($amount, Config::PAY_MIN_FEE, 2) === -1) {
62 | throw new PayException('支付金额不能低于 ' . Config::PAY_MIN_FEE . ' 元');
63 | }
64 |
65 | // 检查商品类型
66 | if (empty($goodsType)) {// 默认为实物类商品
67 | $this->goods_type = 1;
68 | } elseif (! in_array($goodsType, [0 ,1])) {
69 | throw new PayException('商品类型可取值为:0-虚拟类商品 1-实物类商品');
70 | }
71 |
72 | // 返回参数进行urlencode编码
73 | if (! empty($passBack) && ! is_string($passBack)) {
74 | throw new PayException('回传参数必须是字符串');
75 | }
76 | if (!empty($passBack)) {
77 | $this->return_param = urlencode($passBack);
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/Trans/WxTransfer.php:
--------------------------------------------------------------------------------
1 | config->returnRaw) {
31 | $ret['channel'] = Config::WX_TRANSFER;
32 | return $ret;
33 | }
34 |
35 | // 请求失败,可能是网络
36 | if ($ret['return_code'] != 'SUCCESS') {
37 | return $retData = [
38 | 'is_success' => 'F',
39 | 'error' => $ret['return_msg'],
40 | 'channel' => Config::WX_TRANSFER,
41 | ];
42 | }
43 |
44 | // 业务失败
45 | if ($ret['result_code'] != 'SUCCESS') {
46 | return $retData = [
47 | 'is_success' => 'F',
48 | 'error' => $ret['err_code_des'],
49 | 'channel' => Config::WX_TRANSFER,
50 | ];
51 | }
52 |
53 | return $this->createBackData($ret);
54 | }
55 |
56 | /**
57 | * 返回数据
58 | * @param array $data
59 | * @return array
60 | */
61 | protected function createBackData(array $data)
62 | {
63 | $retData = [
64 | 'is_success' => 'T',
65 | 'response' => [
66 | 'trans_no' => $data['partner_trade_no'],
67 | 'transaction_id' => $data['payment_no'],
68 | 'pay_date' => $data['payment_time'],// 企业付款成功时间 2015-05-19 15:26:59
69 | 'device_info' => $data['device_info'],
70 | 'channel' => Config::WX_TRANSFER,
71 | ],
72 | ];
73 |
74 | return $retData;
75 | }
76 |
77 | /**
78 | * 企业转账,不需要签名,使用返回true
79 | * @param array $retData
80 | * @return bool
81 | */
82 | protected function verifySign(array $retData)
83 | {
84 | return true;
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/src/Client/Charge.php:
--------------------------------------------------------------------------------
1 | initCharge($channel, $config);
55 | } catch (PayException $e) {
56 | throw $e;
57 | }
58 |
59 | return static::$instance;
60 | }
61 |
62 | /**
63 | * @param string $channel
64 | * @param array $config
65 | * @param array $metadata
66 | *
67 | * @return mixed
68 | * @throws PayException
69 | */
70 | public static function run($channel, $config, $metadata)
71 | {
72 | if (! in_array($channel, self::$supportChannel)) {
73 | throw new PayException('sdk当前不支持该支付渠道,当前仅支持:' . implode(',', self::$supportChannel));
74 | }
75 |
76 | try {
77 | $instance = self::getInstance($channel, $config);
78 |
79 | $ret = $instance->charge($metadata);
80 | } catch (PayException $e) {
81 | throw $e;
82 | }
83 |
84 | return $ret;
85 | }
86 | }
--------------------------------------------------------------------------------
/src/Common/Weixin/Data/Charge/WapChargeData.php:
--------------------------------------------------------------------------------
1 | scene_info;
23 | if (! is_array($info) || empty($info)) {
24 | throw new PayException('微信 H5 支付,必须提供该参数');
25 | }
26 | }
27 |
28 | protected function buildData()
29 | {
30 | $info = $this->scene_info;
31 | $sceneInfo = [];
32 | if ($info && is_array($info)) {
33 | $sceneInfo['h5_info'] = $info;
34 | }
35 |
36 | $signData = [
37 | 'appid' => trim($this->appId),
38 | 'mch_id' => trim($this->mchId),
39 | 'device_info' => $this->terminal_id,
40 | 'nonce_str' => $this->nonceStr,
41 | 'sign_type' => $this->signType,
42 | 'body' => trim($this->subject),
43 | //'detail' => json_encode($this->body, JSON_UNESCAPED_UNICODE),
44 | 'attach' => trim($this->return_param),
45 | 'out_trade_no' => trim($this->order_no),
46 | 'fee_type' => $this->feeType,
47 | 'total_fee' => $this->amount,
48 | 'spbill_create_ip' => trim($this->client_ip),
49 | 'time_start' => $this->timeStart,
50 | 'time_expire' => $this->timeout_express,
51 | //'goods_tag' => '订单优惠标记',
52 | 'notify_url' => $this->notifyUrl,
53 | 'trade_type' => $this->tradeType, //设置APP支付
54 | //'product_id' => '商品id',
55 | 'limit_pay' => $this->limitPay, // 指定不使用信用卡
56 | 'openid' => $this->openid,
57 | 'scene_info' => $sceneInfo ? json_encode($sceneInfo, JSON_UNESCAPED_UNICODE) : '',
58 |
59 | // 服务商
60 | 'sub_appid' => $this->sub_appid,
61 | 'sub_mch_id' => $this->sub_mch_id,
62 | 'sub_openid' => $this->sub_openid,
63 | ];
64 |
65 | // 移除数组中的空值
66 | $this->retData = ArrayUtil::paraFilter($signData);
67 | }
68 | }
--------------------------------------------------------------------------------
/src/Client/Notify.php:
--------------------------------------------------------------------------------
1 | initNotify($type, $config);
47 | } catch (PayException $e) {
48 | throw $e;
49 | }
50 |
51 | return static::$instance;
52 | }
53 |
54 | /**
55 | * 执行异步工作
56 | * @param string $type
57 | * @param array $config
58 | * @param PayNotifyInterface $callback
59 | * @return array
60 | * @throws PayException
61 | */
62 | public static function run($type, $config, $callback)
63 | {
64 | if (! in_array($type, self::$supportChannel)) {
65 | throw new PayException('sdk当前不支持该异步方式,当前仅支持:' . implode(',', self::$supportChannel));
66 | }
67 |
68 | try {
69 | $instance = self::getInstance($type, $config);
70 |
71 | $ret = $instance->notify($callback);
72 | } catch (PayException $e) {
73 | throw $e;
74 | }
75 |
76 | return $ret;
77 | }
78 |
79 | /**
80 | * 返回异步通知的结果
81 | * @param $type
82 | * @param $config
83 | * @return array|false
84 | * @throws PayException
85 | */
86 | public static function getNotifyData($type, $config)
87 | {
88 | try {
89 | $instance = self::getInstance($type, $config);
90 |
91 | return $instance->getNotifyData();
92 | } catch (PayException $e) {
93 | throw $e;
94 | }
95 | }
96 | }
--------------------------------------------------------------------------------
/src/Refund/AliRefund.php:
--------------------------------------------------------------------------------
1 | config->method = $this->method;
26 | return RefundData::class;
27 | }
28 |
29 | /**
30 | * 返回数据
31 | * @param array $data
32 | * @return array|string
33 | * @throws PayException
34 | */
35 | protected function retData(array $data)
36 | {
37 | $reqData = parent::retData($data);
38 |
39 | try {
40 | $ret = $this->sendReq($reqData);
41 | } catch (PayException $e) {
42 | throw $e;
43 | }
44 | $content = \GuzzleHttp\json_decode($data['biz_content'], true);
45 | $refundNo = $content['out_request_no'];
46 |
47 | if ($this->config->returnRaw) {
48 | $ret['channel'] = Config::ALI_REFUND;
49 | $ret['refund_no'] = $refundNo;
50 | return $ret;
51 | }
52 |
53 | if ($ret['code'] !== '10000') {
54 | return [
55 | 'is_success' => 'F',
56 | 'error' => $ret['sub_msg'],
57 | 'refund_no' => $refundNo
58 | ];
59 | }
60 |
61 | $retData = [
62 | 'is_success' => 'T',
63 | 'response' => [
64 | 'transaction_id' => $ret['trade_no'],
65 | 'order_no' => $ret['out_trade_no'],
66 | 'logon_id' => $ret['buyer_logon_id'],
67 | 'fund_change' => $ret['fund_change'],// 本次退款是否发生了资金变化
68 | 'refund_fee' => $ret['refund_fee'],// 返回的总金额,这里支付宝会累计
69 | 'refund_time' => $ret['gmt_refund_pay'],
70 | 'refund_detail_item_list' => ArrayUtil::get($ret, 'refund_detail_item_list'),// 退款使用的资金渠道
71 | 'refund_no' => $refundNo,
72 | 'channel' => Config::ALI_REFUND,
73 | 'buyer_id' => $ret['buyer_user_id'],
74 | 'store_name' => ArrayUtil::get($ret, 'store_name'),
75 | ],
76 | ];
77 |
78 | return $retData;
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/Common/Cmb/Data/RefundData.php:
--------------------------------------------------------------------------------
1 | refund_no;// 商户退款单号
35 | $date = $this->date;// 商户订单日期,支付时的订单日期 格式:yyyyMMdd
36 | $outTradeNo = $this->out_trade_no;
37 | $refundFee = $this->refund_fee;
38 | $operatorId = $this->operator_id;
39 |
40 | if (empty($date) || mb_strlen($date) !== 8) {
41 | throw new PayException('商户订单日期必须提供,格式:yyyyMMdd');
42 | }
43 |
44 | if (empty($outTradeNo)) {
45 | throw new PayException('必须提供商户网站唯一订单号。');
46 | }
47 |
48 | if (empty($refundNo) && mb_strlen($refundNo) < 21) {
49 | throw new PayException('退款流水号,商户生成,不能超过20位');
50 | }
51 |
52 | if (empty($refundFee) || ! is_numeric($refundFee)) {
53 | throw new PayException('退款金额,格式xxxx.xx');
54 | }
55 |
56 | if (empty($operatorId)) {
57 | throw new PayException('必须提供 商户结账系统的操作员号');
58 | }
59 | }
60 |
61 | protected function getReqData()
62 | {
63 | $rc4 = new Rc4Encrypt($this->merKey);
64 |
65 | $reqData = [
66 | 'dateTime' => $this->dateTime,
67 | 'branchNo' => $this->branchNo,
68 | 'merchantNo' => $this->merchantNo,
69 | 'date' => $this->date,
70 | 'orderNo' => $this->out_trade_no,
71 | 'refundSerialNo' => trim($this->refund_no),
72 | 'amount' => $this->refund_fee,
73 | 'desc' => $this->reason,
74 | 'operatorNo' => $this->operator_id,
75 | 'encrypType' => 'RC4',// 这里不让用户控制,直接采用 rc4加密
76 | 'pwd' => $rc4->encrypt($this->opPwd),
77 | ];
78 |
79 | // 这里不能进行过滤空值,招商的空值也要加入签名中
80 | return $reqData;
81 | }
82 | }
--------------------------------------------------------------------------------
/src/Common/Weixin/Data/Charge/ChargeBaseData.php:
--------------------------------------------------------------------------------
1 | order_no;
36 | $amount = $this->amount;
37 | $subject = $this->subject;
38 | $body = $this->body;
39 | $deviceInfo = $this->terminal_id;
40 |
41 | // 检查订单号是否合法
42 | if (empty($orderNo) || mb_strlen($orderNo) > 64) {
43 | throw new PayException('订单号不能为空,并且长度不能超过64位');
44 | }
45 |
46 | // 检查金额不能低于0.01
47 | if (bccomp($amount, Config::PAY_MIN_FEE, 2) === -1) {
48 | throw new PayException('支付金额不能低于 ' . Config::PAY_MIN_FEE . ' 元');
49 | }
50 |
51 | // 检查 商品名称 与 商品描述
52 | if (empty($subject) || empty($body)) {
53 | throw new PayException('必须提供商品名称与商品详情');
54 | }
55 |
56 | // 初始 微信订单过期时间,最短失效时间间隔必须大于5分钟
57 | if ($this->timeout_express - strtotime($this->timeStart) < 5) {
58 | throw new PayException('必须设置订单过期时间,且需要大于5分钟.如果不正确请检查是否正确设置时区');
59 | } else {
60 | $this->timeout_express = date('YmdHis', $this->timeout_express);
61 | }
62 |
63 | // 微信使用的单位位分.此处进行转化
64 | $this->amount = bcmul($amount, 100, 0);
65 |
66 | // 设置ip地址
67 | $clientIp = $this->client_ip;
68 | if (empty($clientIp)) {
69 | $this->client_ip = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '127.0.0.1';
70 | }
71 |
72 | // 设置设备号
73 | if (empty($deviceInfo)) {
74 | $this->terminal_id = 'WEB';
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/Common/Ali/Data/Charge/BarChargeData.php:
--------------------------------------------------------------------------------
1 | strval($this->order_no),
31 | 'scene' => $this->scene,
32 | 'auth_code' => $this->auth_code,
33 | 'product_code' => 'FACE_TO_FACE_PAYMENT',
34 |
35 | 'subject' => strval($this->subject),
36 | // TODO 支付宝用户ID
37 | // 'seller_id' => $this->partner,
38 |
39 | 'body' => strval($this->body),
40 | 'total_amount' => strval($this->amount),
41 | // TODO 折扣金额
42 | // 'discountable_amount' => '',
43 | // TODO 业务扩展参数 订单商品列表信息,待支持
44 | // 'extend_params => '',
45 | // 'goods_detail' => '',
46 |
47 | 'operator_id' => $this->operator_id,
48 | 'store_id' => $this->store_id,
49 | 'terminal_id' => $this->terminal_id,
50 | ];
51 |
52 | $timeExpire = $this->timeout_express;
53 | if (! empty($timeExpire)) {
54 | $express = floor(($timeExpire - strtotime($this->timestamp)) / 60);
55 | ($express > 0) && $content['timeout_express'] = $express . 'm';// 超时时间 统一使用分钟计算
56 | }
57 |
58 | return $content;
59 | }
60 |
61 | protected function checkDataParam()
62 | {
63 | parent::checkDataParam(); // TODO: Change the autogenerated stub
64 |
65 | $scene = $this->scene;
66 | $authCode = $this->auth_code;
67 |
68 | if (empty($scene) || ! in_array($scene, ['bar_code', 'wave_code'])) {
69 | throw new PayException('支付场景 scene 必须设置 条码支付:bar_code 声波支付:wave_code');
70 | }
71 |
72 | if (empty($authCode)) {
73 | throw new PayException('请提供支付授权码');
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/src/Utils/DataParser.php:
--------------------------------------------------------------------------------
1 | ";
25 | foreach ($values as $key => $val) {
26 | if (is_numeric($val)) {
27 | $xml.="<".$key.">".$val."".$key.">";
28 | } else {
29 | $xml.="<".$key.">".$key.">";
30 | }
31 | }
32 | $xml.="";
33 | return $xml;
34 | }
35 |
36 | /**
37 | * 将xml转为array
38 | * @param string $xml
39 | * @return array|false
40 | */
41 | public static function toArray($xml)
42 | {
43 | if (!$xml) {
44 | return false;
45 | }
46 |
47 | // 检查xml是否合法
48 | $xml_parser = xml_parser_create();
49 | if (!xml_parse($xml_parser, $xml, true)) {
50 | xml_parser_free($xml_parser);
51 | return false;
52 | }
53 |
54 | //将XML转为array
55 | //禁止引用外部xml实体
56 | libxml_disable_entity_loader(true);
57 |
58 | $data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
59 |
60 | return $data;
61 | }
62 |
63 | /**
64 | * google api 二维码生成【QRcode可以存储最多4296个字母数字类型的任意文本,具体可以查看二维码数据格式】
65 | * @param string $text 二维码包含的信息,可以是数字、字符、二进制信息、汉字。不能混合数据类型,数据必须经过UTF-8 URL-encoded
66 | * @param string $widthHeight 生成二维码的尺寸设置
67 | * @param string $ecLevel 可选纠错级别,QR码支持四个等级纠错,用来恢复丢失的、读错的、模糊的、数据。
68 | * L-默认:可以识别已损失的7%的数据
69 | * M-可以识别已损失15%的数据
70 | * Q-可以识别已损失25%的数据
71 | * H-可以识别已损失30%的数据
72 | *
73 | * @param string $margin 生成的二维码离图片边框的距离
74 | *
75 | * @return string
76 | */
77 | public static function toQRimg($text, $widthHeight = '150', $ecLevel = 'L', $margin = '0')
78 | {
79 | $chl = urlencode($text);
80 |
81 | return "http://chart.apis.google.com/chart?chs={$widthHeight}x{$widthHeight}&cht=qr&chld={$ecLevel}|{$margin}&chl={$chl}";
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/Query/Ali/AliRefundQuery.php:
--------------------------------------------------------------------------------
1 | config->method = $this->method;
24 | return RefundQueryData::class;
25 | }
26 |
27 | protected function retData(array $data)
28 | {
29 | $reqData = parent::retData($data);
30 |
31 | try {
32 | $ret = $this->sendReq($reqData);
33 | } catch (PayException $e) {
34 | throw $e;
35 | }
36 |
37 | if ($this->config->returnRaw) {
38 | $ret['channel'] = Config::ALI_REFUND;
39 | return $ret;
40 | }
41 |
42 |
43 | return $this->createBackData($ret);
44 | }
45 |
46 | /**
47 | * 返回数据给客户端 未完成,目前没有数据提供
48 | * @param array $data
49 | * @return array
50 | * @author helei
51 | */
52 | protected function createBackData(array $data)
53 | {
54 | if ($data['code'] !== '10000') {
55 | return $retData = [
56 | 'is_success' => 'F',
57 | 'error' => $data['sub_msg'],
58 | 'channel' => Config::ALI_REFUND,
59 | ];
60 | }
61 |
62 | // 这里有个诡异情况。查询数据全部为空。仅返回一个成功的标记
63 | if (empty($data['out_trade_no'])) {
64 | return [
65 | 'is_success' => 'T',
66 | 'msg' => strtolower($data['msg']),
67 | 'channel' => Config::ALI_REFUND,
68 | ];
69 | }
70 |
71 | $retData = [
72 | 'is_success' => 'T',
73 | 'response' => [
74 | 'transaction_id' => ArrayUtil::get($data, 'trade_no'),// 支付宝订单号
75 | 'order_no' => ArrayUtil::get($data, 'out_trade_no'),// 商户订单号
76 | 'refund_no' => ArrayUtil::get($data, 'out_request_no'),// 本笔退款对应的退款请求号
77 | 'reason' => ArrayUtil::get($data, 'refund_reason'),// 退款理由
78 | 'amount' => ArrayUtil::get($data, 'total_amount'),// 订单总金额
79 | 'refund_amount' => ArrayUtil::get($data, 'refund_amount'),// 退款金额
80 | 'channel' => Config::ALI_REFUND,
81 | ]
82 | ];
83 |
84 | return $retData;
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/src/Config.php:
--------------------------------------------------------------------------------
1 | config->method = $this->method;
22 | return TransferQueryData::class;
23 | }
24 |
25 | protected function retData(array $data)
26 | {
27 | $reqData = parent::retData($data); // TODO: Change the autogenerated stub
28 |
29 | try {
30 | $ret = $this->sendReq($reqData);
31 | } catch (PayException $e) {
32 | throw $e;
33 | }
34 |
35 | if ($this->config->returnRaw) {
36 | $ret['channel'] = Config::ALI_TRANSFER;
37 | return $ret;
38 | }
39 |
40 | return $this->createBackData($ret);
41 | }
42 |
43 | /**
44 | * 返回数据给客户端 未完成,目前没有数据提供
45 | * @param array $data
46 | * @return array
47 | * @author helei
48 | */
49 | protected function createBackData(array $data)
50 | {
51 | if ($data['code'] !== '10000') {
52 | return $retData = [
53 | 'is_success' => 'F',
54 | 'error' => $data['sub_msg'],
55 | 'channel' => Config::ALI_TRANSFER,
56 | ];
57 | }
58 |
59 | $retData = [
60 | 'is_success' => 'T',
61 | 'response' => [
62 | 'transaction_id' => ArrayUtil::get($data, 'order_id'),// 支付宝订单号
63 | 'status' => strtolower(ArrayUtil::get($data, 'status')),
64 | 'pay_date' => ArrayUtil::get($data, 'pay_date'),// 转账日期
65 | 'arrival_time_end' => ArrayUtil::get($data, 'arrival_time_end'),// 预计到账时间,转账到银行卡专用,格式为yyyy-MM-dd HH:mm:ss
66 | 'amount' => ArrayUtil::get($data, 'order_fee'),// 转账金额
67 | 'trans_no' => ArrayUtil::get($data, 'out_biz_no'),// 商户转账订单号
68 | 'channel' => Config::ALI_TRANSFER,
69 | ]
70 | ];
71 | if (isset($data['error_code'])) {
72 | $retData['response']['error_code'] = ArrayUtil::get($data, 'error_code');
73 | // 查询到的订单状态为FAIL失败或REFUND退票时,返回具体的原因。
74 | $retData['response']['fail_reason'] = ArrayUtil::get($data, 'fail_reason');
75 | }
76 |
77 | return $retData;
78 | }
79 | }
--------------------------------------------------------------------------------
/src/Common/Weixin/Data/Charge/QrChargeData.php:
--------------------------------------------------------------------------------
1 | scene_info;
26 | $sceneInfo = [];
27 | if ($info && is_array($info)) {
28 | $sceneInfo['store_info'] = $info;
29 | }
30 |
31 | $signData = [
32 | 'appid' => trim($this->appId),
33 | 'mch_id' => trim($this->mchId),
34 | 'device_info' => $this->terminal_id,
35 | 'nonce_str' => $this->nonceStr,
36 | 'sign_type' => $this->signType,
37 | 'body' => trim($this->subject),
38 | //'detail' => json_encode($this->body, JSON_UNESCAPED_UNICODE),
39 | 'attach' => trim($this->return_param),
40 | 'out_trade_no' => trim($this->order_no),
41 | 'fee_type' => $this->feeType,
42 | 'total_fee' => $this->amount,
43 | 'spbill_create_ip' => trim($this->client_ip),
44 | 'time_start' => $this->timeStart,
45 | 'time_expire' => $this->timeout_express,
46 | //'goods_tag' => '订单优惠标记',
47 | 'notify_url' => $this->notifyUrl,
48 | 'trade_type' => $this->tradeType, //设置APP支付
49 | 'product_id' => $this->product_id,
50 | 'limit_pay' => $this->limitPay, // 指定不使用信用卡
51 | 'openid' => $this->openid,
52 | 'scene_info' => $sceneInfo ? json_encode($sceneInfo, JSON_UNESCAPED_UNICODE) : '',
53 |
54 | // 服务商
55 | 'sub_appid' => $this->sub_appid,
56 | 'sub_mch_id' => $this->sub_mch_id,
57 | 'sub_openid' => $this->sub_openid,
58 | ];
59 |
60 | // 移除数组中的空值
61 | $this->retData = ArrayUtil::paraFilter($signData);
62 | }
63 |
64 | /**
65 | * 检查扫码支付必须的参数信息
66 | * @throws PayException
67 | */
68 | protected function checkDataParam()
69 | {
70 | parent::checkDataParam(); // TODO: Change the autogenerated stub
71 |
72 | // 扫码支付,必须设置product_id 参数
73 | $productId = $this->product_id;
74 | if (empty($productId)) {
75 | throw new PayException('扫码支付,必须设置商品ID.');
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/Refund/WxRefund.php:
--------------------------------------------------------------------------------
1 | config->returnRaw) {
32 | $ret['channel'] = Config::WX_REFUND;
33 | return $ret;
34 | }
35 |
36 | // 请求失败,可能是网络
37 | if ($ret['return_code'] != 'SUCCESS') {
38 | return $retData = [
39 | 'is_success' => 'F',
40 | 'error' => $ret['return_msg']
41 | ];
42 | }
43 |
44 | // 业务失败
45 | if ($ret['result_code'] != 'SUCCESS') {
46 | return $retData = [
47 | 'is_success' => 'F',
48 | 'error' => $ret['err_code_des']
49 | ];
50 | }
51 |
52 | return $this->createBackData($ret);
53 | }
54 |
55 | /**
56 | * 处理返回的数据
57 | * @param array $data
58 | * @return array
59 | * @author helei
60 | */
61 | protected function createBackData(array $data)
62 | {
63 | // 将订单总金额金额处理为元
64 | $total_fee = bcdiv($data['total_fee'], 100, 2);
65 | // 将订单退款金额处理为元
66 | $refund_fee = bcdiv($data['refund_fee'], 100, 2);
67 |
68 | $retData = [
69 | 'is_success' => 'T',
70 | 'response' => [
71 | 'transaction_id' => $data['transaction_id'],
72 | 'order_no' => $data['out_trade_no'],
73 | 'refund_no' => $data['out_refund_no'],
74 | 'refund_id' => $data['refund_id'],
75 | 'refund_fee' => $refund_fee,
76 | 'refund_channel' => $data['refund_channel'],
77 | 'amount' => $total_fee,
78 | 'channel' => Config::WX_REFUND,
79 |
80 | 'coupon_refund_fee' => bcdiv($data['coupon_refund_fee'], 100, 2),
81 | 'coupon_refund_count' => $data['coupon_refund_count'],
82 | 'cash_fee' => bcdiv($data['cash_fee'], 100, 2),
83 | 'cash_refund_fee' => bcdiv($data['cash_refund_fee'], 100, 2),
84 | ],
85 | ];
86 |
87 | return $retData;
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/Common/Ali/Data/TransData.php:
--------------------------------------------------------------------------------
1 | trans_no;
34 | $payeeType = $this->payee_type;
35 | $payeeAccount = $this->payee_account;
36 | $amount = $this->amount;
37 | $remark = $this->remark;
38 |
39 | if (empty($transNo)) {
40 | throw new PayException('请传入 商户转账唯一订单号');
41 | }
42 |
43 | if (empty($payeeType) || ! in_array($payeeType, ['ALIPAY_USERID', 'ALIPAY_LOGONID'])) {
44 | throw new PayException('请传入收款账户类型');
45 | }
46 |
47 | if (empty($payeeAccount)) {
48 | throw new PayException('请传入转账帐号');
49 | }
50 |
51 | if (empty($amount) || bccomp($amount, 0, 2) !== 1) {
52 | throw new PayException('请输入转账金额,且大于0');
53 | }
54 |
55 | if (bccomp($amount, Config::TRANS_FEE, 2) !== -1 && empty($remark)) {
56 | throw new PayException('转账金额大于等于' . Config::TRANS_FEE , '必须设置 remark');
57 | }
58 | }
59 |
60 | /**
61 | * 业务请求参数的集合,最大长度不限,除公共参数外所有请求参数都必须放在这个参数中传递
62 | *
63 | * @return string
64 | */
65 | protected function getBizContent()
66 | {
67 | $content = [
68 | 'out_biz_no' => $this->trans_no,// 商户转账唯一订单号
69 | 'payee_type' => strtoupper($this->payee_type),// 收款方账户类型
70 | 'payee_account' => $this->payee_account,// 收款方账户
71 | 'amount' => $this->amount,
72 | 'payer_show_name' => $this->payer_show_name,
73 | 'payer_real_name' => $this->payer_real_name,
74 | 'payee_real_name' => $this->payee_real_name,
75 | 'remark' => $this->remark,
76 | ];
77 |
78 | return $content;
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/Utils/StrUtil.php:
--------------------------------------------------------------------------------
1 | date('Ymd'),
20 | 'agr_no' => '430802198004014374',
21 | 'serial_no' => time() . rand(1000, 9999),
22 | 'mobile' => '13500007108',
23 | 'user_id' => '100',
24 | 'lon' => '',
25 | 'lat' => '',
26 | 'riskLevel' => '1',
27 | ];
28 |
29 | try {
30 | $data = Helper::run(Config::CMB_BIND, $cmbConfig, $signData);
31 | } catch (PayException $e) {
32 | echo $e->errorMessage();
33 | exit;
34 | }
35 |
36 | $btnText = '点我开始签约';
37 |
38 | ?>
39 |
40 |
41 |
42 |
43 |
44 | 签约一网通支付
45 |
46 |
47 |
84 |
85 |
86 |
87 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/src/Common/Weixin/Data/TransferData.php:
--------------------------------------------------------------------------------
1 | retData = [
38 | 'mch_appid' => $this->appId,
39 | 'mchid' => $this->mchId,
40 | 'device_info' => $this->terminal_id,
41 | 'nonce_str' => $this->nonceStr,
42 | 'partner_trade_no' => $this->trans_no,
43 | 'openid' => $this->openid,
44 |
45 | 'check_name' => $this->check_name,
46 | 're_user_name' => $this->payer_real_name,
47 | 'amount' => $this->amount,// 此处需要处理单位为分
48 | 'desc' => $this->desc,
49 |
50 | // $_SERVER["REMOTE_ADDR"] 获取客户端接口。此处获取php所在机器的ip 如果无法获取,则使用该ip
51 | 'spbill_create_ip' => $this->client_ip,
52 | ];
53 |
54 | $this->retData = ArrayUtil::paraFilter($this->retData);
55 | }
56 |
57 | /**
58 | * 检查相关参数是否设置
59 | * @author helei
60 | */
61 | protected function checkDataParam()
62 | {
63 | $openId = $this->openid;
64 | $transNo = $this->trans_no;
65 | $checkName = $this->check_name;
66 | $realName = $this->payer_real_name;
67 | $amount = $this->amount;
68 | $clientIp = $this->client_ip;
69 |
70 | if (empty($openId)) {
71 | throw new PayException('商户appid下,某用户的openid 必须传入');
72 | }
73 |
74 | if (empty($transNo)) {
75 | throw new PayException('商户订单号,需保持唯一性');
76 | }
77 |
78 | if ($checkName !== 'NO_CHECK' && empty($realName)) {
79 | throw new PayException('请传入收款人真实姓名');
80 | }
81 |
82 | // 微信使用的单位位分.此处进行转化
83 | $this->amount = bcmul($amount, 100, 0);
84 | if (empty($amount) || $amount < 0) {
85 | throw new PayException('转账金额错误');
86 | }
87 |
88 | if (empty($clientIp)) {
89 | $this->client_ip = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '127.0.0.1';
90 | }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/src/Common/Weixin/Data/Charge/PubChargeData.php:
--------------------------------------------------------------------------------
1 | openid;
28 | if (empty($openid)) {
29 | throw new PayException('用户在商户appid下的唯一标识,公众号支付,必须设置该参数.');
30 | }
31 |
32 | $subMchId = $this->sub_mch_id;// 如果是服务商模式,则 sub_openid 必须提供
33 | $subOpenid = $this->sub_openid;
34 | if ($subMchId && empty($subOpenid)) {
35 | throw new PayException('公众号的服务商模式,必须提供 sub_openid 参数.');
36 | }
37 | }
38 |
39 | protected function buildData()
40 | {
41 | $info = $this->scene_info;
42 | $sceneInfo = [];
43 | if ($info && is_array($info)) {
44 | $sceneInfo['store_info'] = $info;
45 | }
46 |
47 | $signData = [
48 | 'appid' => trim($this->appId),
49 | 'mch_id' => trim($this->mchId),
50 | 'device_info' => $this->terminal_id,
51 | 'nonce_str' => $this->nonceStr,
52 | 'sign_type' => $this->signType,
53 | 'body' => trim($this->subject),
54 | //'detail' => json_encode($this->body, JSON_UNESCAPED_UNICODE),
55 | 'attach' => trim($this->return_param),
56 | 'out_trade_no' => trim($this->order_no),
57 | 'fee_type' => $this->feeType,
58 | 'total_fee' => $this->amount,
59 | 'spbill_create_ip' => trim($this->client_ip),
60 | 'time_start' => $this->timeStart,
61 | 'time_expire' => $this->timeout_express,
62 | //'goods_tag' => '订单优惠标记',
63 | 'notify_url' => $this->notifyUrl,
64 | 'trade_type' => $this->tradeType, //设置APP支付
65 | //'product_id' => '商品id',
66 | 'limit_pay' => $this->limitPay, // 指定不使用信用卡
67 | // 业务数据
68 | 'openid' => $this->openid,
69 | 'scene_info' => $sceneInfo ? json_encode($sceneInfo, JSON_UNESCAPED_UNICODE) : '',
70 |
71 | // 服务商
72 | 'sub_appid' => $this->sub_appid,
73 | 'sub_mch_id' => $this->sub_mch_id,
74 | 'sub_openid' => $this->sub_openid,
75 | ];
76 |
77 | // 移除数组中的空值
78 | $this->retData = ArrayUtil::paraFilter($signData);
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/Utils/RsaEncrypt.php:
--------------------------------------------------------------------------------
1 | key = $key;
18 | }
19 |
20 | /**
21 | * 设置key
22 | * @param $key
23 | * @author helei
24 | */
25 | public function setKey($key)
26 | {
27 | $this->key = $key;
28 | }
29 |
30 | /**
31 | * RSA签名, 此处秘钥是私有秘钥
32 | * @param string $data 签名的数组
33 | * @throws \Exception
34 | * @return string
35 | * @author helei
36 | */
37 | public function encrypt($data)
38 | {
39 | if ($this->key === false) {
40 | return '';
41 | }
42 |
43 | $res = openssl_get_privatekey($this->key);
44 | if (empty($res)) {
45 | throw new \Exception('您使用的私钥格式错误,请检查RSA私钥配置');
46 | }
47 |
48 | openssl_sign($data, $sign, $res);
49 | openssl_free_key($res);
50 |
51 | //base64编码
52 | $sign = base64_encode($sign);
53 | return $sign;
54 | }
55 |
56 | /**
57 | * RSA解密 此处秘钥是用户私有秘钥
58 | * @param string $content 需要解密的内容,密文
59 | * @throws \Exception
60 | * @return string
61 | * @author helei
62 | */
63 | public function decrypt($content)
64 | {
65 | if ($this->key === false) {
66 | return '';
67 | }
68 |
69 | $res = openssl_get_privatekey($this->key);
70 | if (empty($res)) {
71 | throw new \Exception('您使用的私钥格式错误,请检查RSA私钥配置');
72 | }
73 |
74 | //用base64将内容还原成二进制
75 | $content = base64_decode($content);
76 | //把需要解密的内容,按128位拆开解密
77 | $result = '';
78 | for ($i = 0; $i < strlen($content)/128; $i++) {
79 | $data = substr($content, $i * 128, 128);
80 | openssl_private_decrypt($data, $decrypt, $res);
81 | $result .= $decrypt;
82 | }
83 | openssl_free_key($res);
84 | return $result;
85 | }
86 |
87 | /**
88 | * RSA验签 ,此处的秘钥,是第三方公钥
89 | * @param string $data 待签名数据
90 | * @param string $sign 要校对的的签名结果
91 | * @throws \Exception
92 | * @return bool
93 | * @author helei
94 | */
95 | public function rsaVerify($data, $sign)
96 | {
97 | // 初始时,使用公钥key
98 | $res = openssl_get_publickey($this->key);
99 | if (empty($res)) {
100 | throw new \Exception('支付宝RSA公钥错误。请检查公钥文件格式是否正确');
101 | }
102 |
103 | $result = (bool)openssl_verify($data, base64_decode($sign), $res);
104 | openssl_free_key($res);
105 | return $result;
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/src/Utils/Rsa2Encrypt.php:
--------------------------------------------------------------------------------
1 | key = $key;
18 | }
19 |
20 | /**
21 | * 设置key
22 | * @param $key
23 | * @author helei
24 | */
25 | public function setKey($key)
26 | {
27 | $this->key = $key;
28 | }
29 |
30 | /**
31 | * RSA2签名, 此处秘钥是私有秘钥
32 | * @param string $data 签名的数组
33 | * @throws \Exception
34 | * @return string
35 | * @author helei
36 | */
37 | public function encrypt($data)
38 | {
39 | if ($this->key === false) {
40 | return '';
41 | }
42 |
43 | $res = openssl_get_privatekey($this->key);
44 | if (empty($res)) {
45 | throw new \Exception('您使用的私钥格式错误,请检查RSA私钥配置');
46 | }
47 |
48 | openssl_sign($data, $sign, $res, OPENSSL_ALGO_SHA256);
49 | openssl_free_key($res);
50 |
51 | //base64编码
52 | $sign = base64_encode($sign);
53 | return $sign;
54 | }
55 |
56 | /**
57 | * RSA2解密 此处秘钥是用户私有秘钥
58 | * @param string $content 需要解密的内容,密文
59 | * @throws \Exception
60 | * @return string
61 | * @author helei
62 | */
63 | public function decrypt($content)
64 | {
65 | if ($this->key === false) {
66 | return '';
67 | }
68 |
69 | $res = openssl_get_privatekey($this->key);
70 | if (empty($res)) {
71 | throw new \Exception('您使用的私钥格式错误,请检查RSA私钥配置');
72 | }
73 |
74 | //用base64将内容还原成二进制
75 | $decodes = base64_decode($content);
76 |
77 | $str = '';
78 | $dcyCont = '';
79 | foreach ($decodes as $n => $decode) {
80 | if (!openssl_private_decrypt($decode, $dcyCont, $res)) {
81 | echo "
" . openssl_error_string() . "
";
82 | }
83 | $str .= $dcyCont;
84 | }
85 |
86 | openssl_free_key($res);
87 | return $str;
88 | }
89 |
90 | /**
91 | * RSA2验签 ,此处的秘钥,是第三方公钥
92 | * @param string $data 待签名数据
93 | * @param string $sign 要校对的的签名结果
94 | * @throws \Exception
95 | * @return bool
96 | * @author helei
97 | */
98 | public function rsaVerify($data, $sign)
99 | {
100 | // 初始时,使用公钥key
101 | $res = openssl_get_publickey($this->key);
102 | if (empty($res)) {
103 | throw new \Exception('支付宝RSA公钥错误。请检查公钥文件格式是否正确');
104 | }
105 |
106 | $result = (bool)openssl_verify($data, base64_decode($sign), $res, OPENSSL_ALGO_SHA256);
107 | openssl_free_key($res);
108 | return $result;
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/src/Common/Cmb/Data/CmbBaseData.php:
--------------------------------------------------------------------------------
1 | signType) {
51 | case 'SHA-256':
52 | $sign = hash('sha256', "$signStr&{$this->merKey}");
53 | break;
54 | default:
55 | $sign = '';
56 | }
57 |
58 | return $sign;
59 | }
60 |
61 | /**
62 | * 构建数据
63 | */
64 | protected function buildData()
65 | {
66 | $signData = [
67 | // 公共参数
68 | 'version' => $this->version,
69 | 'charset' => $this->charset,
70 | 'signType' => $this->signType,
71 | 'reqData' => $this->getReqData(),
72 | ];
73 |
74 | // 移除数组中的空值
75 | $this->retData = ArrayUtil::paraFilter($signData);
76 | }
77 |
78 | /**
79 | * 检查基本数据
80 | */
81 | protected function checkDataParam()
82 | {
83 | $branchNo = $this->branchNo;
84 | $merchantNo = $this->merchantNo;
85 |
86 | if (empty($branchNo) || mb_strlen($branchNo) !== 4) {
87 | throw new PayException('商户分行号,4位数字');
88 | }
89 |
90 | if (empty($merchantNo) || mb_strlen($merchantNo) !== 6) {
91 | throw new PayException('商户号,6位数字');
92 | }
93 | }
94 |
95 | /**
96 | * 请求数据
97 | *
98 | * @return array
99 | */
100 | abstract protected function getReqData();
101 | }
--------------------------------------------------------------------------------
/src/Notify/NotifyStrategy.php:
--------------------------------------------------------------------------------
1 | getNotifyData();
32 | if ($notifyData === false) {// 失败,就返回错误
33 | return $this->replyNotify(false, '获取通知数据失败');
34 | }
35 |
36 | // 检查异步通知返回的数据是否有误
37 | $checkRet = $this->checkNotifyData($notifyData);
38 | if ($checkRet === false) {// 失败,就返回错误
39 | return $this->replyNotify(false, '返回数据验签失败,可能数据被篡改');
40 | }
41 |
42 | // 回调商户的业务逻辑
43 | $flag = $this->callback($notify, $notifyData);
44 | if ($flag) {
45 | $msg = 'OK';
46 | } else {
47 | $msg = '商户逻辑调用出错';
48 | }
49 | // 返回响应值
50 | return $this->replyNotify($flag, $msg);
51 | }
52 |
53 | /**
54 | * 回调商户的业务逻辑,根据返回的true 或者 false 向第三方返回数据
55 | * @param PayNotifyInterface $notify
56 | * @param array $notifyData
57 | *
58 | * @return boolean
59 | * @author helei
60 | */
61 | protected function callback(PayNotifyInterface $notify, array $notifyData)
62 | {
63 | $data = $this->getRetData($notifyData);
64 |
65 | if ($data === false) {
66 | return false;
67 | }
68 |
69 | return $notify->notifyProcess($data);
70 | }
71 |
72 | /**
73 | * 获取移除通知的数据 并进行简单处理(如:格式化为数组)
74 | *
75 | * 如果获取数据失败,返回false
76 | *
77 | * @return array|false
78 | * @author helei
79 | */
80 | abstract public function getNotifyData();
81 |
82 | /**
83 | * 检查异步通知的数据是否合法
84 | *
85 | * 如果检查失败,返回false
86 | *
87 | * @param array $data 由 $this->getNotifyData() 返回的数据
88 | * @return boolean
89 | * @author helei
90 | */
91 | abstract public function checkNotifyData(array $data);
92 |
93 | /**
94 | * 向客户端返回必要的数据
95 | * @param array $data 回调机构返回的回调通知数据
96 | * @return array|false
97 | * @author helei
98 | */
99 | abstract protected function getRetData(array $data);
100 |
101 | /**
102 | * 根据返回结果,回答支付机构。是否回调通知成功
103 | * @param boolean $flag 每次返回的bool值
104 | * @param string $msg 通知信息,错误原因
105 | * @return mixed
106 | * @author helei
107 | */
108 | abstract protected function replyNotify($flag, $msg = 'OK');
109 | }
110 |
--------------------------------------------------------------------------------
/src/Query/Wx/WxChargeQuery.php:
--------------------------------------------------------------------------------
1 | config->returnRaw) {
40 | $data['channel'] = Config::WX_CHARGE;
41 | return $data;
42 | }
43 |
44 | // 请求失败,可能是网络
45 | if ($data['return_code'] != 'SUCCESS') {
46 | return $retData = [
47 | 'is_success' => 'F',
48 | 'error' => $data['return_msg'],
49 | 'channel' => Config::WX_CHARGE,// 支付查询
50 | ];
51 | }
52 |
53 | // 业务失败
54 | if ($data['result_code'] != 'SUCCESS') {
55 | return $retData = [
56 | 'is_success' => 'F',
57 | 'error' => $data['err_code_des'],
58 | 'channel' => Config::WX_CHARGE,// 支付查询
59 | ];
60 | }
61 |
62 | // 正确
63 | return $this->createBackData($data);
64 | }
65 |
66 | /**
67 | * 返回数据给客户端
68 | * @param array $data
69 | * @return array
70 | * @author helei
71 | */
72 | protected function createBackData(array $data)
73 | {
74 | // 将金额处理为元
75 | $totalFee = bcdiv($data['total_fee'], 100, 2);
76 |
77 | $retData = [
78 | 'is_success' => 'T',
79 | 'response' => [
80 | 'amount' => $totalFee,
81 | 'channel' => Config::WX_CHARGE,// 支付查询
82 | 'order_no' => $data['out_trade_no'],
83 | 'buyer_id' => $data['openid'],
84 | 'trade_state' => strtolower($data['trade_state']),
85 | 'transaction_id' => $data['transaction_id'],
86 | 'time_end' => date('Y-m-d H:i:s', strtotime($data['time_end'])),
87 | 'return_param' => $data['attach'],
88 | 'terminal_id' => $data['device_info'],
89 | 'trade_type' => $data['trade_type'],
90 | 'bank_type' => $data['bank_type'],
91 | 'trade_state_desc' => isset($data['trade_state_desc']) ? $data['trade_state_desc'] : '交易成功',
92 | ],
93 | ];
94 |
95 | return ArrayUtil::paraFilter($retData);
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/examples/cmb/charge.php:
--------------------------------------------------------------------------------
1 | $orderNo,// 招行订单位数变更为32位
23 | 'timeout_express' => time() + 600,// 表示必须 600s 内付款
24 | 'amount' => '0.01',// 单位为元 ,最小为0.01
25 | 'return_param' => 'tatata',
26 | 'client_ip' => isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '127.0.0.1',// 客户地址
27 | 'date' => date('Ymd'),
28 | 'agr_no' => '430802198004014358',// 建议用身份证
29 | 'serial_no' => time() . rand(1000, 9999),// 协议开通请求流水号,开通协议时必填
30 | 'user_id' => '888',
31 | 'mobile' => '13500007107',
32 | 'lon' => '',
33 | 'lat' => '',
34 | 'risk_level' => '3',
35 | ];
36 |
37 | try {
38 | $data = Charge::run(Config::CMB_CHANNEL_APP, $cmbConfig, $payData);
39 | } catch (PayException $e) {
40 | echo $e->errorMessage();
41 | exit;
42 | }
43 |
44 | $btnText = '点我开始支付';
45 |
46 | ?>
47 |
48 |
49 |
50 |
51 |
52 | 一网通支付
53 |
54 |
55 |
92 |
93 |
94 |
95 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/src/Common/Ali/Data/AliBaseData.php:
--------------------------------------------------------------------------------
1 | signType) {
51 | case 'RSA':
52 | $rsa = new RsaEncrypt($this->rsaPrivateKey);
53 |
54 | $sign = $rsa->encrypt($signStr);
55 | break;
56 | case 'RSA2':
57 | $rsa = new Rsa2Encrypt($this->rsaPrivateKey);
58 |
59 | $sign = $rsa->encrypt($signStr);
60 | break;
61 | default:
62 | $sign = '';
63 | }
64 |
65 | return $sign;
66 | }
67 |
68 | /**
69 | * 构建 支付 加密数据
70 | * @author helei
71 | */
72 | protected function buildData()
73 | {
74 | $bizContent = $this->getBizContent();
75 | $bizContent = ArrayUtil::paraFilter($bizContent);// 过滤掉空值,下面不用在检查是否为空
76 |
77 | $signData = [
78 | // 公共参数
79 | 'app_id' => $this->appId,
80 | 'method' => $this->method,
81 | 'format' => $this->format,
82 | 'charset' => $this->charset,
83 | 'sign_type' => $this->signType,
84 | 'timestamp' => $this->timestamp,
85 | 'version' => $this->version,
86 | 'notify_url' => $this->notifyUrl,
87 |
88 | // 业务参数
89 | 'biz_content' => json_encode($bizContent, JSON_UNESCAPED_UNICODE),
90 | ];
91 |
92 | // 电脑支付 wap支付添加额外参数
93 | if (in_array($this->method, ['alipay.trade.page.pay', 'alipay.trade.wap.pay'])) {
94 | $signData['return_url'] = $this->returnUrl;
95 | }
96 |
97 | // 移除数组中的空值
98 | $this->retData = ArrayUtil::paraFilter($signData);
99 | }
100 |
101 | /**
102 | * 支付宝构建请求查询的数据
103 | * @return mixed
104 | */
105 | abstract protected function getBizContent();
106 | }
107 |
--------------------------------------------------------------------------------
/src/QueryContext.php:
--------------------------------------------------------------------------------
1 | query = new AliChargeQuery($config);
46 | break;
47 | case Config::ALI_REFUND:// 支付宝退款订单查询
48 | $this->query = new AliRefundQuery($config);
49 | break;
50 | case Config::ALI_TRANSFER:
51 | $this->query = new AliTransferQuery($config);
52 | break;
53 |
54 | case Config::WX_CHARGE:// 微信支付订单查询
55 | $this->query = new WxChargeQuery($config);
56 | break;
57 | case Config::WX_REFUND:// 微信退款订单查询
58 | $this->query = new WxRefundQuery($config);
59 | break;
60 | case Config::WX_TRANSFER:// 微信转款订单查询
61 | $this->query = new WxTransferQuery($config);
62 | break;
63 |
64 | case Config::CMB_CHARGE:// 招商支付查询
65 | $this->query = new CmbChargeQuery($config);
66 | break;
67 | case Config::CMB_REFUND:// 招商退款查询
68 | $this->query = new CmbRefundQuery($config);
69 | break;
70 | default:
71 | throw new PayException('当前仅支持:ALI_CHARGE ALI_REFUND WX_CHARGE WX_REFUND WX_TRANSFER CMB_CHARGE CMB_REFUND');
72 | }
73 | } catch (PayException $e) {
74 | throw $e;
75 | }
76 | }
77 |
78 | /**
79 | * 通过环境类调用支付异步通知
80 | *
81 | * @param array $data
82 | * // 二者设置一个即可
83 | * $data => [
84 | * 'transaction_id' => '原付款支付宝交易号',
85 | * 'order_no' => '商户订单号',
86 | * ];
87 | *
88 | * @return array
89 | * @throws PayException
90 | * @author helei
91 | */
92 | public function query(array $data)
93 | {
94 | if (! $this->query instanceof BaseStrategy) {
95 | throw new PayException('请检查初始化是否正确');
96 | }
97 |
98 | try {
99 | return $this->query->handle($data);
100 | } catch (PayException $e) {
101 | throw $e;
102 | }
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/src/Query/Wx/WxTransferQuery.php:
--------------------------------------------------------------------------------
1 | config->returnRaw) {
33 | $data['channel'] = Config::WX_TRANSFER;
34 | return $data;
35 | }
36 |
37 | // 请求失败,可能是网络
38 | if ($data['return_code'] != 'SUCCESS') {
39 | return $retData = [
40 | 'is_success' => 'F',
41 | 'error' => $data['return_msg'],
42 | 'channel' => Config::WX_TRANSFER,
43 | ];
44 | }
45 |
46 | // 业务失败
47 | if ($data['result_code'] != 'SUCCESS') {
48 | return $retData = [
49 | 'is_success' => 'F',
50 | 'error' => $data['err_code_des'],
51 | 'channel' => Config::WX_TRANSFER,
52 | ];
53 | }
54 |
55 | // 正确
56 | return $this->createBackData($data);
57 | }
58 |
59 | /**
60 | * 返回数据给客户端
61 | * @param array $data
62 | * @return array
63 | * @author helei
64 | */
65 | protected function createBackData(array $data)
66 | {
67 | // 将金额处理为元
68 | $amount = bcdiv($data['payment_amount'], 100, 2);
69 |
70 | $retData = [
71 | 'is_success' => 'T',
72 | 'response' => [
73 | 'trans_no' => $data['partner_trade_no'],// 商户单号
74 | 'transaction_id' => $data['detail_id'],// 付款单号
75 | 'status' => strtolower($data['status']),// 转账状态
76 | 'reason' => $data['reason'],// 失败原因
77 | 'openid' => $data['openid'],
78 | 'payee_name' => $data['transfer_name'],// 收款用户姓名
79 | 'amount' => $amount,
80 | 'pay_date' => $data['transfer_time'],
81 | 'desc' => $data['desc'],// 付款描述
82 | 'channel' => Config::WX_TRANSFER,
83 | ],
84 | ];
85 |
86 | return $retData;
87 | }
88 |
89 | /**
90 | * @param array $data
91 | * @author helei
92 | * @throws PayException
93 | * @return array|string
94 | */
95 | public function handle(array $data)
96 | {
97 | $buildClass = $this->getBuildDataClass();
98 |
99 | try {
100 | $this->reqData = new $buildClass($this->config, $data);
101 | } catch (PayException $e) {
102 | throw $e;
103 | }
104 |
105 | $this->reqData->setSign();
106 |
107 | $xml = DataParser::toXml($this->reqData->getData());
108 | $ret = $this->sendReq($xml);
109 |
110 | return $this->retData($ret);
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/src/Common/Cmb/Data/Charge/ChargeData.php:
--------------------------------------------------------------------------------
1 | amount;
33 | // 订单号交给支付系统自己检查
34 |
35 | // 检查金额不能低于0.01
36 | if (bccomp($amount, Config::PAY_MIN_FEE, 2) === -1) {
37 | throw new PayException('支付金额不能低于 ' . Config::PAY_MIN_FEE . ' 元');
38 | }
39 |
40 | // 设置ip地址
41 | $clientIp = $this->client_ip;
42 | if (empty($clientIp)) {
43 | $this->client_ip = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '127.0.0.1';
44 | }
45 |
46 | $timeExpire = $this->timeout_express;
47 | if (! empty($timeExpire)) {
48 | $express = floor(($timeExpire - strtotime($this->dateTime)) / 60);
49 |
50 | if ($express > CmbConfig::MAX_EXPIRE_TIME || $express < 0) {// 招商规定
51 | $this->timeout_express = CmbConfig::MAX_EXPIRE_TIME;
52 | } else {
53 | $this->timeout_express = $express;
54 | }
55 | }
56 | }
57 |
58 | /**
59 | * 请求数据
60 | */
61 | protected function getReqData()
62 | {
63 | $reqData = [
64 | 'dateTime' => $this->dateTime,
65 | 'branchNo' => $this->branchNo,
66 | 'merchantNo' => $this->merchantNo,
67 | 'date' => $this->date ? $this->date : date('Ymd', time()),
68 | 'orderNo' => $this->order_no,
69 | 'amount' => $this->amount,
70 | 'expireTimeSpan' => $this->timeout_express ? $this->timeout_express : '',
71 | 'payNoticeUrl' => $this->notifyUrl,
72 | 'payNoticePara' => $this->return_param ? $this->return_param : '',
73 | 'returnUrl' => $this->returnUrl ? $this->returnUrl : '',
74 | 'clientIP' => $this->client_ip,
75 | 'cardType' => $this->limitPay ? $this->limitPay : '',
76 | 'agrNo' => $this->agr_no,
77 | 'merchantSerialNo' => $this->serial_no ? $this->serial_no : '',
78 | 'userID' => $this->user_id ? $this->user_id : '',
79 | 'mobile' => $this->mobile ? $this->mobile : '',
80 | 'lon' => $this->lon ? $this->lon : '',
81 | 'lat' => $this->lat ? $this->lat : '',
82 | 'riskLevel' => $this->risk_level ? $this->risk_level : '',
83 | 'signNoticeUrl' => $this->signNoticeUrl ? $this->signNoticeUrl : '',
84 | 'signNoticePara' => $this->return_param ? $this->return_param : '',
85 |
86 | // 暂时先不支持下面方式
87 | 'extendInfo' => '',
88 | 'extendInfoEncrypType' => '',
89 | ];
90 |
91 | // 这里不能进行过滤空值,招商的空值也要加入签名中
92 | return $reqData;
93 | }
94 | }
--------------------------------------------------------------------------------
/src/Query/Ali/AliChargeQuery.php:
--------------------------------------------------------------------------------
1 | config->method = $this->method;
29 | return ChargeQueryData::class;
30 | }
31 |
32 | /**
33 | * 请求后得到的返回数据
34 | * @param array $data
35 | * @return array|mixed
36 | * @throws PayException
37 | */
38 | protected function retData(array $data)
39 | {
40 | $data = parent::retData($data); // TODO: Change the autogenerated stub
41 |
42 | try {
43 | $ret = $this->sendReq($data);
44 | } catch (PayException $e) {
45 | throw $e;
46 | }
47 |
48 | if ($this->config->returnRaw) {
49 | $ret['channel'] = Config::ALI_CHARGE;
50 | return $ret;
51 | }
52 |
53 | return $this->createBackData($ret);
54 | }
55 |
56 | /**
57 | * 处理支付宝返回的数据,统一处理后返回
58 | * @param array $data 支付宝返回的数据
59 | * @return array
60 | * @author helei
61 | */
62 | protected function createBackData(array $data)
63 | {
64 | // 新版本
65 | if ($data['code'] !== '10000') {
66 | return [
67 | 'is_success' => 'F',
68 | 'error' => $data['sub_msg'],
69 | 'channel' => Config::ALI_CHARGE,
70 | ];
71 | }
72 |
73 | // 正确情况
74 | $retData = [
75 | 'is_success' => 'T',
76 | 'response' => [
77 | 'channel' => Config::ALI_CHARGE,
78 | 'transaction_id' => $data['trade_no'],// 支付宝交易号
79 | 'order_no' => $data['out_trade_no'],// 商家订单号
80 | 'logon_id' => $data['buyer_logon_id'],// 买家支付宝账号
81 | 'trade_state' => $this->getTradeStatus($data['trade_status']),
82 | 'amount' => $data['total_amount'],
83 | 'receipt_amount' => $data['receipt_amount'],// 实收金额,单位为元,两位小数。
84 |
85 | 'pay_amount' => ArrayUtil::get($data, 'buyer_pay_amount'),// 买家实付金额,单位为元
86 | 'point_amount' => ArrayUtil::get($data, 'point_amount'),// 使用集分宝支付的金额
87 | 'invoice_amount' => ArrayUtil::get($data, 'invoice_amount'),// 交易中用户支付的可开具发票的金额,单位为元,两位小数
88 | 'time_end' => ArrayUtil::get($data, 'send_pay_date'),// 本次交易打款给卖家的时间
89 | 'store_id' => ArrayUtil::get($data, 'store_id'),
90 | 'terminal_id' => ArrayUtil::get($data, 'terminal_id'),
91 | 'store_name' => ArrayUtil::get($data, 'store_name'),
92 | 'buyer_id' => ArrayUtil::get($data, 'buyer_user_id'),
93 | 'fund_bill_list' => ArrayUtil::get($data, 'fund_bill_list', []),// 支付成功的各个渠道金额信息
94 | ],
95 | ];
96 |
97 | return $retData;
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/examples/aliconfig.php:
--------------------------------------------------------------------------------
1 | true,// 是否使用沙盒模式
25 |
26 | 'app_id' => '2016073100130857',
27 | 'sign_type' => 'RSA2',// RSA RSA2
28 |
29 | // 可以填写文件路径,或者密钥字符串 当前字符串是 rsa2 的支付宝公钥(开放平台获取)
30 | 'ali_public_key' => 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmBjJu2eA5HVSeHb7jZsuKKbPp3w0sKEsLTVvBKQOtyb7bjQRWMWBI7FrcwEekM1nIL+rDv71uFtgv7apMMJdQQyF7g6Lnn9niG8bT1ttB8Fp0eud5L97eRjFTOa9NhxUVFjGDqQ3b88o6u20HNJ3PRckZhNaFJJQzlahCpxaiIRX2umAWFkaeQu1fcjmoS3l3BLj8Ly2zRZAnczv8Jnkp7qsVYeYt01EPsAxd6dRZRw3uqsv9pxSvyEYA7GV7XL6da+JdvXECalQeyvUFzn9u1K5ivGID7LPUakdTBUDzlYIhbpU1VS8xO1BU3GYXkAaumdWQt7f+khoFoSw+x8yqQIDAQAB',
31 |
32 | // 可以填写文件路径,或者密钥字符串 我的沙箱模式,rsa与rsa2的私钥相同,为了方便测试
33 | 'rsa_private_key' => 'MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC/z+Ue/oS0GjO2
34 | myYrkdopw5qq6Ih/xlHBx0HBE0xA2dRinpMuZeI0LUUtN54UAUZbDz8rcaOCb0je
35 | loeYolw54tadcIw4Q2hbdeJPplldJZyi1BDYtBJZvAveeRSidHdmBSUtOtCBXUBl
36 | JUP3I8/R4c34Ii4Pm/K4vmhwLf/zqZAedKGhYP6m5q+p8sfBHRPy97/KluLPiSTR
37 | FqGSRmd0IitUGK+KQ5qsAfJXyN1oVR4jBYaxfx7dWkTWmxAfNqtKfMvu2a5lH6hv
38 | ClN+w4RUDBu3939bLjCYKcAomkv3QMquMP46m+D8Ny+3mGk5L9Ul4jyxlFTlV4L4
39 | JM3g/02xAgMBAAECggEBALZliwseHDLnd6V9g56K41ozlzBOTv6yJ6yNPgnLwAcr
40 | HLtq76p/V8smAVIuQTPkwnJ03S0CsumlyTVhDzAltG2XN14fWDdoYiQWxU3YccIR
41 | shFkd2CaW5jZKLA1k1moRqHM4r1P4FYjxshn12l7tHNwtdvvJL3THcxvxABovauF
42 | OVtznpRlnfJLjn2Lg+xNsxaYy3zL8L6nL7MXUWLKvmLiZn64PFcw7cf+9n2exRDs
43 | wn0wDCpypGqOVVXVFeZaXTwmOoxgIUAZfAExdLtabGGCAz1lTsA0+r4DW2nSTe8C
44 | Fy1Db+fcCTm+uQ3y6jDwuS3tB8V+PQKog3+ReZp/9sECgYEA/NEr+ln6DTy7u4rC
45 | Wq7mixRJ1kaiAUph/hADrUwhkMiUapSMNAIXblFB+BQUjFZQmXEbcvz0Y70g9Zi9
46 | JCXVTiDTBe7jj/FK63MU0F9KY5OducpVV+RhSpNy/i1M2qeW4gO351PpPHUpRUYr
47 | GkYvAKktqrSOdBEWD3IeKLYDXxMCgYEAwjoavGjWzD9Xckbpb8yrQ+gHfLeWDKh7
48 | BgvoBGagyqbzIOZU9wg3dSQ2F5eMWDxWVRGqap3fIHxcA0/VMqXG1DrvSIUC4SE8
49 | Zys515fR00c9h3W3IugHnKgdYcV7nZrJoPZXlMjPOo39FCBnfbrUOgnKwxMlz3lV
50 | vC6465ODhKsCgYEAmUtTuTd5kTE0O+FFO6s1iztAEjc94D5z8JNRR3EUITAeHgn4
51 | gUiLYI7Qy1WRqA5mTMPyeuS6Ywe4xnJYrWRrVDY+/if9v7f1T5K2GirNdld5mb//
52 | w41tGMUTQt/A7AwWRvEuP4v3rnr0DVcgp4vK0EHEuO9GOUZq8+6kLtc+cBUCgYBF
53 | J/kzEsVAjmEtkHA33ZExqaFY1+l2clrziTPAtWYVIiK5mSmxl9xfOliER/KxzDIV
54 | MigStEmpQH5ms3s/AGXuVVmz4aBn1rSyK2L6D9WnO9t9qv1dUW68aeOkV3OvZ1jZ
55 | lj0S/flDaSEulGclDmvYinoGwX+aAyLy0VQIlUqj5wKBgHEUEf7YDnvw/IBnF1E4
56 | 983/7zBx9skoHhpEZsh2+1or7LIw6z0m3lsNBnK0MZZBmW/7HwOtVfhXUUPbVrOJ
57 | di70YoMynX3gjK3LTXhzISheZgcNRKTqiJgVunPokJxQRyYcAfaQeuIm9O8cCPE1
58 | rZpNAzCdd4NSj83UZRm3YOmC',
59 |
60 | 'limit_pay' => [
61 | //'balance',// 余额
62 | //'moneyFund',// 余额宝
63 | //'debitCardExpress',// 借记卡快捷
64 | //'creditCard',//信用卡
65 | //'creditCardExpress',// 信用卡快捷
66 | //'creditCardCartoon',//信用卡卡通
67 | //'credit_group',// 信用支付类型(包含信用卡卡通、信用卡快捷、花呗、花呗分期)
68 | ],// 用户不可用指定渠道支付当有多个渠道时用“,”分隔
69 |
70 | // 与业务相关参数
71 | 'notify_url' => 'https://helei112g.github.io/v1/notify/ali',
72 | 'return_url' => 'https://helei112g.github.io/',
73 |
74 | 'return_raw' => false,// 在处理回调时,是否直接返回原始数据,默认为 true
75 | ];
76 |
--------------------------------------------------------------------------------
/src/Utils/ArrayUtil.php:
--------------------------------------------------------------------------------
1 |