Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

There isn't a very reliable way (in my opinion) to get the mime type of a specific extension, regardless of the file actually being of that type or not.

This type of thing usually is used when sending a different Content-type when you intend to send, for example, an image.

class MIMETypes {

    /**
     * @var string Contains the default type when none is found
     * @access protected
     */
    static private $default='application/octet-stream';

    /**
     * @var array Contains all the mime types and extensions
     * @access protected
     */
    static private $mimes=array(
        'text'=>array(
            'plain'=>array(
                'php','php5','php4','php3','inc','sphp','phps','phtml',
                'htm','html',
                'txt'
            )
        ),
        'audio'=>array(
            'aac'=>array('aac'),
            'midi'=>array('mid','midi'),
            'mp4'=>array('mp4','m4a'),
            'mpeg'=>array('m2a','mp1','mp2','mp3','mp4','mpg','mpeg','mpa','mpga'),
            'ogg'=>array('oga','ogg'),
            'wav'=>array('wav','wave','pcm'),
            'webm'=>array('webm'),
            'x-mpequrl'=>array('m3u')
        ),
        'video'=>array(
            'mp4'=>array('mp4','m4v','m1v','m2v'),
            'ogg'=>array('ogv'),
            'webm'=>array('webm')
        )
    );

    /**
     * @var array Contains the last accessed contents and comes pre-initialized with some extensions and mime types that didn't matched
     * @access protected
     */     
    static private $cache=array(
        'ext'=>array(
            'txt'=>array('plain/text')
        ),
        'mime'=>array(
            '*/*'=>array()
        )
    );

    /**
     * Creates a list of matching mime types for that file extension
     * @param string $ext The extension to look for
     * @param string|null $hint Hint to reduce the search load for only that mime "group"<br/>
     *    *WARNING*: Setting this parameter will ignore the cache!
     * @return array An array with the multiple mime types
     */
    static function fromExt( $ext, $hint=null )
    {
        //this will have all matched mime types
        $exts = array();

        //clean up the $ext var, to hold nothing but an extension
        $ext = preg_replace( '@^(?:.*\.)*([^.\\]+)$@', '$1', $ext );

        if( func_num_args() > 1 )
        {
            $hint = strtolower( trim($hint) );

            foreach( self::$mimes[$hint] as $mime=>$types)
            {
                if( in_array( $ext, $types) )
                {
                    $exts[] = $hint . '/' . $mime;
                }
            }
        }
        else if( self::$cache['ext'][$ext] )
        {
            return self::$cache['ext'][$ext];
        }
        else
        {
            foreach( self::$mimes as $mime=>$mimes)
            {
                foreach( $mimes as $type=>$types)
                {
                    if( in_array( $ext, $list) )
                    {
                        $exts[] = $mime . '/' . $type;
                    }
                }
            }

            if(!$exts)
            {
                $exts=array( self::$default );
            }
        }

        return self::$cache['ext'][$ext] = $exts;
    }

    /**
     * Creates a list of matching extensions for that mime type
     * @param string $mime The extension to look for
     * @return array An array with the multiple extensions
     */
    static function fromMIME( $mime )
    {
        //'clean' blindly-exploded mime type 
        $mime_c=explode('/', $mime, 2);

        if( self::$cache['mime'][$mime] )
        {
            return array(); //self::$cache['mime'][$mime];
        }
        else if( self::$mimes[$mime_c[0]] )
        {
            return self::$mimes[$mime_c[0]][$mime_c[1]];
        }
        else
        {
            return self::$cache['mime'][$mime] = array();
        }
    }
}

The functioning of the class is complete, but I'm aware that there are lots of missing mime types like the image/* or application/*.

What can I do to improve my code in quality and make a better class and (maybe) make it production-ready?

What should I improve in terms of performance?

share|improve this question
    
What if you have two different mime types that share the same file extension? This is a possibility. Personally, I would determine the mime type based on the data contain in the file, and cache the findings. Then when the file is requested, get the mime type from the cache. –  Bonner Jan 7 at 16:12
    
@Bonner If you already have a 'hint' on what mime type the file will have (if you are dealing with audio files, for example), you can set the 2nd parameter on the method fromExt(). E.g.: MIMETypes::fromExt('mp4','audio') and it should return an array with only 1 mime type. If you don't set, it will return an array with all the mime types matching that extension. An example would be the extension mp4 (MIMETypes::fromExt('mp4')) which will return an array containing the mime types audio/mp4 and video/mp4. –  Ismael Miguel Jan 7 at 18:05

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Browse other questions tagged or ask your own question.