Completed
Push — master ( 2fad31...6b685a )
by Songda
01:59
created

src/Gateways/Alipay.php (2 issues)

Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace Yansongda\Pay\Gateways;
4
5
use Symfony\Component\HttpFoundation\Request;
6
use Symfony\Component\HttpFoundation\Response;
7
use Yansongda\Pay\Contracts\GatewayApplicationInterface;
8
use Yansongda\Pay\Contracts\GatewayInterface;
9
use Yansongda\Pay\Events;
10
use Yansongda\Pay\Exceptions\GatewayException;
11
use Yansongda\Pay\Exceptions\InvalidGatewayException;
12
use Yansongda\Pay\Exceptions\InvalidSignException;
13
use Yansongda\Pay\Gateways\Alipay\Support;
14
use Yansongda\Pay\Log;
15
use Yansongda\Supports\Collection;
16
use Yansongda\Supports\Config;
17
use Yansongda\Supports\Str;
18
19
/**
20
 * @method Response app(array $config) APP 支付
21
 * @method Collection pos(array $config) 刷卡支付
22
 * @method Collection scan(array $config) 扫码支付
23
 * @method Collection transfer(array $config) 帐户转账
24
 * @method Response wap(array $config) 手机网站支付
25
 * @method Response web(array $config) 电脑支付
26
 * @method Collection mini(array $config) 小程序支付
27
 */
