Completed
Push — master ( c3ded3...e46555 )
by Songda
13s
created

src/Gateways/Alipay.php (3 issues)

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\Exceptions\InvalidGatewayException;
10
use Yansongda\Pay\Exceptions\InvalidSignException;
11
use Yansongda\Pay\Gateways\Alipay\Support;
12
use Yansongda\Pay\Log;
13
use Yansongda\Supports\Collection;
14
use Yansongda\Supports\Config;
15
use Yansongda\Supports\Str;
16
17
/**
18
 * @method Response app(array $config) APP 支付
19
 * @method Collection pos(array $config) 刷卡支付
20
 * @method Collection scan(array $config) 扫码支付
21
 * @method Collection transfer(array $config) 帐户转账
22
 * @method Response wap(array $config) 手机网站支付
23
 * @method Response web(array $config) 电脑支付
24
 */
25
class Alipay implements GatewayApplicationInterface
26
{
27
    /**
28
     * Const mode_normal.
29
     */
30
    const MODE_NORMAL = 'normal';
31
32
    /**
33
     * Const mode_dev.
34
     */
35
    const MODE_DEV = 'dev';
36
37
    /**
38
     * Const url.
39
     */
40
    const URL = [
41
        self::MODE_NORMAL => 'https://openapi.alipay.com/gateway.do',
42
        self::MODE_DEV    => 'https://openapi.alipaydev.com/gateway.do',
43
    ];
44
45
    /**
46
     * Alipay payload.
47
     *
48
     * @var array
49
     */
50
    protected $payload;
51
52
    /**
53
     * Alipay gateway.
54
     *
55
     * @var string
56
     */
57
    protected $gateway;
58
59
    /**
60
     * Bootstrap.
61
     *
62
     * @author yansongda <[email protected]>
63
     *
64
     * @param Config $config
65
     *
66
     * @throws \Yansongda\Pay\Exceptions\InvalidArgumentException
67
     */
68
    public function __construct(Config $config)
69
    {
70
        $this->gateway = Support::getInstance($config)->getBaseUri();
71
        $this->payload = [
72
            'app_id'      => $config->get('app_id'),
73
            'method'      => '',
74
            'format'      => 'JSON',
75
            'charset'     => 'utf-8',
76
            'sign_type'   => 'RSA2',
77
            'version'     => '1.0',
78
            'return_url'  => $config->get('return_url'),
79
            'notify_url'  => $config->get('notify_url'),
80
            'timestamp'   => date('Y-m-d H:i:s'),
81
            'sign'        => '',
82
            'biz_content' => '',
83
        ];
84
    }
85
86
    /**
87
     * Magic pay.
88
     *
89
     * @author yansongda <[email protected]>
90
     *
91
     * @param string $method
92
     * @param array  $params
93
     *
94
     * @throws InvalidGatewayException
95
     *
96
     * @return Response|Collection
97
     */
98
    public function __call($method, $params)
99
    {
100
        return $this->pay($method, ...$params);
101
    }
102
103
    /**
104
     * Pay an order.
105
     *
106
     * @author yansongda <[email protected]>
107
     *
108
     * @param string $gateway
109
     * @param array  $params
110
     *
111
     * @throws InvalidGatewayException
112
     *
113
     * @return Response|Collection
114
     */
115
    public function pay($gateway, $params = [])
116
    {
117
        Log::debug('Starting To Alipay', [$gateway, $params]);
118
119
        $this->payload['return_url'] = $params['return_url'] ?? $this->payload['return_url'];
120
        $this->payload['notify_url'] = $params['notify_url'] ?? $this->payload['notify_url'];
121
122
        unset($params['return_url'], $params['notify_url']);
123
124
        $this->payload['biz_content'] = json_encode($params);
125
126
        $gateway = get_class($this).'\\'.Str::studly($gateway).'Gateway';
127
128
        if (class_exists($gateway)) {
129
            return $this->makePay($gateway);
130
        }
131
132
        throw new InvalidGatewayException("Pay Gateway [{$gateway}] not exists");
133
    }
134
135
    /**
136
     * Verify sign.
137
     *
138
     * @author yansongda <[email protected]>
139
     *
140
     * @param null|array $data
141
     * @param bool       $refund
142
     *
143
     * @throws InvalidSignException
144
     * @throws \Yansongda\Pay\Exceptions\InvalidArgumentException
145
     * @throws \Yansongda\Pay\Exceptions\InvalidConfigException
146
     *
147
     * @return Collection
148
     */
149
    public function verify($data = null, $refund = false): Collection
150
    {
151
        if (is_null($data)) {
152
            $request = Request::createFromGlobals();
153
154
            $data = $request->request->count() > 0 ? $request->request->all() : $request->query->all();
155
            $data = Support::encoding($data, 'utf-8', $data['charset'] ?? 'gb2312');
156
        }
157
158
        Log::info('Received Alipay Request', $data);
159
160
        if (Support::verifySign($data)) {
161
            return new Collection($data);
162
        }
163
164
        Log::warning('Alipay Sign Verify FAILED', $data);
165
166
        throw new InvalidSignException('Alipay Sign Verify FAILED', $data);
167
    }
168
169
    /**
170
     * Query an order.
171
     *
172
     * @author yansongda <[email protected]>
173
     *
174
     * @param string|array $order
175
     * @param bool         $refund
176
     * @param bool         $transfer
177
     *
178
     * @throws InvalidSignException
179
     * @throws \Yansongda\Pay\Exceptions\GatewayException
180
     * @throws \Yansongda\Pay\Exceptions\InvalidConfigException
181
     * @throws \Yansongda\Pay\Exceptions\InvalidArgumentException
182
     *
183
     * @return Collection
184
     */
185
    public function find($order, $refund = false, $transfer = false): Collection
186
    {
187
        $method = 'alipay.trade.query';
188
        $requestOrder = is_array($order) ? $order : ['out_trade_no' => $order];
189
        if ($refund) {
190
            $method = 'alipay.trade.fastpay.refund.query';
191
        }
192
        if ($transfer) {
193
            $requestOrder = is_array($order) ? $order : ['out_biz_no' => $order];
194
            $method = 'alipay.fund.trans.order.query';
195
        }
196
        $this->payload['method'] = $method;
197
        $this->payload['biz_content'] = json_encode($requestOrder);
198
        $this->payload['sign'] = Support::generateSign($this->payload);
199
200
        Log::info('Starting To Find An Alipay Order', [$this->gateway, $this->payload]);
201
202
        return Support::requestApi($this->payload);
203
    }
204
205
    /**
206
     * Refund an order.
207
     *
208
     * @author yansongda <[email protected]>
209
     *
210
     * @param array $order
211
     *
212
     * @throws InvalidSignException
213
     * @throws \Yansongda\Pay\Exceptions\GatewayException
214
     * @throws \Yansongda\Pay\Exceptions\InvalidConfigException
215
     * @throws \Yansongda\Pay\Exceptions\InvalidArgumentException
216
     *
217
     * @return Collection
218
     */
219
    public function refund($order): Collection
220
    {
221
        $this->payload['method'] = 'alipay.trade.refund';
222
        $this->payload['biz_content'] = json_encode($order);
223
        $this->payload['sign'] = Support::generateSign($this->payload);
224
225
        Log::info('Starting To Refund An Alipay Order', [$this->gateway, $this->payload]);
226
227
        return Support::requestApi($this->payload);
228
    }
229
230
    /**
231
     * Cancel an order.
232
     *
233
     * @author yansongda <[email protected]>
234
     *
235
     * @param string|array $order
236
     *
237
     * @throws InvalidSignException
238
     * @throws \Yansongda\Pay\Exceptions\GatewayException
239
     * @throws \Yansongda\Pay\Exceptions\InvalidConfigException
240
     * @throws \Yansongda\Pay\Exceptions\InvalidArgumentException
241
     *
242
     * @return Collection
243
     */
244 View Code Duplication
    public function cancel($order): Collection
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
245
    {
246
        $this->payload['method'] = 'alipay.trade.cancel';
247
        $this->payload['biz_content'] = json_encode(is_array($order) ? $order : ['out_trade_no' => $order]);
248
        $this->payload['sign'] = Support::generateSign($this->payload);
249
250
        Log::info('Starting To Cancel An Alipay Order', [$this->gateway, $this->payload]);
251
252
        return Support::requestApi($this->payload);
253
    }
254
255
    /**
256
     * Close an order.
257
     *
258
     * @author yansongda <[email protected]>
259
     *
260
     * @param string|array $order
261
     *
262
     * @throws InvalidSignException
263
     * @throws \Yansongda\Pay\Exceptions\GatewayException
264
     * @throws \Yansongda\Pay\Exceptions\InvalidArgumentException
265
     * @throws \Yansongda\Pay\Exceptions\InvalidConfigException
266
     *
267
     * @return Collection
268
     */
269 View Code Duplication
    public function close($order): Collection
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
270
    {
271
        $this->payload['method'] = 'alipay.trade.close';
272
        $this->payload['biz_content'] = json_encode(is_array($order) ? $order : ['out_trade_no' => $order]);
273
        $this->payload['sign'] = Support::generateSign($this->payload);
274
275
        Log::info('Starting To Close An Alipay Order', [$this->gateway, $this->payload]);
276
277
        return Support::requestApi($this->payload);
278
    }
279
280
    /**
281
     * Download bill.
282
     *
283
     * @author yansongda <[email protected]>
284
     *
285
     * @param string|array $bill
286
     *
287
     * @throws InvalidSignException
288
     * @throws \Yansongda\Pay\Exceptions\GatewayException
289
     * @throws \Yansongda\Pay\Exceptions\InvalidArgumentException
290
     * @throws \Yansongda\Pay\Exceptions\InvalidConfigException
291
     *
292
     * @return string
293
     */
294
    public function download($bill): string
295
    {
296
        $this->payload['method'] = 'alipay.data.dataservice.bill.downloadurl.query';
297
        $this->payload['biz_content'] = json_encode(is_array($bill) ? $bill : ['bill_type' => 'trade', 'bill_date' => $bill]);
298
        $this->payload['sign'] = Support::generateSign($this->payload);
299
300
        Log::info('Starting To Download The Alipay Bill', [$this->gateway, $this->payload]);
301
302
        $result = Support::requestApi($this->payload);
303
304
        return ($result instanceof Collection) ? $result->bill_download_url : '';
305
    }
306
307
    /**
308
     * Reply success to alipay.
309
     *
310
     * @author yansongda <[email protected]>
311
     *
312
     * @return Response
313
     */
314
    public function success(): Response
315
    {
316
        return Response::create('success');
317
    }
318
319
    /**
320
     * Make pay gateway.
321
     *
322
     * @author yansongda <[email protected]>
323
     *
324
     * @param string $gateway
325
     *
326
     * @throws InvalidGatewayException
327
     *
328
     * @return Response|Collection
329
     */
330 View Code Duplication
    protected function makePay($gateway)
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
331
    {
332
        $app = new $gateway();
333
334
        if ($app instanceof GatewayInterface) {
335
            return $app->pay($this->gateway, $this->payload);
336
        }
337
338
        throw new InvalidGatewayException("Pay Gateway [{$gateway}] Must Be An Instance Of GatewayInterface");
339
    }
340
}
341