MDL-44828 filelib: Fix open error for force-downloaded files in mobile

Allow guessing of file's MIME type by default. Fallback to
application/octet-stream if MIME type cannot be determined.
This commit is contained in:
Jun Pataleta 2015-08-13 17:35:06 +08:00
parent 57739a72cb
commit 0c4c3b9aed
2 changed files with 61 additions and 18 deletions

View File

@ -1390,6 +1390,29 @@ function &get_mimetypes_array() {
return core_filetypes::get_types();
}
/**
* Determine a file's MIME type based on the given filename using the function mimeinfo.
*
* This function retrieves a file's MIME type for a file that will be sent to the user.
* This should only be used for file-sending purposes just like in send_stored_file, send_file, and send_temp_file.
* Should the file's MIME type cannot be determined by mimeinfo, it will return 'application/octet-stream' as a default
* MIME type which should tell the browser "I don't know what type of file this is, so just download it.".
*
* @param string $filename The file's filename.
* @return string The file's MIME type or 'application/octet-stream' if it cannot be determined.
*/
function get_mimetype_for_sending($filename = '') {
// Guess the file's MIME type using mimeinfo.
$mimetype = mimeinfo('type', $filename);
// Use octet-stream as fallback if MIME type cannot be determined by mimeinfo.
if (!$mimetype || $mimetype === 'document/unknown') {
$mimetype = 'application/octet-stream';
}
return $mimetype;
}
/**
* Obtains information about a filetype based on its extension. Will
* use a default if no information is present about that particular
@ -1988,12 +2011,8 @@ function readstring_accel($string, $mimetype, $accelerate) {
function send_temp_file($path, $filename, $pathisstring=false) {
global $CFG;
if (core_useragent::is_firefox()) {
// only FF is known to correctly save to disk before opening...
$mimetype = mimeinfo('type', $filename);
} else {
$mimetype = 'application/x-forcedownload';
}
// Guess the file's MIME type.
$mimetype = get_mimetype_for_sending($filename);
// close session - not needed anymore
\core\session\manager::write_close();
@ -2076,12 +2095,10 @@ function send_file($path, $filename, $lifetime = null , $filter=0, $pathisstring
\core\session\manager::write_close(); // Unlock session during file serving.
// Use given MIME type if specified, otherwise guess it using mimeinfo.
// IE, Konqueror and Opera open html file directly in browser from web even when directed to save it to disk :-O
// only Firefox saves all files locally before opening when content-disposition: attachment stated
$isFF = core_useragent::is_firefox(); // only FF properly tested
$mimetype = ($forcedownload and !$isFF) ? 'application/x-forcedownload' :
($mimetype ? $mimetype : mimeinfo('type', $filename));
// Use given MIME type if specified, 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()) {
@ -2254,13 +2271,15 @@ function send_stored_file($stored_file, $lifetime=null, $filter=0, $forcedownloa
\core\session\manager::write_close(); // Unlock session during file serving.
// Use given MIME type if specified, otherwise guess it using mimeinfo.
// IE, Konqueror and Opera open html file directly in browser from web even when directed to save it to disk :-O
// only Firefox saves all files locally before opening when content-disposition: attachment stated
$filename = is_null($filename) ? $stored_file->get_filename() : $filename;
$isFF = core_useragent::is_firefox(); // only FF properly tested
$mimetype = ($forcedownload and !$isFF) ? 'application/x-forcedownload' :
($stored_file->get_mimetype() ? $stored_file->get_mimetype() : mimeinfo('type', $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()) {

View File

@ -879,6 +879,30 @@ EOF;
$this->assertEquals(true, $mimeinfo['txt']['defaulticon']);
}
/**
* Tests for get_mimetype_for_sending function.
*/
public function test_get_mimetype_for_sending() {
// Without argument.
$this->assertEquals('application/octet-stream', get_mimetype_for_sending());
// Argument is null.
$this->assertEquals('application/octet-stream', get_mimetype_for_sending(null));
// Filename having no extension.
$this->assertEquals('application/octet-stream', get_mimetype_for_sending('filenamewithoutextension'));
// Test using the extensions listed from the get_mimetypes_array function.
$mimetypes = get_mimetypes_array();
foreach ($mimetypes as $ext => $info) {
if ($ext === 'xxx') {
$this->assertEquals('application/octet-stream', get_mimetype_for_sending('SampleFile.' . $ext));
} else {
$this->assertEquals($info['type'], get_mimetype_for_sending('SampleFile.' . $ext));
}
}
}
/**
* Test curl agent settings.
*/