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

JeniusHttp::getSettings()   A

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
c 1
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 0
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