server_type === 'ip') { $result = $this->pingServer($server->ip_address); $isOnline = $result['online']; $responseTime = $result['response_time']; } else { // For subdomains, try HTTP first, then fallback to ping if HTTP fails $result = $this->httpCheck($server->ip_address); $isOnline = $result['online']; $responseTime = $result['response_time']; // If HTTP fails, try ping as fallback for subdomains if (!$isOnline) { Log::info('HTTP check failed for subdomain, trying ping as fallback: ' . $server->ip_address); $pingResult = $this->pingServer($server->ip_address); if ($pingResult['online']) { $isOnline = true; $responseTime = $pingResult['response_time']; Log::info('Ping fallback successful for subdomain: ' . $server->ip_address); } } } $endTime = microtime(true); $totalTime = round(($endTime - $startTime) * 1000, 2); return [ 'online' => $isOnline, 'response_time' => $responseTime, 'check_time' => $totalTime, ]; } catch (\Exception $e) { Log::error('Uptime check failed for server: ' . $server->name, [ 'error' => $e->getMessage(), 'server_id' => $server->id, 'server_type' => $server->server_type, 'ip_address' => $server->ip_address, ]); return [ 'online' => false, 'response_time' => null, 'check_time' => null, ]; } } /** * Ping an IP address or domain */ private function pingServer(string $ip): array { $command = "ping -c 1 -W 5 " . escapeshellarg($ip) . " 2>&1"; $output = shell_exec($command); if (preg_match('/time=(\d+\.?\d*)\s*ms/', $output, $matches)) { return [ 'online' => true, 'response_time' => (int) $matches[1], ]; } return [ 'online' => false, 'response_time' => null, ]; } /** * Check HTTP response for subdomains */ private function httpCheck(string $domain): array { try { // Remove any protocol prefix if present $cleanDomain = preg_replace('/^https?:\/\//', '', $domain); // Try HTTP first $response = Http::timeout(10) ->withHeaders([ 'User-Agent' => 'Paymenter-UptimeLab/1.0', 'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', ]) ->get('http://' . $cleanDomain); if ($response->successful()) { $responseTime = $this->calculateResponseTime($response); return [ 'online' => true, 'response_time' => $responseTime, ]; } // If HTTP fails, try HTTPS $httpsResponse = Http::timeout(10) ->withHeaders([ 'User-Agent' => 'Paymenter-UptimeLab/1.0', 'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', ]) ->get('https://' . $cleanDomain); if ($httpsResponse->successful()) { $responseTime = $this->calculateResponseTime($httpsResponse); return [ 'online' => true, 'response_time' => $responseTime, ]; } // If both HTTP and HTTPS fail, check if domain resolves if (gethostbyname($cleanDomain) !== $cleanDomain) { // Domain resolves but HTTP/HTTPS failed return [ 'online' => false, 'response_time' => null, ]; } // Domain doesn't resolve return [ 'online' => false, 'response_time' => null, ]; } catch (\Exception $e) { Log::warning('HTTP check failed for domain: ' . $domain, [ 'error' => $e->getMessage(), 'domain' => $domain, ]); // Try DNS resolution as fallback if (gethostbyname($cleanDomain) !== $cleanDomain) { return [ 'online' => false, // Domain resolves but HTTP failed 'response_time' => null, ]; } return [ 'online' => false, 'response_time' => null, ]; } } /** * Calculate response time from HTTP response */ private function calculateResponseTime($response): ?int { try { // Try to get response time from handler stats if (method_exists($response, 'handlerStats')) { $stats = $response->handlerStats(); if (isset($stats['total_time_us'])) { return (int) ($stats['total_time_us'] / 1000); // Convert to milliseconds } } // Fallback: estimate response time based on current time return null; } catch (\Exception $e) { return null; } } /** * Update server status */ public function updateServerStatus(UptimeServer $server, array $checkResult): void { $wasOnline = $server->status === 'online'; $isOnline = $checkResult['online']; $server->update([ 'status' => $isOnline ? 'online' : 'offline', 'last_check' => now(), 'response_time' => $checkResult['response_time'], ]); // Update last online/offline timestamps if ($isOnline && !$wasOnline) { $server->update(['last_online' => now()]); } elseif (!$isOnline && $wasOnline) { $server->update(['last_offline' => now()]); } // Calculate uptime percentage (simplified calculation) $this->calculateUptimePercentage($server); } /** * Calculate uptime percentage */ private function calculateUptimePercentage(UptimeServer $server): void { // Calculate uptime based on server status and monitoring history $now = now(); $uptimePercentage = 0; if ($server->status === 'online') { // Server is currently online if ($server->last_offline) { // Server has been offline before, calculate based on recent performance $lastOfflineTime = $server->last_offline; $timeSinceOffline = $now->diffInHours($lastOfflineTime); if ($timeSinceOffline > 24) { // If server has been online for more than 24 hours, give high uptime $uptimePercentage = 99.5; } elseif ($timeSinceOffline > 12) { // If server has been online for more than 12 hours $uptimePercentage = 98.0; } elseif ($timeSinceOffline > 6) { // If server has been online for more than 6 hours $uptimePercentage = 96.0; } elseif ($timeSinceOffline > 1) { // If server has been online for more than 1 hour $uptimePercentage = 92.0; } else { // Server just came back online $uptimePercentage = 85.0; } } else { // Server has never been offline (new server or always online) $uptimePercentage = 99.9; } } else { // Server is currently offline if ($server->last_online) { // Server was online before, calculate based on downtime $lastOnlineTime = $server->last_online; $timeSinceOnline = $now->diffInHours($lastOnlineTime); if ($timeSinceOnline < 1) { // Server just went offline $uptimePercentage = 95.0; } elseif ($timeSinceOnline < 6) { // Server has been offline for a few hours $uptimePercentage = 85.0; } elseif ($timeSinceOnline < 24) { // Server has been offline for a day $uptimePercentage = 70.0; } else { // Server has been offline for a long time $uptimePercentage = 50.0; } } else { // Server has never been online $uptimePercentage = 0.0; } } // Ensure percentage is between 0 and 100 $uptimePercentage = max(0, min(100, $uptimePercentage)); $server->update([ 'uptime_percentage' => round($uptimePercentage, 2), ]); } /** * Check all active servers */ public function checkAllServers(): void { $servers = UptimeServer::where('is_active', true)->get(); foreach ($servers as $server) { try { $checkResult = $this->checkServerStatus($server); $this->updateServerStatus($server, $checkResult); Log::info('Server status checked', [ 'server' => $server->name, 'status' => $checkResult['online'] ? 'online' : 'offline', 'response_time' => $checkResult['response_time'], 'server_type' => $server->server_type, ]); } catch (\Exception $e) { Log::error('Failed to check server: ' . $server->name, [ 'error' => $e->getMessage(), 'server_id' => $server->id, ]); } // Add a small delay between checks to avoid overwhelming the system usleep(200000); // 0.1 second delay } } }