<?php
/**
 * The MIME_Magic:: class provides an interface to determine a
 * MIME type for various content, if it provided with different
 * levels of information.
 *
 * $Horde: horde/lib/MIME/Magic.php,v 1.35 2003/08/15 16:15:00 chuck Exp $
 *
 * Copyright 1999-2003 Anil Madhavapeddy <anil@recoil.org>
 * Copyright 2002-2003 Michael Slusarz <slusarz@bigworm.colorado.edu>
 *
 * See the enclosed file COPYING for license information (LGPL). If you
 * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
 *
 * @author  Anil Madhavapeddy <anil@recoil.org>
 * @author  Michael Slusarz <slusarz@bigworm.colorado.edu>
 * @version $Revision: 1.35 $
 * @since   Horde 1.3
 * @package horde.mime
 */
class MIME_Magic {

    /**
     * Returns a copy of the MIME extension map.
     *
     * @access private
     *
     * @return array  The MIME extension map.
     */
    function &_getMimeExtensionMap()
    {
        static $mime_extension_map;

        if (!isset($mime_extension_map)) {
            require dirname(__FILE__) . '/mime.mapping.php';
        }

        return $mime_extension_map;
    }

    /**
     * Returns a copy of the MIME magic file.
     *
     * @access private
     *
     * @return array  The MIME magic file.
     */
    function &_getMimeMagicFile()
    {
        static $mime_magic;

        if (!isset($mime_magic)) {
            require dirname(__FILE__) . '/mime.magic.php';
        }

        return $mime_magic;
    }

    /**
     * Attempt to convert a file extension to a MIME type, based
     * on the global Horde and application specific config files.
     *
     * If we cannot map the file extension to a specific type, then
     * we fall back to a custom MIME handler x-extension/type, which
     * can be used as a normal MIME type internally throughout Horde.
     *
     * @access public
     *
     * @param string $ext  The file extension to be mapped to a MIME type.
     *
     * @return string  The MIME type of the file extension.
     */
    function extToMIME($ext)
    {
        if (empty($ext)) {
           return 'text/plain';
        } else {
            $ext = String::lower($ext);
            $map = &MIME_Magic::_getMimeExtensionMap();
            if (!array_key_exists($ext, $map)) {
                return "x-extension/$ext";
            } else {
                return $map[$ext];
            }
        }
    }

    /**
     * Attempt to convert a filename to a MIME type, based on the
     * global Horde and application specific config files.
     *
     * Unlike extToMIME(), this function will return
     * 'application/octet-stream' for any unknown or empty extension.
     *
     * @access public
     *
     * @param string $filename  The filename to be mapped to a MIME type.
     *
     * @return string  The MIME type of the filename.
     *
     * @since Horde 2.2
     */
    function filenameToMIME($filename)
    {
        $pos = strrpos($filename, '.');
        if (!empty($pos)) {
            $type = MIME_Magic::extToMIME(substr($filename, $pos + 1));
            if (!stristr($type, 'x-extension')) {
                return $type;
            }
        }

        return 'application/octet-stream';
    }

    /**
     * Attempt to convert a MIME type to a file extension, based
     * on the global Horde and application specific config files.
     *
     * If we cannot map the type to a file extension, we return false.
     *
     * @access public
     *
     * @param string $type  The MIME type to be mapped to a file extension.
     *
     * @return string  The file extension of the MIME type.
     */
    function MIMEToExt($type)
    {
        $key = array_search($type, MIME_Magic::_getMimeExtensionMap());
        if (empty($type) || ($key === false)) {
            list($major, $minor) = explode('/', $type);
            if ($major == 'x-extension') {
                return $minor;
            }
            if (substr($minor, 0, 2) == 'x-') {
                return substr($minor, 2);
            }
            return false;
        } else {
            return $key;
        }
    }

    /**
     * Uses variants of the UNIX "file" command to attempt to determine the
     * MIME type of an unknown file.
     *
     * @access public
     *
     * @param string $path  The path to the file to analyze.
     *
     * @return string  The MIME type of the file.  Returns false if either
     *                 the file type isn't recognized or the file command is
     *                 not available.
     */
    function analyzeFile($path)
    {
        global $conf;

        /* If the PHP Mimetype extension is available, use that. */
        if (Horde::extensionExists('mime_magic')) {
            return mime_content_type($path);
        } else {
            /* Use a built-in magic file. */
            $mime_magic = &MIME_Magic::_getMimeMagicFile();
            if (!($fp = @fopen($path, 'rb'))) {
                return false;
            }
            foreach ($mime_magic as $offset => $odata) {
                foreach ($odata as $length => $ldata) {
                    @fseek($fp, $offset, SEEK_SET);
                    $lookup = @fread($fp, $length);
                    if (!empty($ldata[$lookup])) {
                        fclose($fp);
                        return $ldata[$lookup];
                    }
                }
            }
            fclose($fp);
        }

        return false;
    }

}
