· 6 years ago · Mar 03, 2019, 03:04 PM
1<?php
2/**
3 * UnitPay Payment Module
4 *
5 * NOTICE OF LICENSE
6 *
7 * This source file is subject to the Open Software License (OSL 3.0)
8 * that is available through the world-wide-web at this URL:
9 * http://opensource.org/licenses/osl-3.0.php
10 *
11 * @category UnitPay
12 * @package unitpay/unitpay
13 * @version 1.0.0
14 * @author UnitPay
15 * @copyright Copyright (c) 2015 UnitPay
16 * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
17 *
18 * EXTENSION INFORMATION
19 *
20 * UNITPAY API https://unitpay.ru/doc
21 *
22 */
23
24
25/**
26 * Value object for paid goods
27 */
28class CashItem
29{
30 private $name;
31
32 private $count;
33
34 private $price;
35
36 /**
37 * @param string $name
38 * @param int $count
39 * @param float $price
40 */
41 public function __construct($name, $count, $price)
42 {
43 $this->name = $name;
44 $this->count = $count;
45 $this->price = $price;
46 }
47
48 /**
49 * @return string
50 */
51 public function getName()
52 {
53 return $this->name;
54 }
55
56 /**
57 * @return int
58 */
59 public function getCount()
60 {
61 return $this->count;
62 }
63
64 /**
65 * @return float
66 */
67 public function getPrice()
68 {
69 return $this->price;
70 }
71}
72
73/**
74 * Payment method UnitPay process
75 *
76 * @author UnitPay <support@unitpay.ru>
77 */
78class UnitPay
79{
80 private $supportedCurrencies = array('EUR','UAH', 'BYR', 'USD','RUB');
81 private $supportedUnitpayMethods = array('initPayment', 'getPayment');
82 private $requiredUnitpayMethodsParams = array(
83 'initPayment' => array('desc', 'account', 'sum'),
84 'getPayment' => array('paymentId')
85 );
86 private $supportedPartnerMethods = array('check', 'pay', 'error');
87 private $supportedUnitpayIp = array(
88 '31.186.100.49',
89 '87.245.198.42',
90 '178.132.203.105',
91 '52.29.152.23',
92 '104.24.105.36',
93 '104.24.97.7',
94 '52.19.56.234',
95 '104.24.96.7'
96 );
97
98 private $secretKey;
99
100 private $params = array();
101
102 const API_URL = 'https://unitpay.ru/api';
103 const FORM_URL = 'https://unitpay.ru/pay/';
104
105 public function __construct($secretKey = null)
106 {
107 $this->secretKey = $secretKey;
108 }
109
110 /**
111 * Create SHA-256 digital signature
112 *
113 * @param array $params
114 * @param $method
115 *
116 * @return string
117 */
118 function getSignature(array $params, $method = null)
119 {
120 ksort($params);
121 unset($params['sign']);
122 unset($params['signature']);
123 array_push($params, $this->secretKey);
124
125 if ($method) {
126 array_unshift($params, $method);
127 }
128
129 return hash('sha256', join('{up}', $params));
130 }
131
132 /**
133 * Return IP address
134 *
135 * @return string
136 */
137 protected function getIp()
138 {
139 return $_SERVER['REMOTE_ADDR'];
140 }
141
142 /**
143 * Get URL for pay through the form
144 *
145 * @param string $publicKey
146 * @param string|float|int $sum
147 * @param string $account
148 * @param string $desc
149 * @param string $currency
150 * @param string $locale
151 *
152 * @return string
153 */
154 public function form($publicKey, $sum, $account, $desc, $currency = 'RUB', $locale = 'ru')
155 {
156 $vitalParams = array(
157 'account' => $account,
158 'currency' => $currency,
159 'desc' => $desc,
160 'sum' => $sum
161 );
162
163 $this->params = array_merge($this->params, $vitalParams);
164
165 if ($this->secretKey) {
166 $this->params['signature'] = $this->getSignature($vitalParams);
167 }
168
169 $this->params['locale'] = $locale;
170
171 return self::FORM_URL . $publicKey . '/qiwi?' . http_build_query($this->params);
172 }
173
174 /**
175 * Set customer email
176 *
177 * @param string $email
178 *
179 * @return UnitPay
180 */
181 public function setCustomerEmail($email)
182 {
183 $this->params['customerEmail'] = $email;
184 return $this;
185 }
186
187 /**
188 * Set customer phone number
189 *
190 * @param string $phone
191 *
192 * @return UnitPay
193 */
194 public function setCustomerPhone($phone)
195 {
196 $this->params['customerPhone'] = $phone;
197 return $this;
198 }
199
200 /**
201 * Set list of paid goods
202 *
203 * @param CashItem[] $items
204 *
205 * @return UnitPay
206 */
207 public function setCashItems($items)
208 {
209 $this->params['cashItems'] = base64_encode(
210 json_encode(
211 array_map(function ($item) {
212 /** @var CashItem $item */
213 return array(
214 'name' => $item->getName(),
215 'count' => $item->getCount(),
216 'price' => $item->getPrice()
217 );
218 }, $items)));
219
220 return $this;
221 }
222
223 /**
224 * Set callback URL
225 *
226 * @param string $backUrl
227 * @return UnitPay
228 */
229 public function setBackUrl($backUrl)
230 {
231 $this->params['backUrl'] = $backUrl;
232 return $this;
233 }
234
235 /**
236 * Call API
237 *
238 * @param $method
239 * @param array $params
240 *
241 * @return object
242 *
243 * @throws InvalidArgumentException
244 * @throws UnexpectedValueException
245 */
246 public function api($method, $params = array())
247 {
248 if (!in_array($method, $this->supportedUnitpayMethods)) {
249 throw new UnexpectedValueException('Method is not supported');
250 }
251
252 if (isset($this->requiredUnitpayMethodsParams[$method])) {
253 foreach ($this->requiredUnitpayMethodsParams[$method] as $rParam) {
254 if (!isset($params[$rParam])) {
255 throw new InvalidArgumentException('Param '.$rParam.' is null');
256 }
257 }
258 }
259
260 $params['secretKey'] = $this->secretKey;
261 if (empty($params['secretKey'])) {
262 throw new InvalidArgumentException('SecretKey is null');
263 }
264
265 $requestUrl = self::API_URL . '?' . http_build_query([
266 'method' => $method,
267 'params' => $params
268 ], null, '&', PHP_QUERY_RFC3986);
269
270 $response = json_decode(file_get_contents($requestUrl));
271 if (!is_object($response)) {
272 throw new InvalidArgumentException('Temporary server error. Please try again later.');
273 }
274
275 return $response;
276 }
277
278 /**
279 * Check request on handler from UnitPay
280 *
281 * @return bool
282 *
283 * @throws InvalidArgumentException
284 * @throws UnexpectedValueException
285 */
286 public function checkHandlerRequest()
287 {
288 $ip = $this->getIp();
289 if (!isset($_GET['method'])) {
290 throw new InvalidArgumentException('Method is null');
291 }
292
293 if (!isset($_GET['params'])) {
294 throw new InvalidArgumentException('Params is null');
295 }
296
297 list($method, $params) = array($_GET['method'], $_GET['params']);
298
299 if (!in_array($method, $this->supportedPartnerMethods)) {
300 throw new UnexpectedValueException('Method is not supported');
301 }
302
303 if (!isset($params['signature']) || $params['signature'] != $this->getSignature($params, $method)) {
304 throw new InvalidArgumentException('Wrong signature');
305 }
306
307 /**
308 * IP address check
309 * @link http://help.unitpay.ru/article/67-ip-addresses
310 */
311 if (!in_array($ip, $this->supportedUnitpayIp)) {
312 throw new InvalidArgumentException('IP address Error');
313 }
314
315 return true;
316 }
317
318 /**
319 * Response for UnitPay if handle success
320 *
321 * @param $message
322 *
323 * @return string
324 */
325 public function getSuccessHandlerResponse($message, $params)
326 {
327 return json_encode(array(
328 "result" => array(
329 "message" => $message,
330 "result" => $params
331 )
332 ));
333 }
334
335 /**
336 * Response for UnitPay if handle error
337 *
338 * @param $message
339 *
340 * @return string
341 */
342 public function getErrorHandlerResponse($message)
343 {
344 return json_encode(array(
345 "error" => array(
346 "message" => $message
347 )
348 ));
349 }
350}