Failed Conditions
Push — mediacsp ( 6cda96 )
by Andreas
05:35 queued 03:04
created

inc/fetch.functions.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * Functions used by lib/exe/fetch.php
4
 * (not included by other parts of dokuwiki)
5
 */
6
7
/**
8
 * Set headers and send the file to the client
9
 *
10
 * The $cache parameter influences how long files may be kept in caches, the $public parameter
11
 * influences if this caching may happen in public proxis or in the browser cache only FS#2734
12
 *
13
 * This function will abort the current script when a 304 is sent or file sending is handled
14
 * through x-sendfile
15
 *
16
 * @param string $file local file to send
17
 * @param string $mime mime type of the file
18
 * @param bool $dl set to true to force a browser download
19
 * @param int $cache remaining cache time in seconds (-1 for $conf['cache'], 0 for no-cache)
20
 * @param bool $public is this a public ressource or a private one?
21
 * @param string $orig original file to send - the file name will be used for the Content-Disposition
22
 * @param array $csp The ContentSecurityPolicy to send
23
 * @author Andreas Gohr <[email protected]>
24
 * @author Ben Coburn <[email protected]>
25
 * @author Gerry Weissbach <[email protected]>
26
 *
27
 */
28
function sendFile($file, $mime, $dl, $cache, $public = false, $orig = null, $csp=[]) {
29
    global $conf;
30
    // send mime headers
31
    header("Content-Type: $mime");
32
33
    // send security policy if given
34
    if ($csp) dokuwiki\HTTP\Headers::contentSecurityPolicy($csp);
0 ignored issues
show
Bug Best Practice introduced by
The expression $csp of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
35
36
    // calculate cache times
37
    if($cache == -1) {
38
        $maxage  = max($conf['cachetime'], 3600); // cachetime or one hour
39
        $expires = time() + $maxage;
40
    } else if($cache > 0) {
41
        $maxage  = $cache; // given time
42
        $expires = time() + $maxage;
43
    } else { // $cache == 0
44
        $maxage  = 0;
45
        $expires = 0; // 1970-01-01
46
    }
47
48
    // smart http caching headers
49
    if($maxage) {
50
        if($public) {
51
            // cache publically
52
            header('Expires: '.gmdate("D, d M Y H:i:s", $expires).' GMT');
53
            header('Cache-Control: public, proxy-revalidate, no-transform, max-age='.$maxage);
54
        } else {
55
            // cache in browser
56
            header('Expires: '.gmdate("D, d M Y H:i:s", $expires).' GMT');
57
            header('Cache-Control: private, no-transform, max-age='.$maxage);
58
        }
59
    } else {
60
        // no cache at all
61
        header('Expires: Thu, 01 Jan 1970 00:00:00 GMT');
62
        header('Cache-Control: no-cache, no-transform');
63
    }
64
65
    //send important headers first, script stops here if '304 Not Modified' response
66
    $fmtime = @filemtime($file);
67
    http_conditionalRequest($fmtime);
68
69
    // Use the current $file if is $orig is not set.
70
    if ( $orig == null ) {
71
        $orig = $file;
72
    }
73
74
    //download or display?
75
    if ($dl) {
76
        header('Content-Disposition: attachment;' . rfc2231_encode(
77
                'filename', \dokuwiki\Utf8\PhpString::basename($orig)) . ';'
78
        );
79
    } else {
80
        header('Content-Disposition: inline;' . rfc2231_encode(
81
                'filename', \dokuwiki\Utf8\PhpString::basename($orig)) . ';'
82
        );
83
    }
84
85
    //use x-sendfile header to pass the delivery to compatible webservers
86
    http_sendfile($file);
87
88
    // send file contents
89
    $fp = @fopen($file, "rb");
90
    if($fp) {
91
        http_rangeRequest($fp, filesize($file), $mime);
92
    } else {
93
        http_status(500);
94
        print "Could not read $file - bad permissions?";
95
    }
96
}
97
98
/**
99
 * Try an rfc2231 compatible encoding. This ensures correct
100
 * interpretation of filenames outside of the ASCII set.
101
 * This seems to be needed for file names with e.g. umlauts that
102
 * would otherwise decode wrongly in IE.
103
 *
104
 * There is no additional checking, just the encoding and setting the key=value for usage in headers
105
 *
106
 * @author Gerry Weissbach <[email protected]>
107
 * @param string $name      name of the field to be set in the header() call
108
 * @param string $value     value of the field to be set in the header() call
109
 * @param string $charset   used charset for the encoding of value
110
 * @param string $lang      language used.
111
 * @return string           in the format " name=value" for values WITHOUT special characters
112
 * @return string           in the format " name*=charset'lang'value" for values WITH special characters
113
 */
