Files
karczma-aplikacja-stoliki/api/analytics.php

158 lines
4.4 KiB
PHP

<?php
header('Content-Type: application/json; charset=utf-8');
require_once __DIR__ . '/../config/database.php';
require_once __DIR__ . '/get_table_name.php';
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
echo json_encode([
'status' => 'error',
'message' => 'Method not allowed'
], JSON_UNESCAPED_UNICODE);
exit;
}
$rawBody = file_get_contents('php://input');
$data = json_decode($rawBody, true);
if (!is_array($data)) {
http_response_code(400);
echo json_encode([
'status' => 'error',
'message' => 'Invalid JSON payload'
], JSON_UNESCAPED_UNICODE);
exit;
}
$eventName = isset($data['eventName']) ? trim((string)$data['eventName']) : '';
$sessionId = isset($data['sessionId']) ? trim((string)$data['sessionId']) : '';
$tableId = isset($data['tableId']) ? trim((string)$data['tableId']) : null;
$zone = isset($data['zone']) ? trim((string)$data['zone']) : null;
$qrHash = isset($data['qrHash']) ? trim((string)$data['qrHash']) : null;
$deviceType = isset($data['deviceType']) ? trim((string)$data['deviceType']) : null;
$browser = isset($data['browser']) ? trim((string)$data['browser']) : null;
$payload = isset($data['payload']) && is_array($data['payload']) ? $data['payload'] : null;
$allowedEvents = [
'qr_scan',
'session_start',
'geo_check_started',
'geo_check_passed',
'geo_check_failed',
'geo_bypass_host',
'waiter_call_requested',
'view_status',
'view_menu',
'menu_search',
'bill_dialog_opened',
'bill_request_sent',
];
if ($eventName === '' || !in_array($eventName, $allowedEvents, true)) {
http_response_code(422);
echo json_encode([
'status' => 'error',
'message' => 'Invalid eventName'
], JSON_UNESCAPED_UNICODE);
exit;
}
if ($sessionId === '' || strlen($sessionId) > 64) {
http_response_code(422);
echo json_encode([
'status' => 'error',
'message' => 'Invalid sessionId'
], JSON_UNESCAPED_UNICODE);
exit;
}
if ($qrHash && !$tableId && isset($conn)) {
$resolved = getTableNameByHash($conn, $qrHash);
if ($resolved !== '') {
$tableId = $resolved;
}
}
if ($tableId !== null && strlen($tableId) > 32) {
$tableId = substr($tableId, 0, 32);
}
if ($zone !== null && strlen($zone) > 16) {
$zone = substr($zone, 0, 16);
}
if ($qrHash !== null && strlen($qrHash) > 128) {
$qrHash = substr($qrHash, 0, 128);
}
if ($deviceType !== null && strlen($deviceType) > 16) {
$deviceType = substr($deviceType, 0, 16);
}
if ($browser !== null && strlen($browser) > 32) {
$browser = substr($browser, 0, 32);
}
$ip = '';
if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$parts = explode(',', (string)$_SERVER['HTTP_X_FORWARDED_FOR']);
$ip = trim($parts[0]);
} elseif (!empty($_SERVER['REMOTE_ADDR'])) {
$ip = trim((string)$_SERVER['REMOTE_ADDR']);
}
$ipHash = $ip !== '' ? hash('sha256', $ip . '|karczma_analytics_v1') : null;
$payload = is_array($payload) ? $payload : [];
if ($ip !== '' && !isset($payload['ipAddress'])) {
$payload['ipAddress'] = $ip;
}
$payloadJson = $payload ? json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) : null;
try {
$pdo = getAnalyticsPdo();
$stmt = $pdo->prepare("
INSERT INTO analytics_events (
created_at,
event_name,
session_id,
table_id,
zone,
qr_hash,
device_type,
browser,
ip_hash,
payload_json
) VALUES (
NOW(3),
:event_name,
:session_id,
:table_id,
:zone,
:qr_hash,
:device_type,
:browser,
:ip_hash,
:payload_json
)
");
$stmt->execute([
':event_name' => $eventName,
':session_id' => $sessionId,
':table_id' => $tableId,
':zone' => $zone,
':qr_hash' => $qrHash,
':device_type' => $deviceType,
':browser' => $browser,
':ip_hash' => $ipHash,
':payload_json' => $payloadJson,
]);
echo json_encode([
'status' => 'success'
], JSON_UNESCAPED_UNICODE);
} catch (Throwable $e) {
// Best-effort analytics: return success=false, but do not crash frontend flow.
http_response_code(200);
echo json_encode([
'status' => 'error',
'message' => 'Analytics insert failed'
], JSON_UNESCAPED_UNICODE);
}