All checks were successful
Deploy bericht / deploy (push) Successful in 1s
_inc.php setzt standardmäßig Content-Type: application/json — das hat photo.php beim Bildversand blockiert (die Blob kam als JSON rein und der Browser konnte sie nicht als Bild darstellen). Jetzt lädt photo.php Dolibarr direkt, dekodiert JWT manuell (mit Query-Param-Support für Fallback ohne Header-Auth) und sendet NUR image/jpeg-Header beim Ausliefern. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> [deploy]
108 lines
4 KiB
PHP
108 lines
4 KiB
PHP
<?php
|
|
/* GET /api/photo.php?relpath=<path>
|
|
* 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 <name>_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 direkt nutzen, sondern JWT + 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__.'/_jwt.php';
|
|
require_once __DIR__.'/../lib/bericht.lib.php';
|
|
|
|
// Support Token via Header ODER Query-String (für <img src> ohne Header)
|
|
$token_str = '';
|
|
$hdr = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
|
|
if ($hdr && stripos($hdr, 'bearer ') === 0) $token_str = trim(substr($hdr, 7));
|
|
if (!$token_str && !empty($_GET['jwt'])) $token_str = (string) $_GET['jwt'];
|
|
|
|
$payload = $token_str ? bericht_jwt_decode($token_str) : null;
|
|
if (!$payload || empty($payload['sub'])) {
|
|
http_response_code(401);
|
|
header('Content-Type: text/plain');
|
|
echo 'Token ungültig oder fehlt';
|
|
exit;
|
|
}
|
|
|
|
require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
|
|
$u = new User($db);
|
|
if ($u->fetch((int) $payload['sub']) <= 0 || empty($u->statut)) {
|
|
http_response_code(401);
|
|
header('Content-Type: text/plain');
|
|
echo 'User ungültig';
|
|
exit;
|
|
}
|
|
$u->loadRights();
|
|
if (!$u->hasRight('bericht', 'read')) {
|
|
http_response_code(403);
|
|
header('Content-Type: text/plain');
|
|
echo 'Permission denied';
|
|
exit;
|
|
}
|
|
$user = $u;
|
|
|
|
$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';
|
|
|
|
header('Content-Type: '.$mime);
|
|
header('Content-Length: '.filesize($full));
|
|
header('Cache-Control: private, max-age=3600');
|
|
header('Access-Control-Allow-Origin: *');
|
|
readfile($full);
|
|
exit;
|