Passed
Push — master ( 8226ea...3847e9 )
by Iman
01:35
created

JeniusHttp::paymentRequest()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 50
Code Lines 31

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 31
c 1
b 0
f 0
dl 0
loc 50
rs 9.424
cc 1
nc 1
nop 8

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
namespace Jenius;
4
5
use Carbon\Carbon;
6
use Unirest\Request;
7
use Unirest\Request\Body;
8
use Unirest\Response;
9
10
class JeniusHttp
11
{
12
    /**
13
     * Default Timezone.
14
     *
15
     * @var string
16
     */
17
    private static $timezone = 'Asia/Jakarta';
18
19
    /**
20
     * Default Jenius Port.
21
     *
22
     * @var int
23
     */
24
    private static $port = 443;
25
26
    /**
27
     * Default Jenius Host.
28
     *
29
     * @var string
30
     */
31
    private static $hostName = 'apidev.btpn.com';
32
33
    /**
34
     * Default Jenius Scheme.
35
     *
36
     * @var string
37
     */
38
    private static $scheme = 'https';
39
40
    /**
41
     * Default Jenius Segment.
42
     *
43
     * @var string
44
     */
45
    private static $segment = 'pay';
46
47
    /**
48
     * Timeout curl.
49
     *
50
     * @var int
51
     */
52
    private static $timeOut = 60;
53
54
    /**
55
     * Default Curl Options.
56
     *
57
     * @var int
58
     */
59
    private static $curlOptions = array(
60
        CURLOPT_SSL_VERIFYHOST => 0,
61
        CURLOPT_SSLVERSION => 6,
62
        CURLOPT_SSL_VERIFYPEER => false,
63
        CURLOPT_TIMEOUT => 60
64
    );
65
66
    /**
67
     * Default Jenius Settings.
68
     *
69
     * @var array
70
     */
71
    protected $settings = array(
72
        'x_channel_id' => '',
73
        'client_id' => '',
74
        'client_secret' => '',
75
        'api_key' => '',
76
        'secret_key' => '',
77
        'curl_options' => array(),
78
        // Backward compatible
79
        'host' => 'apidev.btpn.com',
80
        'scheme' => 'https',
81
        'segment' => 'pay',
82
        'timeout' => 60,
83
        'port' => 443,
84
        // New Options
85
        'options' => array(
86
            'host' => 'apidev.btpn.com',
87
            'scheme' => 'https',
88
            'segment' => 'pay',
89
            'timeout' => 60,
90
            'port' => 443
91
        )
92
    );
93
94
    /**
95
     * Default Constructor.
96
     *
97
     * @param string $x_channel_id
98
     * @param string $client_id
99
     * @param string $client_secret
100
     * @param string $api_key
101
     * @param string $secret_key
102
     * @param array $options
103
     */
104
    public function __construct($x_channel_id, $client_id, $client_secret, $api_key, $secret_key, array $options = [])
105
    {
106
        // Required parameters.
107
        $this->settings['x-channel-id'] = $x_channel_id;
108
        $this->settings['client_id'] = $client_id;
109
        $this->settings['client_secret'] = $client_secret;
110
        $this->settings['api_key'] = $api_key;
111
        $this->settings['secret_key'] = $secret_key;
112
        $this->settings['host'] =
113
            preg_replace('/http[s]?\:\/\//', '', $this->settings['host'], 1);
114
115
        foreach ($options as $key => $value) {
116
            if (isset($this->settings[$key])) {
117
                $this->settings[$key] = $value;
118
            }
119
        }
120
121
        // Setup optional scheme, if scheme is empty
122
        if (isset($options['scheme'])) {
123
            $this->settings['scheme'] = $options['scheme'];
124
            $this->settings['options']['scheme'] = $options['scheme'];
125
        } else {
126
            $this->settings['scheme'] = self::getScheme();
127
            $this->settings['options']['scheme'] = self::getScheme();
128
        }
129
130
        // Setup optional host, if host is empty
131
        if (isset($options['host'])) {
132
            $this->settings['host'] = $options['host'];
133
            $this->settings['options']['host'] = $options['host'];
134
        } else {
135
            $this->settings['host'] = self::getHostName();
136
            $this->settings['options']['host'] = self::getHostName();
137
        }
138
139
        // Setup optional segment, if segment is empty
140
        if (isset($options['segment'])) {
141
            $this->settings['segment'] = $options['segment'];
142
            $this->settings['options']['segment'] = $options['segment'];
143
        } else {
144
            $this->settings['segment'] = self::getSegment();
145
            $this->settings['options']['segment'] = self::getSegment();
146
        }
147
148
        // Setup optional port, if port is empty
149
        if (isset($options['port'])) {
150
            $this->settings['port'] = $options['port'];
151
            $this->settings['options']['port'] = $options['port'];
152
        } else {
153
            $this->settings['port'] = self::getPort();
154
            $this->settings['options']['port'] = self::getPort();
155
        }
156
157
        // Setup optional timeout, if timeout is empty
158
        if (isset($options['timeout'])) {
159
            $this->settings['timeout'] = $options['timeout'];
160
            $this->settings['options']['timeout'] = $options['timeout'];
161
        } else {
162
            $this->settings['timeout'] = self::getTimeOut();
163
            $this->settings['options']['timeout'] = self::getTimeOut();
164
        }
165
166
        // Set Default Curl Options.
167
        Request::curlOpts(self::$curlOptions);
0 ignored issues
show
Bug introduced by
self::curlOptions of type integer is incompatible with the type array expected by parameter $options of Unirest\Request::curlOpts(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

167
        Request::curlOpts(/** @scrutinizer ignore-type */ self::$curlOptions);
Loading history...
168
169
        // Set custom curl options
170
        if (!empty($this->settings['curl_options'])) {
171
            $data = self::mergeCurlOptions(self::$curlOptions, $this->settings['curl_options']);
0 ignored issues
show
Bug introduced by
self::curlOptions of type integer is incompatible with the type array expected by parameter $existing_options of Jenius\JeniusHttp::mergeCurlOptions(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

171
            $data = self::mergeCurlOptions(/** @scrutinizer ignore-type */ self::$curlOptions, $this->settings['curl_options']);
Loading history...
172
            Request::curlOpts($data);
173
        }
174
    }
175
176
    /**
177
     * Get Settings
178
     *
179
     * @return array
180
     */
181
    public function getSettings()
182
    {
183
        return $this->settings;
184
    }
185
186
    /**
187
     * Build the ddn domain.
188
     * output = 'https://apidev.btpn.com:443'
189
     * scheme = http(s)
190
     * host = apidev.btpn.com
191
     * port = 80 ? 443
192
     *
193
     * @return string
194
     */
195
    private function ddnDomain()
196
    {
197
        return $this->settings['scheme'] . '://' . $this->settings['host'] . ':' . $this->settings['port'] . '/';
198
    }
199
200
    /**
201
     * Get Token
202
     *
203
     * @return Response
204
     */
205
    public function httpAuth()
206
    {
207
        $client_id = $this->settings['client_id'];
208
        $client_secret = $this->settings['client_secret'];
209
210
        $headerToken = base64_encode("$client_id:$client_secret");
211
212
        $headers = array(
213
            'Content-Type' => 'application/x-www-form-urlencoded',
214
            'Accept' => 'application/json',
215
            'Authorization' => "Basic $headerToken"
216
        );
217
218
        $request_path = "oauth/token";
219
        $domain = $this->ddnDomain();
220
        $full_url = $domain . $request_path;
221
222
        $data = array('grant_type' => 'client_credentials');
223
        $body = Body::form($data);
224
        $response = Request::post($full_url, $headers, $body);
225
226
        return $response;
227
    }
228
229
    /**
230
     * Create payment request
231
     *
232
     * @param string $oauth_token
233
     * @param int $amount
234
     * @param $cashtag
235
     * @param $promoCode
236
     * @param $urlCallback
237
     * @param $purchageDesc
238
     * @param $createdAt
239
     * @param $referenceNo
240
     * @return Response
241
     */
242
    public function paymentRequest(
243
        $oauth_token,
244
        $amount,
245
        $cashtag,
246
        $promoCode,
247
        $urlCallback,
248
        $purchageDesc,
249
        $createdAt,
250
        $referenceNo
251
    ) {
252
        $uriSign = "POST:/" . $this->settings['segment'] . "/payrequest";
253
        $apiKey = $this->settings['api_key'];
254
        $apiSecret = $this->settings['secret_key'];
255
256
        $btpnTimestamp = self::generateBtpnTimestamp();
257
        $btpnOriginalTimestamp = self::generateOriginalTimestamp($createdAt);
258
259
        $headers = array();
260
        $headers['Accept'] = 'application/json';
261
        $headers['Content-Type'] = 'application/json';
262
        $headers['Authorization'] = "Bearer $oauth_token";
263
        $headers['BTPN-ApiKey'] = $apiKey;
264
        $headers['BTPN-Timestamp'] = $btpnTimestamp;
265
        $headers['X-Channel-Id'] = $this->settings['x-channel-id'];
266
        $headers['X-Node'] = 'Jenius Pay';
267
        $headers['X-Transmission-Date-Time'] = $btpnTimestamp;
268
        $headers['X-Original-Transmission-Date-Time'] = $btpnOriginalTimestamp;
269
        $headers['X-Reference-No'] = $referenceNo;
270
271
        $request_path = $this->settings['segment'] . "/payrequest";
272
        $domain = $this->ddnDomain();
273
        $full_url = $domain . $request_path;
274
275
        $bodyData = array();
276
        $bodyData['txn_amount'] = $amount;
277
        $bodyData['cashtag'] = $cashtag;
278
        $bodyData['promo_code'] = $promoCode;
279
        $bodyData['url_callback'] = $urlCallback;
280
        $bodyData['purchase_desc'] = $purchageDesc;
281
282
        $authSignature = self::generateSign($uriSign, $apiKey, $apiSecret, $btpnTimestamp, $bodyData);
283
284
        $headers['BTPN-Signature'] = $authSignature;
285
286
        $encoderData = json_encode($bodyData, JSON_UNESCAPED_SLASHES);
287
288
        $body = Body::form($encoderData);
289
        $response = Request::post($full_url, $headers, $body);
290
291
        return $response;
292
    }
293
294
    /**
295
     * Get payment status
296
     *
297
     * @param string $oauth_token
298
     * @param $referenceNo
299
     * @param $createdAt
300
     * @return Response
301
     */
302
    public function getPaymentStatus(
303
        $oauth_token,
304
        $referenceNo,
305
        $createdAt
306
    ) {
307
        $uriSign = "GET:/" . $this->settings['segment'] . "/paystatus";
308
        $apiKey = $this->settings['api_key'];
309
        $apiSecret = $this->settings['secret_key'];
310
311
        $btpnTimestamp = self::generateBtpnTimestamp();
312
        $btpnOriginalTimestamp = self::generateOriginalTimestamp($createdAt);
313
314
        $headers = array();
315
        $headers['Accept'] = 'application/json';
316
        $headers['Content-Type'] = 'application/json';
317
        $headers['Authorization'] = "Bearer $oauth_token";
318
        $headers['BTPN-ApiKey'] = $apiKey;
319
        $headers['BTPN-Timestamp'] = $btpnTimestamp;
320
        $headers['X-Channel-Id'] = $this->settings['x-channel-id'];
321
        $headers['X-Node'] = 'Jenius Pay';
322
        $headers['X-Transmission-Date-Time'] = $btpnTimestamp;
323
        $headers['X-Original-Transmission-Date-Time'] = $btpnOriginalTimestamp;
324
        $headers['X-Reference-No'] = $referenceNo;
325
326
        $request_path = $this->settings['segment'] . "/paystatus";
327
        $domain = $this->ddnDomain();
328
        $full_url = $domain . $request_path;
329
330
        $authSignature = self::generateSign($uriSign, $apiKey, $apiSecret, $btpnTimestamp, []);
331
332
        $headers['BTPN-Signature'] = $authSignature;
333
334
        $response = Request::get($full_url, $headers, null);
335
336
        return $response;
337
    }
338
339
    /**
340
     * Generate Signature.
341
     *
342
     * @param string $url Url yang akan disign.
343
     * @param $apiKey
344
     * @param $apiSecret
345
     * @param $btpnTimestamp
346
     * @param array|mixed $bodyToHash array Body yang akan dikirimkan ke Server Jenius.
347
     *
348
     * @return string
349
     */
350
    public static function generateSign($url, $apiKey, $apiSecret, $btpnTimestamp, $bodyToHash = [])
351
    {
352
        if (!empty($bodyToHash)) {
353
            $encoderData = json_encode($bodyToHash, JSON_UNESCAPED_SLASHES);
354
            $stringToSign = $url . ":" . $apiKey . ":" . $btpnTimestamp . ":" . $encoderData;
355
        } else {
356
            $stringToSign = $url . ":" . $apiKey . ":" . $btpnTimestamp;
357
        }
358
359
        $auth_signature = hash_hmac('sha256', $stringToSign, $apiSecret, true);
360
        return base64_encode($auth_signature);
361
    }
362
363
    /**
364
     * Set TimeZone.
365
     *
366
     * @param string $timeZone
367
     *
368
     * @return string
369
     */
370
    public static function setTimeZone($timeZone)
371
    {
372
        self::$timezone = $timeZone;
373
    }
374
375
    /**
376
     * Get TimeZone.
377
     *
378
     * @return string
379
     */
380
    public static function getTimeZone()
381
    {
382
        return self::$timezone;
383
    }
384
385
    /**
386
     * Set Jenius Hostname
387
     *
388
     * @param string $hostName
389
     *
390
     * @return string
391
     */
392
    public static function setHostName($hostName)
393
    {
394
        self::$hostName = $hostName;
395
    }
396
397
    /**
398
     * Get Jenius Hostname
399
     *
400
     * @return string
401
     */
402
    public static function getHostName()
403
    {
404
        return self::$hostName;
405
    }
406
407
    /**
408
     * Set Jenius Segment
409
     *
410
     * @param string $segment
411
     *
412
     * @return string
413
     */
414
    public static function setSegment($segment)
415
    {
416
        self::$segment = $segment;
417
    }
418
419
    /**
420
     * Get Jenius Segment
421
     *
422
     * @return string
423
     */
424
    public static function getSegment()
425
    {
426
        return self::$segment;
427
    }
428
429
    /**
430
     * Get Max Execution Time.
431
     *
432
     * @return string
433
     */
434
    public static function getTimeOut()
435
    {
436
        return self::$timeOut;
437
    }
438
439
    /**
440
     * Get Curl Options
441
     *
442
     * @return string
443
     */
444
    public static function getCurlOptions()
445
    {
446
        return self::$curlOptions;
447
    }
448
449
    /**
450
     * Setup Curl Options.
451
     *
452
     * @param array $curlOpts
453
     * @return void
454
     */
455
    public static function setCurlOptions(array $curlOpts = [])
456
    {
457
        $data = self::mergeCurlOptions(self::$curlOptions, $curlOpts);
0 ignored issues
show
Bug introduced by
self::curlOptions of type integer is incompatible with the type array expected by parameter $existing_options of Jenius\JeniusHttp::mergeCurlOptions(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

457
        $data = self::mergeCurlOptions(/** @scrutinizer ignore-type */ self::$curlOptions, $curlOpts);
Loading history...
458
        self::$curlOptions = $data;
0 ignored issues
show
Documentation Bug introduced by
It seems like $data of type array is incompatible with the declared type integer of property $curlOptions.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
459
    }
460
461
    /**
462
     * Set Max Execution Time
463
     *
464
     * @param int $timeOut
465
     *
466
     * @return string
467
     */
468
    public static function setTimeOut($timeOut)
469
    {
470
        self::$timeOut = $timeOut;
471
        return self::$timeOut;
472
    }
473
474
    /**
475
     * Set Jenius Port
476
     *
477
     * @param int $port
478
     *
479
     * @return void
480
     */
481
    public static function setPort($port)
482
    {
483
        self::$port = $port;
484
    }
485
486
    /**
487
     * Get Jenius Port
488
     *
489
     * @return int
490
     */
491
    public static function getPort()
492
    {
493
        return self::$port;
494
    }
495
496
    /**
497
     * Set Jenius Scheme
498
     *
499
     * @param int $scheme
500
     *
501
     * @return string
502
     */
503
    public static function setScheme($scheme)
504
    {
505
        self::$scheme = $scheme;
506
    }
507
508
    /**
509
     * Get Jenius Scheme
510
     *
511
     * @return string
512
     */
513
    public static function getScheme()
514
    {
515
        return self::$scheme;
516
    }
517
518
    /**
519
     * Generate ISO8601 Time.
520
     *
521
     * @return string
522
     */
523
    public static function generateBtpnTimestamp()
524
    {
525
        $date = Carbon::now(self::getTimeZone());
526
        date_default_timezone_set(self::getTimeZone());
527
        $fmt = $date->format('Y-m-d\TH:i:s');
528
        $ISO8601 = sprintf("$fmt.%s%s", substr(microtime(), 2, 3), date('P'));
529
530
        return $ISO8601;
531
    }
532
533
    // 2020-09-26T21:14:07
534
    public static function generateOriginalTimestamp($date)
535
    {
536
        $ISO8601 = sprintf("$date.%s%s", substr(microtime(), 2, 3), date('P'));
537
        return $ISO8601;
538
    }
539
540
    /**
541
     * Merge from existing array.
542
     *
543
     * @param array $existing_options
544
     * @param array $new_options
545
     * @return array
546
     */
547
    private static function mergeCurlOptions(&$existing_options, $new_options)
548
    {
549
        $existing_options = $new_options + $existing_options;
550
        return $existing_options;
551
    }
552
553
    /**
554
     * Implode an array with the key and value pair giving
555
     * a glue, a separator between pairs and the array
556
     * to implode.
557
     *
558
     * @param string $glue The glue between key and value
559
     * @param string $separator Separator between pairs
560
     * @param array $array The array to implode
561
     *
562
     * @return string The imploded array
563
     * @throws JeniusHttpException error
564
     */
565
    public static function arrayImplode($glue, $separator, $array = [])
566
    {
567
        if (!is_array($array)) {
0 ignored issues
show
introduced by
The condition is_array($array) is always true.
Loading history...
568
            throw new JeniusHttpException('Data should array.');
569
        }
570
        if (empty($array)) {
571
            throw new JeniusHttpException('Parameter can`t be empty.');
572
        }
573
        foreach ($array as $key => $val) {
574
            if (is_array($val)) {
575
                $val = implode(',', $val);
576
            }
577
            $string[] = "{$key}{$glue}{$val}";
578
        }
579
580
        return implode($separator, $string);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $string seems to be defined by a foreach iteration on line 573. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
581
    }
582
}
583