'Method not allowed']); exit; } $data = json_decode(file_get_contents('php://input'), true); if (!isset($data['type']) || !isset($data['page'])) { http_response_code(400); echo json_encode(['error' => 'Missing required fields']); exit; } $dataDir = __DIR__ . '/../data/analytics'; // Calculate date and hour from current timestamp to ensure timezone consistency $now = time(); $date = date('Y-m-d', $now); $hour = (int)date('H', $now); $filename = $dataDir . '/visits_' . $date . '.json'; // Load existing data - because we're not starting from scratch every time $visits = []; if (file_exists($filename)) { $visits = json_decode(file_get_contents($filename), true) ?: []; } // Generate visitor ID - a simple fingerprint that's probably unique enough // Privacy advocates hate this one simple trick $visitorId = isset($data['visitorId']) ? $data['visitorId'] : md5($_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT']); // Check if new or returning visitor - because we care about your browsing habits $isNewVisitor = true; foreach ($visits as $visit) { if ($visit['visitorId'] === $visitorId) { $isNewVisitor = false; break; // Found you, you can't hide } } // Add visit record - we're watching, always watching // Timestamps are the only truth in this digital wasteland $timestamp = time(); $visitRecord = [ 'timestamp' => $timestamp, 'hour' => (int)date('H', $timestamp), 'visitorId' => $visitorId, 'page' => $data['page'], 'type' => $data['type'], 'isNew' => $isNewVisitor, 'userAgent' => $_SERVER['HTTP_USER_AGENT'] ?? '', 'ip' => $_SERVER['REMOTE_ADDR'] ?? '' ]; // Add platform if it's a share if ($data['type'] === 'share' && isset($data['platform'])) { $visitRecord['platform'] = $data['platform']; } $visits[] = $visitRecord; // Save data file_put_contents($filename, json_encode($visits, JSON_PRETTY_PRINT)); // Also update daily summary - because raw data is messy and we like order $summaryFile = $dataDir . '/summary_' . $date . '.json'; $summary = []; if (file_exists($summaryFile)) { $summary = json_decode(file_get_contents($summaryFile), true) ?: []; } if (!isset($summary['total'])) $summary['total'] = 0; if (!isset($summary['new'])) $summary['new'] = 0; if (!isset($summary['returning'])) $summary['returning'] = 0; if (!isset($summary['byHour'])) $summary['byHour'] = array_fill(0, 24, 0); if (!isset($summary['shares'])) $summary['shares'] = ['mastodon' => 0, 'bluesky' => 0, 'copy' => 0]; if (!isset($summary['rss'])) $summary['rss'] = 0; if ($data['type'] === 'share' && isset($data['platform'])) { // Track share $platform = $data['platform']; if (isset($summary['shares'][$platform])) { $summary['shares'][$platform]++; } } else if ($data['type'] === 'rss_click') { // Track RSS button click $summary['rss']++; } else { // Track pageview $summary['total']++; if ($isNewVisitor) { $summary['new']++; } else { $summary['returning']++; } // Use hour calculated from timestamp for consistency $hourFromTimestamp = (int)date('H', $timestamp); $summary['byHour'][$hourFromTimestamp]++; } file_put_contents($summaryFile, json_encode($summary, JSON_PRETTY_PRINT)); echo json_encode(['success' => true, 'visitorId' => $visitorId, 'isNew' => $isNewVisitor]); ?>