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
Unused Code
introduced
by
![]() |
|||||||
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
![]() 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
![]() |
|||||||
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
![]() 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
![]() |
|||||||
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 |