fix: Accurate Nabeh OTP response parsing and live gateway error reporting

This commit is contained in:
Hamza-Ayed
2026-08-26 23:01:25 +03:00
parent b4a241bf62
commit cee6265930
2 changed files with 72 additions and 23 deletions
+29 -7
View File
@@ -90,9 +90,35 @@ class AuthController
// 4. Send OTP via Nabeh Service
$nabeh = new NabehService();
$sent = $nabeh->sendOtp($cleanPhone, $otp, 'image', $appName);
$sendResult = $nabeh->sendOtp($cleanPhone, $otp, 'image', $appName);
$isDebug = filter_var(getenv('APP_DEBUG') ?: true, FILTER_VALIDATE_BOOLEAN);
$isDebug = filter_var(getenv('APP_DEBUG'), FILTER_VALIDATE_BOOLEAN);
if (!$sendResult['success']) {
$errorMsg = $sendResult['error'] ?? 'تعذر إرسال رمز التحقق عبر الواتساب من منصة نبيه';
if ($isDebug) {
// In debug mode, allow progression with debug OTP
$response->json([
'status' => 'success',
'message' => 'وضع التطوير نشط (تعذر الإرسال الفعلي) — الرمز: ' . $otp,
'debug_otp' => $otp,
'data' => [
'phone_masked' => substr($cleanPhone, 0, 3) . '****' . substr($cleanPhone, -3),
'expires_in' => 300,
'gateway_error' => $sendResult
]
]);
return;
}
$response->status(502)->json([
'status' => 'error',
'message' => $errorMsg,
'gateway_error' => $sendResult
]);
return;
}
$resData = [
'status' => 'success',
@@ -103,12 +129,8 @@ class AuthController
]
];
// Expose OTP only in debug mode for seamless local testing
if ($isDebug || !$sent) {
if ($isDebug) {
$resData['debug_otp'] = $otp;
if (!$sent) {
$resData['message'] = 'تم توليد رمز التحقق (بيئة التطوير / محاكاة الإرسال)';
}
}
$response->json($resData);
+43 -16
View File
@@ -18,7 +18,6 @@ class NabehService
$this->email = (string)getenv('NABEH_EMAIL');
$this->password = (string)getenv('NABEH_PASSWORD');
// Strict validation: NO fallback defaults allowed
$missing = [];
if (empty($this->authUrl)) $missing[] = 'NABEH_AUTH_URL';
if (empty($this->sendUrl)) $missing[] = 'NABEH_SEND_URL';
@@ -39,7 +38,7 @@ class NabehService
try {
$redis = RedisClient::getInstance();
$cachedToken = $redis->get('nabeh_bearer_token');
if ($cachedToken) {
if ($cachedToken && strlen((string)$cachedToken) > 20) {
return (string)$cachedToken;
}
} catch (\Exception $e) {
@@ -57,8 +56,10 @@ class NabehService
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $payload,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 15,
CURLOPT_TIMEOUT => 30,
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_SSL_VERIFYPEER => false,
]);
$response = curl_exec($ch);
@@ -101,11 +102,18 @@ class NabehService
if (!$bearerToken) {
return [
'success' => false,
'error' => 'فشل الحصول على توكن المصادقة من منصة نبيه. تأكد من صحة NABEH_EMAIL و NABEH_PASSWORD.'
'error' => 'فشل الحصول على توكن المصادقة من منصة نبيه. تأكد من صحة NABEH_EMAIL و NABEH_PASSWORD في .env.'
];
}
// Clean phone format: ensure Jordan numbers are standardized (9627XXXXXXXX)
$phoneRaw = preg_replace('/\D+/', '', $receiver);
if (str_starts_with($phoneRaw, '07')) {
$phoneRaw = '962' . substr($phoneRaw, 1);
} elseif (str_starts_with($phoneRaw, '7') && strlen($phoneRaw) === 9) {
$phoneRaw = '962' . $phoneRaw;
}
$type = in_array($method, ['text', 'voice', 'image'], true) ? $method : 'image';
// 1. First attempt with image
@@ -116,8 +124,13 @@ class NabehService
// 2. Fallback to text if image fails
if ($type === 'image') {
error_log("ℹ️ [Nabeh OTP Fallback] Image failed, retrying with text type...");
return $this->attemptSend($phoneRaw, 'text', $otp, $appName, $bearerToken);
error_log("ℹ️ [Nabeh OTP Fallback] Image failed, retrying with text type for phone {$phoneRaw}...");
$textResult = $this->attemptSend($phoneRaw, 'text', $otp, $appName, $bearerToken);
if ($textResult['success']) {
return $textResult;
}
// Return text attempt with details
return $textResult;
}
return $result;
@@ -137,7 +150,9 @@ class NabehService
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $payload,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 15,
CURLOPT_TIMEOUT => 35,
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
"Authorization: Bearer {$bearerToken}",
@@ -150,30 +165,42 @@ class NabehService
curl_close($ch);
if ($curlError) {
error_log("❌ [Nabeh OTP cURL Error] " . $curlError);
return [
'success' => false,
'error' => 'cURL Connection Error: ' . $curlError,
'response' => null
'success' => false,
'http_code' => $httpCode,
'error' => 'cURL Connection Error: ' . $curlError,
'response' => null
];
}
error_log("ℹ️ [Nabeh OTP Response (HTTP {$httpCode})] " . $response);
if ($httpCode === 200 && $response) {
$decoded = json_decode($response, true);
if ($decoded) {
$statusStr = strtolower((string)($decoded['status'] ?? ''));
$msgStr = strtolower((string)($decoded['message'] ?? ''));
$msgStr = strtolower((string)($decoded['message'] ?? ''));
$errStr = strtolower((string)($decoded['error'] ?? ''));
if (
!empty($decoded['success']) ||
in_array($statusStr, ['success', 'ok', 'true', '200', 'sent', 'queued', '1'], true) ||
($decoded['status'] ?? false) === true ||
($decoded['code'] ?? 0) === 200 ||
!empty($decoded['message_id']) ||
!empty($decoded['id']) ||
!empty($decoded['token']) ||
str_contains($msgStr, 'success') ||
str_contains($msgStr, 'sent') ||
str_contains($msgStr, 'تم')
str_contains($msgStr, 'تم') ||
str_contains($errStr, 'via gateway')
) {
return [
'success' => true,
'message' => 'تم إرسال رمز التحقق بنجاح عبر الواتساب',
'raw' => $decoded
'success' => true,
'http_code' => 200,
'message' => 'تم إرسال رمز التحقق بنجاح عبر الواتساب',
'raw' => $decoded
];
}
}
@@ -182,7 +209,7 @@ class NabehService
return [
'success' => false,
'http_code' => $httpCode,
'error' => 'Nabeh Gateway rejected OTP request',
'error' => 'Nabeh Gateway rejected request (HTTP ' . $httpCode . ')',
'response' => $response
];
}