bluzphp /
module-payments
| 1 | <?php |
||
| 2 | |||
| 3 | /** |
||
| 4 | * @namespace |
||
| 5 | */ |
||
| 6 | |||
| 7 | namespace Liqpay; |
||
| 8 | |||
| 9 | /** |
||
| 10 | * Liqpay |
||
| 11 | * |
||
| 12 | * @package Liqpay |
||
| 13 | * @author Anton Shevchuk |
||
| 14 | * @link https://www.liqpay.ua/ru/doc/checkout |
||
| 15 | */ |
||
| 16 | class Request |
||
| 17 | { |
||
| 18 | public const ACTION_AUTH = 'auth'; |
||
| 19 | public const ACTION_PAY = 'pay'; |
||
| 20 | public const ACTION_HOLD = 'hold'; |
||
| 21 | public const ACTION_PAYDONATE = 'paydonate'; |
||
| 22 | public const ACTION_SUBSCRIBE = 'subscribe'; |
||
| 23 | public const ACTION_3DS_VERIFY = '3ds_verify'; |
||
| 24 | |||
| 25 | public const CURRENCY_EUR = 'EUR'; |
||
| 26 | public const CURRENCY_USD = 'USD'; |
||
| 27 | public const CURRENCY_UAH = 'UAH'; |
||
| 28 | public const CURRENCY_RUB = 'RUB'; |
||
| 29 | |||
| 30 | protected $supportedActions = [ |
||
| 31 | self::ACTION_AUTH, |
||
| 32 | self::ACTION_PAY, |
||
| 33 | self::ACTION_HOLD, |
||
| 34 | self::ACTION_SUBSCRIBE, |
||
| 35 | self::ACTION_PAYDONATE, |
||
| 36 | self::ACTION_3DS_VERIFY |
||
| 37 | ]; |
||
| 38 | |||
| 39 | protected $supportedCurrencies = [ |
||
| 40 | self::CURRENCY_EUR, |
||
| 41 | self::CURRENCY_USD, |
||
| 42 | self::CURRENCY_UAH, |
||
| 43 | self::CURRENCY_RUB, |
||
| 44 | ]; |
||
| 45 | |||
| 46 | /** |
||
| 47 | * Публичный ключ - идентификатор магазина. Получить ключ можно в настройках магазина |
||
| 48 | * @var string |
||
| 49 | */ |
||
| 50 | protected $publicKey; // Required |
||
| 51 | |||
| 52 | /** |
||
| 53 | * @var string |
||
| 54 | */ |
||
| 55 | protected $privateKey; |
||
| 56 | |||
| 57 | /** |
||
| 58 | * Версия API. |
||
| 59 | * Текущее значение - 3 |
||
| 60 | * |
||
| 61 | * @required |
||
| 62 | * @var integer |
||
| 63 | */ |
||
| 64 | protected $version = 3; |
||
| 65 | |||
| 66 | /** |
||
| 67 | * Тип операции. |
||
| 68 | * Возможные значения: |
||
| 69 | * |
||
| 70 | * pay - платеж |
||
| 71 | * hold - блокировка средств на счету отправителя |
||
| 72 | * subscribe - регулярный платеж |
||
| 73 | * paydonate - пожертвование |
||
| 74 | * auth - предавторизация карты |
||
| 75 | * |
||
| 76 | * @required |
||
| 77 | * @var string |
||
| 78 | */ |
||
| 79 | protected $action; |
||
| 80 | |||
| 81 | /** |
||
| 82 | * Cумма платежа. |
||
| 83 | * Например: 5, 7.34 |
||
| 84 | * |
||
| 85 | * @required |
||
| 86 | * @var float |
||
| 87 | */ |
||
| 88 | protected $amount; |
||
| 89 | |||
| 90 | /** |
||
| 91 | * Валюта платежа. |
||
| 92 | * Возможные значения: USD, EUR, RUB, UAH |
||
| 93 | * |
||
| 94 | * @required |
||
| 95 | * @var string |
||
| 96 | */ |
||
| 97 | protected $currency = self::CURRENCY_UAH; |
||
| 98 | |||
| 99 | /** |
||
| 100 | * Назначение платежа. |
||
| 101 | * |
||
| 102 | * @required |
||
| 103 | * @var string |
||
| 104 | */ |
||
| 105 | protected $description; |
||
| 106 | |||
| 107 | /** |
||
| 108 | * Уникальный ID покупки в Вашем магазине. |
||
| 109 | * Максимальная длина 255 символов. |
||
| 110 | * |
||
| 111 | * @required |
||
| 112 | * @var string |
||
| 113 | */ |
||
| 114 | protected $orderId; |
||
| 115 | |||
| 116 | /** |
||
| 117 | * Время до которого клиент может оплатить счет по UTC. |
||
| 118 | * Передается в формате 2016-04-24 00:00:00 |
||
| 119 | * |
||
| 120 | * @var string |
||
| 121 | */ |
||
| 122 | protected $expiredDate; |
||
| 123 | |||
| 124 | /** |
||
| 125 | * Язык клиента ru, uk, en |
||
| 126 | * |
||
| 127 | * @var string |
||
| 128 | */ |
||
| 129 | protected $language; |
||
| 130 | |||
| 131 | /** |
||
| 132 | * Параметр в котором передаются способы оплаты, которые будут отображены на чекауте. |
||
| 133 | * Возможные значения |
||
| 134 | * card - оплата картой |
||
| 135 | * liqpay - через кабинет liqpay |
||
| 136 | * privat24 - через кабинет приват24, |
||
| 137 | * masterpass - через кабинет masterpass, |
||
| 138 | * moment_part - рассрочка, |
||
| 139 | * cash - наличными, |
||
| 140 | * invoice - счет на e-mail, |
||
| 141 | * qr - сканирование qr-кода. |
||
| 142 | * Если параметр не передан, то применяются настройки магазина, вкладка Checkout. |
||
| 143 | * |
||
| 144 | * @var string |
||
| 145 | */ |
||
| 146 | protected $payTypes; |
||
| 147 | |||
| 148 | /** |
||
| 149 | * URL в Вашем магазине на который покупатель будет переадресован после завершения покупки. |
||
| 150 | * Максимальная длина 510 символов. |
||
| 151 | * |
||
| 152 | * @var string |
||
| 153 | */ |
||
| 154 | protected $resultUrl; |
||
| 155 | |||
| 156 | /** |
||
| 157 | * Включает тестовый режим. |
||
| 158 | * Средства с карты плательщика не списываются. |
||
| 159 | * Для включения тестового режима необходимо передать значение 1. |
||
| 160 | * Все тестовые платежи будут иметь статус sandbox - успешный тестовый платеж. |
||
| 161 | * |
||
| 162 | * @var bool |
||
| 163 | */ |
||
| 164 | protected $sandbox = false; |
||
| 165 | |||
| 166 | /** |
||
| 167 | * URL API в Вашем магазине для уведомлений об изменении статуса платежа (сервер->сервер). |
||
| 168 | * Максимальная длина 510 символов. |
||
| 169 | * |
||
| 170 | * @var string |
||
| 171 | */ |
||
| 172 | protected $serverUrl; |
||
| 173 | |||
| 174 | /** |
||
| 175 | * Возможное значение Y. |
||
| 176 | * Динамический код верификации, генерируется и возвращается в Callback. |
||
| 177 | * Так же сгенерированный код будет передан в транзакции верификации для отображения в выписке по карте клиента. |
||
| 178 | * Работает для action= auth. |
||
| 179 | * |
||
| 180 | * @var string |
||
| 181 | */ |
||
| 182 | protected $verifyCode; |
||
| 183 | |||
| 184 | /** |
||
| 185 | * Constructor of Liqpay |
||
| 186 | * |
||
| 187 | * @access public |
||
| 188 | */ |
||
| 189 | public function __construct($public, $private) |
||
| 190 | { |
||
| 191 | if (empty($public)) { |
||
| 192 | throw new \InvalidArgumentException('Public key is required'); |
||
| 193 | } |
||
| 194 | |||
| 195 | if (empty($private)) { |
||
| 196 | throw new \InvalidArgumentException('Private key is required'); |
||
| 197 | } |
||
| 198 | |||
| 199 | $this->publicKey = $public; |
||
| 200 | $this->privateKey = $private; |
||
| 201 | } |
||
| 202 | |||
| 203 | /** |
||
| 204 | * data |
||
| 205 | * |
||
| 206 | * @param array $params |
||
| 207 | * @return string |
||
| 208 | */ |
||
| 209 | public function data(array $params = []): ?string |
||
| 210 | { |
||
| 211 | $this->setParams($params); |
||
| 212 | |||
| 213 | // try to validate |
||
| 214 | $this->validate(); |
||
| 215 | |||
| 216 | // build data array |
||
| 217 | // required |
||
| 218 | $data = [ |
||
| 219 | 'action' => $this->getAction(), |
||
| 220 | 'amount' => $this->getAmount(), |
||
| 221 | 'currency' => $this->getCurrency(), |
||
| 222 | 'description' => $this->getDescription(), |
||
| 223 | 'order_id' => $this->getOrderId(), |
||
| 224 | 'version' => $this->version, |
||
| 225 | 'public_key' => $this->publicKey, |
||
| 226 | ]; |
||
| 227 | |||
| 228 | if ($expireDate = $this->getExpiredDate()) { |
||
| 229 | $data['expired_date'] = $expireDate; |
||
| 230 | } |
||
| 231 | |||
| 232 | if ($language = $this->getLanguage()) { |
||
| 233 | $data['language'] = $language; |
||
| 234 | } |
||
| 235 | |||
| 236 | if ($payTypes = $this->getPayTypes()) { |
||
| 237 | $data['paytypes'] = $payTypes; |
||
| 238 | } |
||
| 239 | |||
| 240 | if ($resultUrl = $this->getResultUrl()) { |
||
| 241 | $data['result_url'] = $resultUrl; |
||
| 242 | } |
||
| 243 | |||
| 244 | if ($serverUrl = $this->getServerUrl()) { |
||
| 245 | $data['server_url'] = $serverUrl; |
||
| 246 | } |
||
| 247 | |||
| 248 | if ($sandbox = $this->getSandbox()) { |
||
|
0 ignored issues
–
show
Unused Code
introduced
by
Loading history...
|
|||
| 249 | $data['sandbox'] = 1; |
||
| 250 | } |
||
| 251 | |||
| 252 | if ($verifyCode = $this->getVerifyCode()) { |
||
| 253 | $data['verifycode'] = $verifyCode; |
||
| 254 | } |
||
| 255 | |||
| 256 | $data = array_map('strval', $data); |
||
| 257 | |||
| 258 | return base64_encode(json_encode($data)); |
||
| 259 | } |
||
| 260 | |||
| 261 | /** |
||
| 262 | * signature |
||
| 263 | * |
||
| 264 | * @return string |
||
| 265 | */ |
||
| 266 | public function signature() |
||
| 267 | { |
||
| 268 | $string = $this->privateKey . $this->data() . $this->privateKey; |
||
| 269 | return base64_encode(sha1($string, 1)); |
||
| 270 | } |
||
| 271 | |||
| 272 | /** |
||
| 273 | * @return string |
||
| 274 | */ |
||
| 275 | public function getAction(): ?string |
||
| 276 | { |
||
| 277 | return $this->action; |
||
| 278 | } |
||
| 279 | |||
| 280 | /** |
||
| 281 | * @param string $action |
||
| 282 | */ |
||
| 283 | public function setAction(string $action): void |
||
| 284 | { |
||
| 285 | $this->action = $action; |
||
| 286 | } |
||
| 287 | |||
| 288 | /** |
||
| 289 | * @return float |
||
| 290 | */ |
||
| 291 | public function getAmount(): ?float |
||
| 292 | { |
||
| 293 | return $this->amount; |
||
| 294 | } |
||
| 295 | |||
| 296 | /** |
||
| 297 | * @param float $amount |
||
| 298 | */ |
||
| 299 | public function setAmount(float $amount): void |
||
| 300 | { |
||
| 301 | $this->amount = $amount; |
||
| 302 | } |
||
| 303 | |||
| 304 | /** |
||
| 305 | * @return string |
||
| 306 | */ |
||
| 307 | public function getCurrency(): ?string |
||
| 308 | { |
||
| 309 | return $this->currency; |
||
| 310 | } |
||
| 311 | |||
| 312 | /** |
||
| 313 | * @param string $currency |
||
| 314 | */ |
||
| 315 | public function setCurrency(string $currency): void |
||
| 316 | { |
||
| 317 | $this->currency = $currency; |
||
| 318 | } |
||
| 319 | |||
| 320 | /** |
||
| 321 | * @return string |
||
| 322 | */ |
||
| 323 | public function getDescription(): ?string |
||
| 324 | { |
||
| 325 | return $this->description; |
||
| 326 | } |
||
| 327 | |||
| 328 | /** |
||
| 329 | * @param string $description |
||
| 330 | */ |
||
| 331 | public function setDescription(string $description): void |
||
| 332 | { |
||
| 333 | $this->description = $description; |
||
| 334 | } |
||
| 335 | |||
| 336 | /** |
||
| 337 | * @return string |
||
| 338 | */ |
||
| 339 | public function getOrderId(): ?string |
||
| 340 | { |
||
| 341 | return $this->orderId; |
||
| 342 | } |
||
| 343 | |||
| 344 | /** |
||
| 345 | * @param string $orderId |
||
| 346 | */ |
||
| 347 | public function setOrderId(string $orderId): void |
||
| 348 | { |
||
| 349 | $this->orderId = $orderId; |
||
| 350 | } |
||
| 351 | |||
| 352 | /** |
||
| 353 | * @return string |
||
| 354 | */ |
||
| 355 | public function getExpiredDate(): ?string |
||
| 356 | { |
||
| 357 | return $this->expiredDate; |
||
| 358 | } |
||
| 359 | |||
| 360 | /** |
||
| 361 | * @param string $expiredDate |
||
| 362 | */ |
||
| 363 | public function setExpiredDate(string $expiredDate): void |
||
| 364 | { |
||
| 365 | $this->expiredDate = $expiredDate; |
||
| 366 | } |
||
| 367 | |||
| 368 | /** |
||
| 369 | * @return string |
||
| 370 | */ |
||
| 371 | public function getLanguage(): ?string |
||
| 372 | { |
||
| 373 | return $this->language; |
||
| 374 | } |
||
| 375 | |||
| 376 | /** |
||
| 377 | * @param string $language |
||
| 378 | */ |
||
| 379 | public function setLanguage(string $language): void |
||
| 380 | { |
||
| 381 | $this->language = $language; |
||
| 382 | } |
||
| 383 | |||
| 384 | /** |
||
| 385 | * @return string |
||
| 386 | */ |
||
| 387 | public function getPayTypes(): ?string |
||
| 388 | { |
||
| 389 | return $this->payTypes; |
||
| 390 | } |
||
| 391 | |||
| 392 | /** |
||
| 393 | * @param string $payTypes |
||
| 394 | */ |
||
| 395 | public function setPayTypes(string $payTypes): void |
||
| 396 | { |
||
| 397 | $this->payTypes = $payTypes; |
||
| 398 | } |
||
| 399 | |||
| 400 | /** |
||
| 401 | * @return string |
||
| 402 | */ |
||
| 403 | public function getResultUrl(): ?string |
||
| 404 | { |
||
| 405 | return $this->resultUrl; |
||
| 406 | } |
||
| 407 | |||
| 408 | /** |
||
| 409 | * @param string $resultUrl |
||
| 410 | */ |
||
| 411 | public function setResultUrl(string $resultUrl): void |
||
| 412 | { |
||
| 413 | $this->resultUrl = $resultUrl; |
||
| 414 | } |
||
| 415 | |||
| 416 | /** |
||
| 417 | * @return bool |
||
| 418 | */ |
||
| 419 | public function getSandbox(): bool |
||
| 420 | { |
||
| 421 | return $this->sandbox; |
||
| 422 | } |
||
| 423 | |||
| 424 | /** |
||
| 425 | * @return void |
||
| 426 | */ |
||
| 427 | public function setSandbox(): void |
||
| 428 | { |
||
| 429 | $this->sandbox = true; |
||
| 430 | } |
||
| 431 | |||
| 432 | /** |
||
| 433 | * @return string |
||
| 434 | */ |
||
| 435 | public function getServerUrl(): ?string |
||
| 436 | { |
||
| 437 | return $this->serverUrl; |
||
| 438 | } |
||
| 439 | |||
| 440 | /** |
||
| 441 | * @param string $serverUrl |
||
| 442 | */ |
||
| 443 | public function setServerUrl(string $serverUrl): void |
||
| 444 | { |
||
| 445 | $this->serverUrl = $serverUrl; |
||
| 446 | } |
||
| 447 | |||
| 448 | /** |
||
| 449 | * @return string |
||
| 450 | */ |
||
| 451 | public function getVerifyCode(): ?string |
||
| 452 | { |
||
| 453 | return $this->verifyCode; |
||
| 454 | } |
||
| 455 | |||
| 456 | /** |
||
| 457 | * @param string $verifyCode |
||
| 458 | */ |
||
| 459 | public function setVerifyCode(string $verifyCode): void |
||
| 460 | { |
||
| 461 | $this->verifyCode = $verifyCode; |
||
| 462 | } |
||
| 463 | |||
| 464 | /** |
||
| 465 | * Set param by key over setter |
||
| 466 | * |
||
| 467 | * @param string $key |
||
| 468 | * @param string $value |
||
| 469 | * |
||
| 470 | * @return void |
||
| 471 | */ |
||
| 472 | public function setParam($key, $value): void |
||
| 473 | { |
||
| 474 | $method = 'set' . $this->toCamelCase($key); |
||
| 475 | if (method_exists($this, $method)) { |
||
| 476 | $this->$method($value); |
||
| 477 | } |
||
| 478 | } |
||
| 479 | |||
| 480 | /** |
||
| 481 | * Set params |
||
| 482 | * |
||
| 483 | * Requirements |
||
| 484 | * - options must be a array |
||
| 485 | * - options can be empty |
||
| 486 | * |
||
| 487 | * @param array $params |
||
| 488 | * |
||
| 489 | * @return void |
||
| 490 | */ |
||
| 491 | public function setParams(array $params = []): void |
||
| 492 | { |
||
| 493 | // apply params |
||
| 494 | foreach ($params as $key => $value) { |
||
| 495 | $this->setParam($key, $value); |
||
| 496 | } |
||
| 497 | } |
||
| 498 | |||
| 499 | /** |
||
| 500 | * Validate request |
||
| 501 | * |
||
| 502 | * @return void |
||
| 503 | */ |
||
| 504 | private function validate() |
||
| 505 | { |
||
| 506 | // check required |
||
| 507 | if (empty($this->version)) { |
||
| 508 | throw new \InvalidArgumentException('Version is required'); |
||
| 509 | } |
||
| 510 | if (empty($this->amount)) { |
||
| 511 | throw new \InvalidArgumentException('Amount is required'); |
||
| 512 | } |
||
| 513 | if (empty($this->action)) { |
||
| 514 | throw new \InvalidArgumentException('Actions is required'); |
||
| 515 | } |
||
| 516 | if (!in_array($this->action, $this->supportedActions)) { |
||
| 517 | throw new \InvalidArgumentException('Actions is not supported'); |
||
| 518 | } |
||
| 519 | if (empty($this->currency)) { |
||
| 520 | throw new \InvalidArgumentException('Currency is required'); |
||
| 521 | } |
||
| 522 | if (!in_array($this->currency, $this->supportedCurrencies)) { |
||
| 523 | throw new \InvalidArgumentException('Currency is not supported'); |
||
| 524 | } |
||
| 525 | if (empty($this->description)) { |
||
| 526 | throw new \InvalidArgumentException('Description is required'); |
||
| 527 | } |
||
| 528 | } |
||
| 529 | |||
| 530 | /** |
||
| 531 | * Encode params |
||
| 532 | * |
||
| 533 | * @param array $params |
||
| 534 | * @return string |
||
| 535 | */ |
||
| 536 | private function encode($params) |
||
| 537 | { |
||
| 538 | return base64_encode(json_encode($params)); |
||
| 539 | } |
||
| 540 | |||
| 541 | /** |
||
| 542 | * @param $subject |
||
| 543 | * |
||
| 544 | * @return string |
||
| 545 | */ |
||
| 546 | private function toCamelCase($subject): string |
||
| 547 | { |
||
| 548 | $subject = str_replace(['_', '-'], ' ', strtolower($subject)); |
||
| 549 | return str_replace(' ', '', ucwords($subject)); |
||
| 550 | } |
||
| 551 | } |
||
| 552 |