Browse Source

commit after adding the array checks again

pull/109/merge
Paul Pound 13 years ago
parent
commit
72c1771e2e
  1. 23
      RestConnection.inc
  2. 4
      includes/ingest-menu.inc
  3. 27
      includes/islandora.ingest.inc
  4. 80
      islandora.module
  5. 21
      islandora_basic_collection/islandora_basic_collection.module
  6. 359
      utils/MimeClass.inc

23
RestConnection.inc

@ -13,9 +13,32 @@ require_once 'sites/all/libraries/tuque/FedoraRelationships.php';
class RestConnection { class RestConnection {
/**
* Connection to the repository
*
* @var RepositoryConnection
*/
public $connection = NULL; public $connection = NULL;
/**
* The Fedora API we are using
*
* @var FedoraAPI
*/
public $api = NULL; public $api = NULL;
/**
* The cache we use to connect.
*
* @var SimpleCache
*/
public $cache = NULL; public $cache = NULL;
/**
* The repository object.
*
* @var FedoraRepository
*/
public $repository = NULL; public $repository = NULL;
function RestConnection($user) { function RestConnection($user) {

4
includes/ingest-menu.inc

@ -22,7 +22,7 @@ function islandora_ingest_callback($collection_pid) {
} }
elseif ($registry_count == 1) { elseif ($registry_count == 1) {
// One registry implementation, go there // One registry implementation, go there
drupal_goto($ingest_registry[0]['url']); drupal_goto($ingest_registry[0]['url'] . "/$collection_pid");
} }
else { else {
// Multiple ingest routes registered // Multiple ingest routes registered
@ -37,7 +37,7 @@ function islandora_ingest_registry_render($ingest_registry) {
'#markup' => '', '#markup' => '',
); );
foreach ($ingest_registry AS $ingest_route) { foreach ($ingest_registry AS $ingest_route) {
$output['#markup'] .= l($ingest_route['name'], $ingest_route['url']) . '<br/>'; $output['#markup'] .= l($ingest_route['name'], $ingest_route['url']. "/$collection_pid") . '<br/>';
} }
return $output; return $output;
} }

27
includes/islandora.ingest.inc

@ -0,0 +1,27 @@
<?php
function islandora_ingest_get_information(AbstractFedoraObject $collection_object) {
$models = $collection_object->models;
$collection_info = module_invoke_all('islandora_ingest_get_information', $models, $collection_object);
return $collection_info;
}
function islandora_ingest_get_object($content_models, $collection_pid, $relationship, $namespace) {
module_load_include('inc', 'islandora', 'RestConnection');
global $user;
$connection = new RestConnection($user);
$object = $connection->repository->constructObject($namespace);
foreach($content_models as $contentmodel) {
$object->relationships->add(FEDORA_MODEL_URI, 'hasModel', $content_model);
}
$object->relationships->add($relationship['uri'], $relationship['value'], $collection_pid);
module_invoke_all('islandora_ingest_pre_ingest', $object, $content_models, $collection_pid);
return $object;
}
function islandora_ingest_add_object(&$object) {
$object->repository->ingestObject($object);
module_invoke_all('islandora_ingest_post_ingest', $object);
return $object;
}

80
islandora.module

@ -98,9 +98,12 @@ function islandora_menu() {
'access arguments' => array(FEDORA_VIEW), 'access arguments' => array(FEDORA_VIEW),
); );
$items['islandora/object/%/add'] = array( $items['islandora/object/%/add'] = array(
'title' => 'Add stream', 'title' => 'Add to an object',
'page callback' => 'islandora_add_stream', 'file' => 'includes/add-menu.inc',
'page callback' => 'islandora_add_callback',
'page arguments' => array(2),
'type' => MENU_NORMAL_ITEM, 'type' => MENU_NORMAL_ITEM,
'access arguments' => array(FEDORA_ADD_DS) 'access arguments' => array(FEDORA_ADD_DS)
); );
@ -158,7 +161,7 @@ function islandora_menu() {
$items['islandora/object/%/datastream/%/edit'] = array( $items['islandora/object/%/datastream/%/edit'] = array(
'title' => 'Edit datastream', 'title' => 'Edit datastream',
'page callback' => 'islandora_edit_stream', 'page callback' => 'islandora_edit_datastream',
'page arguments' => array(2, 4), 'page arguments' => array(2, 4),
'type' => MENU_CALLBACK, 'type' => MENU_CALLBACK,
'access arguments' => array(FEDORA_METADATA_EDIT), 'access arguments' => array(FEDORA_METADATA_EDIT),
@ -166,7 +169,7 @@ function islandora_menu() {
$items['islandora/object/%/datastream/%/delete'] = array( $items['islandora/object/%/datastream/%/delete'] = array(
'title' => 'Purge data stream', 'title' => 'Purge data stream',
'page callback' => 'islandora_purge_stream', 'page callback' => 'islandora_purge_datastream',
'page arguments' => array(2, 4), 'page arguments' => array(2, 4),
'type' => MENU_CALLBACK, 'type' => MENU_CALLBACK,
'access arguments' => array(FEDORA_PURGE), 'access arguments' => array(FEDORA_PURGE),
@ -233,7 +236,7 @@ function islandora_purge_object($object_id) {
$restConnection = new RestConnection($user); $restConnection = new RestConnection($user);
$fedora_object = new FedoraObject($object_id, $restConnection->repository); $fedora_object = new FedoraObject($object_id, $restConnection->repository);
} catch (Exception $e) { } catch (Exception $e) {
drupal_set_message(t('Error getting Islandora object %s', array('%s' => $object_id)), 'error'); drupal_set_message(t('Error getting Islandora object %s %e', array('%s' => $object_id, '%e' => $e)), 'error');
return ""; return "";
} }
if (!isset($fedora_object)) { if (!isset($fedora_object)) {
@ -242,11 +245,11 @@ function islandora_purge_object($object_id) {
} }
$content_models = $fedora_object->models; $content_models = $fedora_object->models;
$arr = module_invoke_all('islandora_pre_purge_object', $fedora_object); //notify modules of pending deletion $arr = module_invoke_all('islandora_pre_purge_object', $fedora_object); //notify modules of pending deletion
if ($arr['delete']) { if (isset($arr['delete']) && $arr['delete']) {
try { try {
$fedora_object->delete(); $fedora_object->delete();
} catch (Exception $e) { } catch (Exception $e) {
drupal_set_message(t('Error deleting Islandora object %s', array('%s' => $object_id)), 'error'); drupal_set_message(t('Error deleting Islandora object %s %e', array('%s' => $object_id, '%e' => $e)), 'error');
return ""; return "";
} }
} }
@ -254,17 +257,16 @@ function islandora_purge_object($object_id) {
try { try {
$restConnection->repository->purgeObject($object_id); $restConnection->repository->purgeObject($object_id);
} catch (Exception $e) { } catch (Exception $e) {
drupal_set_message(t('Error purging Islandora object %s', array('%s' => $object_id)), 'error'); drupal_set_message(t('Error purging Islandora object %s %e', array('%s' => $object_id, '%e' => $e)), 'error');
return ""; return "";
} }
} }
module_invoke_all('islandora_post_purge_object', $object_id, $content_models); //notify modules post deletion module_invoke_all('islandora_post_purge_object', $object_id, $content_models); //notify modules post deletion
drupal_goto('islandora');
} }
/** /**
* returns an array listing object types provided by sub modules * returns an array listing object types provided by sub modules
* The array should contain the cmodels it listens for and the hooks it answers to
* example array ('islandora:collectionCModel' => array ('islandora_edit_object' => TRUE, 'islandora_view_object' => TRUE);
* @return array * @return array
*/ */
function islandora_get_types() { function islandora_get_types() {
@ -294,13 +296,12 @@ function islandora_edit_object($object_id) {
foreach ($arr as $key => $value) { foreach ($arr as $key => $value) {
$output .= $key . '<br />' . $value; //if we have multiple modules handle one cmodel we need to iterate over multiple $output .= $key . '<br />' . $value; //if we have multiple modules handle one cmodel we need to iterate over multiple
} }
//we could do another module invoke all here to build the edit tab with a default implemented in this module?
return $output; return $output;
} }
/** /**
* checks to see if any other modules implement this functionality and if there are none
* builds a default page for the edit tab * builds a default page for the edit tab
*
* @param object $fedora_object * @param object $fedora_object
* A tuque Fedora Object * A tuque Fedora Object
*/ */
@ -317,22 +318,67 @@ function islandora_islandora_edit_object($fedora_object) {
} }
/** /**
* Gives the option of purging or deleting a datastream.
* *
* The default behaviour is to purge the datastream but this can be overridden using the
* 'islandora_pre_purge_datastream' hook. The returned array can include a 'block' => TRUE
* pair which will prevent the datastream from being deleted if it particularly needed for
* a certain function. Returning 'delete' => TRUE will cause the datastream to be put into
* a deleted state.
*
* @param string $object_id
* ID of the object
* @param string $datastream_id * @param string $datastream_id
* @return type * ID of the datastream
*
*/ */
function islandora_purge_datastream($object_id, $datastream_id) { function islandora_purge_datastream($object_id, $datastream_id) {
module_load_include('inc', 'islandora', 'RestConnection');
global $user;
if (!isset($datastream_id)) { if (!isset($datastream_id)) {
drupal_set_message(t('Cannot remove datastream, datastream id not set')); drupal_set_message(t('Cannot remove datastream, datastream id not set'));
return; return;
} }
$object = new Object($object_id); try {
if (!isset($object)) { $restConnection = new RestConnection($user);
$fedora_object = new FedoraObject($object_id, $restConnection->repository);
} catch (Exception $e) {
drupal_set_message(t('Error getting Islandora object %s %e', array('%s' => $object_id, '%e' => $e)), 'error');
return "";
}
if (!isset($fedora_object)) {
drupal_set_message(t('Could not remove object, object not found'));
return;
}
if (!isset($fedora_object)) {
drupal_set_message(t('Could not remove object, object not found')); drupal_set_message(t('Could not remove object, object not found'));
return; return;
} }
module_invoke_all('islandora_purge_datastream', $datastream); //notify modules of pending deletion so we can update rels etc $arr = module_invoke_all('islandora_pre_purge_datastream', $fedora_object, $datastream_id); //notify modules of pending deletion so we can update rels etc
$object->deleteDatastream(); if (isset($arr['block']) && $arr['block']) {
drupal_set_message(t('Purging of the %d datastream was blocked', array('%d' => $datastream_id)), 'warning');
return;
}
if (isset($arr['delete']) && $arr['delete']) {
try {
$datastream = new FedoraDatastream($datastream_id, $fedora_object, $restConnection->repository);
$datastream->state = 'D';
} catch (Exception $e) {
drupal_set_message(t('Error deleting %s datastream from Islandora object %o %e', array('%s' => $datastream_id, '%o' => $object_id, '%e' => $e)), 'error');
return;
}
}
else {
try {
$fedora_object->purgeDatastream($datastream_id);
} catch (Exception $e) {
drupal_set_message(t('Error purging %s datastream from Islandora object %o %e', array('%s' => $datastream_id, '%o' => $object_id, '%e' => $e)), 'error');
return;
}
}
module_invoke_all('islandora_post_purge_datastream', $fedora_object, $datastream_id); //notify modules post deletion
drupal_set_message(t('%d datastream sucessfully purged from Islandora object %o', array('%d' => $datastream_id, '%o' => $object_id)));
drupal_goto('islandora/object/' . $object_id);
} }
/** /**

21
islandora_basic_collection/islandora_basic_collection.module

@ -137,3 +137,24 @@ function islandora_basic_collection_get_objects($object) {
return $results; return $results;
} }
function islandora_basic_collection_islandora_ingest_get_information($models, $object) {
if(in_array('islandora:collectionCModel', $models) && isset($object['COLLECTION_POLICY'])) {
try {
$return = array();
$xml = new SimpleXMLElement($object['COLLECTION_POLICY']);
$cms = $xml->getElementsByTagName('content_models')->item(0)->getElementsByTagName('content_model');
$return['contentsmodels'] = array();
foreach($cms as $cm) {
$contentmodel = array();
$contentmodel['name'] = (string) $cm['name'];
$contentmodel['namespace'] = (string) $cm['namespace'];
$contentmodel['pid'] = (string) $cm['pid'];
$return['contentsmodels'] = (string) $contentmodel;
}
$return['relationship'] = trim($xml->getElementsByTagName('relationship')->item(0)->nodeValue);
return $return;
}
catch (Exception $e) { }
}
}

359
utils/MimeClass.inc

@ -0,0 +1,359 @@
<?php
/**
* @file
* 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.
*
* 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.
*
* Drupal 7 will have better mime handlers. See:
* http://api.drupal.org/api/function/file_default_mimetype_mapping/7
*
*/
class MimeClass {
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",
"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';
/**
* Construtor
*/
public function __construct() {
// Populate the reverse shortlist:
$this->protectedFileExtensions = array_flip($this->protectedMimeTypes);
// Pick up a local mime.types file if it is available.
if (is_readable('mime.types')) {
$this->etcMimeTypes = 'mime.types';
}
}
/**
* description: returns a mimetype associated with the file extension of
* $filename
*
* @param string $filename
* The filename
* @param boolean $debug
* Returns a debug array.
*
* @return mixed
* string or an array
*/
public function getMimetype($filename, $debug = FALSE) {
$file_name_and_extension = explode('.', $filename);
$ext = strtolower(array_pop($file_name_and_extension));
if (!empty($this->protectedMimeTypes[$ext])) {
if (TRUE === $debug) {
return array('mime_type' => $this->protectedMimeTypes[$ext], 'method' => 'from_array');
}
return $this->protectedMimeTypes[$ext];
}
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;
}
}
if (!isset($this->systemTypes)) {
$this->systemTypes = $this->systemExtensionMimetypes();
}
if (isset($this->systemTypes[$ext])) {
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';
}
/**
* function: get_extension
* description: returns *one* valid file extension for a 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];
}
if (!isset($this->systemExts)) {
$this->systemExts = $this->systemMimetypeExtensions();
}
if (isset($this->systemExts[$mime_type])) {
if (TRUE == $debug) {
return array('extension' => $this->systemExts[$mime_type], 'method' => 'mime.types');
}
return $this->systemExts[$mime_type];
}
if (TRUE == $debug) {
return array('extension' => 'bin', 'method' => 'last_resort');
}
return 'bin';
}
/**
* function: systemMimetypeExtensions
* description: populates an internal array of mimetype/extension associations
* from the system mime.types file, or a local mime.types if one is found (see
* __constuctor).
* return: array of mimetype => extension
*/
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;
}
/**
* function: systemMimetypeExtensions
* description: populates an internal array of mimetype/extension associations
* from the system mime.types file, or a local mime.types if one is found (see
* __constuctor).
* return: array of extension => mimetype
*/
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;
}
}
Loading…
Cancel
Save