Request::encode()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
nc 1
nop 1
dl 0
loc 3
c 1
b 0
f 0
cc 1
rs 10
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
The assignment to $sandbox is dead and can be removed.
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