154 lines
5.8 KiB
PHP
154 lines
5.8 KiB
PHP
<?php
|
|||
|
|
|
||
|
|
namespace App\Services;
|
||
|
|
|
||
|
|
class JibitIdentityService
|
||
|
|
{
|
||
|
|
/**
|
||
|
|
* @param mixed $response
|
||
|
|
* @return array{ok: bool, code: string, message: string}
|
||
|
|
*/
|
||
|
|
public static function interpretNationalMobileMatch($response): array
|
||
|
|
{
|
||
|
|
if (! is_array($response) || $response === []) {
|
||
|
|
return [
|
||
|
|
'ok' => false,
|
||
|
|
'code' => 'jibit_no_response',
|
||
|
|
'message' => 'پاسخ سرویس احراز هویت دریافت نشد. اتصال سرور به جیبیت یا توکن را بررسی کنید.',
|
||
|
|
];
|
||
|
|
}
|
||
|
|
|
||
|
|
if (array_key_exists('matched', $response) && self::isTruthyMatch($response['matched'])) {
|
||
|
|
return [
|
||
|
|
'ok' => true,
|
||
|
|
'code' => 'jibit_matched',
|
||
|
|
'message' => '',
|
||
|
|
];
|
||
|
|
}
|
||
|
|
|
||
|
|
if (array_key_exists('matched', $response) && self::isFalseyMatch($response['matched'])) {
|
||
|
|
return [
|
||
|
|
'ok' => false,
|
||
|
|
'code' => 'jibit_mismatch',
|
||
|
|
'message' => 'کد ملی و شماره موبایل در سامانه شاهکار مطابقت ندارند. سیمکارت باید به نام صاحب همین کد ملی باشد.',
|
||
|
|
];
|
||
|
|
}
|
||
|
|
|
||
|
|
$apiCode = strtolower(trim((string) ($response['code'] ?? $response['errorCode'] ?? '')));
|
||
|
|
$mapped = self::mapApiCode($apiCode);
|
||
|
|
if ($mapped !== null) {
|
||
|
|
return [
|
||
|
|
'ok' => false,
|
||
|
|
'code' => $apiCode !== '' ? 'jibit_'.$apiCode : 'jibit_error',
|
||
|
|
'message' => $mapped,
|
||
|
|
];
|
||
|
|
}
|
||
|
|
|
||
|
|
$detail = trim(implode(' — ', array_filter([
|
||
|
|
$apiCode !== '' ? 'کد جیبیت: '.$apiCode : '',
|
||
|
|
self::stringifyApiMessage($response),
|
||
|
|
isset($response['http_status']) ? 'وضعیت HTTP: '.$response['http_status'] : '',
|
||
|
|
], fn ($part) => $part !== '' && $part !== null)));
|
||
|
|
|
||
|
|
return [
|
||
|
|
'ok' => false,
|
||
|
|
'code' => $apiCode !== '' ? 'jibit_'.$apiCode : 'jibit_unknown',
|
||
|
|
'message' => 'احراز هویت از طرف جیبیت تأیید نشد'
|
||
|
|
.($detail !== '' ? ' ('.$detail.')' : '.')
|
||
|
|
.' اطلاعات پروفایل ذخیره شد؛ تا تأیید مدیر امکان معامله نیست.',
|
||
|
|
];
|
||
|
|
}
|
||
|
|
|
||
|
|
public static function nationalCodeError(?string $nCode): ?string
|
||
|
|
{
|
||
|
|
$digits = preg_replace('/\D+/', '', (string) $nCode) ?? '';
|
||
|
|
if ($digits === '') {
|
||
|
|
return 'کد ملی وارد نشده است.';
|
||
|
|
}
|
||
|
|
if (strlen($digits) !== 10) {
|
||
|
|
return 'کد ملی باید ۱۰ رقم باشد.';
|
||
|
|
}
|
||
|
|
if (! self::isValidIranianNationalCode($digits)) {
|
||
|
|
return 'کد ملی از نظر رقم کنترل نامعتبر است.';
|
||
|
|
}
|
||
|
|
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
public static function isValidIranianNationalCode(string $digits): bool
|
||
|
|
{
|
||
|
|
if (! preg_match('/^\d{10}$/', $digits)) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
if (preg_match('/^(\d)\1{9}$/', $digits)) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
$sum = 0;
|
||
|
|
for ($i = 0; $i < 9; $i++) {
|
||
|
|
$sum += (int) $digits[$i] * (10 - $i);
|
||
|
|
}
|
||
|
|
$remainder = $sum % 11;
|
||
|
|
$check = (int) $digits[9];
|
||
|
|
|
||
|
|
return $remainder < 2 ? $check === $remainder : $check === (11 - $remainder);
|
||
|
|
}
|
||
|
|
|
||
|
|
private static function isTruthyMatch($value): bool
|
||
|
|
{
|
||
|
|
return $value === true || $value === 1 || $value === '1' || $value === 'true';
|
||
|
|
}
|
||
|
|
|
||
|
|
private static function isFalseyMatch($value): bool
|
||
|
|
{
|
||
|
|
return $value === false || $value === 0 || $value === '0' || $value === 'false';
|
||
|
|
}
|
||
|
|
|
||
|
|
private static function mapApiCode(string $apiCode): ?string
|
||
|
|
{
|
||
|
|
return match ($apiCode) {
|
||
|
|
'forbidden', 'unauthorized', 'unauthenticated' => 'اتصال به جیبیت مجاز نیست (توکن یا کلید API). با پشتیبانی فنی بررسی کنید.',
|
||
|
|
'empty_response', 'token_failed' => 'سرویس احراز هویت پاسخ معتبر نداد. چند دقیقه دیگر دوباره تلاش کنید.',
|
||
|
|
'too_many_requests', 'rate_limit', 'rate.limit' => 'تعداد استعلام احراز هویت بیش از حد مجاز است. کمی بعد دوباره تلاش کنید.',
|
||
|
|
'invalid_national_code', 'nationalcode.invalid', 'national_code.invalid' => 'کد ملی از نظر سرویس احراز هویت نامعتبر است.',
|
||
|
|
'invalid_mobile_number', 'mobilenumber.invalid', 'mobile.invalid' => 'شماره موبایل از نظر سرویس احراز هویت نامعتبر است.',
|
||
|
|
default => null,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @param array<string, mixed> $response
|
||
|
|
*/
|
||
|
|
private static function stringifyApiMessage(array $response): string
|
||
|
|
{
|
||
|
|
$message = $response['message'] ?? null;
|
||
|
|
if (is_string($message) && trim($message) !== '') {
|
||
|
|
return self::sanitizeDetail($message);
|
||
|
|
}
|
||
|
|
|
||
|
|
$errors = $response['errors'] ?? null;
|
||
|
|
if (is_array($errors)) {
|
||
|
|
foreach ($errors as $value) {
|
||
|
|
if (is_string($value) && trim($value) !== '') {
|
||
|
|
return self::sanitizeDetail($value);
|
||
|
|
}
|
||
|
|
if (is_array($value) && isset($value[0]) && is_string($value[0]) && trim($value[0]) !== '') {
|
||
|
|
return self::sanitizeDetail($value[0]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return '';
|
||
|
|
}
|
||
|
|
|
||
|
|
private static function sanitizeDetail(string $text): string
|
||
|
|
{
|
||
|
|
$plain = trim(html_entity_decode(strip_tags($text), ENT_QUOTES | ENT_HTML5, 'UTF-8'));
|
||
|
|
if (mb_strlen($plain) > 180) {
|
||
|
|
$plain = mb_substr($plain, 0, 180).'…';
|
||
|
|
}
|
||
|
|
|
||
|
|
return $plain;
|
||
|
|
}
|
||
|
|
}
|