Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
moodle
moodle
Commits
e890de55
Commit
e890de55
authored
Mar 01, 2017
by
Andrew Nicols
Browse files
Merge branch 'm33_MDL-57789_Add_Cache_Control_Immutable_Support' of
https://github.com/scara/moodle
parents
dd6b41a5
203c5bce
Changes
10
Hide whitespace changes
Inline
Side-by-side
lib/csslib.php
View file @
e890de55
...
...
@@ -284,15 +284,15 @@ function css_chunk_by_selector_count($css, $importurl, $maxselectors = 4095, $bu
* @param string $etag The revision to make sure we utilise any caches.
*/
function
css_send_cached_css
(
$csspath
,
$etag
)
{
//
6
0 days only -
the revision may get incremented quite often
.
$lifetime
=
60
*
60
*
24
*
6
0
;
//
9
0 days only -
based on Moodle point release cadence being every 3 months
.
$lifetime
=
60
*
60
*
24
*
9
0
;
header
(
'Etag: "'
.
$etag
.
'"'
);
header
(
'Content-Disposition: inline; filename="styles.php"'
);
header
(
'Last-Modified: '
.
gmdate
(
'D, d M Y H:i:s'
,
filemtime
(
$csspath
))
.
' GMT'
);
header
(
'Expires: '
.
gmdate
(
'D, d M Y H:i:s'
,
time
()
+
$lifetime
)
.
' GMT'
);
header
(
'Pragma: '
);
header
(
'Cache-Control: public, max-age='
.
$lifetime
);
header
(
'Cache-Control: public, max-age='
.
$lifetime
.
', immutable'
);
header
(
'Accept-Ranges: none'
);
header
(
'Content-Type: text/css; charset=utf-8'
);
if
(
!
min_enable_zlib_compression
())
{
...
...
@@ -310,15 +310,15 @@ function css_send_cached_css($csspath, $etag) {
* @param string $etag The revision to make sure we utilise any caches.
*/
function
css_send_cached_css_content
(
$csscontent
,
$etag
)
{
//
6
0 days only -
the revision may get incremented quite often
.
$lifetime
=
60
*
60
*
24
*
6
0
;
//
9
0 days only -
based on Moodle point release cadence being every 3 months
.
$lifetime
=
60
*
60
*
24
*
9
0
;
header
(
'Etag: "'
.
$etag
.
'"'
);
header
(
'Content-Disposition: inline; filename="styles.php"'
);
header
(
'Last-Modified: '
.
gmdate
(
'D, d M Y H:i:s'
,
time
())
.
' GMT'
);
header
(
'Expires: '
.
gmdate
(
'D, d M Y H:i:s'
,
time
()
+
$lifetime
)
.
' GMT'
);
header
(
'Pragma: '
);
header
(
'Cache-Control: public, max-age='
.
$lifetime
);
header
(
'Cache-Control: public, max-age='
.
$lifetime
.
', immutable'
);
header
(
'Accept-Ranges: none'
);
header
(
'Content-Type: text/css; charset=utf-8'
);
if
(
!
min_enable_zlib_compression
())
{
...
...
@@ -363,8 +363,8 @@ function css_send_uncached_css($css) {
* @param string $etag
*/
function
css_send_unmodified
(
$lastmodified
,
$etag
)
{
//
6
0 days only -
the revision may get incremented quite often
.
$lifetime
=
60
*
60
*
24
*
6
0
;
//
9
0 days only -
based on Moodle point release cadence being every 3 months
.
$lifetime
=
60
*
60
*
24
*
9
0
;
header
(
'HTTP/1.1 304 Not Modified'
);
header
(
'Expires: '
.
gmdate
(
'D, d M Y H:i:s'
,
time
()
+
$lifetime
)
.
' GMT'
);
header
(
'Cache-Control: public, max-age='
.
$lifetime
);
...
...
lib/editor/tinymce/plugins/loader.php
View file @
e890de55
...
...
@@ -62,7 +62,7 @@ if ($allowcache) {
// Set it to expire a year later. Note that this means we should never get
// If-Modified-Since requests so there is no need to handle them specially.
header
(
'Expires: '
.
date
(
'r'
,
time
()
+
365
*
24
*
3600
));
header
(
'Cache-Control: max-age='
.
365
*
24
*
3600
);
header
(
'Cache-Control: max-age='
.
365
*
24
*
3600
.
', immutable'
);
// Pragma is set to no-cache by default so must be overridden.
header
(
'Pragma:'
);
}
...
...
lib/filelib.php
View file @
e890de55
...
...
@@ -2139,11 +2139,14 @@ function file_safe_save_content($content, $destination) {
* byteranges etc.
*
* @category files
* @param string $path Path of file on disk (including real filename), or actual content of file as string
* @param string|stored_file $path Path of file on disk (including real filename),
* or actual content of file as string,
* or stored_file object
* @param string $filename Filename to send
* @param int $lifetime Number of seconds before the file should expire from caches (null means $CFG->filelifetime)
* @param int $filter 0 (default)=no filtering, 1=all files, 2=html files only
* @param bool $pathisstring If true (default false), $path is the content to send and not the pathname
* @param bool $pathisstring If true (default false), $path is the content to send and not the pathname.
* Forced to false when $path is a stored_file object.
* @param bool $forcedownload If true (default false), forces download of file rather than view in browser/plugin
* @param string $mimetype Include to specify the MIME type; leave blank to have it guess the type from $filename
* @param bool $dontdie - return control to caller afterwards. this is not recommended and only used for cleanup tasks.
...
...
@@ -2152,6 +2155,7 @@ function file_safe_save_content($content, $destination) {
* and should not be reopened.
* @param array $options An array of options, currently accepts:
* - (string) cacheability: public, or private.
* - (string|null) immutable
* @return null script execution stopped unless $dontdie is true
*/
function
send_file
(
$path
,
$filename
,
$lifetime
=
null
,
$filter
=
0
,
$pathisstring
=
false
,
$forcedownload
=
false
,
$mimetype
=
''
,
...
...
@@ -2166,6 +2170,10 @@ function send_file($path, $filename, $lifetime = null , $filter=0, $pathisstring
$lifetime
=
$CFG
->
filelifetime
;
}
if
(
is_object
(
$path
))
{
$pathisstring
=
false
;
}
\
core\session\manager
::
write_close
();
// Unlock session during file serving.
// Use given MIME type if specified, otherwise guess it.
...
...
@@ -2188,6 +2196,14 @@ function send_file($path, $filename, $lifetime = null , $filter=0, $pathisstring
}
if
(
$lifetime
>
0
)
{
$immutable
=
''
;
if
(
!
empty
(
$options
[
'immutable'
]))
{
$immutable
=
', immutable'
;
// Overwrite lifetime accordingly:
// 90 days only - based on Moodle point release cadence being every 3 months.
$lifetimemin
=
60
*
60
*
24
*
90
;
$lifetime
=
max
(
$lifetime
,
$lifetimemin
);
}
$cacheability
=
' public,'
;
if
(
!
empty
(
$options
[
'cacheability'
])
&&
(
$options
[
'cacheability'
]
===
'public'
))
{
// This file must be cache-able by both browsers and proxies.
...
...
@@ -2200,7 +2216,7 @@ function send_file($path, $filename, $lifetime = null , $filter=0, $pathisstring
$cacheability
=
' private,'
;
}
$nobyteserving
=
false
;
header
(
'Cache-Control:'
.
$cacheability
.
' max-age='
.
$lifetime
.
', no-transform'
);
header
(
'Cache-Control:'
.
$cacheability
.
' max-age='
.
$lifetime
.
', no-transform'
.
$immutable
);
header
(
'Expires: '
.
gmdate
(
'D, d M Y H:i:s'
,
time
()
+
$lifetime
)
.
' GMT'
);
header
(
'Pragma: '
);
...
...
@@ -2231,8 +2247,13 @@ function send_file($path, $filename, $lifetime = null , $filter=0, $pathisstring
$options
=
new
stdClass
();
$options
->
noclean
=
true
;
$options
->
nocache
=
true
;
// temporary workaround for MDL-5136
$text
=
$pathisstring
?
$path
:
implode
(
''
,
file
(
$path
));
if
(
is_object
(
$path
))
{
$text
=
$path
->
get_content
();
}
else
if
(
$pathisstring
)
{
$text
=
$path
;
}
else
{
$text
=
implode
(
''
,
file
(
$path
));
}
$output
=
format_text
(
$text
,
FORMAT_HTML
,
$options
,
$COURSE
->
id
);
readstring_accel
(
$output
,
$mimetype
,
false
);
...
...
@@ -2242,7 +2263,13 @@ function send_file($path, $filename, $lifetime = null , $filter=0, $pathisstring
$options
=
new
stdClass
();
$options
->
newlines
=
false
;
$options
->
noclean
=
true
;
$text
=
htmlentities
(
$pathisstring
?
$path
:
implode
(
''
,
file
(
$path
)),
ENT_QUOTES
,
'UTF-8'
);
if
(
is_object
(
$path
))
{
$text
=
$path
->
get_content
();
}
else
if
(
$pathisstring
)
{
$text
=
htmlentities
(
$path
,
ENT_QUOTES
,
'UTF-8'
);
}
else
{
$text
=
htmlentities
(
implode
(
''
,
file
(
$path
)),
ENT_QUOTES
,
'UTF-8'
);
}
$output
=
'<pre>'
.
format_text
(
$text
,
FORMAT_MOODLE
,
$options
,
$COURSE
->
id
)
.
'</pre>'
;
readstring_accel
(
$output
,
$mimetype
,
false
);
...
...
@@ -2276,6 +2303,8 @@ function send_file($path, $filename, $lifetime = null , $filter=0, $pathisstring
* (string|null) cacheability - force the cacheability setting of the HTTP response, "private" or "public",
* when $lifetime is greater than 0. Cacheability defaults to "private" when logged in as other than guest; otherwise,
* defaults to "public".
* (string|null) immutable - set the immutable cache setting in the HTTP response, when served under HTTPS.
* Note: it's up to the consumer to set it properly i.e. when serving a "versioned" URL.
*
* @category files
* @param stored_file $stored_file local file object
...
...
@@ -2343,101 +2372,18 @@ function send_stored_file($stored_file, $lifetime=null, $filter=0, $forcedownloa
die
;
}
if
(
$dontdie
)
{
ignore_user_abort
(
true
);
}
\
core\session\manager
::
write_close
();
// Unlock session during file serving.
$filename
=
is_null
(
$filename
)
?
$stored_file
->
get_filename
()
:
$filename
;
$filename
=
is_null
(
$filename
)
?
$stored_file
->
get_filename
()
:
$filename
;
// Use given MIME type if specified.
$mimetype
=
$stored_file
->
get_mimetype
();
// Otherwise guess it.
if
(
!
$mimetype
||
$mimetype
===
'document/unknown'
)
{
$mimetype
=
get_mimetype_for_sending
(
$filename
);
}
// if user is using IE, urlencode the filename so that multibyte file name will show up correctly on popup
if
(
core_useragent
::
is_ie
())
{
$filename
=
rawurlencode
(
$filename
);
}
if
(
$forcedownload
)
{
header
(
'Content-Disposition: attachment; filename="'
.
$filename
.
'"'
);
}
else
if
(
$mimetype
!==
'application/x-shockwave-flash'
)
{
// If this is an swf don't pass content-disposition with filename as this makes the flash player treat the file
// as an upload and enforces security that may prevent the file from being loaded.
header
(
'Content-Disposition: inline; filename="'
.
$filename
.
'"'
);
}
if
(
$lifetime
>
0
)
{
$cacheability
=
' public,'
;
if
(
!
empty
(
$options
[
'cacheability'
])
&&
(
$options
[
'cacheability'
]
===
'public'
))
{
// This file must be cache-able by both browsers and proxies.
$cacheability
=
' public,'
;
}
else
if
(
!
empty
(
$options
[
'cacheability'
])
&&
(
$options
[
'cacheability'
]
===
'private'
))
{
// This file must be cache-able only by browsers.
$cacheability
=
' private,'
;
}
else
if
(
isloggedin
()
and
!
isguestuser
())
{
$cacheability
=
' private,'
;
}
header
(
'Cache-Control:'
.
$cacheability
.
' max-age='
.
$lifetime
.
', no-transform'
);
header
(
'Expires: '
.
gmdate
(
'D, d M Y H:i:s'
,
time
()
+
$lifetime
)
.
' GMT'
);
header
(
'Pragma: '
);
}
else
{
// Do not cache files in proxies and browsers
if
(
is_https
())
{
// HTTPS sites - watch out for IE! KB812935 and KB316431.
header
(
'Cache-Control: private, max-age=10, no-transform'
);
header
(
'Expires: '
.
gmdate
(
'D, d M Y H:i:s'
,
0
)
.
' GMT'
);
header
(
'Pragma: '
);
}
else
{
//normal http - prevent caching at all cost
header
(
'Cache-Control: private, must-revalidate, pre-check=0, post-check=0, max-age=0, no-transform'
);
header
(
'Expires: '
.
gmdate
(
'D, d M Y H:i:s'
,
0
)
.
' GMT'
);
header
(
'Pragma: no-cache'
);
}
}
// Allow cross-origin requests only for Web Services.
// This allow to receive requests done by Web Workers or webapps in different domains.
if
(
WS_SERVER
)
{
header
(
'Access-Control-Allow-Origin: *'
);
}
if
(
empty
(
$filter
))
{
// send the contents
readfile_accel
(
$stored_file
,
$mimetype
,
!
$dontdie
);
}
else
{
// Try to put the file through filters
if
(
$mimetype
==
'text/html'
||
$mimetype
==
'application/xhtml+xml'
)
{
$options
=
new
stdClass
();
$options
->
noclean
=
true
;
$options
->
nocache
=
true
;
// temporary workaround for MDL-5136
$text
=
$stored_file
->
get_content
();
$output
=
format_text
(
$text
,
FORMAT_HTML
,
$options
,
$COURSE
->
id
);
readstring_accel
(
$output
,
$mimetype
,
false
);
}
else
if
((
$mimetype
==
'text/plain'
)
and
(
$filter
==
1
))
{
// only filter text if filter all files is selected
$options
=
new
stdClass
();
$options
->
newlines
=
false
;
$options
->
noclean
=
true
;
$text
=
$stored_file
->
get_content
();
$output
=
'<pre>'
.
format_text
(
$text
,
FORMAT_MOODLE
,
$options
,
$COURSE
->
id
)
.
'</pre>'
;
readstring_accel
(
$output
,
$mimetype
,
false
);
}
else
{
// Just send it out raw
readfile_accel
(
$stored_file
,
$mimetype
,
!
$dontdie
);
}
}
if
(
$dontdie
)
{
return
;
}
die
;
//no more chars to output!!!
send_file
(
$stored_file
,
$filename
,
$lifetime
,
$filter
,
false
,
$forcedownload
,
$mimetype
,
$dontdie
,
$options
);
}
/**
...
...
lib/jslib.php
View file @
e890de55
...
...
@@ -34,14 +34,15 @@ defined('MOODLE_INTERNAL') || die();
function
js_send_cached
(
$jspath
,
$etag
,
$filename
=
'javascript.php'
)
{
require
(
__DIR__
.
'/xsendfilelib.php'
);
$lifetime
=
60
*
60
*
24
*
60
;
// 60 days only - the revision may get incremented quite often
// 90 days only - based on Moodle point release cadence being every 3 months.
$lifetime
=
60
*
60
*
24
*
90
;
header
(
'Etag: "'
.
$etag
.
'"'
);
header
(
'Content-Disposition: inline; filename="'
.
$filename
.
'"'
);
header
(
'Last-Modified: '
.
gmdate
(
'D, d M Y H:i:s'
,
filemtime
(
$jspath
))
.
' GMT'
);
header
(
'Expires: '
.
gmdate
(
'D, d M Y H:i:s'
,
time
()
+
$lifetime
)
.
' GMT'
);
header
(
'Pragma: '
);
header
(
'Cache-Control: public, max-age='
.
$lifetime
);
header
(
'Cache-Control: public, max-age='
.
$lifetime
.
', immutable'
);
header
(
'Accept-Ranges: none'
);
header
(
'Content-Type: application/javascript; charset=utf-8'
);
...
...
@@ -81,7 +82,8 @@ function js_send_uncached($js, $filename = 'javascript.php') {
* @param string $etag
*/
function
js_send_unmodified
(
$lastmodified
,
$etag
)
{
$lifetime
=
60
*
60
*
24
*
60
;
// 60 days only - the revision may get incremented quite often
// 90 days only - based on Moodle point release cadence being every 3 months.
$lifetime
=
60
*
60
*
24
*
90
;
header
(
'HTTP/1.1 304 Not Modified'
);
header
(
'Expires: '
.
gmdate
(
'D, d M Y H:i:s'
,
time
()
+
$lifetime
)
.
' GMT'
);
header
(
'Cache-Control: public, max-age='
.
$lifetime
);
...
...
lib/upgrade.txt
View file @
e890de55
...
...
@@ -52,6 +52,7 @@ information provided here is intended especially for developers.
- the following "<element_string>" exists:
* get_user_capability_course() now has an additional parameter 'limit'. This can be used to return a set number of records with
the submitted capability. The parameter 'fieldsexceptid' will now accept context fields which can be used for preloading.
* The caching option 'immutable' has been added to send_stored_file() and send_file().
=== 3.2 ===
...
...
theme/font.php
View file @
e890de55
...
...
@@ -106,7 +106,8 @@ if ($rev > 0) {
if
(
!
empty
(
$_SERVER
[
'HTTP_IF_NONE_MATCH'
])
||
!
empty
(
$_SERVER
[
'HTTP_IF_MODIFIED_SINCE'
]))
{
// We do not actually need to verify the etag value because our files
// never change in cache because we increment the rev parameter.
$lifetime
=
60
*
60
*
24
*
60
;
// 60 days only - the revision may get incremented quite often.
// 90 days only - based on Moodle point release cadence being every 3 months.
$lifetime
=
60
*
60
*
24
*
90
;
header
(
'HTTP/1.1 304 Not Modified'
);
header
(
'Expires: '
.
gmdate
(
'D, d M Y H:i:s'
,
time
()
+
$lifetime
)
.
' GMT'
);
header
(
'Cache-Control: public, max-age='
.
$lifetime
);
...
...
@@ -173,14 +174,15 @@ function send_cached_font($fontpath, $etag, $font, $mimetype) {
global
$CFG
;
require
(
"
$CFG->dirroot
/lib/xsendfilelib.php"
);
$lifetime
=
60
*
60
*
24
*
60
;
// 60 days only - the revision may get incremented quite often.
// 90 days only - based on Moodle point release cadence being every 3 months.
$lifetime
=
60
*
60
*
24
*
90
;
header
(
'Etag: "'
.
$etag
.
'"'
);
header
(
'Content-Disposition: inline; filename="'
.
$font
.
'"'
);
header
(
'Last-Modified: '
.
gmdate
(
'D, d M Y H:i:s'
,
filemtime
(
$fontpath
))
.
' GMT'
);
header
(
'Expires: '
.
gmdate
(
'D, d M Y H:i:s'
,
time
()
+
$lifetime
)
.
' GMT'
);
header
(
'Pragma: '
);
header
(
'Cache-Control: public, max-age='
.
$lifetime
);
header
(
'Cache-Control: public, max-age='
.
$lifetime
.
', immutable'
);
header
(
'Accept-Ranges: none'
);
header
(
'Content-Type: '
.
$mimetype
);
header
(
'Content-Length: '
.
filesize
(
$fontpath
));
...
...
theme/image.php
View file @
e890de55
...
...
@@ -105,9 +105,10 @@ if ($rev > 0) {
}
if
(
$cacheimage
)
{
if
(
!
empty
(
$_SERVER
[
'HTTP_IF_NONE_MATCH'
])
||
!
empty
(
$_SERVER
[
'HTTP_IF_MODIFIED_SINCE'
]))
{
// we do not actually need to verify the etag value because our files
// never change in cache because we increment the rev parameter
$lifetime
=
60
*
60
*
24
*
60
;
// 60 days only - the revision may get incremented quite often
// We do not actually need to verify the etag value because our files
// never change in cache because we increment the rev parameter.
// 90 days only - based on Moodle point release cadence being every 3 months.
$lifetime
=
60
*
60
*
24
*
90
;
$mimetype
=
get_contenttype_from_ext
(
$ext
);
header
(
'HTTP/1.1 304 Not Modified'
);
header
(
'Expires: '
.
gmdate
(
'D, d M Y H:i:s'
,
time
()
+
$lifetime
)
.
' GMT'
);
...
...
@@ -219,7 +220,8 @@ function send_cached_image($imagepath, $etag) {
global
$CFG
;
require
(
"
$CFG->dirroot
/lib/xsendfilelib.php"
);
$lifetime
=
60
*
60
*
24
*
60
;
// 60 days only - the revision may get incremented quite often
// 90 days only - based on Moodle point release cadence being every 3 months.
$lifetime
=
60
*
60
*
24
*
90
;
$pathinfo
=
pathinfo
(
$imagepath
);
$imagename
=
$pathinfo
[
'filename'
]
.
'.'
.
$pathinfo
[
'extension'
];
...
...
@@ -230,7 +232,7 @@ function send_cached_image($imagepath, $etag) {
header
(
'Last-Modified: '
.
gmdate
(
'D, d M Y H:i:s'
,
filemtime
(
$imagepath
))
.
' GMT'
);
header
(
'Expires: '
.
gmdate
(
'D, d M Y H:i:s'
,
time
()
+
$lifetime
)
.
' GMT'
);
header
(
'Pragma: '
);
header
(
'Cache-Control: public, max-age='
.
$lifetime
.
', no-transform'
);
header
(
'Cache-Control: public, max-age='
.
$lifetime
.
', no-transform
, immutable
'
);
header
(
'Accept-Ranges: none'
);
header
(
'Content-Type: '
.
$mimetype
);
header
(
'Content-Length: '
.
filesize
(
$imagepath
));
...
...
theme/jquery.php
View file @
e890de55
...
...
@@ -76,7 +76,8 @@ if (!$file or is_dir($file)) {
}
$etag
=
sha1
(
"
$component
/
$path
"
);
$lifetime
=
60
*
60
*
24
*
120
;
// 120 days should be enough.
// 90 days only - based on Moodle point release cadence being every 3 months.
$lifetime
=
60
*
60
*
24
*
90
;
$pathinfo
=
pathinfo
(
$path
);
if
(
empty
(
$pathinfo
[
'extension'
]))
{
...
...
@@ -125,7 +126,7 @@ header('Content-Disposition: inline; filename="'.$filename.'"');
header
(
'Last-Modified: '
.
gmdate
(
'D, d M Y H:i:s'
,
filemtime
(
$file
))
.
' GMT'
);
header
(
'Expires: '
.
gmdate
(
'D, d M Y H:i:s'
,
time
()
+
$lifetime
)
.
' GMT'
);
header
(
'Pragma: '
);
header
(
'Cache-Control: public, max-age='
.
$lifetime
);
header
(
'Cache-Control: public, max-age='
.
$lifetime
.
', immutable'
);
header
(
'Accept-Ranges: none'
);
header
(
'Content-Type: '
.
$mimetype
);
...
...
theme/yui_combo.php
View file @
e890de55
...
...
@@ -377,7 +377,7 @@ function combo_send_cached($content, $mimetype, $etag, $lastmodified) {
header
(
'Last-Modified: '
.
gmdate
(
'D, d M Y H:i:s'
,
$lastmodified
)
.
' GMT'
);
header
(
'Expires: '
.
gmdate
(
'D, d M Y H:i:s'
,
time
()
+
$lifetime
)
.
' GMT'
);
header
(
'Pragma: '
);
header
(
'Cache-Control: public, max-age='
.
$lifetime
);
header
(
'Cache-Control: public, max-age='
.
$lifetime
.
', immutable'
);
header
(
'Accept-Ranges: none'
);
header
(
'Content-Type: '
.
$mimetype
);
header
(
'Etag: "'
.
$etag
.
'"'
);
...
...
theme/yui_image.php
View file @
e890de55
...
...
@@ -123,7 +123,7 @@ function yui_image_cached($imagepath, $imagename, $mimetype, $etag) {
header
(
'Last-Modified: '
.
gmdate
(
'D, d M Y H:i:s'
,
filemtime
(
$imagepath
))
.
' GMT'
);
header
(
'Expires: '
.
gmdate
(
'D, d M Y H:i:s'
,
time
()
+
$lifetime
)
.
' GMT'
);
header
(
'Pragma: '
);
header
(
'Cache-Control: public, max-age=
315360000
, no-transform'
);
header
(
'Cache-Control: public, max-age=
'
.
$lifetime
.
'
, no-transform
, immutable
'
);
header
(
'Accept-Ranges: none'
);
header
(
'Content-Type: '
.
$mimetype
);
header
(
'Content-Length: '
.
filesize
(
$imagepath
));
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment