shetabit /
multipay
| 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
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
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
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
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
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 |