114
function rfc2231_encode($name, $value, $charset='utf-8', $lang='en') {
115
    $internal = preg_replace_callback(
116
        '/[\x00-\x20*\'%()<>@,;:\\\\"\/[\]?=\x80-\xFF]/',
117
        function ($match) {
118
            return rawurlencode($match[0]);
119
        },
120
        $value
121
    );
122
    if ( $value != $internal ) {
123
        return ' '.$name.'*='.$charset."'".$lang."'".$internal;
124
    } else {
125
        return ' '.$name.'="'.$value.'"';
126
    }
127
}
128
129
/**
130
 * Check for media for preconditions and return correct status code
131
 *
132
 * READ: MEDIA, MIME, EXT, CACHE
133
 * WRITE: MEDIA, FILE, array( STATUS, STATUSMESSAGE )
134
 *
135
 * @author Gerry Weissbach <[email protected]>
136
 *
137
 * @param string $media  reference to the media id
138
 * @param string $file   reference to the file variable
139
 * @param string $rev
140
 * @param int    $width
141
 * @param int    $height
142
 * @return array as array(STATUS, STATUSMESSAGE)
143
 */
144
function checkFileStatus(&$media, &$file, $rev = '', $width=0, $height=0) {
145
    global $MIME, $EXT, $CACHE, $INPUT;
146
147
    //media to local file
148
    if(media_isexternal($media)) {
149
        //check token for external image and additional for resized and cached images
150
        if(media_get_token($media, $width, $height) !== $INPUT->str('tok')) {
151
            return array(412, 'Precondition Failed');
152
        }
153
        //handle external images
154
        if(strncmp($MIME, 'image/', 6) == 0) $file = media_get_from_URL($media, $EXT, $CACHE);
155
        if(!$file) {
156
            //download failed - redirect to original URL
157
            return array(302, $media);
158
        }
159
    } else {
160
        $media = cleanID($media);
161
        if(empty($media)) {
162
            return array(400, 'Bad request');
163
        }
164
        // check token for resized images
165
        if (($width || $height) && media_get_token($media, $width, $height) !== $INPUT->str('tok')) {
166
            return array(412, 'Precondition Failed');
167
        }
168
169
        //check permissions (namespace only)
170
        if(auth_quickaclcheck(getNS($media).':X') < AUTH_READ) {
171
            return array(403, 'Forbidden');
172
        }
173
        $file = mediaFN($media, $rev);
174
    }
175
176
    //check file existance
177
    if(!file_exists($file)) {
178
        return array(404, 'Not Found');
179
    }
180
181
    return array(200, null);
182
}
183
184
/**
185
 * Returns the wanted cachetime in seconds
186
 *
187
 * Resolves named constants
188
 *
189
 * @author  Andreas Gohr <[email protected]>
190
 *
191
 * @param string $cache
192
 * @return int cachetime in seconds
193
 */
194
function calc_cache($cache) {
195
    global $conf;
196
197
    if(strtolower($cache) == 'nocache') return 0; //never cache
198
    if(strtolower($cache) == 'recache') return $conf['cachetime']; //use standard cache
199
    return -1; //cache endless
200
}
201