query(" SELECT region, url FROM regions ORDER BY id ASC ")->fetchAll(); function runCheck(string $url): array { $ch = curl_init($url); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_FOLLOWLOCATION => true, CURLOPT_TIMEOUT => 10, CURLOPT_CONNECTTIMEOUT => 5, CURLOPT_NOBODY => false, CURLOPT_ENCODING => '', CURLOPT_USERAGENT => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) ' . 'AppleWebKit/605.1.15 (KHTML, like Gecko) ' . 'Version/17.0 Safari/605.1.15', ]); $start = microtime(true); curl_exec($ch); $status = curl_getinfo($ch, CURLINFO_HTTP_CODE); $error = curl_error($ch); $end = microtime(true); curl_close($ch); $rt = (int) round(($end - $start) * 1000); // default values $up = 0; $note = null; $lat = $rt; if ($error) { // cannot reach the domain at all $up = 0; $lat = null; $note = 'cannot_fetch_web'; } else { // 200–499 = server is UP if ($status >= 200 && $status < 500) { $up = 1; if ($status === 403) { $note = 'blocked_by_protection'; } elseif ($status === 429) { $note = 'too_many_requests'; } } // 500–599 = Cloudflare-style origin error / server-side error elseif ($status >= 500 && $status <= 599) { $up = 0; $note = 'cloudflare_origin_error'; } } return [ 'status' => $status, 'up' => $up, 'latency' => $lat, 'error' => $note ]; } $stmt = db()->prepare(" INSERT INTO checks ( region, monitor_url, checked_at, status_code, is_up, response_time_ms, error_message ) VALUES ( :region, :url, NOW(), :status, :up, :lat, :err ) "); $output = []; foreach ($regions as $r) { $check = runCheck($r['url']); $stmt->execute([ ':region' => $r['region'], ':url' => $r['url'], ':status' => $check['status'], ':up' => $check['up'], ':lat' => $check['latency'], ':err' => $check['error'] ]); $output[] = [ 'region' => $r['region'], 'url' => $r['url'], 'check' => $check ]; } header("Content-Type: application/json; charset=utf-8"); echo json_encode($output, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);