Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1dc5ccc11d | ||
|
|
cf748dfd7c | ||
|
|
de06d1cd75 |
@@ -37,8 +37,18 @@ try {
|
|||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
$logs = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
$logs = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
// Decrypt names or just return them
|
// Decrypt names since they are encrypted in the passengers table
|
||||||
// (Names are not encrypted in this schema, only phones are, so we can return directly)
|
foreach ($logs as &$log) {
|
||||||
|
if (!empty($log['first_name'])) {
|
||||||
|
$decName = $encryptionHelper->decryptData($log['first_name']);
|
||||||
|
if ($decName) $log['first_name'] = $decName;
|
||||||
|
}
|
||||||
|
if (!empty($log['last_name'])) {
|
||||||
|
$decName = $encryptionHelper->decryptData($log['last_name']);
|
||||||
|
if ($decName) $log['last_name'] = $decName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unset($log);
|
||||||
|
|
||||||
// Aggregate statistics for Dashboard charts
|
// Aggregate statistics for Dashboard charts
|
||||||
$sqlStats = "SELECT message_type, COUNT(*) as count
|
$sqlStats = "SELECT message_type, COUNT(*) as count
|
||||||
|
|||||||
@@ -74,17 +74,23 @@ try {
|
|||||||
$allPassengers = $stmtTarget->fetchAll(PDO::FETCH_ASSOC);
|
$allPassengers = $stmtTarget->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
$targets = [];
|
$targets = [];
|
||||||
|
$debugCounts = ['JO' => 0, 'SY' => 0, 'EG' => 0, 'IQ' => 0, 'UNKNOWN' => 0, 'DECRYPT_FAIL' => 0];
|
||||||
foreach ($allPassengers as $p) {
|
foreach ($allPassengers as $p) {
|
||||||
$decryptedPhone = $encryptionHelper->decryptData($p['phone']);
|
$decryptedPhone = $encryptionHelper->decryptData($p['phone']);
|
||||||
if (!$decryptedPhone) continue;
|
if (!$decryptedPhone) {
|
||||||
|
$debugCounts['DECRYPT_FAIL']++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
$cleanPhone = preg_replace('/[^0-9]/', '', $decryptedPhone);
|
$cleanPhone = preg_replace('/[^0-9]/', '', $decryptedPhone);
|
||||||
$pCountry = '';
|
$pCountry = 'UNKNOWN';
|
||||||
if (strpos($cleanPhone, '962') === 0 || strpos($cleanPhone, '07') === 0) $pCountry = 'JO';
|
if (strpos($cleanPhone, '962') === 0 || strpos($cleanPhone, '07') === 0) $pCountry = 'JO';
|
||||||
elseif (strpos($cleanPhone, '963') === 0 || (strpos($cleanPhone, '09') === 0 && strlen($cleanPhone) == 10)) $pCountry = 'SY';
|
elseif (strpos($cleanPhone, '963') === 0 || (strpos($cleanPhone, '09') === 0 && strlen($cleanPhone) == 10)) $pCountry = 'SY';
|
||||||
elseif (strpos($cleanPhone, '20') === 0 || (strpos($cleanPhone, '01') === 0 && strlen($cleanPhone) == 11)) $pCountry = 'EG';
|
elseif (strpos($cleanPhone, '20') === 0 || (strpos($cleanPhone, '01') === 0 && strlen($cleanPhone) == 11)) $pCountry = 'EG';
|
||||||
elseif (strpos($cleanPhone, '964') === 0) $pCountry = 'IQ';
|
elseif (strpos($cleanPhone, '964') === 0) $pCountry = 'IQ';
|
||||||
|
|
||||||
|
$debugCounts[$pCountry]++;
|
||||||
|
|
||||||
if ($pCountry === strtoupper($countryCode)) {
|
if ($pCountry === strtoupper($countryCode)) {
|
||||||
$targets[] = ['passenger_id' => $p['passenger_id'], 'decrypted_phone' => $decryptedPhone];
|
$targets[] = ['passenger_id' => $p['passenger_id'], 'decrypted_phone' => $decryptedPhone];
|
||||||
}
|
}
|
||||||
@@ -124,32 +130,39 @@ try {
|
|||||||
$stmtToken->execute([':pid' => $passengerId]);
|
$stmtToken->execute([':pid' => $passengerId]);
|
||||||
$fcmToken = $stmtToken->fetchColumn();
|
$fcmToken = $stmtToken->fetchColumn();
|
||||||
|
|
||||||
|
$pushSent = false;
|
||||||
if ($fcmToken) {
|
if ($fcmToken) {
|
||||||
// Send FCM Push Notification (Free channel - no anti-spam restriction needed)
|
$decryptedToken = $encryptionHelper->decryptData($fcmToken);
|
||||||
$fcmData = [
|
if ($decryptedToken) {
|
||||||
'type' => 'marketing_campaign',
|
// Send FCM Push Notification (Free channel - no anti-spam restriction needed)
|
||||||
'promo_code' => $promoCode,
|
$fcmData = [
|
||||||
'discount' => (string)$discountVal
|
'type' => 'marketing_campaign',
|
||||||
];
|
'promo_code' => $promoCode,
|
||||||
|
'discount' => (string)$discountVal
|
||||||
|
];
|
||||||
|
|
||||||
$fcmResult = sendFcmNotification(
|
$fcmResult = sendFcmNotification(
|
||||||
$fcmToken,
|
$decryptedToken,
|
||||||
$pushTitle,
|
$pushTitle,
|
||||||
$pushBody,
|
$pushBody,
|
||||||
$fcmData,
|
$fcmData,
|
||||||
'Marketing',
|
'Marketing',
|
||||||
'notification'
|
'notification'
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($fcmResult['status'] === 'success') {
|
if ($fcmResult['status'] === 'success') {
|
||||||
$sentFcm++;
|
$sentFcm++;
|
||||||
// Log campaign dispatch
|
// Log campaign dispatch
|
||||||
$logStmt = $con->prepare("INSERT INTO marketing_campaigns_log (passenger_id, message_type, country_code, region_name, triggered_by) VALUES (?, 'push', ?, ?, 'autopilot')");
|
$logStmt = $con->prepare("INSERT INTO marketing_campaigns_log (passenger_id, message_type, country_code, region_name, triggered_by) VALUES (?, 'push', ?, ?, 'autopilot')");
|
||||||
$logStmt->execute([$passengerId, $countryCode, $regionName]);
|
$logStmt->execute([$passengerId, $countryCode, $regionName]);
|
||||||
$dispatchedPassengers[] = $passengerId;
|
$dispatchedPassengers[] = $passengerId;
|
||||||
|
$pushSent = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
// Churned user (Deleted the app / No token) -> Send WhatsApp or SMS
|
|
||||||
|
if (!$pushSent) {
|
||||||
|
// Fallback: Churned user (No token) OR Push failed -> Send WhatsApp or SMS
|
||||||
// Check anti-spam first to prevent unnecessary marketing cost
|
// Check anti-spam first to prevent unnecessary marketing cost
|
||||||
if ($spamCount === 0) {
|
if ($spamCount === 0) {
|
||||||
// Fetch and decrypt passenger phone number
|
// Fetch and decrypt passenger phone number
|
||||||
@@ -206,7 +219,13 @@ try {
|
|||||||
'whatsapp_sent_count' => $sentWhatsApp,
|
'whatsapp_sent_count' => $sentWhatsApp,
|
||||||
'sms_sent_count' => $sentSms
|
'sms_sent_count' => $sentSms
|
||||||
],
|
],
|
||||||
'total_dispatched' => count($dispatchedPassengers)
|
'total_dispatched' => count($dispatchedPassengers),
|
||||||
|
'debug_info' => [
|
||||||
|
'requested_country' => $countryCode,
|
||||||
|
'total_passengers_in_db' => count($allPassengers),
|
||||||
|
'matched_targets' => count($targets),
|
||||||
|
'distribution' => $debugCounts
|
||||||
|
]
|
||||||
]);
|
]);
|
||||||
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
|
|||||||
@@ -53,6 +53,32 @@ class EncryptionHelper
|
|||||||
$decoded = base64_decode($cipherText, true);
|
$decoded = base64_decode($cipherText, true);
|
||||||
if ($decoded === false) return false;
|
if ($decoded === false) return false;
|
||||||
|
|
||||||
|
// محاولة أولى: استخراج IV عشوائي من أول 16 بايت (كما كان في encrypt_decrypt.php)
|
||||||
|
if (strlen($decoded) >= 16) {
|
||||||
|
$iv = substr($decoded, 0, 16);
|
||||||
|
$payload = substr($decoded, 16);
|
||||||
|
if (strlen($payload) > 0) {
|
||||||
|
$decrypted_rand = openssl_decrypt($payload, self::ALGO_CBC, $this->key, OPENSSL_RAW_DATA, $iv);
|
||||||
|
if ($decrypted_rand !== false) {
|
||||||
|
$pad = ord($decrypted_rand[strlen($decrypted_rand) - 1]);
|
||||||
|
if ($pad >= 1 && $pad <= 16) {
|
||||||
|
// Check if padding is valid
|
||||||
|
$isValidPad = true;
|
||||||
|
for ($i = 1; $i <= $pad; $i++) {
|
||||||
|
if (ord($decrypted_rand[strlen($decrypted_rand) - $i]) !== $pad) {
|
||||||
|
$isValidPad = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($isValidPad) {
|
||||||
|
return substr($decrypted_rand, 0, -$pad);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// محاولة ثانية: IV ثابت
|
||||||
$decrypted = openssl_decrypt($decoded, self::ALGO_CBC, $this->key, OPENSSL_RAW_DATA, $this->cbcIv);
|
$decrypted = openssl_decrypt($decoded, self::ALGO_CBC, $this->key, OPENSSL_RAW_DATA, $this->cbcIv);
|
||||||
if ($decrypted === false) return false;
|
if ($decrypted === false) return false;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user