MediaFile loses dependency on PEAR::MIME
At the same time we remove the "filecommand" setting, since we will likely not have use of it thanks to PECL fileinfo. Also the "supported" list for attachment mime types has changed format, so we can keep track of at least some known file extensions.
This commit is contained in:
parent
0eb38b8f84
commit
6faed0e451
@ -549,10 +549,6 @@ supported: an array of mime types you accept to store and distribute,
|
|||||||
setup your server to properly recognize the types you want to
|
setup your server to properly recognize the types you want to
|
||||||
support.
|
support.
|
||||||
uploads: false to disable uploading files with notices (true by default).
|
uploads: false to disable uploading files with notices (true by default).
|
||||||
filecommand: The required MIME_Type library may need to use the 'file'
|
|
||||||
command. It tries the one in the Web server's path, but if
|
|
||||||
you're having problems with uploads, try setting this to the
|
|
||||||
correct value. Note: 'file' must accept '-b' and '-i' options.
|
|
||||||
|
|
||||||
For quotas, be sure you've set the upload_max_filesize and post_max_size
|
For quotas, be sure you've set the upload_max_filesize and post_max_size
|
||||||
in php.ini to be large enough to handle your upload. In httpd.conf
|
in php.ini to be large enough to handle your upload. In httpd.conf
|
||||||
@ -577,9 +573,6 @@ path: URL path, relative to the server, to find files. Defaults to
|
|||||||
main path + '/file/'.
|
main path + '/file/'.
|
||||||
ssl: whether to use HTTPS for file URLs. Defaults to null, meaning to
|
ssl: whether to use HTTPS for file URLs. Defaults to null, meaning to
|
||||||
guess based on other SSL settings.
|
guess based on other SSL settings.
|
||||||
filecommand: command to use for determining the type of a file. May be
|
|
||||||
skipped if fileinfo extension is installed. Defaults to
|
|
||||||
'/usr/bin/file'.
|
|
||||||
sslserver: if specified, this server will be used when creating HTTPS
|
sslserver: if specified, this server will be used when creating HTTPS
|
||||||
URLs. Otherwise, the site SSL server will be used, with /file/ path.
|
URLs. Otherwise, the site SSL server will be used, with /file/ path.
|
||||||
sslpath: if this and the sslserver are specified, this path will be used
|
sslpath: if this and the sslserver are specified, this path will be used
|
||||||
|
@ -213,42 +213,42 @@ $default =
|
|||||||
'sslserver' => null,
|
'sslserver' => null,
|
||||||
'sslpath' => null,
|
'sslpath' => null,
|
||||||
'ssl' => null,
|
'ssl' => null,
|
||||||
'supported' => array('image/png',
|
'supported' => array(
|
||||||
'image/jpeg',
|
'application/vnd.oasis.opendocument.chart' => 'odc',
|
||||||
'image/gif',
|
'application/vnd.oasis.opendocument.formula' => 'odf',
|
||||||
'image/svg+xml',
|
'application/vnd.oasis.opendocument.graphics' => 'odg',
|
||||||
'audio/mpeg',
|
'application/vnd.oasis.opendocument.graphics-template' => 'otg',
|
||||||
'audio/x-speex',
|
'application/vnd.oasis.opendocument.image' => 'odi',
|
||||||
'application/ogg',
|
'application/vnd.oasis.opendocument.presentation' => 'odp',
|
||||||
'application/pdf',
|
'application/vnd.oasis.opendocument.presentation-template' => 'otp',
|
||||||
'application/vnd.oasis.opendocument.text',
|
'application/vnd.oasis.opendocument.spreadsheet' => 'ods',
|
||||||
'application/vnd.oasis.opendocument.text-template',
|
'application/vnd.oasis.opendocument.spreadsheet-template' => 'ots',
|
||||||
'application/vnd.oasis.opendocument.graphics',
|
'application/vnd.oasis.opendocument.text' => 'odt',
|
||||||
'application/vnd.oasis.opendocument.graphics-template',
|
'application/vnd.oasis.opendocument.text-master' => 'odm',
|
||||||
'application/vnd.oasis.opendocument.presentation',
|
'application/vnd.oasis.opendocument.text-template' => 'ott',
|
||||||
'application/vnd.oasis.opendocument.presentation-template',
|
'application/vnd.oasis.opendocument.text-web' => 'oth',
|
||||||
'application/vnd.oasis.opendocument.spreadsheet',
|
'application/pdf' => 'pdf',
|
||||||
'application/vnd.oasis.opendocument.spreadsheet-template',
|
'application/zip' => 'zip',
|
||||||
'application/vnd.oasis.opendocument.chart',
|
'image/png' => 'png',
|
||||||
'application/vnd.oasis.opendocument.chart-template',
|
'image/jpeg' => 'jpg',
|
||||||
'application/vnd.oasis.opendocument.image',
|
'image/gif' => 'gif',
|
||||||
'application/vnd.oasis.opendocument.image-template',
|
'image/svg+xml' => 'svg',
|
||||||
'application/vnd.oasis.opendocument.formula',
|
'image/vnd.microsoft.icon' => 'ico',
|
||||||
'application/vnd.oasis.opendocument.formula-template',
|
'audio/ogg' => 'ogg',
|
||||||
'application/vnd.oasis.opendocument.text-master',
|
'audio/mpeg' => 'mpg',
|
||||||
'application/vnd.oasis.opendocument.text-web',
|
'audio/x-speex' => 'spx',
|
||||||
'application/x-zip',
|
'application/ogg' => 'ogx',
|
||||||
'application/zip',
|
'text/plain' => 'txt',
|
||||||
'text/plain',
|
'video/mpeg' => 'mpeg',
|
||||||
'video/mpeg',
|
'video/mp4' => 'mp4',
|
||||||
'video/mp4',
|
'video/ogg' => 'ogv',
|
||||||
'video/quicktime',
|
'video/quicktime' => 'mov',
|
||||||
'video/webm'),
|
'video/webm' => 'webm',
|
||||||
|
),
|
||||||
'file_quota' => 5000000,
|
'file_quota' => 5000000,
|
||||||
'user_quota' => 50000000,
|
'user_quota' => 50000000,
|
||||||
'monthly_quota' => 15000000,
|
'monthly_quota' => 15000000,
|
||||||
'uploads' => true,
|
'uploads' => true,
|
||||||
'filecommand' => '/usr/bin/file',
|
|
||||||
'show_thumbs' => true, // show thumbnails in notice lists for uploaded images, and photos and videos linked remotely that provide oEmbed info
|
'show_thumbs' => true, // show thumbnails in notice lists for uploaded images, and photos and videos linked remotely that provide oEmbed info
|
||||||
'thumb_width' => 100,
|
'thumb_width' => 100,
|
||||||
'thumb_height' => 75,
|
'thumb_height' => 75,
|
||||||
|
@ -228,7 +228,7 @@ class MediaFile
|
|||||||
// Throws exception if additional size does not respect quota
|
// Throws exception if additional size does not respect quota
|
||||||
File::respectsQuota($scoped, $_FILES[$param]['size']);
|
File::respectsQuota($scoped, $_FILES[$param]['size']);
|
||||||
|
|
||||||
$mimetype = MediaFile::getUploadedFileType($_FILES[$param]['tmp_name'],
|
$mimetype = self::getUploadedMimeType($_FILES[$param]['tmp_name'],
|
||||||
$_FILES[$param]['name']);
|
$_FILES[$param]['name']);
|
||||||
|
|
||||||
$basename = basename($_FILES[$param]['name']);
|
$basename = basename($_FILES[$param]['name']);
|
||||||
@ -252,7 +252,7 @@ class MediaFile
|
|||||||
|
|
||||||
File::respectsQuota($scoped, filesize($stream['uri']));
|
File::respectsQuota($scoped, filesize($stream['uri']));
|
||||||
|
|
||||||
$mimetype = MediaFile::getUploadedFileType($stream['uri']);
|
$mimetype = self::getUploadedMimeType($stream['uri']);
|
||||||
|
|
||||||
$filename = File::filename($scoped, "email", $mimetype);
|
$filename = File::filename($scoped, "email", $mimetype);
|
||||||
|
|
||||||
@ -273,77 +273,58 @@ class MediaFile
|
|||||||
/**
|
/**
|
||||||
* Attempt to identify the content type of a given file.
|
* Attempt to identify the content type of a given file.
|
||||||
*
|
*
|
||||||
* @param mixed $f file handle resource, or filesystem path as string
|
* @param string $filepath filesystem path as string (file must exist)
|
||||||
* @param string $originalFilename (optional) for extension-based detection
|
* @param string $originalFilename (optional) for extension-based detection
|
||||||
* @return string
|
* @return string
|
||||||
*
|
*
|
||||||
* @fixme is this an internal or public method? It's called from GetFileAction
|
|
||||||
* @fixme this seems to tie a front-end error message in, kinda confusing
|
* @fixme this seems to tie a front-end error message in, kinda confusing
|
||||||
* @fixme this looks like it could return a PEAR_Error in some cases, if
|
|
||||||
* type can't be identified and $config['attachments']['supported'] is true
|
|
||||||
*
|
*
|
||||||
* @throws ClientException if type is known, but not supported for local uploads
|
* @throws ClientException if type is known, but not supported for local uploads
|
||||||
*/
|
*/
|
||||||
static function getUploadedFileType($f, $originalFilename=false) {
|
static function getUploadedMimeType($filepath, $originalFilename=false) {
|
||||||
global $_PEAR;
|
|
||||||
|
|
||||||
require_once 'MIME/Type.php';
|
|
||||||
require_once 'MIME/Type/Extension.php';
|
|
||||||
|
|
||||||
// We have to disable auto handling of PEAR errors
|
|
||||||
$_PEAR->staticPushErrorHandling(PEAR_ERROR_RETURN);
|
|
||||||
$mte = new MIME_Type_Extension();
|
|
||||||
|
|
||||||
$cmd = &$_PEAR->getStaticProperty('MIME_Type', 'fileCmd');
|
|
||||||
$cmd = common_config('attachments', 'filecommand');
|
|
||||||
|
|
||||||
$filetype = null;
|
|
||||||
|
|
||||||
// If we couldn't get a clear type from the file extension,
|
|
||||||
// we'll go ahead and try checking the content. Content checks
|
|
||||||
// are unambiguous for most image files, but nearly useless
|
|
||||||
// for office document formats.
|
|
||||||
|
|
||||||
// We only accept filenames to existing files
|
// We only accept filenames to existing files
|
||||||
$filetype = MIME_Type::autoDetect($f);
|
$mimelookup = new finfo(FILEINFO_MIME_TYPE);
|
||||||
|
$mimetype = $mimelookup->file($filepath);
|
||||||
|
|
||||||
// The content-based sources for MIME_Type::autoDetect()
|
// Unclear types are such that we can't really tell by the auto
|
||||||
// are wildly unreliable for office-type documents. If we've
|
// detect what they are (.bin, .exe etc. are just "octet-stream")
|
||||||
// gotten an unclear reponse back or just couldn't identify it,
|
|
||||||
// we'll try detecting a type from its extension...
|
|
||||||
$unclearTypes = array('application/octet-stream',
|
$unclearTypes = array('application/octet-stream',
|
||||||
'application/vnd.ms-office',
|
'application/vnd.ms-office',
|
||||||
'application/zip',
|
'application/zip',
|
||||||
// TODO: for XML we could do better content-based sniffing too
|
// TODO: for XML we could do better content-based sniffing too
|
||||||
'text/xml');
|
'text/xml');
|
||||||
|
|
||||||
if ($originalFilename && (!$filetype || in_array($filetype, $unclearTypes))) {
|
$supported = common_config('attachments', 'supported');
|
||||||
$type = $mte->getMIMEType($originalFilename);
|
|
||||||
if (is_string($type)) {
|
// If we didn't match, or it is an unclear match
|
||||||
$filetype = $type;
|
if ($originalFilename && (!$mimetype || in_array($mimetype, $unclearTypes))) {
|
||||||
|
$type = common_supported_ext_to_mime($originalFilename);
|
||||||
|
if (!empty($type)) {
|
||||||
|
return $type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$supported = common_config('attachments', 'supported');
|
// If $config['attachments']['supported'] equals boolean true, accept any mimetype
|
||||||
if ($supported === true || in_array($filetype, $supported)) {
|
if ($supported === true || array_key_exists($mimetype, $supported)) {
|
||||||
// Restore PEAR error handlers for our DB code...
|
// FIXME: Don't know if it always has a mimetype here because
|
||||||
$_PEAR->staticPopErrorHandling();
|
// finfo->file CAN return false on error: http://php.net/finfo_file
|
||||||
return $filetype;
|
// so if $supported === true, this may return something unexpected.
|
||||||
|
return $mimetype;
|
||||||
}
|
}
|
||||||
$media = MIME_Type::getMedia($filetype);
|
|
||||||
|
// We can conclude that we have failed to get the MIME type
|
||||||
|
$media = common_get_mime_media($mimetype);
|
||||||
if ('application' !== $media) {
|
if ('application' !== $media) {
|
||||||
// TRANS: Client exception thrown trying to upload a forbidden MIME type.
|
// TRANS: Client exception thrown trying to upload a forbidden MIME type.
|
||||||
// TRANS: %1$s is the file type that was denied, %2$s is the application part of
|
// TRANS: %1$s is the file type that was denied, %2$s is the application part of
|
||||||
// TRANS: the MIME type that was denied.
|
// TRANS: the MIME type that was denied.
|
||||||
$hint = sprintf(_('"%1$s" is not a supported file type on this server. ' .
|
$hint = sprintf(_('"%1$s" is not a supported file type on this server. ' .
|
||||||
'Try using another %2$s format.'), $filetype, $media);
|
'Try using another %2$s format.'), $mimetype, $media);
|
||||||
} else {
|
} else {
|
||||||
// TRANS: Client exception thrown trying to upload a forbidden MIME type.
|
// TRANS: Client exception thrown trying to upload a forbidden MIME type.
|
||||||
// TRANS: %s is the file type that was denied.
|
// TRANS: %s is the file type that was denied.
|
||||||
$hint = sprintf(_('"%s" is not a supported file type on this server.'), $filetype);
|
$hint = sprintf(_('"%s" is not a supported file type on this server.'), $mimetype);
|
||||||
}
|
}
|
||||||
// Restore PEAR error handlers for our DB code...
|
|
||||||
$_PEAR->staticPopErrorHandling();
|
|
||||||
throw new ClientException($hint);
|
throw new ClientException($hint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
25
lib/util.php
25
lib/util.php
@ -1797,6 +1797,31 @@ function common_accept_to_prefs($accept, $def = '*/*')
|
|||||||
return $prefs;
|
return $prefs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Match by our supported file extensions
|
||||||
|
function common_supported_ext_to_mime($fileext)
|
||||||
|
{
|
||||||
|
// Accept a filename and take out the extension
|
||||||
|
if (strpos($fileext, '.') !== false) {
|
||||||
|
$fileext = substr(strrchr($fileext, '.'), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
$supported = common_config('attachments', 'supported');
|
||||||
|
foreach($supported as $type => $ext) {
|
||||||
|
if ($ext === $fileext) {
|
||||||
|
return $type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The MIME "media" is the part before the slash (video in video/webm)
|
||||||
|
function common_get_mime_media($type)
|
||||||
|
{
|
||||||
|
$tmp = explode('/', $type);
|
||||||
|
return strtolower($tmp[0]);
|
||||||
|
}
|
||||||
|
|
||||||
function common_mime_type_match($type, $avail)
|
function common_mime_type_match($type, $avail)
|
||||||
{
|
{
|
||||||
if(array_key_exists($type, $avail)) {
|
if(array_key_exists($type, $avail)) {
|
||||||
|
@ -29,13 +29,13 @@ class MediaFileTest extends PHPUnit_Framework_TestCase
|
|||||||
* @dataProvider fileTypeCases
|
* @dataProvider fileTypeCases
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function testFileType($filename, $expectedType)
|
public function testMimeType($filename, $expectedType)
|
||||||
{
|
{
|
||||||
if (!file_exists($filename)) {
|
if (!file_exists($filename)) {
|
||||||
throw new Exception("WTF? $filename test file missing");
|
throw new Exception("WTF? $filename test file missing");
|
||||||
}
|
}
|
||||||
|
|
||||||
$type = MediaFile::getUploadedFileType($filename, basename($filename));
|
$type = MediaFile::getUploadedMimeType($filename, basename($filename));
|
||||||
$this->assertEquals($expectedType, $type);
|
$this->assertEquals($expectedType, $type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ class MediaFileTest extends PHPUnit_Framework_TestCase
|
|||||||
* @dataProvider fileTypeCases
|
* @dataProvider fileTypeCases
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public function testUploadedFileType($filename, $expectedType)
|
public function testUploadedMimeType($filename, $expectedType)
|
||||||
{
|
{
|
||||||
if (!file_exists($filename)) {
|
if (!file_exists($filename)) {
|
||||||
throw new Exception("WTF? $filename test file missing");
|
throw new Exception("WTF? $filename test file missing");
|
||||||
@ -52,7 +52,7 @@ class MediaFileTest extends PHPUnit_Framework_TestCase
|
|||||||
fwrite($tmp, file_get_contents($filename));
|
fwrite($tmp, file_get_contents($filename));
|
||||||
|
|
||||||
$tmp_metadata = stream_get_meta_data($tmp);
|
$tmp_metadata = stream_get_meta_data($tmp);
|
||||||
$type = MediaFile::getUploadedFileType($tmp_metadata['uri'], basename($filename));
|
$type = MediaFile::getUploadedMimeType($tmp_metadata['uri'], basename($filename));
|
||||||
$this->assertEquals($expectedType, $type);
|
$this->assertEquals($expectedType, $type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user