'error', 'message' => 'Method not allowed', ], JSON_UNESCAPED_UNICODE); exit; } $config = require __DIR__ . '/../config/menu.php'; $languages = is_array($config['languages'] ?? null) ? $config['languages'] : []; $lang = strtolower(trim((string) ($_GET['lang'] ?? 'pl'))); if ($lang === '' || !isset($languages[$lang])) { http_response_code(422); echo json_encode([ 'status' => 'error', 'message' => 'Unsupported language', 'allowed' => array_keys($languages), ], JSON_UNESCAPED_UNICODE); exit; } $langConfig = $languages[$lang]; $source = (string) ($langConfig['source'] ?? 'upstream'); $ttl = max(60, (int) ($config['ttl_seconds'] ?? 1800)); $timeout = max(3, (int) ($config['timeout_seconds'] ?? 12)); $cacheDir = __DIR__ . '/cache'; $cacheFile = $cacheDir . '/menu_' . $lang . '.json'; if (!is_dir($cacheDir)) { @mkdir($cacheDir, 0755, true); } function readMenuCache(string $cacheFile): ?array { if (!is_file($cacheFile)) { return null; } $raw = file_get_contents($cacheFile); if ($raw === false || $raw === '') { return null; } $decoded = json_decode($raw, true); return is_array($decoded) ? $decoded : null; } function writeMenuCache(string $cacheFile, array $payload): void { file_put_contents( $cacheFile, json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), LOCK_EX ); } function fetchUpstreamMenu(string $url, int $timeout): ?array { $body = false; $httpCode = 0; if (function_exists('curl_init')) { $ch = curl_init($url); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_FOLLOWLOCATION => true, CURLOPT_TIMEOUT => $timeout, CURLOPT_HTTPHEADER => ['Accept: application/json'], ]); $body = curl_exec($ch); $errno = curl_errno($ch); $httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($errno !== 0) { $body = false; } } else { $context = stream_context_create([ 'http' => [ 'method' => 'GET', 'timeout' => $timeout, 'header' => "Accept: application/json\r\n", 'ignore_errors' => true, ], ]); $body = @file_get_contents($url, false, $context); if (isset($http_response_header[0]) && preg_match('/\s(\d{3})\s/', $http_response_header[0], $m)) { $httpCode = (int) $m[1]; } } if ($body === false || ($httpCode > 0 && ($httpCode < 200 || $httpCode >= 300))) { return null; } $decoded = json_decode($body, true); return is_array($decoded) ? $decoded : null; } function mapUpstreamMenu(array $raw, string $lang, string $source): array { $categories = []; foreach ($raw['categories'] ?? [] as $cat) { if (!is_array($cat)) { continue; } $id = trim((string) ($cat['id'] ?? '')); $name = trim((string) ($cat['name'] ?? '')); if ($id === '' || $name === '') { continue; } $categories[] = ['id' => $id, 'name' => $name]; } $sections = []; foreach ($raw['tables'] ?? [] as $table) { if (!is_array($table)) { continue; } $sectionName = trim((string) ($table['name'] ?? '')); if ($sectionName === '') { continue; } $items = []; foreach ($table['items'] ?? [] as $item) { if (!is_array($item)) { continue; } $items[] = [ 'position' => (string) ($item['id'] ?? ''), 'categoryId' => (string) ($item['category'] ?? ''), 'tag' => '', 'image' => (string) ($item['image'] ?? ''), 'title' => trim((string) ($item['name'] ?? '')), 'description' => trim((string) ($item['name_extra'] ?? '')), 'price' => (string) ($item['price'] ?? ''), ]; } $sections[] = [ 'categoryName' => $sectionName, 'items' => $items, ]; } return [ 'status' => 'success', 'lang' => $lang, 'source' => $source, 'cachedAt' => gmdate('c'), 'categories' => $categories, 'sections' => $sections, ]; } $cached = readMenuCache($cacheFile); $now = time(); $cachedAtTs = 0; if ($cached && !empty($cached['cachedAt'])) { $cachedAtTs = strtotime((string) $cached['cachedAt']) ?: 0; } $isFresh = $cached && $cachedAtTs > 0 && ($now - $cachedAtTs) < $ttl; if ($isFresh) { echo json_encode($cached, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); exit; } if ($source === 'ai') { if ($cached) { echo json_encode($cached, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); exit; } http_response_code(503); echo json_encode([ 'status' => 'error', 'message' => 'AI menu not available yet', 'lang' => $lang, ], JSON_UNESCAPED_UNICODE); exit; } $base = rtrim((string) ($config['upstream_base'] ?? ''), '/'); $url = $base . '/' . rawurlencode($lang); $raw = fetchUpstreamMenu($url, $timeout); if ($raw === null) { if ($cached) { echo json_encode($cached, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); exit; } http_response_code(502); echo json_encode([ 'status' => 'error', 'message' => 'Failed to fetch menu', 'lang' => $lang, ], JSON_UNESCAPED_UNICODE); exit; } $mapped = mapUpstreamMenu($raw, $lang, 'upstream'); writeMenuCache($cacheFile, $mapped); echo json_encode($mapped, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);