xref: /dokuwiki/lib/exe/fetch.php (revision dd9e8e5ea54469964faab99223a61bd48146ac42)
1<?php
2
3/**
4 * DokuWiki media passthrough file
5 *
6 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
7 * @author     Andreas Gohr <andi@splitbrain.org>
8 */
9
10use dokuwiki\Input\Input;
11use dokuwiki\Extension\Event;
12
13if (!defined('DOKU_INC')) define('DOKU_INC', __DIR__ . '/../../');
14if (!defined('DOKU_DISABLE_GZIP_OUTPUT')) define('DOKU_DISABLE_GZIP_OUTPUT', 1);
15require_once(DOKU_INC . 'inc/init.php');
16session_write_close(); //close session
17
18require_once(DOKU_INC . 'inc/fetch.functions.php');
19
20if (defined('SIMPLE_TEST')) {
21    $INPUT = new Input();
22}
23
24// BEGIN main
25$mimetypes = getMimeTypes();
26
27//get input
28$MEDIA = stripctl(getID('media', false)); // no cleaning except control chars - maybe external
29$CACHE = calc_cache($INPUT->str('cache'));
30$WIDTH = $INPUT->int('w');
31$HEIGHT = $INPUT->int('h');
32$FIT = $INPUT->bool('fit');
33$REV = &$INPUT->ref('rev');
34//sanitize revision
35$REV = preg_replace('/[^0-9]/', '', $REV);
36
37[$EXT, $MIME, $DL] = mimetype($MEDIA, false);
38if ($EXT === false) {
39    $EXT = 'unknown';
40    $MIME = 'application/octet-stream';
41    $DL = true;
42}
43
44// check for permissions, preconditions and cache external files
45[$STATUS, $STATUSMESSAGE] = checkFileStatus($MEDIA, $FILE, $REV, $WIDTH, $HEIGHT);
46
47// prepare data for plugin events
48$data = [
49    'media' => $MEDIA,
50    'file' => $FILE,
51    'orig' => $FILE,
52    'mime' => $MIME,
53    'download' => $DL,
54    'cache' => $CACHE,
55    'ext' => $EXT,
56    'width' => $WIDTH,
57    'height' => $HEIGHT,
58    'fit' => $FIT,
59    'status' => $STATUS,
60    'statusmessage' => $STATUSMESSAGE,
61    'ispublic' => media_ispublic($MEDIA),
62    'csp' => [
63        'default-src' => "'none'",
64        'style-src' => "'unsafe-inline'",
65        'media-src' => "'self'",
66        'object-src' => "'self'",
67        'font-src' => "'self' data:",
68        'form-action' => "'none'",
69        'frame-ancestors' => "'self'",
70    ]
71];
72
73// handle the file status
74$evt = new Event('FETCH_MEDIA_STATUS', $data);
75if ($evt->advise_before()) {
76    // redirects
77    if ($data['status'] > 300 && $data['status'] <= 304) {
78        if (defined('SIMPLE_TEST')) return; //TestResponse doesn't recognize redirects
79        send_redirect($data['statusmessage']);
80    }
81    // send any non 200 status
82    if ($data['status'] != 200) {
83        http_status($data['status'], $data['statusmessage']);
84    }
85    // die on errors
86    if ($data['status'] > 203) {
87        echo $data['statusmessage'];
88        if (defined('SIMPLE_TEST')) return;
89        exit;
90    }
91}
92$evt->advise_after();
93unset($evt);
94
95//handle image resizing/cropping
96$evt = new Event('MEDIA_RESIZE', $data);
97if ($evt->advise_before()) {
98    if (
99        $MIME != 'image/svg+xml' &&
100        str_starts_with($MIME, 'image') &&
101        ($WIDTH || $HEIGHT)
102    ) {
103        if ($HEIGHT && $WIDTH && !$FIT) {
104            $data['file'] = $FILE = media_crop_image($data['file'], $EXT, $WIDTH, $HEIGHT);
105        } else {
106            $data['file'] = $FILE = media_resize_image($data['file'], $EXT, $WIDTH, $HEIGHT);
107        }
108    }
109}
110$evt->advise_after();
111unset($evt);
112
113// finally send the file to the client
114$evt = new Event('MEDIA_SENDFILE', $data);
115if ($evt->advise_before()) {
116    sendFile(
117        $data['file'],
118        $data['mime'],
119        $data['download'],
120        $data['cache'],
121        $data['ispublic'],
122        $data['orig'],
123        $data['csp']
124    );
125}
126// Do something after the download finished.
127$evt->advise_after();  // will not be emitted on 304 or x-sendfile
128
129// END DO main
130