GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

Pay::notify()   C
last analyzed

Complexity

Conditions 13
Paths 15

Size

Total Lines 32
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 13
eloc 19
nc 15
nop 1
dl 0
loc 32
rs 6.6166
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Class Pay
4
 *
5
 * @link https://www.icy2003.com/
6
 * @author icy2003 <[email protected]>
7
 * @copyright Copyright (c) 2017, icy2003
8
 */
9
namespace icy2003\php\iapis\alipay;
10
11
use Exception;
12
use icy2003\php\I;
13
use icy2003\php\iapis\Api;
14
use icy2003\php\ihelpers\Base64;
15
use icy2003\php\ihelpers\Charset;
16
use icy2003\php\ihelpers\Crypto;
17
use icy2003\php\ihelpers\Json;
18
use icy2003\php\ihelpers\Request;
19
use icy2003\php\ihelpers\Strings;
20
21
/**
22
 * 支付宝支付
23
 *
24
 * - 参看[支付宝支付开发文档](https://docs.open.alipay.com/)
25
 */
26
class Pay extends Api
27
{
28
    use PaySetterTrait;
29
30
    /**
31
     * 初始化
32
     *
33
     * @param string $appId 支付宝分配给开发者的应用ID
34
     * @param string $rsaPrivateKey 商户私钥
35
     */
36
    public function __construct($appId, $rsaPrivateKey)
37
    {
38
        $this->_appId = $appId;
39
        if (null === $this->_appId) {
40
            throw new Exception("缺少应用 ID");
41
        }
42
        $this->_rsaPrivateKey = $rsaPrivateKey;
43
        if (null === $this->_rsaPrivateKey) {
44
            throw new Exception("缺少商户私钥");
45
        }
46
    }
47
48
    /**
49
     * 支付类型:APP
50
     */
51
    const TRADE_TYPE_APP = 'APP';
52
53
    /**
54
     * 支付接口
55
     *
56
     * - APP支付:返回的字符串需给客户端拉起支付宝
57
     *
58
     * @return static
59
     */
60
    public function pay()
61
    {
62
        if (null === $this->_tradeType) {
63
            throw new Exception('请使用 setTradeType 定义支付类型');
64
        }
65
        // APP 支付
66
        if (self::TRADE_TYPE_APP === $this->_tradeType) {
67
            if (null === I::get($this->_options, 'biz_content.total_amount')) {
68
                throw new Exception('请使用 setBizContentTotalAmount 设置 biz_content.total_amount');
69
            }
70
            if (null === I::get($this->_options, 'biz_content.subject')) {
71
                throw new Exception('请使用 setBizContentSubject 设置:biz_content.subject');
72
            }
73
            if (null === I::get($this->_options, 'biz_content.out_trade_no')) {
74
                throw new Exception('请使用 setBizContentOutTradeNo 设置:biz_content.out_trade_no');
75
            }
76
            $values = array_filter([
77
                'app_id' => $this->_appId,
78
                'method' => 'alipay.trade.app.pay',
79
                'format' => I::get($this->_options, 'format'),
80
                'return_url' => I::get($this->_options, 'return_url'),
81
                'charset' => I::get($this->_options, 'charset', 'utf-8'),
82
                'sign_type' => I::get($this->_options, 'sign_type', 'RSA2'),
83
                'timestamp' => I::get($this->_options, 'timestamp', date('Y-m-d H:i:s')),
84
                'version' => '1.0',
85
                'notify_url' => I::get($this->_options, 'notify_url'),
86
                'app_auth_token' => I::get($this->_options, 'app_auth_token'),
87
                'biz_content' => Json::encode(I::get($this->_options, 'biz_content', [])),
88
            ]);
89
            $values['sign'] = $this->getSign($values);
90
            $this->_result = http_build_query($values);
0 ignored issues
show
Documentation Bug introduced by
It seems like http_build_query($values) of type string is incompatible with the declared type array of property $_result.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
91
        }
92
93
        return $this;
94
    }
95
96
    /**
97
     * 生成签名
98
     *
99
     * @param array $params 签名参数
100
     *
101
     * @return string
102
     */
103
    public function getSign($params)
104
    {
105
        ksort($params);
106
        // 不得不吐槽,支付宝这部分代码写的比微信的烂
107
        $array = [];
108
        $params = array_filter($params);
109
        foreach ($params as $key => $value) {
110
            if ('sign' !== $key && false === Strings::isStartsWith($value, '@')) {
111
                $array[] = $key . '=' . Charset::convertTo($value, (string)I::get($this->_options, 'charset', 'utf-8'));
112
            }
113
        }
114
        $string = implode('&', $array);
115
        $crypto = new Crypto();
116
        $crypto->setPair([null, $this->_rsaPrivateKey]);
117
        $signType = I::get($this->_options, 'sign_type', 'RSA2');
118
        if ('RSA' === $signType) {
119
            $sign = $crypto->getSignature($string, OPENSSL_ALGO_SHA1);
120
        } elseif ('RSA2' === $signType) {
121
            $sign = $crypto->getSignature($string, OPENSSL_ALGO_SHA256);
122
        } else {
123
            throw new Exception("不支持的签名类型");
124
        }
125
        $sign = Base64::encode($sign);
126
        return $sign;
127
    }
128
129
    /**
130
     * 支付结果通知以及退款结果通知的数据处理
131
     *
132
     * 请参考[交易状态问题解析](https://openclub.alipay.com/club/history/read/5407)
133
     *
134
     * @return array
135
     */
136
    public function getNotifyArray()
137
    {
138
        return (new Request())->post();
139
    }
140
141
    /**
142
     * 返回通知成功时发送给支付宝的字符串
143
     *
144
     * @return string
145
     */
146
    public function getNotifyReturn()
147
    {
148
        return 'success';
149
    }
150
151
    /**
152
     * self::getNotifyArray 和 self::getNotifyReturn 的结合:通知为交易成功时,$callback 为 true,则输出成功给微信
153
     *
154
     * - 回调参数:
155
     *      1. 通知数组:$array 支付宝返回的原始数据
156
     *      2. 是否支付成功:$isPay
157
     *      3. 是否退款成功:$isRefund
158
     *      4. 是否全额退款:$isRefundFull 退款金额(refund_fee)永远和总金额(total_amount)对比,不考虑优惠,如需计算优惠,请直接使用 $array 原始数据自行计算
159
     * - 回调函数返回 true 时才会输出成功给支付宝
160
     *
161
     * @param callback $callback 回调函数
162
     *
163
     * @return void
164
     * @info 此函数之后不得有任何输出
165
     */
166
    public function notify($callback = null)
167
    {
168
        $array = $this->getNotifyArray();
169
        if (!empty($array)) {
170
            $isPay = $isRefund = $isRefundFull = null;
171
            $tradeStatus = I::get($array, 'trade_status');
172
            $refundFee = I::get($array, 'refund_fee');
173
            $totalAmount = I::get($array, 'total_amount');
174
            if ($refundFee > 0) {
175
                $isRefund = true;
176
                if ('TRADE_CLOSED' === $tradeStatus && $refundFee === $totalAmount) {
177
                    // 3、交易成功后,交易全额退款交易状态转为TRADE_CLOSED(交易关闭)
178
                    // 7、如果一直部分退款退完所有交易金额则交易状态转为TRADE_CLOSED(交易关闭)
179
                    $isRefundFull = true;
180
                } elseif ('TRADE_SUCCESS' === $tradeStatus && $refundFee < $totalAmount) {
181
                    // 6、交易成功后部分退款,交易状态仍为TRADE_SUCCESS(交易成功)
182
                    $isRefundFull = false;
183
                }
184
            } elseif ($totalAmount > 0) {
185
                if ('TRADE_CLOSED' === $tradeStatus) {
186
                    // 2、交易创建成功后,用户未付款交易超时关闭交易状态转为TRADE_CLOSED(交易关闭)
187
                    $isPay = false;
188
                } elseif ('TRADE_SUCCESS' === $tradeStatus || 'TRADE_FINISHED' === $tradeStatus) {
189
                    // 1、交易创建成功后,用户支付成功,交易状态转为TRADE_SUCCESS(交易成功)
190
                    // 4、交易创建成功后,用户支付成功后,若用户商品不支持退款,交易状态直接转为TRADE_FINISHED(交易完成)
191
                    // 5、交易成功后,默认退款时间三个月内没有退款,交易状态转为TRADE_FINISHED(交易完成)不可退款
192
                    // 8、如果未退完所有交易金额,三个月后交易状态转为TRADE_FINISHED(交易完成)不可退款
193
                    $isPay = true;
194
                }
195
            }
196
            if (null === $callback || true === I::call($callback, [$array, $isPay, $isRefund, $isRefundFull])) {
197
                echo $this->getNotifyReturn();
198
            }
199
        }
200
    }
201
202
}
203