<?php
/**
 * Fichier  : api/image.php
 * Auteur   : KREMER Régis
 * Version  : 2.6.18
 * Date     : 2026-07-08
 * Description : API — Proxy sécurisé des images locales publiques (uploads/assets) pour éviter les casses de chemins.
 *
 * Changelog :
 *   v2.6.18 (2026-07-08) — Création proxy image authentifié : produits, inventaires et logo entreprise restent affichés après filtres/déploiements.
 */
require_once dirname(__DIR__).'/config.php';
startSession();
requireAuth();

$raw = trim((string)($_GET['src'] ?? $_GET['path'] ?? ''));
if ($raw === '') {
    http_response_code(404);
    exit;
}

// Refuser les URL distantes et les schémas spéciaux : ce proxy ne sert que les fichiers locaux.
if (preg_match('#^(?:https?:)?//#i', $raw) || preg_match('#^(?:data|blob|file|php|phar):#i', $raw)) {
    http_response_code(400);
    exit;
}

$path = str_replace('\\', '/', $raw);
$path = preg_replace('#^\./+#', '', $path);
$path = ltrim($path, '/');
$path = preg_replace('#/+#', '/', $path) ?: '';

// Tolérer les chemins déjà préfixés par le base path applicatif.
$base = trim(appBasePath(), '/');
if ($base !== '' && str_starts_with($path, $base . '/')) {
    $path = substr($path, strlen($base) + 1);
}

if ($path === '' || str_contains($path, '..')) {
    http_response_code(400);
    exit;
}

$allowedPrefixes = [
    'uploads/',
    'assets/img/',
];
$allowed = false;
foreach ($allowedPrefixes as $prefix) {
    if (str_starts_with($path, $prefix)) {
        $allowed = true;
        break;
    }
}
if (!$allowed) {
    http_response_code(403);
    exit;
}

$file = APP_ROOT . '/' . $path;
$realRoot = realpath(APP_ROOT);
$realFile = realpath($file);
if (!$realRoot || !$realFile || !str_starts_with($realFile, $realRoot . DIRECTORY_SEPARATOR) || !is_file($realFile)) {
    http_response_code(404);
    exit;
}

$mime = '';
$finfo = function_exists('finfo_open') ? finfo_open(FILEINFO_MIME_TYPE) : false;
if ($finfo) {
    $mime = (string)finfo_file($finfo, $realFile);
    finfo_close($finfo);
}
if (!preg_match('#^image/(?:jpeg|png|gif|webp|svg\+xml|x-icon|vnd\.microsoft\.icon)$#i', $mime)) {
    $ext = strtolower(pathinfo($realFile, PATHINFO_EXTENSION));
    $mime = match ($ext) {
        'jpg', 'jpeg' => 'image/jpeg',
        'png' => 'image/png',
        'gif' => 'image/gif',
        'webp' => 'image/webp',
        'svg' => 'image/svg+xml',
        'ico' => 'image/x-icon',
        default => '',
    };
}
if ($mime === '') {
    http_response_code(415);
    exit;
}

$etag = '"' . sha1($path . '|' . filesize($realFile) . '|' . filemtime($realFile)) . '"';
if ((string)($_SERVER['HTTP_IF_NONE_MATCH'] ?? '') === $etag) {
    header('ETag: ' . $etag);
    http_response_code(304);
    exit;
}

header('Content-Type: ' . $mime);
header('Content-Length: ' . filesize($realFile));
header('Cache-Control: private, max-age=86400');
header('ETag: ' . $etag);
readfile($realFile);
exit;
