148 lines
6.2 KiB
PHP
148 lines
6.2 KiB
PHP
<?php
|
|
// ============================================================
|
|
// webhook_sms/webhook.php — مستقبِل الرسائل الواردة
|
|
//
|
|
// تطبيق أندرويد على هاتف يحمل رقمنا الثابت يوجّه كل رسالة تصله إلى
|
|
// هنا. الرسائل نوعان ولكلٍّ مساره:
|
|
// • إشعار دفع (Orange Money وأخواته) — النمط الأصلي
|
|
// • طلب رحلة من راكب بلا إنترنت — بند 3.1 من دراسة الفرص
|
|
//
|
|
// الفرز أولاً ثم التوجيه: خلط المسارين في نمط واحد كان سيجعل كل
|
|
// إضافة نمط جديد تخاطر بكسر الآخر.
|
|
// ============================================================
|
|
|
|
header('Content-Type: application/json; charset=utf-8');
|
|
|
|
require_once __DIR__ . '/../core/bootstrap.php';
|
|
require_once __DIR__ . '/../sms/ride_request.php';
|
|
|
|
// !! تأكد أن هذا المفتاح يطابق المفتاح في تطبيق الأندرويد !!
|
|
//define('SECRET_KEY', 'YOUR_SUPER_SECRET_KEY_123__');
|
|
$secretKeyPath = getenv('WEBHOOK_SECRET_KEY_PATH');
|
|
$secretKey = '';
|
|
if ($secretKeyPath && file_exists($secretKeyPath)) {
|
|
$secretKey = trim(file_get_contents($secretKeyPath));
|
|
}
|
|
if (empty($secretKey)) {
|
|
$secretKey = getenv('WEBHOOK_SECRET_KEY') ?: '';
|
|
}
|
|
|
|
// --- 1. التحقق من صحة الطلب ---
|
|
$authHeader = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
|
|
if (empty($secretKey) || !hash_equals('Bearer ' . $secretKey, $authHeader)) {
|
|
http_response_code(403);
|
|
echo json_encode(['status' => 'error', 'message' => 'Unauthorized Access']);
|
|
exit();
|
|
}
|
|
|
|
// --- 2. قراءة البيانات المرسلة ---
|
|
$json_data = file_get_contents('php://input');
|
|
$data = json_decode($json_data, true);
|
|
|
|
if ($data === null || !isset($data['sender']) || !isset($data['message'])) {
|
|
http_response_code(400);
|
|
echo json_encode(['status' => 'error', 'message' => 'Invalid data received']);
|
|
exit();
|
|
}
|
|
|
|
// --- 3. استخراج البيانات والتحضير للمعالجة ---
|
|
$sender = $data['sender'];
|
|
$message_body = $data['message'];
|
|
$received_at = date('Y-m-d H:i:s');
|
|
$log_entry = "[$received_at] From: $sender | Message: $message_body";
|
|
|
|
// --- 3.5 الفرز والتوجيه ---------------------------------------
|
|
// نحفظ الوارد الخام دائماً قبل أي تحليل. المحلّل سيخطئ في البداية
|
|
// حتماً (لهجات، أخطاء إملائية، صيغ لم نتوقّعها)، وبلا الخام لن نعرف
|
|
// لماذا أخطأ ولا كيف نحسّنه.
|
|
$senderNorm = smsNormalizePhone((string) $sender);
|
|
$inboxId = null;
|
|
$isRide = smsLooksLikeRideRequest((string) $message_body);
|
|
|
|
try {
|
|
$con = Database::get('main');
|
|
|
|
$ins = $con->prepare("
|
|
INSERT INTO sms_inbox (sender, sender_norm, body, intent)
|
|
VALUES (?, ?, ?, ?)
|
|
");
|
|
$ins->execute([
|
|
mb_substr((string) $sender, 0, 32),
|
|
$senderNorm,
|
|
(string) $message_body,
|
|
$isRide ? 'ride' : 'payment',
|
|
]);
|
|
$inboxId = (int) $con->lastInsertId();
|
|
} catch (Throwable $e) {
|
|
error_log('[sms] تعذّر حفظ الوارد: ' . $e->getMessage());
|
|
$con = null;
|
|
}
|
|
|
|
if ($con && $isRide) {
|
|
// معالجة فورية لا مؤجَّلة للكرون: الراكب واقف ينتظر رداً، ودقيقة
|
|
// تأخير في قناة كهذه تعني أنه ظنّ أن الرقم لا يعمل. الكرون يبقى
|
|
// شبكة أمان لما يفشل هنا فقط.
|
|
$request = smsIntakeRideMessage($con, $senderNorm, (string) $message_body, $inboxId);
|
|
if ($request) {
|
|
smsProcessRequest($con, $request);
|
|
}
|
|
|
|
$log_entry .= ' | ROUTED: ride request' . PHP_EOL;
|
|
$logDir = __DIR__ . '/../../logs';
|
|
if (!is_dir($logDir)) @mkdir($logDir, 0750, true);
|
|
@file_put_contents($logDir . '/sms_webhook_log.txt', $log_entry, FILE_APPEND);
|
|
|
|
http_response_code(200);
|
|
echo json_encode(['status' => 'success', 'message' => 'Ride request processed'],
|
|
JSON_UNESCAPED_UNICODE);
|
|
exit();
|
|
}
|
|
|
|
// --- 4. تحليل الرسالة (يركز على Orange Money فقط حالياً) ---
|
|
|
|
// تعريف المتغيرات التي سنستخرجها
|
|
$amount = 0;
|
|
$payer_phone = null;
|
|
$currency = null;
|
|
|
|
// النمط الوحيد الفعّال حالياً: لرسائل Orange Money الأردنية
|
|
$pattern_orangemoney_jo = '/تم استقبال حوالة مالية من (\d+)\s+من مزود الخدمة:\s+Orange Money إلى محفظتك بمبلغ ([\d,.]+)\s+دينار/';
|
|
|
|
/*
|
|
// أنماط أخرى يمكن تفعيلها لاحقاً
|
|
// $pattern_chambank = '/حوالة واردة خارجية بمبلغ\s+([\d,.]+)\s+ليرة سورية/';
|
|
// $pattern_wallet_syr = '/تم استلام مبلغ ([\d,.]+) ل\.س من الرقم (09\d{8})/';
|
|
*/
|
|
|
|
if (preg_match($pattern_orangemoney_jo, $message_body, $matches)) {
|
|
// --- تطابق نمط Orange Money الأردني ---
|
|
$payer_phone = $matches[1];
|
|
$amount_str = $matches[2];
|
|
$amount = (float) str_replace(',', '', $amount_str);
|
|
$currency = 'JOD'; // دينار أردني
|
|
|
|
$log_entry .= " | MATCH: Orange Money JO | SUCCESS: Parsed Amount = $amount, Payer Phone = $payer_phone, Currency = $currency" . PHP_EOL;
|
|
|
|
// TODO: اكتب منطق قاعدة البيانات هنا
|
|
/*
|
|
- ابحث عن معاملة "pending" تطابق المبلغ $amount ورقم الهاتف $payer_phone.
|
|
- $sql = "UPDATE transactions SET status = 'completed' WHERE amount = ? AND phone_number = ? AND currency = 'JOD' AND status = 'pending' LIMIT 1";
|
|
*/
|
|
|
|
} else {
|
|
// إذا لم تتطابق الرسالة مع نمط Orange Money
|
|
$log_entry .= " | INFO: Message did not match the Orange Money pattern. Ignored." . PHP_EOL;
|
|
}
|
|
|
|
// كتابة كل شيء في ملف السجل (بالمسار المطلق)
|
|
$logDir = __DIR__ . '/../../logs';
|
|
if (!is_dir($logDir)) @mkdir($logDir, 0750, true);
|
|
file_put_contents($logDir . '/sms_webhook_log.txt', $log_entry, FILE_APPEND);
|
|
|
|
|
|
// --- 5. إرسال رد إلى تطبيق الأندرويد ---
|
|
http_response_code(200);
|
|
echo json_encode(['status' => 'success', 'message' => 'Data received and processed.']);
|
|
?>
|
|
|