Issues (52)

src/Drivers/Irankish/Irankish.php (6 issues)

1
<?php
2
3
namespace Shetabit\Multipay\Drivers\Irankish;
4
5
use Shetabit\Multipay\Abstracts\Driver;
6
use Shetabit\Multipay\Exceptions\InvalidPaymentException;
7
use Shetabit\Multipay\Exceptions\PurchaseFailedException;
8
use Shetabit\Multipay\Contracts\ReceiptInterface;
9
use Shetabit\Multipay\Invoice;
10
use Shetabit\Multipay\Receipt;
11
use Shetabit\Multipay\RedirectionForm;
12
use Shetabit\Multipay\Request;
13
14
class Irankish extends Driver
15
{
16
    /**
17
     * Invoice
18
     *
19
     * @var Invoice
20
     */
21
    protected $invoice;
22
23
    /**
24
     * Driver settings
25
     *
26
     * @var object
27
     */
28
    protected $settings;
29
30
    /**
31
     * Irankish constructor.
32
     * Construct the class with the relevant settings.
33
     *
34
     * @param Invoice $invoice
35
     * @param $settings
36
     */
37
    public function __construct(Invoice $invoice, $settings)
38
    {
39
        $this->invoice($invoice);
40
        $this->settings = (object) $settings;
41
    }
42
43
    private function generateAuthenticationEnvelope($pubKey, $terminalID, $password, $amount)
44
    {
45
        $data = $terminalID . $password . str_pad($amount, 12, '0', STR_PAD_LEFT) . '00';
46
        $data = hex2bin($data);
47
        $AESSecretKey = openssl_random_pseudo_bytes(16);
48
        $ivlen = openssl_cipher_iv_length($cipher = "AES-128-CBC");
49
        $iv = openssl_random_pseudo_bytes($ivlen);
50
        $ciphertext_raw = openssl_encrypt($data, $cipher, $AESSecretKey, $options = OPENSSL_RAW_DATA, $iv);
51
        $hmac = hash('sha256', $ciphertext_raw, true);
52
        $crypttext = '';
53
54
        openssl_public_encrypt($AESSecretKey . $hmac, $crypttext, $pubKey);
55
56
        return array(
57
            "data" => bin2hex($crypttext),
58
            "iv" => bin2hex($iv),
59
        );
60
    }
61
62
    /**
63
     * Purchase Invoice.
64
     *
65
     * @return string
66
     *
67
     * @throws PurchaseFailedException
68
     * @throws \SoapFault
69
     */
70
    public function purchase()
71
    {
72
        if (!empty($this->invoice->getDetails()['description'])) {
73
            $description = $this->invoice->getDetails()['description'];
0 ignored issues
show
The assignment to $description is dead and can be removed.
Loading history...
74
        } else {
75
            $description = $this->settings->description;
76
        }
77
78
        $pubKey = $this->settings->pubKey;
79
        $terminalID = $this->settings->terminalId;
80
        $password = $this->settings->password;
81
        $amount = $this->invoice->getAmount() * ($this->settings->currency == 'T' ? 10 : 1); // convert to rial
82
83
        $token = $this->generateAuthenticationEnvelope($pubKey, $terminalID, $password, $amount);
84
85
        $data = [];
86
        $data['request'] = [
87
            'acceptorId' => $this->settings->acceptorId,
88
            'amount' => $amount,
89
            'billInfo' => null,
90
            "paymentId" => null,
91
            "requestId" => uniqid(),
92
            "requestTimestamp" => time(),
93
            "revertUri" => $this->settings->callbackUrl,
94
            "terminalId" => $this->settings->terminalId,
95
            "transactionType" => "Purchase",
96
        ];
97
        $data['authenticationEnvelope'] = $token;
98
        $dataString = json_encode($data);
99
100
        $ch = curl_init($this->settings->apiPurchaseUrl);
101
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
102
        curl_setopt($ch, CURLOPT_POSTFIELDS, $dataString);
103
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
104
        curl_setopt($ch, CURLOPT_HTTPHEADER, array(
105
            'Content-Type: application/json',
106
            'Content-Length: ' . strlen($dataString)
107
        ));
108
        curl_setopt($ch, CURLOPT_SSL_CIPHER_LIST, 'DEFAULT@SECLEVEL=1');
109
110
        $result = curl_exec($ch);
111
        curl_close($ch);
112
113
        $response = json_decode($result, JSON_OBJECT_AS_ARRAY);
0 ignored issues
show
Shetabit\Multipay\Driver...sh\JSON_OBJECT_AS_ARRAY of type integer is incompatible with the type boolean|null expected by parameter $associative of json_decode(). ( Ignorable by Annotation )

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

113
        $response = json_decode($result, /** @scrutinizer ignore-type */ JSON_OBJECT_AS_ARRAY);
Loading history...
It seems like $result can also be of type true; however, parameter $json of json_decode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

113
        $response = json_decode(/** @scrutinizer ignore-type */ $result, JSON_OBJECT_AS_ARRAY);
Loading history...
114
115
        if (!$response || $response["responseCode"] != "00") {
116
            // error has happened
117
            $message = $response["description"] ?? 'خطا در هنگام درخواست برای پرداخت رخ داده است.';
118
            throw new PurchaseFailedException($message);
119
        }
120
121
        $this->invoice->transactionId($response['result']['token']);
122
123
        // return the transaction's id
124
        return $this->invoice->getTransactionId();
125
    }
126
127
    /**
128
     * Pay the Invoice
129
     *
130
     * @return RedirectionForm
131
     */
132
    public function pay() : RedirectionForm
133
    {
134
        $payUrl = $this->settings->apiPaymentUrl;
135
136
        return $this->redirectWithForm(
137
            $payUrl,
138
            [
139
                'tokenIdentity' => $this->invoice->getTransactionId()
140
            ],
141
            'POST'
142
        );
143
    }
144
145
    /**
146
     * Verify payment
147
     *
148
     * @return ReceiptInterface
149
     *
150
     * @throws InvalidPaymentException
151
     */
152
    public function verify() : ReceiptInterface
153
    {
154
        $status = Request::input('responseCode');
155
        if (Request::input('responseCode') != "00") {
156
            return $this->notVerified($status);
157
        }
158
159
        $data = [
160
            'terminalId' => $this->settings->terminalId,
161
            'retrievalReferenceNumber' => Request::input('retrievalReferenceNumber'),
162
            'systemTraceAuditNumber' => Request::input('systemTraceAuditNumber'),
163
            'tokenIdentity' => Request::input('token'),
164
        ];
165
166
        $dataString = json_encode($data);
167
168
        $ch = curl_init($this->settings->apiVerificationUrl);
169
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
170
        curl_setopt($ch, CURLOPT_POSTFIELDS, $dataString);
171
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
172
        curl_setopt($ch, CURLOPT_HTTPHEADER, array(
173
            'Content-Type: application/json',
174
            'Content-Length: ' . strlen($dataString)
175
        ));
176
        curl_setopt($ch, CURLOPT_SSL_CIPHER_LIST, 'DEFAULT@SECLEVEL=1');
177
178
        $result = curl_exec($ch);
179
        if ($result === false || !$data['retrievalReferenceNumber']) {
180
            $this->notVerified($status);
181
        }
182
        curl_close($ch);
183
184
        $response = json_decode($result, JSON_OBJECT_AS_ARRAY);
0 ignored issues
show
Shetabit\Multipay\Driver...sh\JSON_OBJECT_AS_ARRAY of type integer is incompatible with the type boolean|null expected by parameter $associative of json_decode(). ( Ignorable by Annotation )

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

184
        $response = json_decode($result, /** @scrutinizer ignore-type */ JSON_OBJECT_AS_ARRAY);
Loading history...
The assignment to $response is dead and can be removed.
Loading history...
It seems like $result can also be of type true; however, parameter $json of json_decode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

184
        $response = json_decode(/** @scrutinizer ignore-type */ $result, JSON_OBJECT_AS_ARRAY);
Loading history...
185
186
        return $this->createReceipt($data['retrievalReferenceNumber']);
187
    }
188
189
    /**
190
     * Generate the payment's receipt
191
     *
192
     * @param $referenceId
193
     *
194
     * @return Receipt
195
     */
196
    protected function createReceipt($referenceId)
197
    {
198
        return new Receipt('irankish', $referenceId);
199
    }
200
201
    /**
202
     * Trigger an exception
203
     *
204
     * @param $status
205
     * @throws InvalidPaymentException
206
     */
207
    private function notVerified($status)
208
    {
209
        $translations = [
210
            5 => 'از انجام تراکنش صرف نظر شد',
211
            17 => 'از انجام تراکنش صرف نظر شد',
212
            3 => 'پذیرنده فروشگاهی نامعتبر است',
213
            64 => 'مبلغ تراکنش نادرست است، جمع مبالغ تقسیم وجوه برابر مبلغ کل تراکنش نمی باشد',
214
            94 => 'تراکنش تکراری است',
215
            25 => 'تراکنش اصلی یافت نشد',
216
            77 => 'روز مالی تراکنش نا معتبر است',
217
            63 => 'کد اعتبار سنجی پیام نا معتبر است',
218
            97 => 'کد تولید کد اعتبار سنجی نا معتبر است',
219
            30 => 'فرمت پیام نادرست است',
220
            86 => 'شتاب در حال  Off Sign است',
221
            55 => 'رمز کارت نادرست است',
222
            40 => 'عمل درخواستی پشتیبانی نمی شود',
223
            57 => 'انجام تراکنش مورد درخواست توسط پایانه انجام دهنده مجاز نمی باشد',
224
            58 => 'انجام تراکنش مورد درخواست توسط پایانه انجام دهنده مجاز نمی باشد',
225
//            63 => 'تمهیدات امنیتی نقض گردیده است',
226
            96 => 'قوانین سامانه نقض گردیده است ، خطای داخلی سامانه',
227
            2 => 'تراکنش قبال برگشت شده است',
228
            54 => 'تاریخ انقضا کارت سررسید شده است',
229
            62 => 'کارت محدود شده است',
230
            75 => 'تعداد دفعات ورود رمز اشتباه از حد مجاز فراتر رفته است',
231
            14 => 'اطالعات کارت صحیح نمی باشد',
232
            51 => 'موجودی حساب کافی نمی باشد',
233
            56 => 'اطالعات کارت یافت نشد',
234
            61 => 'مبلغ تراکنش بیش از حد مجاز است',
235
            65 => 'تعداد دفعات انجام تراکنش بیش از حد مجاز است',
236
            78 => 'کارت فعال نیست',
237
            79 => 'حساب متصل به کارت بسته یا دارای اشکال است',
238
            42 => 'کارت یا حساب مبدا در وضعیت پذیرش نمی باشد',
239
//            42 => 'کارت یا حساب مقصد در وضعیت پذیرش نمی باشد',
240
            31 => 'عدم تطابق کد ملی خریدار با دارنده کارت',
241
            98 => 'سقف استفاده از رمز دوم ایستا به پایان رسیده است',
242
            901 => 'درخواست نا معتبر است )Tokenization(',
243
            902 => 'پارامترهای اضافی درخواست نامعتبر می باشد )Tokenization(',
244
            903 => 'شناسه پرداخت نامعتبر می باشد )Tokenization(',
245
            904 => 'اطالعات مرتبط با قبض نا معتبر می باشد )Tokenization(',
246
            905 => 'شناسه درخواست نامعتبر می باشد )Tokenization(',
247
            906 => 'درخواست تاریخ گذشته است )Tokenization(',
248
            907 => 'آدرس بازگشت نتیجه پرداخت نامعتبر می باشد )Tokenization(',
249
            909 => 'پذیرنده نامعتبر می باشد)Tokenization(',
250
            910 => 'پارامترهای مورد انتظار پرداخت تسهیمی تامین نگردیده است)Tokenization(',
251
            911 => 'پارامترهای مورد انتظار پرداخت تسهیمی نا معتبر یا دارای اشکال می باشد)Tokenization(',
252
            912 => 'تراکنش درخواستی برای پذیرنده فعال نیست )Tokenization(',
253
            913 => 'تراکنش تسهیم برای پذیرنده فعال نیست )Tokenization(',
254
            914 => 'آدرس آی پی دریافتی درخواست نا معتبر می باشد',
255
            915 => 'شماره پایانه نامعتبر می باشد )Tokenization(',
256
            916 => 'شماره پذیرنده نا معتبر می باشد )Tokenization(',
257
            917 => 'نوع تراکنش اعالم شده در خواست نا معتبر می باشد )Tokenization(',
258
            918 => 'پذیرنده فعال نیست)Tokenization(',
259
            919 => 'مبالغ تسهیمی ارائه شده با توجه به قوانین حاکم بر وضعیت تسهیم پذیرنده ، نا معتبر است )Tokenization(',
260
            920 => 'شناسه نشانه نامعتبر می باشد',
261
            921 => 'شناسه نشانه نامعتبر و یا منقضی شده است',
262
            922 => 'نقض امنیت درخواست )Tokenization(',
263
            923 => 'ارسال شناسه پرداخت در تراکنش قبض مجاز نیست)Tokenization(',
264
            928 => 'مبلغ مبادله شده نا معتبر می باشد)Tokenization(',
265
            929 => 'شناسه پرداخت ارائه شده با توجه به الگوریتم متناظر نا معتبر می باشد)Tokenization(',
266
            930 => 'کد ملی ارائه شده نا معتبر می باشد)Tokenization('
267
        ];
268
        if (array_key_exists($status, $translations)) {
269
            throw new InvalidPaymentException($translations[$status], (int)$status);
270
        } else {
271
            throw new InvalidPaymentException('خطای ناشناخته ای رخ داده است.', (int)$status);
272
        }
273
    }
274
}
275