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 $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; } }