Browse Source

updated mime_detect.inc to use internal drupal file_mimetype_mapping function

A SimpleTest file has also been included to allow you to test this file
for errors.

Please note the require once directive at the top of
tests/MimeClass.test.  I am not sure if this is Drupal kosher, but the
test wouldn't work without it.
There is probably a way around this include statement but I will leave
this to the Drupal experts.

Note that the Drupal 7 function file_mimetype_mapping has a Drupal alter
statement:

// Allow modules to alter the default mapping.
drupal_alter('file_mimetype_mapping', $mapping);

using this hook, you can add to this internal mime type list without
updating drupal core.

Hope this helps! If there are any questions please feel free to email me
at andrewfreddin@gmail.com
pull/308/head
Andrew Reddin 12 years ago
parent
commit
db666dcfdc
  1. 395
      includes/mime_detect.inc
  2. 1
      islandora.info
  3. 1745
      tests/MimeClass.test

395
includes/mime_detect.inc

@ -1,369 +1,132 @@
<?php
/**
* @file
* Class for determining MIME types and file extensions.
*
* This class inspired by Chris Jean's work, here:
* http://chrisjean.com/2009/02/14/generating-mime-type-in-php-is-not-magic/
*
* It does some MIME trickery, inspired by the need to to deal with Openoffice
* and MS Office 2007 file formats -- which are often mis-interpreted by
* mime-magic, fileinfo, and the *nix `file` command.
* Replacement for the original islandora MimeClass.
* Does essentially the same thing, just using the built in drupal 7
* mime system.
*
* In Drupal 6, we also make use of file_get_mimetype. See:
* http://api.drupal.org/api/function/file_get_mimetype/6
* ... however this only provides a uni-directional lookup (ext->mime).
* While I don't have a specific use case for a mime->extension lookup, I think
* it's good to have in here.
* A nice added bonus is that this new class will put a note in watchdog when
* it encounters a filetype it doesnt know.
*
* Drupal 7 will have better mime handlers. See:
* http://api.drupal.org/api/function/file_default_mimetype_mapping/7
*/
class MimeDetect {
protected $protectedMimeTypes = array(
/*
* This is a shortlist of mimetypes which should catch most
* mimetype<-->extension lookups in the context of Islandora collections.
*
* It has been cut from a much longer list.
*
* Two types of mimetypes should be put in this list:
* 1) Special emerging formats which may not yet be expressed in the system
* mime.types file.
* 2) Heavily used mimetypes of particular importance to the Islandora
* project, as lookups against this list will be quicker and less
* resource intensive than other methods.
*
* Lookups are first checked against this short list. If no results are
* found, then the lookup function may move on to check other sources,
* namely the system's mime.types file.
*
* In most cases though, this short list should suffice.
*
* If modifying this list, please note that for promiscuous mimetypes
* (those which map to multiple extensions, such as text/plain)
* The function get_extension will always return the *LAST* extension in
* this list, so you should put your preferred extension *LAST*.
*
* e.g...
* "jpeg" => "image/jpeg",
* "jpe" => "image/jpeg",
* "jpg" => "image/jpeg",
*
* $this->get_extension('image/jpeg') will always return 'jpg'.
*
*/
// Openoffice:
'odb' => 'application/vnd.oasis.opendocument.database',
'odc' => 'application/vnd.oasis.opendocument.chart',
'odf' => 'application/vnd.oasis.opendocument.formula',
'odg' => 'application/vnd.oasis.opendocument.graphics',
'odi' => 'application/vnd.oasis.opendocument.image',
'odm' => 'application/vnd.oasis.opendocument.text-master',
'odp' => 'application/vnd.oasis.opendocument.presentation',
'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
'odt' => 'application/vnd.oasis.opendocument.text',
'otg' => 'application/vnd.oasis.opendocument.graphics-template',
'oth' => 'application/vnd.oasis.opendocument.text-web',
'otp' => 'application/vnd.oasis.opendocument.presentation-template',
'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template',
'ott' => 'application/vnd.oasis.opendocument.text-template',
// Staroffice:
'stc' => 'application/vnd.sun.xml.calc.template',
'std' => 'application/vnd.sun.xml.draw.template',
'sti' => 'application/vnd.sun.xml.impress.template',
'stw' => 'application/vnd.sun.xml.writer.template',
'sxc' => 'application/vnd.sun.xml.calc',
'sxd' => 'application/vnd.sun.xml.draw',
'sxg' => 'application/vnd.sun.xml.writer.global',
'sxi' => 'application/vnd.sun.xml.impress',
'sxm' => 'application/vnd.sun.xml.math',
'sxw' => 'application/vnd.sun.xml.writer',
// K-office:
'kil' => 'application/x-killustrator',
'kpt' => 'application/x-kpresenter',
'kpr' => 'application/x-kpresenter',
'ksp' => 'application/x-kspread',
'kwt' => 'application/x-kword',
'kwd' => 'application/x-kword',
// Ms office 97:
'doc' => 'application/msword',
'xls' => 'application/vnd.ms-excel',
'ppt' => 'application/vnd.ms-powerpoint',
// Office2007:
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'docm' => 'application/vnd.ms-word.document.macroEnabled.12',
'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
'dotm' => 'application/vnd.ms-word.template.macroEnabled.12',
'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'xlsm' => 'application/vnd.ms-excel.sheet.macroEnabled.12',
'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
'xltm' => 'application/vnd.ms-excel.template.macroEnabled.12',
'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'pptm' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12',
'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12',
'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
'potm' => 'application/vnd.ms-powerpoint.template.macroEnabled.12',
'ppam' => 'application/vnd.ms-powerpoint.addin.macroEnabled.12',
'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
'sldm' => 'application/vnd.ms-powerpoint.slide.macroEnabled.12',
// Wordperfect (who cares?):
'wpd' => 'application/wordperfect',
// Common and generic containers:
'pdf' => 'application/pdf',
'eps' => 'application/postscript',
'ps' => 'application/postscript',
'rtf' => 'text/rtf',
'rtx' => 'text/richtext',
'latex' => 'application/x-latex',
'tex' => 'application/x-tex',
'texi' => 'application/x-texinfo',
'texinfo' => 'application/x-texinfo',
// *ml:
'css' => 'text/css',
'htm' => 'text/html',
'html' => 'text/html',
'wbxml' => 'application/vnd.wap.wbxml',
'xht' => 'application/xhtml+xml',
'xhtml' => 'application/xhtml+xml',
'xsl' => 'text/xml',
'xml' => 'text/xml',
'csv' => 'text/csv',
'tsv' => 'text/tab-separated-values',
'txt' => 'text/plain',
// images:
"bmp" => "image/bmp",
'dng' => 'image/x-adobe-dng',
"gif" => "image/gif",
"ief" => "image/ief",
"jpeg" => "image/jpeg",
"jpe" => "image/jpeg",
"jpg" => "image/jpeg",
"jp2" => "image/jp2",
"png" => "image/png",
"tiff" => "image/tiff",
"tif" => "image/tif",
"djvu" => "image/vnd.djvu",
"djv" => "image/vnd.djvu",
"wbmp" => "image/vnd.wap.wbmp",
"ras" => "image/x-cmu-raster",
"pnm" => "image/x-portable-anymap",
"pbm" => "image/x-portable-bitmap",
"pgm" => "image/x-portable-graymap",
"ppm" => "image/x-portable-pixmap",
"rgb" => "image/x-rgb",
"xbm" => "image/x-xbitmap",
"xpm" => "image/x-xpixmap",
"xwd" => "image/x-windowdump",
// videos:
"mpeg" => "video/mpeg",
"mpe" => "video/mpeg",
"mpg" => "video/mpeg",
"m4v" => "video/mp4",
"mp4" => "video/mp4",
"ogv" => "video/ogg",
"qt" => "video/quicktime",
"mov" => "video/quicktime",
"mxu" => "video/vnd.mpegurl",
"avi" => "video/x-msvideo",
"movie" => "video/x-sgi-movie",
"flv" => "video/x-flv",
"swf" => "application/x-shockwave-flash",
// Audio:
"mp3" => "audio/mpeg",
"mp4a" => "audio/mp4",
"m4a" => "audio/mp4",
"oga" => "audio/ogg",
"ogg" => "audio/ogg",
"flac" => "audio/x-flac",
"wav" => "audio/vnd.wave",
// Compressed formats:
// (note: http://svn.cleancode.org/svn/email/trunk/mime.types)
"tgz" => "application/x-gzip",
"gz" => "application/x-gzip",
"tar" => "application/x-tar",
"gtar" => "application/x-gtar",
"zip" => "application/x-zip",
// others:
'bin' => 'application/octet-stream',
);
protected $protectedFileExtensions;
protected $systemTypes;
protected $systemExts;
protected $etcMimeTypes = '/etc/mime.types';
private $mime_types;
private $ext_types;
/**
* Construtor.
* Construtor
*/
public function __construct() {
//Drupal returns the mimetype list as a double assoc array with two entries:
//mimetypes: Integer array of mimetypes
//extensions: Assoc array of extensions
//
//The extension array can be used as a key to get the value in the mimetypes
//array.
//
//Example if $extensions['png'] == 5, then $mimetypes[5] = 'image/png'
//we want to combine this into 1 array for easy access.
$temp = file_mimetype_mapping();
// Populate the reverse shortlist:
$this->protectedFileExtensions = array_flip($this->protectedMimeTypes);
$temp_mime_types = $temp['mimetypes'];
$temp_mime_ext = $temp['extensions'];
// Pick up a local mime.types file if it is available.
if (is_readable('mime.types')) {
$this->etcMimeTypes = 'mime.types';
//free the memory in temp since we don't need it anymore
unset($temp);
//combine the two arrays into one.
foreach ($temp_mime_ext as $key => $val ) {
$this->mime_types[$key] = $temp_mime_types[$val];
}
//flip the mime_type array to make the ext array
$this->ext_types = array_flip($this->mime_types);
}
/**
* Gets MIME type associated with the give file's extension.
* function: getType
* description: An alias to get_mimetype,
* for backwards-compatibility with our old mimetype class.
*
* @param string $filename
* The filename
* @param bool $debug
* Returns a debug array.
* @param type $filename
* @return type
*/
function getType($filename) {
return $this->getMimetype($filename);
}
/**
* function: get_mimetype
* description: returns a mimetype associated with the
* file extension of $filename
*
* @return mixed
* string or an array
* @param type $filename
* @param type $debug
* @return string
* mimetype associated with the file extension of $filename
*/
public function getMimetype($filename, $debug = FALSE) {
//the file extension will be the last index in the exploded string
$ext = @end(explode('.' , $filename));
$ext = strtolower($ext);
$file_name_and_extension = explode('.', $filename);
$ext = drupal_strtolower(array_pop($file_name_and_extension));
if (!empty($this->protectedMimeTypes[$ext])) {
//check the array for a predetermined mime type. If not found, add a warning
//to the watch dog and use the system command to get a value
if (!empty($this->mime_types[$ext])) {
if (TRUE === $debug) {
return array('mime_type' => $this->protectedMimeTypes[$ext], 'method' => 'from_array');
}
return $this->protectedMimeTypes[$ext];
$return_type = $this->mime_types[$ext];
return array('mime_type' => $return_type, 'method' => 'from_array');
}
if (function_exists('file_get_mimetype')) {
$drupal_mimetype = file_get_mimetype($filename);
if ('application/octet-stream' != $drupal_mimetype) {
if (TRUE == $debug) {
return array('mime_type' => $drupal_mimetype, 'method' => 'file_get_mimetype');
}
return $drupal_mimetype;
return $this->mime_types[$ext];
}
else {
//this file was not in the drupal mime system.
//add a line to the watchdog informing us of this incident
$err_msg = 'Found a file extension not covered in the drupal mime func:';
watchdog('MimeClass', $err_msg . $ext );
}
if (!isset($this->systemTypes)) {
$this->systemTypes = $this->systemExtensionMimetypes();
}
if (isset($this->systemTypes[$ext])) {
//by default return application octet stream
if (TRUE == $debug) {
return array('mime_type' => $this->systemTypes[$ext], 'method' => 'mime.types');
}
return $this->systemTypes[$ext];
}
if (TRUE === $debug) {
return array('mime_type' => 'application/octet-stream', 'method' => 'last_resort');
}
return 'application/octet-stream';
}
/**
* Gets one valid file extension for a given MIME type.
*
* @param string $mime_type
* The MIME type.
* @param bool $debug
* Generated debug information?
* function: get_extension
* description: returns *one* valid file extension for a given $mime_type
*
* @return string
* The file extensions associated with the given MIME type.
* @param type $mime_type
* @param type $debug
* @return type
*/
public function getExtension($mime_type, $debug = FALSE) {
if (!empty($this->protectedFileExtensions[$mime_type])) {
if (TRUE == $debug) {
return array('extension' => $this->protectedFileExtensions[$mime_type], 'method' => 'from_array');
}
return $this->protectedFileExtensions[$mime_type];
}
public function getExtension($type, $debug = FALSE) {
if (!isset($this->systemExts)) {
$this->systemExts = $this->systemMimetypeExtensions();
}
if (isset($this->systemExts[$mime_type])) {
if (!empty($this->ext_types[$type])) {
if (TRUE == $debug) {
return array('extension' => $this->systemExts[$mime_type], 'method' => 'mime.types');
return array('extension' => $this->ext_types[$type], 'method' => 'from_array');
}
return $this->systemExts[$mime_type];
return $this->ext_types[$type];
}
else{
//return bin by default... this could cause errors if handled incorrectly
//and probably should return false or -1 or something to be handled
//client side.
if (TRUE == $debug) {
return array('extension' => 'bin', 'method' => 'last_resort');
}
return 'bin';
}
/**
* Gets an associative array of MIME type and extension associations.
*
* Users the system mime.types file, or a local mime.types if one is found
* @see MIMEDetect::__constuctor()
*
* @return array
* An associative array where the keys are MIME types and the values
* extensions.
*/
protected function systemMimetypeExtensions() {
$out = array();
if (file_exists($this->etcMimeTypes)) {
$file = fopen($this->etcMimeTypes, 'r');
while (($line = fgets($file)) !== FALSE) {
$line = trim(preg_replace('/#.*/', '', $line));
if (!$line) {
continue;
}
$parts = preg_split('/\s+/', $line);
if (count($parts) == 1) {
continue;
}
// A single part means a mimetype without extensions, which we ignore.
$type = array_shift($parts);
if (!isset($out[$type])) {
$out[$type] = array_shift($parts);
}
// We take the first ext from the line if many are present.
}
fclose($file);
}
return $out;
}
/**
* Gets a associative array of extensions and MIME types.
*
* Users the system mime.types file, or a local mime.types if one is found
* @see MIMEDetect::__constuctor()
*
* @return array
* An associative array where the keys are extensions and the values
* MIME types.
*/
protected function systemExtensionMimetypes() {
$out = array();
if (file_exists($this->etcMimeTypes)) {
$file = fopen($this->etcMimeTypes, 'r');
while (($line = fgets($file)) !== FALSE) {
$line = trim(preg_replace('/#.*/', '', $line));
if (!$line) {
continue;
}
$parts = preg_split('/\s+/', $line);
if (count($parts) == 1) {
continue;
}
// A single part means a mimetype without extensions, which we ignore.
$type = array_shift($parts);
foreach ($parts as $part) {
$out[$part] = $type;
}
}
fclose($file);
}
return $out;
}
}

1
islandora.info

@ -15,4 +15,5 @@ files[] = tests/web_test_case.inc
files[] = tests/authtokens.test
files[] = tests/hooks.test
files[] = tests/islandora_manage_permissions.test
files[] = tests/MimeClass.test
php = 5.3

1745
tests/MimeClass.test

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save