2025-10-08 14:23:07 +03:00
|
|
|
#!/usr/bin/env php
|
|
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Domain Expiration Check Cron Job
|
|
|
|
|
*
|
|
|
|
|
* This script should be run periodically (recommended: daily) to check domain expirations
|
|
|
|
|
* and send notifications when domains are approaching expiration.
|
|
|
|
|
*
|
|
|
|
|
* Usage: php cron/check_domains.php
|
|
|
|
|
* Crontab: 0 9 * * * /usr/bin/php /path/to/project/cron/check_domains.php
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
require_once __DIR__ . '/../vendor/autoload.php';
|
|
|
|
|
|
|
|
|
|
use Dotenv\Dotenv;
|
|
|
|
|
use App\Models\Domain;
|
|
|
|
|
use App\Models\NotificationChannel;
|
|
|
|
|
use App\Models\NotificationLog;
|
2025-10-08 18:54:34 +03:00
|
|
|
use App\Models\Setting;
|
2025-10-08 14:23:07 +03:00
|
|
|
use App\Services\WhoisService;
|
|
|
|
|
use App\Services\NotificationService;
|
|
|
|
|
use Core\Database;
|
|
|
|
|
|
|
|
|
|
// Load environment variables
|
|
|
|
|
$dotenv = Dotenv::createImmutable(__DIR__ . '/..');
|
|
|
|
|
$dotenv->load();
|
|
|
|
|
|
|
|
|
|
// Initialize database
|
|
|
|
|
new Database();
|
|
|
|
|
|
|
|
|
|
// Initialize services
|
|
|
|
|
$domainModel = new Domain();
|
|
|
|
|
$channelModel = new NotificationChannel();
|
|
|
|
|
$logModel = new NotificationLog();
|
2025-10-08 18:54:34 +03:00
|
|
|
$settingModel = new Setting();
|
2025-10-08 14:23:07 +03:00
|
|
|
$whoisService = new WhoisService();
|
|
|
|
|
$notificationService = new NotificationService();
|
|
|
|
|
|
2025-10-08 18:54:34 +03:00
|
|
|
// Set timezone from settings
|
|
|
|
|
try {
|
|
|
|
|
$appSettings = $settingModel->getAppSettings();
|
|
|
|
|
date_default_timezone_set($appSettings['app_timezone']);
|
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
|
date_default_timezone_set('UTC');
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-08 14:23:07 +03:00
|
|
|
// Log file
|
|
|
|
|
$logFile = __DIR__ . '/../logs/cron.log';
|
|
|
|
|
|
|
|
|
|
function logMessage(string $message) {
|
|
|
|
|
global $logFile;
|
|
|
|
|
$timestamp = date('Y-m-d H:i:s');
|
|
|
|
|
file_put_contents($logFile, "[$timestamp] $message\n", FILE_APPEND);
|
|
|
|
|
echo "[$timestamp] $message\n";
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-08 18:54:34 +03:00
|
|
|
function formatElapsedTime(float $seconds): string {
|
|
|
|
|
if ($seconds < 60) {
|
|
|
|
|
return sprintf("%.2f seconds", $seconds);
|
|
|
|
|
} elseif ($seconds < 3600) {
|
|
|
|
|
$minutes = floor($seconds / 60);
|
|
|
|
|
$remainingSeconds = $seconds - ($minutes * 60);
|
|
|
|
|
return sprintf("%d minute%s %.2f seconds", $minutes, $minutes != 1 ? 's' : '', $remainingSeconds);
|
|
|
|
|
} else {
|
|
|
|
|
$hours = floor($seconds / 3600);
|
|
|
|
|
$remainingMinutes = floor(($seconds - ($hours * 3600)) / 60);
|
|
|
|
|
$remainingSeconds = $seconds - ($hours * 3600) - ($remainingMinutes * 60);
|
|
|
|
|
return sprintf("%d hour%s %d minute%s %.2f seconds", $hours, $hours != 1 ? 's' : '', $remainingMinutes, $remainingMinutes != 1 ? 's' : '', $remainingSeconds);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Record start time
|
|
|
|
|
$startTime = microtime(true);
|
|
|
|
|
|
2025-10-08 14:23:07 +03:00
|
|
|
logMessage("=== Starting domain check cron job ===");
|
|
|
|
|
|
2025-10-08 18:54:34 +03:00
|
|
|
// Get notification days from database settings
|
|
|
|
|
$notificationDays = $settingModel->getNotificationDays();
|
2025-10-08 14:23:07 +03:00
|
|
|
|
|
|
|
|
logMessage("Notification thresholds (days): " . implode(', ', $notificationDays));
|
|
|
|
|
|
|
|
|
|
// Get all active domains
|
|
|
|
|
$domains = $domainModel->where('is_active', 1);
|
|
|
|
|
logMessage("Found " . count($domains) . " active domains to check");
|
|
|
|
|
|
|
|
|
|
$stats = [
|
|
|
|
|
'checked' => 0,
|
|
|
|
|
'updated' => 0,
|
|
|
|
|
'notifications_sent' => 0,
|
|
|
|
|
'errors' => 0
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
foreach ($domains as $domain) {
|
|
|
|
|
$domainName = $domain['domain_name'];
|
|
|
|
|
logMessage("Checking domain: $domainName");
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// Refresh WHOIS data
|
|
|
|
|
$whoisData = $whoisService->getDomainInfo($domainName);
|
|
|
|
|
|
|
|
|
|
if (!$whoisData) {
|
|
|
|
|
logMessage(" ✗ Failed to get WHOIS data for $domainName");
|
|
|
|
|
$stats['errors']++;
|
|
|
|
|
|
|
|
|
|
// Update domain status to error
|
|
|
|
|
$domainModel->update($domain['id'], [
|
|
|
|
|
'status' => 'error',
|
|
|
|
|
'last_checked' => date('Y-m-d H:i:s')
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Update domain information
|
|
|
|
|
$status = $whoisService->getDomainStatus($whoisData['expiration_date'], $whoisData['status'] ?? []);
|
|
|
|
|
$domainModel->update($domain['id'], [
|
|
|
|
|
'registrar' => $whoisData['registrar'],
|
|
|
|
|
'expiration_date' => $whoisData['expiration_date'],
|
|
|
|
|
'last_checked' => date('Y-m-d H:i:s'),
|
|
|
|
|
'status' => $status,
|
|
|
|
|
'whois_data' => json_encode($whoisData)
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$stats['checked']++;
|
|
|
|
|
$stats['updated']++;
|
|
|
|
|
|
|
|
|
|
logMessage(" ✓ Updated WHOIS data for $domainName");
|
|
|
|
|
logMessage(" Expiration: {$whoisData['expiration_date']}, Status: $status");
|
|
|
|
|
|
|
|
|
|
// Check if notifications should be sent
|
|
|
|
|
$daysLeft = $whoisService->daysUntilExpiration($whoisData['expiration_date']);
|
|
|
|
|
|
|
|
|
|
if ($daysLeft === null) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check if this domain should trigger a notification
|
|
|
|
|
$shouldNotify = false;
|
|
|
|
|
$notificationType = '';
|
|
|
|
|
|
|
|
|
|
if ($daysLeft <= 0) {
|
|
|
|
|
$shouldNotify = true;
|
|
|
|
|
$notificationType = 'expired';
|
|
|
|
|
} elseif (in_array($daysLeft, $notificationDays)) {
|
|
|
|
|
$shouldNotify = true;
|
|
|
|
|
$notificationType = "expiring_in_{$daysLeft}_days";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!$shouldNotify) {
|
|
|
|
|
logMessage(" → No notification needed ($daysLeft days left)");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check if notification was already sent recently (within last 23 hours)
|
|
|
|
|
if ($logModel->wasSentRecently($domain['id'], $notificationType, 23)) {
|
|
|
|
|
logMessage(" → Notification already sent recently");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get notification channels for this domain's group
|
|
|
|
|
if (!$domain['notification_group_id']) {
|
|
|
|
|
logMessage(" → No notification group assigned");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$channels = $channelModel->getActiveByGroupId($domain['notification_group_id']);
|
|
|
|
|
|
|
|
|
|
if (empty($channels)) {
|
|
|
|
|
logMessage(" → No active notification channels configured");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
logMessage(" 📤 Sending notifications to " . count($channels) . " channel(s)");
|
|
|
|
|
|
|
|
|
|
// Refresh domain data with group info
|
|
|
|
|
$domainData = $domainModel->find($domain['id']);
|
|
|
|
|
|
|
|
|
|
// Send notifications
|
|
|
|
|
$results = $notificationService->sendDomainExpirationAlert($domainData, $channels);
|
|
|
|
|
|
|
|
|
|
foreach ($results as $result) {
|
|
|
|
|
$success = $result['success'];
|
|
|
|
|
$channel = $result['channel'];
|
|
|
|
|
|
|
|
|
|
if ($success) {
|
|
|
|
|
logMessage(" ✓ Sent to $channel");
|
|
|
|
|
$stats['notifications_sent']++;
|
|
|
|
|
} else {
|
|
|
|
|
logMessage(" ✗ Failed to send to $channel");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Log the notification attempt
|
|
|
|
|
$logModel->log(
|
|
|
|
|
$domain['id'],
|
|
|
|
|
$notificationType,
|
|
|
|
|
$channel,
|
|
|
|
|
"Domain $domainName expires in $daysLeft days",
|
|
|
|
|
$success,
|
|
|
|
|
$success ? null : "Failed to send notification"
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} catch (Exception $e) {
|
|
|
|
|
logMessage(" ✗ Error processing $domainName: " . $e->getMessage());
|
|
|
|
|
$stats['errors']++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-08 18:54:34 +03:00
|
|
|
// Update last check run timestamp
|
|
|
|
|
$settingModel->updateLastCheckRun();
|
|
|
|
|
|
|
|
|
|
// Calculate elapsed time
|
|
|
|
|
$endTime = microtime(true);
|
|
|
|
|
$elapsedTime = $endTime - $startTime;
|
|
|
|
|
$formattedTime = formatElapsedTime($elapsedTime);
|
|
|
|
|
|
2025-10-08 14:23:07 +03:00
|
|
|
// Summary
|
|
|
|
|
logMessage("\n=== Cron job completed ===");
|
|
|
|
|
logMessage("Domains checked: {$stats['checked']}");
|
|
|
|
|
logMessage("Domains updated: {$stats['updated']}");
|
|
|
|
|
logMessage("Notifications sent: {$stats['notifications_sent']}");
|
|
|
|
|
logMessage("Errors: {$stats['errors']}");
|
2025-10-08 18:54:34 +03:00
|
|
|
logMessage("Execution time: $formattedTime");
|
2025-10-08 14:23:07 +03:00
|
|
|
logMessage("==========================\n");
|
|
|
|
|
|
|
|
|
|
exit(0);
|
|
|
|
|
|