dbxapp 4.1.3
CMS, Shop, Workflows und modulare Geschäftsanwendungen
Loading...
Searching...
No Matches
dbxContentMediaResponse.class.php
Go to the documentation of this file.
1<?php
2namespace dbx\dbxContent;
3
8
10 public function serve_request(): void {
11 $modul = (string)($_GET['dbx_modul'] ?? '');
12 $run1 = (string)($_GET['dbx_run1'] ?? '');
13 $mid = isset($_GET['dbx_mid']) ? (int)$_GET['dbx_mid'] : 0;
14 $thumb = isset($_GET['dbx_thumb']) && (string)$_GET['dbx_thumb'] === '1';
15 if ($modul !== 'dbxContent' || $run1 !== 'media' || $mid <= 0) return;
16
17 try {
18 $db = dbx()->get_system_obj('dbxDB');
19 $row = is_object($db)
20 ? $db->select1('dbxMedia', array('id' => $mid, 'active' => 1), '*', 0)
21 : array();
22 if (!is_array($row) || (int)($row['id'] ?? 0) <= 0) {
23 $this->fail(404, $mid);
24 }
25
26 $relKey = $thumb && !empty($row['thumb_file_path']) ? 'thumb_file_path' : 'file_path';
27 $rel = $this->safe_relative_path((string)($row[$relKey] ?? ''));
28 if ($rel === null) {
29 http_response_code(403);
30 exit;
31 }
32
33 $root = dbx()->os_path(rtrim(dbx()->get_file_dir(), '/\\') . '/');
34 $base = realpath($root);
35 $real = $this->readable_file($base, $root, $rel);
36 $servedThumb = $thumb && $relKey === 'thumb_file_path';
37
38 if ($real === null && $servedThumb && !empty($row['file_path'])) {
39 $fallbackRel = $this->safe_relative_path((string)$row['file_path']);
40 if ($fallbackRel !== null) {
41 $fallbackReal = $this->readable_file($base, $root, $fallbackRel);
42 if ($fallbackReal !== null) {
43 $real = $fallbackReal;
44 $rel = $fallbackRel;
45 $servedThumb = false;
46 }
47 }
48 }
49
50 if ($real === null) {
51 $this->fail(404, $mid, $rel);
52 }
53
54 $mime = $servedThumb ? '' : trim((string)($row['mime'] ?? ''));
55 if ($mime === '') {
56 $detected = function_exists('mime_content_type') ? mime_content_type($real) : '';
57 $mime = $detected ?: 'application/octet-stream';
58 }
59
60 $fileName = trim((string)($row['file_name'] ?? ''));
61 if ($fileName === '') $fileName = basename($real);
62 $this->stream_file($real, $mime, $fileName);
63 } catch (\Throwable $e) {
64 dbx()->write_php_error_log(get_class($e), $e->getMessage(), $e->getFile(), $e->getLine());
65 http_response_code(500);
66 exit;
67 }
68 }
69
70 private function missing_key(int $mid, string $rel = ''): string {
71 if (trim($rel) !== '') return ltrim(str_replace('\\', '/', $rel), '/');
72 $uri = trim((string)($_SERVER['REQUEST_URI'] ?? ''));
73 return $uri !== '' ? $uri : 'index.php?dbx_modul=dbxContent&dbx_run1=media&dbx_mid=' . $mid;
74 }
75
76 private function fail(int $code, int $mid, string $rel = ''): void {
77 if ($code === 404) dbx()->log_missing($this->missing_key($mid, $rel));
78 http_response_code($code);
79 exit;
80 }
81
82 private function safe_relative_path(string $rel): ?string {
83 $rel = ltrim(str_replace('\\', '/', rawurldecode($rel)), '/');
84 if ($rel === '' || strpos($rel, '..') !== false || !preg_match('~^(media|dbxContent/media)/~i', $rel)) {
85 return null;
86 }
87 return $rel;
88 }
89
90 private function readable_file($base, string $root, string $rel): ?string {
91 if (!$base) return null;
92 $real = realpath(dbx()->os_path($root . $rel));
93 if (!$real || !is_file($real) || !is_readable($real)) return null;
94
95 $basePath = rtrim(str_replace('\\', '/', (string)$base), '/') . '/';
96 $realPath = str_replace('\\', '/', $real);
97 if (!str_starts_with($realPath, $basePath)) return null;
98 return $real;
99 }
100
101 private function stream_file(string $file, string $mime, string $fileName): void {
102 while (ob_get_level() > 0) {
103 if (!@ob_end_clean()) break;
104 }
105 if (session_status() === PHP_SESSION_ACTIVE) session_write_close();
106
107 $size = (int)filesize($file);
108 $mtime = (int)(filemtime($file) ?: time());
109 $etag = '"' . md5($file . '|' . $size . '|' . $mtime) . '"';
110 $lastModified = gmdate('D, d M Y H:i:s', $mtime) . ' GMT';
111 $ifNoneMatch = trim((string)($_SERVER['HTTP_IF_NONE_MATCH'] ?? ''));
112 $ifModifiedSince = trim((string)($_SERVER['HTTP_IF_MODIFIED_SINCE'] ?? ''));
113 if ($ifNoneMatch === $etag || ($ifModifiedSince !== '' && strtotime($ifModifiedSince) >= $mtime)) {
114 http_response_code(304);
115 header('ETag: ' . $etag);
116 header('Last-Modified: ' . $lastModified);
117 header('Cache-Control: private, no-cache');
118 exit;
119 }
120
121 $start = 0;
122 $end = $size > 0 ? $size - 1 : 0;
123 $range = trim((string)($_SERVER['HTTP_RANGE'] ?? ''));
124 if ($range !== '' && preg_match('/bytes=(\d*)-(\d*)/i', $range, $match)) {
125 if ($match[1] !== '') $start = max(0, (int)$match[1]);
126 if ($match[2] !== '') $end = min($end, (int)$match[2]);
127 if ($match[1] === '' && $match[2] !== '') {
128 $start = max(0, $size - max(0, (int)$match[2]));
129 }
130 if ($start <= $end && $size > 0) {
131 http_response_code(206);
132 header('Content-Range: bytes ' . $start . '-' . $end . '/' . $size);
133 } else {
134 http_response_code(416);
135 header('Content-Range: bytes */' . $size);
136 exit;
137 }
138 }
139
140 $fileName = str_replace('"', '', basename($fileName));
141 header('Content-Type: ' . $mime);
142 header('Content-Length: ' . max(0, $end - $start + 1));
143 header('Content-Disposition: inline; filename="' . $fileName . '"');
144 header('Accept-Ranges: bytes');
145 header('ETag: ' . $etag);
146 header('Last-Modified: ' . $lastModified);
147 header('Cache-Control: private, no-cache');
148 header('X-Content-Type-Options: nosniff');
149
150 if (strtoupper((string)($_SERVER['REQUEST_METHOD'] ?? 'GET')) === 'HEAD') {
151 exit;
152 }
153
154 $out = fopen($file, 'rb');
155 if ($out) {
156 if ($start > 0) fseek($out, $start);
157 $remaining = $end - $start + 1;
158 while ($remaining > 0 && !feof($out)) {
159 $chunk = fread($out, min(8192, $remaining));
160 if ($chunk === false || $chunk === '') break;
161 echo $chunk;
162 $remaining -= strlen($chunk);
163 if (function_exists('connection_aborted') && connection_aborted()) break;
164 }
165 fclose($out);
166 }
167 exit;
168 }
169}
Bedient geschuetzte CMS-Mediendateien direkt aus dem dbxContent-Modul.
serve_request()
Bedient den aktuellen Request, sofern er eine dbxContent-Medien-URL ist.
os_path(string $path)
Normalisiert einen Pfad fuer das aktuelle Betriebssystem.
Definition dbxApi.php:1538
get_file_dir()
Liefert das files/-Verzeichnis der Installation.
Definition dbxApi.php:1524
log_missing($missing='')
Zaehlt einen fehlenden Pfad oder eine fehlende Ressource in dbxMissing.
Definition dbxApi.php:1930
$_SERVER['REQUEST_METHOD']
if(!defined( 'IMG_WEBP')) define( 'IMG_WEBP'
exit
Definition index.php:146
DBX schema administration.