1
|
|
|
<?php |
2
|
|
|
/* |
3
|
|
|
* This file is part of the slince/youzan-pay package. |
4
|
|
|
* |
5
|
|
|
* (c) Slince <[email protected]> |
6
|
|
|
* |
7
|
|
|
* For the full copyright and license information, please view the LICENSE |
8
|
|
|
* file that was distributed with this source code. |
9
|
|
|
*/ |
10
|
|
|
|
11
|
|
|
namespace Slince\YouzanPay; |
12
|
|
|
|
13
|
|
|
use GuzzleHttp\Client; |
14
|
|
|
use Psr\Http\Message\ServerRequestInterface as PSR7Request; |
15
|
|
|
use Slince\YouzanPay\Api\QRCode; |
16
|
|
|
use Slince\YouzanPay\Api\Token; |
17
|
|
|
use Symfony\Component\HttpFoundation\Request as SymfonyRequest; |
18
|
|
|
|
19
|
|
|
class YouzanPay |
20
|
|
|
{ |
21
|
|
|
/** |
22
|
|
|
* @var Client |
23
|
|
|
*/ |
24
|
|
|
protected $httpClient; |
25
|
|
|
|
26
|
|
|
/** |
27
|
|
|
* @var ApiContext |
28
|
|
|
*/ |
29
|
|
|
protected $apiContext; |
30
|
|
|
|
31
|
|
|
public function __construct(ApiContext $apiContext, $options = []) |
32
|
|
|
{ |
33
|
|
|
$this->apiContext = $apiContext; |
34
|
|
|
$this->applyOptions($options); |
35
|
|
|
Requestor::setApiContext($this->apiContext); |
36
|
|
|
Requestor::setHttpClient($this->httpClient); |
37
|
|
|
} |
38
|
|
|
|
39
|
|
|
/** |
40
|
|
|
* 发起交易. |
41
|
|
|
* |
42
|
|
|
* @param array $data |
43
|
|
|
* |
44
|
|
|
* @return QRCode |
45
|
|
|
*/ |
46
|
|
|
public function charge(array $data) |
47
|
|
|
{ |
48
|
|
|
$qrCode = QRCode::fromArray($data); |
49
|
|
|
Requestor::persistQrCode($qrCode); |
50
|
|
|
|
51
|
|
|
return $qrCode; |
52
|
|
|
} |
53
|
|
|
|
54
|
|
|
/** |
55
|
|
|
* 检查支付结果. |
56
|
|
|
* |
57
|
|
|
* @param QRCode|int $qrCodeId |
58
|
|
|
* |
59
|
|
|
* @return bool |
60
|
|
|
*/ |
61
|
|
|
public function checkQRStatus($qrCodeId) |
62
|
|
|
{ |
63
|
|
|
return Requestor::checkQRCodePayResult($qrCodeId); |
64
|
|
|
} |
65
|
|
|
|
66
|
|
|
/** |
67
|
|
|
* 获取trade. |
68
|
|
|
* |
69
|
|
|
* @param int $id |
70
|
|
|
* |
71
|
|
|
* @return Api\Trade |
72
|
|
|
*/ |
73
|
|
|
public function getTrade($id) |
74
|
|
|
{ |
75
|
|
|
return Requestor::getTrade($id); |
76
|
|
|
} |
77
|
|
|
|
78
|
|
|
/** |
79
|
|
|
* 验证推送 |
80
|
|
|
* |
81
|
|
|
* @param SymfonyRequest|PSR7Request|array|null $request |
82
|
|
|
* |
83
|
|
|
* @throws \InvalidArgumentException |
84
|
|
|
* |
85
|
|
|
* @return array |
86
|
|
|
*/ |
87
|
|
|
public function verifyWebhook($request = null) |
88
|
|
|
{ |
89
|
|
|
if ($request instanceof SymfonyRequest) { |
90
|
|
|
$data = \GuzzleHttp\json_decode($request->getContent(), true); |
|
|
|
|
91
|
|
|
} elseif ($request instanceof PSR7Request) { |
92
|
|
|
$data = $request->getParsedBody(); |
93
|
|
|
} elseif(is_array($request)) { |
94
|
|
|
$data = $request; |
95
|
|
|
} else { |
96
|
|
|
$data = \GuzzleHttp\json_decode(file_get_contents('php://input'), true); |
97
|
|
|
} |
98
|
|
|
if (!$this->verifySign($data)) { |
99
|
|
|
throw new \InvalidArgumentException('Bad Youzan message'); |
100
|
|
|
} |
101
|
|
|
|
102
|
|
|
return $data; |
103
|
|
|
} |
104
|
|
|
|
105
|
|
|
protected function verifySign($data) |
106
|
|
|
{ |
107
|
|
|
if (!isset($data['sign'])) { |
108
|
|
|
return false; |
109
|
|
|
} |
110
|
|
|
|
111
|
|
|
return $data['sign'] === md5($this->apiContext->getClientId() |
112
|
|
|
.$data['msg'] |
113
|
|
|
.$this->apiContext->getClientSecret()); |
114
|
|
|
} |
115
|
|
|
|
116
|
|
|
/** |
117
|
|
|
* 设置访问 token. |
118
|
|
|
* |
119
|
|
|
* @param string|Token $token |
120
|
|
|
*/ |
121
|
|
|
public function setAccessToken($token) |
122
|
|
|
{ |
123
|
|
|
if (is_string($token)) { |
124
|
|
|
$token = new Token($token); |
125
|
|
|
} |
126
|
|
|
Requestor::setToken($token); |
127
|
|
|
} |
128
|
|
|
|
129
|
|
|
/** |
130
|
|
|
* 获取access token. |
131
|
|
|
* |
132
|
|
|
* @return Token |
133
|
|
|
*/ |
134
|
|
|
public function getAccessToken() |
135
|
|
|
{ |
136
|
|
|
return Requestor::getAccessToken(); |
137
|
|
|
} |
138
|
|
|
|
139
|
|
|
protected function applyOptions($options) |
140
|
|
|
{ |
141
|
|
|
if (isset($options['httpClient'])) { |
142
|
|
|
$this->httpClient = $options['httpClient']; |
143
|
|
|
} else { |
144
|
|
|
$this->httpClient = new Client([ |
145
|
|
|
'verify' => false, |
146
|
|
|
]); |
147
|
|
|
} |
148
|
|
|
} |
149
|
|
|
} |
This check looks at variables that are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.