MimeTypes.class.php
Upload User: feiyaoda
Upload Date: 2016-11-21
Package Size: 9556k
Code Size: 15k
Category:

WEB Mail

Development Platform:

PHP

  1. <?php
  2. // +----------------------------------------------------------------------+
  3. // | MIME Types Class 0.1 - 21-Dec-2002                                   |
  4. // +----------------------------------------------------------------------+
  5. // | Author: Keyvan Minoukadeh - keyvan@k1m.com - http://www.keyvan.net   |
  6. // +----------------------------------------------------------------------+
  7. // | PHP class for retrieving the appropriate MIME type of a              |
  8. // | file/extension                                                       |
  9. // +----------------------------------------------------------------------+
  10. // | This program is free software; you can redistribute it and/or        |
  11. // | modify it under the terms of the GNU General Public License          |
  12. // | as published by the Free Software Foundation; either version 2       |
  13. // | of the License, or (at your option) any later version.               |
  14. // |                                                                      |
  15. // | This program is distributed in the hope that it will be useful,      |
  16. // | but WITHOUT ANY WARRANTY; without even the implied warranty of       |
  17. // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        |
  18. // | GNU General Public License for more details.                         |
  19. // +----------------------------------------------------------------------+
  20. /**
  21. * MIME Types class
  22. *
  23. * This class allows you to:
  24. *   - Retrieve the appropriate MIME type of a file (based on it's extension, or by utilising
  25. *     the file command to guess it based on the file contents).
  26. *   - Retrieve extension(s) associated with a MIME type.
  27. *   - Load MIME types and extensions from a mime.types file.
  28. *
  29. * Example:
  30. *   $mime =& new Mime_Types('/usr/local/apache/conf/mime.types');
  31. *   echo $mime->get_type('pdf');    // application/pdf
  32. *   echo $mime->get_extension('text/vnd.wap.wmlscript');      // wmls
  33. *
  34. * See test_Mime_Types.php file for more examples.
  35. *
  36. * TODO:
  37. *  - method to write MIME types to file.
  38. *  - get_file_type(): possibly preserving the parameters returned by the file command 
  39. *    (e.g. text/plain; charset=us-ascii)
  40. *
  41. * @author Keyvan Minoukadeh <keyvan@k1m.com>
  42. * @version 0.1
  43. */
  44. class Mime_Types
  45. {
  46.     /**
  47.     * MIME Types
  48.     * Initially we start with the more popular ones.
  49.     *  ["txt"]  => "text/plain",
  50.     *  ["gif"]  => "image/gif",
  51.     *  ["jpg"]  => "image/jpeg",
  52.     *  ["html"] => "text/html",
  53.     *  ["htm"]  => "text/html"
  54.     * @var array
  55.     * @access private
  56.     */
  57.     var $mime_types = array(
  58.         'txt'   => 'text/plain',
  59.         'gif'   => 'image/gif',
  60.         'jpg'   => 'image/jpeg',
  61.         'html'  => 'text/html',
  62.         'htm'   => 'text/html');
  63.     /**
  64.     * Path to file command - empty string disables the use of the file command
  65.     * @var string
  66.     */
  67.     var $file_cmd = '';
  68.     // var $file_cmd = '/usr/bin/file';
  69.     /**
  70.     * File options, used with the file command
  71.     * Example:
  72.     *   ['i'] => null // this option asks file to produce a MIME type if it can
  73.     *   ['b'] => null // this option tells file to be brief
  74.     * will result in 'file -i -b test_file'
  75.     * @var array
  76.     */
  77.     var $file_options = array('b'=>null, 'i'=>null);
  78.     /**
  79.     * Constructor
  80.     * optional parameter can be either a string containing the path to the
  81.     * mime.types files, or an associative array holding the extension
  82.     * as key and the MIME type as value.
  83.     * Example:
  84.     *   $mime =& new Mime_Types('/usr/local/apache/conf/mime.types');
  85.     *  or
  86.     *   $mime =& new Mime_Types(array(
  87.     *        'application/pdf'        => 'pdf', 
  88.     *        'application/postscript' => array('ai','eps')
  89.     *        ));
  90.     * @param mixed $mime_types
  91.     */
  92.     function Mime_Types($mime_types=null)
  93.     {
  94.         if (is_string($mime_types)) {
  95.             $this->load_file($mime_types);
  96.         } elseif (is_array($mime_types)) {
  97.             $this->set($mime_types);
  98.         }
  99.     }
  100.     /**
  101.     * Scan - goes through all MIME types passing the extension and type to the callback function.
  102.     * The types will be sent in alphabetical order.
  103.     * If a type has multiple extensions, each extension will be passed seperately (not as an array).
  104.     *
  105.     * The callback function can be a method from another object (eg. array(&$my_obj, 'my_method')).
  106.     * The callback function should accept 3 arguments:
  107.     *  1- A reference to the Mime_Types object (&$mime)
  108.     *  2- An array holding extension and type, array keys: 
  109.     *     [0]=>ext, [1]=>type
  110.     *  3- An optional parameter which can be used for whatever your function wants :),
  111.     *     even though you might not have a use for this parameter, you need to define
  112.     *     your function to accept it.  (Note: you can have this parameter be passed by reference)
  113.     * The callback function should return a boolean, a value of 'true' will tell scan() you want
  114.     * it to continue with the rest of the types, 'false' will tell scan() to stop calling
  115.     * your callback function.
  116.     *
  117.     * @param mixed $callback function name, or array holding an object and the method to call.
  118.     * @param mixed $param passed as the 3rd argument to $callback
  119.     */
  120.     function scan($callback, &$param)
  121.     {
  122.         if (is_array($callback)) $method =& $callback[1];
  123.         $mime_types = $this->mime_types;
  124.         asort($mime_types);
  125.         foreach ($mime_types as $ext => $type) {
  126.             $ext_type = array($ext, $type);
  127.             if (isset($method)) {
  128.                 $res = $callback[0]->$method($this, $ext_type, $param);
  129.             } else {
  130.                 $res = $callback($this, $ext_type, $param);
  131.             }
  132.             if (!$res) return;
  133.         }
  134.     }
  135.     /**
  136.     * Get file type - returns MIME type by trying to guess it using the file command. 
  137.     * Optional second parameter should be a boolean.  If true (default), get_file_type() will
  138.     * try to guess the MIME type based on the file extension if the file command fails to find
  139.     * a match.
  140.     * Example:
  141.     *   echo $mime->get_file_type('/path/to/my_file', false);
  142.     *  or
  143.     *   echo $mime->get_file_type('/path/to/my_file.gif');
  144.     * @param string $file
  145.     * @param bool $use_ext default: true
  146.     * @return string false if unable to find suitable match
  147.     */
  148.     function get_file_type($file, $use_ext=true)
  149.     {
  150.         $file = trim($file);
  151.         if ($file == '') return false;
  152.         $type = false;
  153.         $result = false;
  154.         if ($this->file_cmd && is_readable($file) && is_executable($this->file_cmd)) {
  155.             $cmd = $this->file_cmd;
  156.             foreach ($this->file_options as $option_key => $option_val) {
  157.                 $cmd .= ' -'.$option_key;
  158.                 if (isset($option_val)) $cmd .= ' '.escapeshellarg($option_val);
  159.             }
  160.             $cmd .= ' '.escapeshellarg($file);
  161.             $result = @exec($cmd);
  162.             if ($result) {
  163.                 $result = strtolower($result);
  164.                 $pattern = '[a-z0-9.+_-]';
  165.                 if (preg_match('!(('.$pattern.'+)/'.$pattern.'+)!', $result, $match)) {
  166.                     if (in_array($match[2], array('application','audio','image','message',
  167.                                                   'multipart','text','video','chemical','model')) ||
  168.                             (substr($match[2], 0, 2) == 'x-')) {
  169.                         $type = $match[1];
  170.                     }
  171.                 }
  172.             }
  173.         }
  174.         // try and get type from extension
  175.         if (!$type && $use_ext && strpos($file, '.')) $type = $this->get_type($file);
  176.         // this should be some sort of attempt to match keywords in the file command output
  177.         // to a MIME type, I'm not actually sure if this is a good idea, but for now, it tries
  178.         // to find an 'ascii' string.
  179.         if (!$type && $result && preg_match('/basciib/', $result)) $type = 'text/plain';
  180.         return $type;
  181.     }
  182.     /**
  183.     * Get type - returns MIME type based on the file extension.
  184.     * Example:
  185.     *   echo $mime->get_type('txt');
  186.     *  or
  187.     *   echo $mime->get_type('test_file.txt');
  188.     * both examples above will return the same result.
  189.     * @param string $ext
  190.     * @return string false if extension not found
  191.     */
  192.     function get_type($ext)
  193.     {
  194.         $ext = strtolower($ext);
  195.         // get position of last dot
  196.         $dot_pos = strrpos($ext, '.');
  197.         if ($dot_pos !== false) $ext = substr($ext, $dot_pos+1);
  198.         if (($ext != '') && isset($this->mime_types[$ext])) return $this->mime_types[$ext];
  199.         return false;
  200.     }
  201.     /**
  202.     * Set - set extension and MIME type
  203.     * Example:
  204.     *   $mime->set('text/plain', 'txt');
  205.     *  or
  206.     *   $mime->set('text/html', array('html','htm'));
  207.     *  or
  208.     *   $mime->set('text/html', 'html htm');
  209.     *  or
  210.     *   $mime->set(array(
  211.     *        'application/pdf'        => 'oda', 
  212.     *        'application/postscript' => array('ai','eps')
  213.     *        ));
  214.     * @param mixed $type either array containing type and extensions, or the type as string
  215.     * @param mixed $exts either array holding extensions, or string holding extensions
  216.     * seperated by space.
  217.     * @return void
  218.     */
  219.     function set($type, $exts=null)
  220.     {
  221.         if (!isset($exts)) {
  222.             if (is_array($type)) {
  223.                 foreach ($type as $mime_type => $exts) {
  224.                     $this->set($mime_type, $exts);
  225.                 }
  226.             }
  227.             return;
  228.         }
  229.         if (!is_string($type)) return;
  230.         // get rid of any parameters which might be included with the MIME type
  231.         // e.g. text/plain; charset=iso-8859-1
  232.         $type = strtr(strtolower(trim($type)), ",;trn", '     ');
  233.         if ($sp_pos = strpos($type, ' ')) $type = substr($type, 0, $sp_pos);
  234.         // not bothering with an extensive check of the MIME type, just checking for slash
  235.         if (!strpos($type, '/')) return;
  236.         // loop through extensions
  237.         if (!is_array($exts)) $exts = explode(' ', $exts);
  238.         foreach ($exts as $ext) {
  239.             $ext = trim(str_replace('.', '', $ext));
  240.             if ($ext == '') continue;
  241.             $this->mime_types[strtolower($ext)] = $type;
  242.         }
  243.     }
  244.     /**
  245.     * Has extension - returns true if extension $ext exists, false otherwise
  246.     * Example:
  247.     *   if ($mime->has_extension('pdf')) echo 'Got it!';
  248.     * @param string $ext
  249.     * @return bool
  250.     */
  251.     function has_extension($ext)
  252.     {
  253.         return (isset($this->mime_types[strtolower($ext)]));
  254.     }
  255.     /**
  256.     * Has type - returns true if type $type exists, false otherwise
  257.     * Example:
  258.     *   if ($mime->has_type('image/gif')) echo 'Got it!';
  259.     * @param string $type
  260.     * @return bool
  261.     */
  262.     function has_type($type)
  263.     {
  264.         return (in_array(strtolower($type), $this->mime_types));
  265.     }
  266.     /**
  267.     * Get extension - returns string containing a extension associated with $type
  268.     * Example:
  269.     *   $ext = $mime->get_extension('application/postscript');
  270.     *   if ($ext) echo $ext;
  271.     * @param string $type
  272.     * @return string false if $type not found
  273.     */
  274.     function get_extension($type)
  275.     {
  276.         $type = strtolower($type);
  277.         foreach ($this->mime_types as $ext => $m_type) {
  278.             if ($m_type == $type) return $ext;
  279.         }
  280.         return false;
  281.     }
  282.     /**
  283.     * Get extensions - returns array containing extension(s)
  284.     * Example:
  285.     *   $exts = $mime->get_extensions('application/postscript');
  286.     *   echo implode(', ', $exts);
  287.     * @param string $type
  288.     * @return array
  289.     */
  290.     function get_extensions($type)
  291.     {
  292.         $type = strtolower($type);
  293.         return (array_keys($this->mime_types, $type));
  294.     }
  295.     /**
  296.     * Remove extension
  297.     * Example:
  298.     *   $mime->remove_extension('txt');
  299.     *  or
  300.     *   $mime->remove_extension('txt exe html');
  301.     *  or
  302.     *   $mime->remove_extension(array('txt', 'exe', 'html'));
  303.     * @param mixed $exts string holding extension(s) seperated by space, or array
  304.     * @return void
  305.     */
  306.     function remove_extension($exts)
  307.     {
  308.         if (!is_array($exts)) $exts = explode(' ', $exts);
  309.         foreach ($exts as $ext) {
  310.             $ext = strtolower(trim($ext));
  311.             if (isset($this->mime_types[$ext])) unset($this->mime_types[$ext]);
  312.         }
  313.     }
  314.     /**
  315.     * Remove type
  316.     * Example:
  317.     *   $mime->remove_type('text/plain');
  318.     *  or
  319.     *   $mime->remove_type('image/*');
  320.     *   // removes all image types
  321.     *  or
  322.     *   $mime->remove_type();
  323.     *   // clears all types
  324.     * @param string $type if omitted, all types will be removed
  325.     * @return void
  326.     */
  327.     function remove_type($type=null)
  328.     {
  329.         if (!isset($type)) {
  330.             $this->mime_types = array();
  331.             return;
  332.         }
  333.         $slash_pos = strpos($type, '/');
  334.         if (!$slash_pos) return;
  335.         $type_info = array('last_match'=>false, 'wildcard'=>false, 'type'=>$type);
  336.         if (substr($type, $slash_pos) == '/*') {
  337.             $type_info['wildcard'] = true;
  338.             $type_info['type'] = substr($type, 0, $slash_pos);
  339.         }
  340.         $this->scan(array(&$this, '_remove_type_callback'), $type_info);
  341.     }
  342.     /**
  343.     * Load file - load file containing mime types.
  344.     * Example:
  345.     *   $result = $mime->load_file('/usr/local/apache/conf/mime.types');
  346.     *   echo (($result) ? 'Success!' : 'Failed');
  347.     * @param string $file
  348.     * @return bool
  349.     */
  350.     function load_file($file)
  351.     {
  352.         if (!file_exists($file) || !is_readable($file)) return false;
  353.         $data = file($file);
  354.         foreach ($data as $line) {
  355.             $line = trim($line);
  356.             if (($line == '') || ($line == '#')) continue;
  357.             $line = preg_split('/s+/', $line, 2);
  358.             if (count($line) < 2) continue;
  359.             $exts = $line[1];
  360.             // if there's a comment on this line, remove it
  361.             $hash_pos = strpos($exts, '#');
  362.             if ($hash_pos !== false) $exts = substr($exts, 0, $hash_pos);
  363.             $this->set($line[0], $exts);
  364.         }
  365.         return true;
  366.     }
  367.     //
  368.     // private methods
  369.     //
  370.     /**
  371.     * Remove type callback
  372.     * @param object $mime
  373.     * @param array $ext_type
  374.     * @param array $type_info
  375.     * @return bool
  376.     * @access private
  377.     */
  378.     function _remove_type_callback(&$mime, $ext_type, $type_info)
  379.     {
  380.         // temporarily we'll put match to false
  381.         $matched = false;
  382.         list($ext, $type) = $ext_type;
  383.         if ($type_info['wildcard']) {
  384.             if (substr($type, 0, strpos($type, '/')) == $type_info['type']) {
  385.                 $matched = true;
  386.             }
  387.         } elseif ($type == $type_info['type']) {
  388.             $matched = true;
  389.         }
  390.         if ($matched) {
  391.             $this->remove_extension($ext);
  392.             $type_info['last_match'] = true;
  393.         } elseif ($type_info['last_match']) {
  394.             // we do not need to continue if the previous type matched, but this type didn't.
  395.             // because all types are sorted in alphabetical order, we can be sure there will be
  396.             // no further successful matches.
  397.             return false;
  398.         }
  399.         return true;
  400.     }        
  401. }
  402. ?>