* Liefert eine Datei aus DOL_DATA_ROOT aus, authentifiziert per JWT. * Whitelist: nur facture/, commande/, propal/, bericht/ * * Für den Thumb-Request der PWA werden auch Thumbnails ausgeliefert * (Dolibarr legt _small.png unter thumbs/ ab). * * Query: * relpath — relativer Pfad unter DOL_DATA_ROOT * size=small|mini (optional, nutzt automatisch das Thumb) */ // Dieser Endpoint liefert Binärdaten aus — KEIN JSON Content-Type! // Deshalb nicht _inc.php nutzen, sondern awlauth + Dolibarr manuell laden. if (!defined('NOLOGIN')) define('NOLOGIN', '1'); if (!defined('NOCSRFCHECK')) define('NOCSRFCHECK', '1'); if (!defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL', '1'); if (!defined('NOREQUIREMENU')) define('NOREQUIREMENU', '1'); if (!defined('NOREQUIREHTML')) define('NOREQUIREHTML', '1'); if (!defined('NOREQUIREAJAX')) define('NOREQUIREAJAX', '1'); $res = 0; if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) $res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php"; $tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME']; $tmp2 = realpath(__FILE__); $i = strlen($tmp) - 1; $j = strlen($tmp2) - 1; while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) { $i--; $j--; } if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) $res = @include substr($tmp, 0, ($i + 1))."/main.inc.php"; if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) $res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php"; if (!$res && file_exists("../../main.inc.php")) $res = @include "../../main.inc.php"; if (!$res && file_exists("../../../main.inc.php")) $res = @include "../../../main.inc.php"; if (!$res) die("Include of main fails"); require_once __DIR__.'/../lib/bericht.lib.php'; // Auth über das zentrale SSO-Cookie awl_sso. Bewusst awlauth_verify (OHNE CSRF), // weil dieser reine GET-Read auch per window.location/ geladen wird // (Download-Link, Audio-Element) und dort kein X-Requested-With setzbar ist. if (!dol_include_once('/awlauth/lib/awlauth.lib.php') || !function_exists('awlauth_verify')) { http_response_code(500); header('Content-Type: text/plain'); echo 'SSO-Modul (awlauth) nicht verfügbar'; exit; } $user = awlauth_verify(); if (!$user || !$user->hasRight('bericht', 'read')) { http_response_code(401); header('Content-Type: text/plain'); echo 'Nicht angemeldet'; exit; } $relpath = (string) ($_GET['relpath'] ?? ''); $size = (string) ($_GET['size'] ?? ''); if (empty($relpath)) { http_response_code(400); header('Content-Type: text/plain'); echo 'relpath fehlt'; exit; } // Whitelist if (!preg_match('#^(facture|commande|propal|bericht)/#', $relpath)) { http_response_code(403); header('Content-Type: text/plain'); echo 'Pfad nicht erlaubt: '.$relpath; exit; } $full = bericht_resolve_data_path($relpath); if (!$full || !file_exists($full)) { http_response_code(404); header('Content-Type: text/plain'); echo 'Datei nicht gefunden: '.$relpath; exit; } // Thumb-Variante if ($size === 'small' || $size === 'mini') { $dir = dirname($full); $base = pathinfo($full, PATHINFO_FILENAME); $ext = pathinfo($full, PATHINFO_EXTENSION); $thumb = $dir.'/thumbs/'.$base.'_'.$size.'.'.$ext; if (file_exists($thumb)) $full = $thumb; } $mime = function_exists('dol_mimetype') ? dol_mimetype($full) : 'application/octet-stream'; $download = !empty($_GET['download']); $filename = $download ? basename($full) : ''; header('Content-Type: '.$mime); header('Content-Length: '.filesize($full)); header('Cache-Control: private, max-age=3600'); if ($download) { header('Content-Disposition: attachment; filename="'.addslashes($filename).'"'); } readfile($full); exit;