'Method Not Allowed']); exit; } $raw = file_get_contents('php://input'); if ($raw === false || $raw === '') { http_response_code(400); echo json_encode(['error' => 'Invalid or empty JSON']); exit; } if (strlen($raw) > MAX_BODY_SIZE) { http_response_code(400); echo json_encode(['error' => 'Request body too large']); exit; } $payload = json_decode($raw, true); if (json_last_error() !== JSON_ERROR_NONE) { http_response_code(400); echo json_encode(['error' => 'Invalid or empty JSON']); exit; } $received = (new DateTimeImmutable('now', new DateTimeZone('UTC')))->format('Y-m-d\TH:i:s.uP'); $dir = dirname($dataPath); if (!is_dir($dir)) { if (!@mkdir($dir, 0755, true)) { http_response_code(500); echo json_encode(['error' => 'Could not create data directory']); exit; } } $fp = fopen($dataPath, 'c+'); if ($fp === false) { http_response_code(500); echo json_encode(['error' => 'Could not open data file']); exit; } if (!flock($fp, LOCK_EX)) { fclose($fp); http_response_code(500); echo json_encode(['error' => 'Could not lock data file']); exit; } $content = stream_get_contents($fp); $data = []; if ($content !== false && $content !== '') { $data = json_decode($content, true); if (!is_array($data)) { $data = []; } } if (!isset($data['einsaetze'])) { $data['einsaetze'] = []; } if (!isset($data['webhook_events'])) { $data['webhook_events'] = []; } $data['webhook_events'][] = [ 'received' => $received, 'data' => $payload, ]; $data['updated'] = $received; $json = json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); if ($json === false) { flock($fp, LOCK_UN); fclose($fp); http_response_code(500); echo json_encode(['error' => 'Could not encode JSON']); exit; } ftruncate($fp, 0); rewind($fp); $written = fwrite($fp, $json); flock($fp, LOCK_UN); fclose($fp); if ($written === false || $written !== strlen($json)) { http_response_code(500); echo json_encode(['error' => 'Could not write data file']); exit; } http_response_code(200); echo json_encode(['ok' => true, 'received' => $received]);