28
class Alipay implements GatewayApplicationInterface
29
{
30
    /**
31
     * Const mode_normal.
32
     */
33
    const MODE_NORMAL = 'normal';
34
35
    /**
36
     * Const mode_dev.
37
     */
38
    const MODE_DEV = 'dev';
39
40
    /**
41
     * Const url.
42
     */
43
    const URL = [
44
        self::MODE_NORMAL => 'https://openapi.alipay.com/gateway.do',
45
        self::MODE_DEV    => 'https://openapi.alipaydev.com/gateway.do',
46
    ];
47
48
    /**
49
     * Alipay payload.
50
     *
51
     * @var array
52
     */
53
    protected $payload;
54
55
    /**
56
     * Alipay gateway.
57
     *
58
     * @var string
59
     */
60
    protected $gateway;
61
62
    /**
63
     * Bootstrap.
64
     *
65
     * @author yansongda <[email protected]>
66
     *
67
     * @param Config $config
68
     */
69
    public function __construct(Config $config)
70
    {
71
        $this->gateway = Support::create($config)->getBaseUri();
72
        $this->payload = [
73
            'app_id'         => $config->get('app_id'),
74
            'method'         => '',
75
            'format'         => 'JSON',
76
            'charset'        => 'utf-8',
77
            'sign_type'      => 'RSA2',
78
            'version'        => '1.0',
79
            'return_url'     => $config->get('return_url'),
80
            'notify_url'     => $config->get('notify_url'),
81
            'timestamp'      => date('Y-m-d H:i:s'),
82
            'sign'           => '',
83
            'biz_content'    => '',
84
            'app_auth_token' => $config->get('app_auth_token'),
85
        ];
86
    }
87
88
    /**
89
     * Magic pay.
90
     *
91
     * @author yansongda <[email protected]>
92
     *
93
     * @param string $method
94
     * @param array  $params
95
     *
96
     * @throws InvalidGatewayException
97
     *
98
     * @return Response|Collection
99
     */
100
    public function __call($method, $params)
101
    {
102
        return $this->pay($method, ...$params);
103
    }
104
105
    /**
106
     * Pay an order.
107
     *
108
     * @author yansongda <[email protected]>
109
     *
110
     * @param string $gateway
111
     * @param array  $params
112
     *
113
     * @throws InvalidGatewayException
114
     *
115
     * @return Response|Collection
116
     */
117
    public function pay($gateway, $params = [])
118
    {
119
        Events::dispatch(Events::PAY_STARTING, new Events\PayStarting('Alipay', $gateway, $params));
120
121
        $this->payload['return_url'] = $params['return_url'] ?? $this->payload['return_url'];
122
        $this->payload['notify_url'] = $params['notify_url'] ?? $this->payload['notify_url'];
123
124
        unset($params['return_url'], $params['notify_url']);
125
126
        $this->payload['biz_content'] = json_encode($params);
127
128
        $gateway = get_class($this).'\\'.Str::studly($gateway).'Gateway';
129
130
        if (class_exists($gateway)) {
131
            return $this->makePay($gateway);
132
        }
133
134
        throw new InvalidGatewayException("Pay Gateway [{$gateway}] not exists");
135
    }
136
137
    /**
138
     * Verify sign.
139
     *
140
     * @author yansongda <[email protected]>
141
     *
142
     * @param null|array $data
143
     * @param bool       $refund
144
     *
145
     * @throws InvalidSignException
146
     * @throws \Yansongda\Pay\Exceptions\InvalidConfigException
147
     *
148
     * @return Collection
149
     */
150
    public function verify($data = null, $refund = false): Collection
151
    {
152
        if (is_null($data)) {
153
            $request = Request::createFromGlobals();
154
155
            $data = $request->request->count() > 0 ? $request->request->all() : $request->query->all();
156
            $data = Support::encoding($data, 'utf-8', $data['charset'] ?? 'gb2312');
157
        }
158
159
        if (isset($data['fund_bill_list'])) {
160
            $data['fund_bill_list'] = htmlspecialchars_decode($data['fund_bill_list']);
161
        }
162
163
        Events::dispatch(Events::REQUEST_RECEIVED, new Events\RequestReceived('Alipay', '', $data));
164
165
        if (Support::verifySign($data)) {
166
            return new Collection($data);
167
        }
168
169
        Events::dispatch(Events::SIGN_FAILED, new Events\SignFailed('Alipay', '', $data));
170
171
        throw new InvalidSignException('Alipay Sign Verify FAILED', $data);
172
    }
173
174
    /**
175
     * Query an order.
176
     *
177
     * @author yansongda <[email protected]>
178
     *
179
     * @param string|array $order
180
     * @param string       $type
181
     * @param bool         $transfer @deprecated since v2.7.3
182
     *
183
     * @throws InvalidSignException
184
     * @throws \Yansongda\Pay\Exceptions\GatewayException
185
     * @throws \Yansongda\Pay\Exceptions\InvalidConfigException
186
     *
187
     * @return Collection
188
     */
189
    public function find($order, $type = 'wap', $transfer = false): Collection
190
    {
191
        if ($type === true || $transfer) {
192
            Log::warning('DEPRECATED: In Alipay->find(), the REFUND/TRANSFER param is deprecated since v2.7.3, use TYPE param instead!');
193
            @trigger_error('In yansongda/pay Alipay->find(), the REFUND/TRANSFER param is deprecated since v2.7.3, use TYPE param instead!', E_USER_DEPRECATED);
194
195
            $type = $type === true ? 'refund' : 'transfer';
196
        }
197
198
        $gateway = get_class($this).'\\'.Str::studly($type).'Gateway';
199
200
        if (!class_exists($gateway) || !is_callable([$gateway, 'find'])) {
201
            throw new GatewayException("{$gateway} Done Not Exist Or Done Not Has FIND Method");
202
        }
203
204
        $config = call_user_func([$gateway, 'find'], $order);
205
206
        $this->payload['method'] = $config['method'];
207
        $this->payload['biz_content'] = $config['biz_content'];
208
        $this->payload['sign'] = Support::generateSign($this->payload);
209
210
        Events::dispatch(Events::METHOD_CALLED, new Events\MethodCalled('Alipay', 'Find', $this->gateway, $this->payload));
211
212
        return Support::requestApi($this->payload);
213
    }
214
215
    /**
216
     * Refund an order.
217
     *
218
     * @author yansongda <[email protected]>
219
     *
220
     * @param array $order
221
     *
222
     * @throws InvalidSignException
223
     * @throws \Yansongda\Pay\Exceptions\GatewayException
224
     * @throws \Yansongda\Pay\Exceptions\InvalidConfigException
225
     *
226
     * @return Collection
227
     */
228
    public function refund($order): Collection
229
    {
230
        $this->payload['method'] = 'alipay.trade.refund';
231
        $this->payload['biz_content'] = json_encode($order);
232
        $this->payload['sign'] = Support::generateSign($this->payload);
233
234
        Events::dispatch(Events::METHOD_CALLED, new Events\MethodCalled('Alipay', 'Refund', $this->gateway, $this->payload));
235
236
        return Support::requestApi($this->payload);
237
    }
238
239
    /**
240
     * Cancel an order.
241
     *
242
     * @author yansongda <[email protected]>
243
     *
244
     * @param string|array $order
245
     *
246
     * @throws InvalidSignException
247
     * @throws \Yansongda\Pay\Exceptions\GatewayException
248
     * @throws \Yansongda\Pay\Exceptions\InvalidConfigException
249
     *
250
     * @return Collection
251
     */
252 View Code Duplication
    public function cancel($order): Collection
253
    {
254
        $this->payload['method'] = 'alipay.trade.cancel';
255
        $this->payload['biz_content'] = json_encode(is_array($order) ? $order : ['out_trade_no' => $order]);
256
        $this->payload['sign'] = Support::generateSign($this->payload);
257
258
        Events::dispatch(Events::METHOD_CALLED, new Events\MethodCalled('Alipay', 'Cancel', $this->gateway, $this->payload));
259
260
        return Support::requestApi($this->payload);
261
    }
262
263
    /**
264
     * Close an order.
265
     *
266
     * @author yansongda <[email protected]>
267
     *
268
     * @param string|array $order
269
     *
270
     * @throws InvalidSignException
271
     * @throws \Yansongda\Pay\Exceptions\GatewayException
272
     * @throws \Yansongda\Pay\Exceptions\InvalidConfigException
273
     *
274
     * @return Collection
275
     */
276 View Code Duplication
    public function close($order): Collection
277
    {
278
        $this->payload['method'] = 'alipay.trade.close';
279
        $this->payload['biz_content'] = json_encode(is_array($order) ? $order : ['out_trade_no' => $order]);
280
        $this->payload['sign'] = Support::generateSign($this->payload);
281
282
        Events::dispatch(Events::METHOD_CALLED, new Events\MethodCalled('Alipay', 'Close', $this->gateway, $this->payload));
283
284
        return Support::requestApi($this->payload);
285
    }
286
287
    /**
288
     * Download bill.
289
     *
290
     * @author yansongda <[email protected]>
291
     *
292
     * @param string|array $bill
293
     *
294
     * @throws InvalidSignException
295
     * @throws \Yansongda\Pay\Exceptions\GatewayException
296
     * @throws \Yansongda\Pay\Exceptions\InvalidConfigException
297
     *
298
     * @return string
299
     */
300
    public function download($bill): string
301
    {
302
        $this->payload['method'] = 'alipay.data.dataservice.bill.downloadurl.query';
303
        $this->payload['biz_content'] = json_encode(is_array($bill) ? $bill : ['bill_type' => 'trade', 'bill_date' => $bill]);
304
        $this->payload['sign'] = Support::generateSign($this->payload);
305
306
        Events::dispatch(Events::METHOD_CALLED, new Events\MethodCalled('Alipay', 'Download', $this->gateway, $this->payload));
307
308
        $result = Support::requestApi($this->payload);
309
310
        return ($result instanceof Collection) ? $result->get('bill_download_url') : '';
311
    }
312
313
    /**
314
     * Reply success to alipay.
315
     *
316
     * @author yansongda <[email protected]>
317
     *
318
     * @return Response
319
     */
320
    public function success(): Response
321
    {
322
        Events::dispatch(Events::METHOD_CALLED, new Events\MethodCalled('Alipay', 'Success', $this->gateway));
323
324
        return Response::create('success');
325
    }
326
327
    /**
328
     * extend.
329
     *
330
     * @author yansongda <[email protected]>
331
     *
332
     * @param string   $method
333
     * @param callable $function
334
     *
335
     * @return void
336
     */
337
    public function extend(string $method, callable $function)
0 ignored issues
show
The parameter $method is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
The parameter $function is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
338
    {
339
    }
340
341
    /**
342
     * Make pay gateway.
343
     *
344
     * @author yansongda <[email protected]>
345
     *
346
     * @param string $gateway
347
     *
348
     * @throws InvalidGatewayException
349
     *
350
     * @return Response|Collection
351
     */
352 View Code Duplication
    protected function makePay($gateway)
353
    {
354
        $app = new $gateway();
355
356
        if ($app instanceof GatewayInterface) {
357
            return $app->pay($this->gateway, array_filter($this->payload, function ($value) {
358
                return $value !== '' && !is_null($value);
359
            }));
360
        }
361
362
        throw new InvalidGatewayException("Pay Gateway [{$gateway}] Must Be An Instance Of GatewayInterface");
363
    }
364
}
365