time(), 'error' => null, 'time' => null, 'response' => null ]; // Validate URL $sanitizedUrl = validateUrl($url); if (!$sanitizedUrl) { $response_data['error'] = 'Invalid URL'; return $response_data; } // Initialize cURL with safe options $curl = curl_init(); curl_setopt_array($curl, [ CURLOPT_URL => $sanitizedUrl, CURLOPT_RETURNTRANSFER => true, CURLOPT_HEADER => false, CURLOPT_FOLLOWLOCATION => true, CURLOPT_MAXREDIRS => 3, CURLOPT_TIMEOUT => 10, CURLOPT_CONNECTTIMEOUT => 5, CURLOPT_SSL_VERIFYPEER => true, CURLOPT_SSL_VERIFYHOST => 2 ]); // Execute request $response = curl_exec($curl); // Check for cURL errors if ($response === false) { $response_data['error'] = curl_error($curl); } else { // Get connection info $info = curl_getinfo($curl); $response_data['time'] = round($info['total_time_us'] / 1000, 2); $response_data['response'] = $info['http_code']; } // Close cURL resource curl_close($curl); return $response_data; } /** * Safely write monitor data * * @param string $name Monitor name * @param array $newData New response data */ function writeMonitorData($name, $newData) { // Validate monitor name (prevent path traversal) if (!preg_match('/^[a-zA-Z0-9_-]+$/', $name)) { error_log("Invalid monitor name: $name"); return; } $monitorFile = PATH . '/monitors/' . $name; // Read existing data $data = []; if (file_exists($monitorFile)) { $fileContent = file_get_contents($monitorFile); $data = json_decode($fileContent, true) ?: []; } // Merge and limit historical data $data[] = $newData; $data = array_slice($data, -MAX_HISTORY_RECORDS); // Securely write file $jsonData = json_encode($data, JSON_PRETTY_PRINT); if (file_put_contents($monitorFile, $jsonData) === false) { error_log("Failed to write monitor data for: $name"); } } // Main monitoring loop foreach ($monitors as $name => $url) { try { $responseData = fetchWebsiteResponse($url); writeMonitorData($name, $responseData); } catch (Exception $e) { error_log("Monitoring error for $name: " . $e->getMessage()); } }