summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorBrion Vibber <brion@pobox.com>2010-05-10 16:18:29 -0700
committerBrion Vibber <brion@pobox.com>2010-06-28 08:59:47 -0700
commit9c7b66984c46668f314f93337d28c62854b6d134 (patch)
tree75c9c75503803f8d863a7bd04f33c2f139a37849 /lib
parent41d81b996fdd8276cc04e750297a12f852a97bf4 (diff)
Enhanced upload file type detection. If given an original filename, we'll attempt to detect type from the extension if we were unable to make a definitive match from content. Generic octet-stream, zip, and MS Office type are explicitly singled out for re-checks, which fixes OpenOffice and MS Office documents to come up with the proper types when misdetected.
File extensions can also be added to the upload type whitelist; they'll be normalized to types for the actual comparison, so only known extensions will work.
Diffstat (limited to 'lib')
-rw-r--r--lib/mediafile.php54
1 files changed, 51 insertions, 3 deletions
diff --git a/lib/mediafile.php b/lib/mediafile.php
index 10d90d008..85d673d92 100644
--- a/lib/mediafile.php
+++ b/lib/mediafile.php
@@ -180,7 +180,8 @@ class MediaFile
return;
}
- $mimetype = MediaFile::getUploadedFileType($_FILES[$param]['tmp_name']);
+ $mimetype = MediaFile::getUploadedFileType($_FILES[$param]['tmp_name'],
+ $_FILES[$param]['name']);
$filename = null;
@@ -241,19 +242,41 @@ class MediaFile
return new MediaFile($user, $filename, $mimetype);
}
- static function getUploadedFileType($f) {
+ /**
+ * Attempt to identify the content type of a given file.
+ *
+ * @param mixed $f file handle resource, or filesystem path as string
+ * @param string $originalFilename (optional) for extension-based detection
+ * @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 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
+ */
+ static function getUploadedFileType($f, $originalFilename=false) {
require_once 'MIME/Type.php';
+ require_once 'MIME/Type/Extension.php';
+ $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.
+
if (is_string($f)) {
// assuming a filename
$filetype = MIME_Type::autoDetect($f);
+
} else {
// assuming a filehandle
@@ -262,7 +285,32 @@ class MediaFile
$filetype = MIME_Type::autoDetect($stream['uri']);
}
- if (common_config('attachments', 'supported') === true || in_array($filetype, common_config('attachments', 'supported'))) {
+ // The content-based sources for MIME_Type::autoDetect()
+ // are wildly unreliable for office-type documents. If we've
+ // 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',
+ 'application/vnd.ms-office',
+ 'application/zip');
+
+ if ($originalFilename && (!$filetype || in_array($filetype, $unclearTypes))) {
+ $type = $mte->getMIMEType($originalFilename);
+ if (is_string($type)) {
+ $filetype = $type;
+ }
+ }
+
+ $supported = common_config('attachments', 'supported');
+ if (is_array($supported)) {
+ // Normalize extensions to mime types
+ foreach ($supported as $i => $entry) {
+ if (strpos($entry, '/') === false) {
+ common_log(LOG_INFO, "sample.$entry");
+ $supported[$i] = $mte->getMIMEType("sample.$entry");
+ }
+ }
+ }
+ if ($supported === true || in_array($filetype, $supported)) {
return $filetype;
}
$media = MIME_Type::getMedia($filetype);