2 /* vim: set expandtab tabstop=4 shiftwidth=4: */
3 // +----------------------------------------------------------------------+
5 // +----------------------------------------------------------------------+
6 // | Copyright (c) 1997-2002, 2008 The PHP Group |
7 // +----------------------------------------------------------------------+
8 // | This source file is subject to version 3.0 of the PHP license, |
9 // | that is bundled with this package in the file LICENSE, and is |
10 // | available at through the world-wide-web at |
11 // | http://www.php.net/license/3_0.txt. |
12 // | If you did not receive a copy of the PHP license and are unable to |
13 // | obtain it through the world-wide-web, please send a note to |
14 // | license@php.net so we can mail you a copy immediately. |
15 // +----------------------------------------------------------------------+
16 // | Authors: Ian Eure <ieure@php.net> |
17 // +----------------------------------------------------------------------+
19 // $Id: Type.php,v 1.6 2009/01/16 11:49:45 cweiske Exp $
21 require_once 'PEAR.php';
23 $_fileCmd = &PEAR::getStaticProperty('MIME_Type', 'fileCmd');
27 * Class for working with MIME types
31 * @license PHP License 3.0
33 * @link http://pear.php.net/package/MIME_Type
34 * @author Ian Eure <ieure@php.net>
46 * The MIME media sub-type
53 * Optional MIME parameters
57 var $parameters = array();
60 * List of valid media types.
61 * A media type is the string in front of the slash.
62 * The media type of "text/xml" would be "text".
66 var $validMediaTypes = array(
80 * If $type is set, if will be parsed and the appropriate class vars set.
81 * If not, you get an empty class.
82 * This is useful, but not quite as useful as parsing a type.
84 * @param string $type MIME type
88 function MIME_Type($type = false)
97 * Parse a mime-type and set the class variables.
99 * @param string $type MIME type to parse
103 function parse($type)
105 $this->media = $this->getMedia($type);
106 $this->subType = $this->getSubType($type);
107 $this->parameters = array();
108 if (MIME_Type::hasParameters($type)) {
109 require_once 'MIME/Type/Parameter.php';
110 foreach (MIME_Type::getParameters($type) as $param) {
111 $param = new MIME_Type_Parameter($param);
112 $this->parameters[$param->name] = $param;
119 * Does this type have any parameters?
121 * @param string $type MIME type to check
123 * @return boolean true if $type has parameters, false otherwise
126 function hasParameters($type)
128 if (strstr($type, ';')) {
136 * Get a MIME type's parameters
138 * @param string $type MIME type to get parameters of
140 * @return array $type's parameters
143 function getParameters($type)
146 $tmp = explode(';', $type);
147 for ($i = 1; $i < count($tmp); $i++) {
148 $params[] = trim($tmp[$i]);
155 * Strip parameters from a MIME type string.
157 * @param string $type MIME type string
159 * @return string MIME type with parameters removed
162 function stripParameters($type)
164 if (strstr($type, ';')) {
165 return substr($type, 0, strpos($type, ';'));
172 * Removes comments from a media type, subtype or parameter.
174 * @param string $string String to strip comments from
175 * @param string &$comment Comment is stored in there.
177 * @return string String without comments
180 function stripComments($string, &$comment)
182 if (strpos($string, '(') === false) {
191 for ($n = 0; $n < strlen($string); $n++) {
193 if ($incomment == 0) {
194 $newstring .= $string[$n];
195 } else if ($comment !== null) {
196 $comment .= $string[$n];
199 } else if ($string[$n] == '\\') {
201 } else if (!$inquote && $incomment > 0 && $string[$n] == ')') {
203 if ($incomment == 0 && $comment !== null) {
206 } else if (!$inquote && $string[$n] == '(') {
208 } else if ($string[$n] == '"') {
214 } else if ($incomment == 0) {
215 $newstring .= $string[$n];
216 } else if ($comment !== null) {
217 $comment .= $string[$n];
221 if ($comment !== null) {
222 $comment = trim($comment);
230 * Get a MIME type's media
232 * @note 'media' refers to the portion before the first slash
234 * @param string $type MIME type to get media of
236 * @return string $type's media
239 function getMedia($type)
241 $tmp = explode('/', $type);
242 return strtolower(trim(MIME_Type::stripComments($tmp[0], $null)));
247 * Get a MIME type's subtype
249 * @param string $type MIME type to get subtype of
251 * @return string $type's subtype, null if invalid mime type
254 function getSubType($type)
256 $tmp = explode('/', $type);
257 if (!isset($tmp[1])) {
260 $tmp = explode(';', $tmp[1]);
261 return strtolower(trim(MIME_Type::stripComments($tmp[0], $null)));
266 * Create a textual MIME type from object values
268 * This function performs the opposite function of parse().
270 * @return string MIME type string
274 $type = strtolower($this->media . '/' . $this->subType);
275 if (count($this->parameters)) {
276 foreach ($this->parameters as $key => $null) {
277 $type .= '; ' . $this->parameters[$key]->get();
285 * Is this type experimental?
287 * @note Experimental types are denoted by a leading 'x-' in the media or
288 * subtype, e.g. text/x-vcard or x-world/x-vrml.
290 * @param string $type MIME type to check
292 * @return boolean true if $type is experimental, false otherwise
295 function isExperimental($type)
297 if (substr(MIME_Type::getMedia($type), 0, 2) == 'x-' ||
298 substr(MIME_Type::getSubType($type), 0, 2) == 'x-') {
306 * Is this a vendor MIME type?
308 * @note Vendor types are denoted with a leading 'vnd. in the subtype.
310 * @param string $type MIME type to check
312 * @return boolean true if $type is a vendor type, false otherwise
315 function isVendor($type)
317 if (substr(MIME_Type::getSubType($type), 0, 4) == 'vnd.') {
325 * Is this a wildcard type?
327 * @param string $type MIME type to check
329 * @return boolean true if $type is a wildcard, false otherwise
332 function isWildcard($type)
334 if ($type == '*/*' || MIME_Type::getSubtype($type) == '*') {
342 * Perform a wildcard match on a MIME type
345 * MIME_Type::wildcardMatch('image/*', 'image/png')
347 * @param string $card Wildcard to check against
348 * @param string $type MIME type to check
350 * @return boolean true if there was a match, false otherwise
353 function wildcardMatch($card, $type)
355 if (!MIME_Type::isWildcard($card)) {
359 if ($card == '*/*') {
363 if (MIME_Type::getMedia($card) == MIME_Type::getMedia($type)) {
372 * Add a parameter to this type
374 * @param string $name Attribute name
375 * @param string $value Attribute value
376 * @param string $comment Comment for this parameter
380 function addParameter($name, $value, $comment = false)
382 $tmp = new MIME_Type_Parameter();
385 $tmp->value = $value;
386 $tmp->comment = $comment;
387 $this->parameters[$name] = $tmp;
392 * Remove a parameter from this type
394 * @param string $name Parameter name
398 function removeParameter($name)
400 unset($this->parameters[$name]);
405 * Autodetect a file's MIME-type
407 * This function may be called staticly.
409 * @internal Tries to use fileinfo extension at first. If that
410 * does not work, mime_magic is used. If this is also not available
411 * or does not succeed, "file" command is tried to be executed with
412 * System_Command. When that fails, too, then we use our in-built
413 * extension-to-mimetype-mapping list.
415 * @param string $file Path to the file to get the type of
416 * @param bool $params Append MIME parameters if true
418 * @return string $file's MIME-type on success, PEAR_Error otherwise
423 function autoDetect($file, $params = false)
426 if (!file_exists($file)) {
427 return PEAR::raiseError("File \"$file\" doesn't exist");
430 if (!is_readable($file)) {
431 return PEAR::raiseError("File \"$file\" is not readable");
434 if (function_exists('finfo_file')) {
435 $finfo = finfo_open(FILEINFO_MIME);
436 $type = finfo_file($finfo, $file);
438 if ($type !== false && $type !== '') {
439 return MIME_Type::_handleDetection($type, $params);
443 if (function_exists('mime_content_type')) {
444 $type = mime_content_type($file);
445 if ($type !== false && $type !== '') {
446 return MIME_Type::_handleDetection($type, $params);
450 @include_once 'System/Command.php';
451 if (class_exists('System_Command')) {
452 return MIME_Type::_handleDetection(
453 MIME_Type::_fileAutoDetect($file),
458 require_once 'MIME/Type/Extension.php';
459 $mte = new MIME_Type_Extension();
460 return $mte->getMIMEType($file);
465 * Handles a detected MIME type and modifies it if necessary.
467 * @param string $type MIME Type of a file
468 * @param bool $params Append MIME parameters if true
470 * @return string $file's MIME-type on success, PEAR_Error otherwise
472 function _handleDetection($type, $params)
474 // _fileAutoDetect() may have returned an error.
475 if (PEAR::isError($type)) {
479 // Don't return an empty string
480 if (!$type || !strlen($type)) {
481 return PEAR::raiseError("Sorry, couldn't determine file type.");
484 // Strip parameters if present & requested
485 if (MIME_Type::hasParameters($type) && !$params) {
486 $type = MIME_Type::stripParameters($type);
494 * Autodetect a file's MIME-type with 'file' and System_Command
496 * This function may be called staticly.
498 * @param string $file Path to the file to get the type of
500 * @return string $file's MIME-type
505 function _fileAutoDetect($file)
507 $cmd = new System_Command();
509 // Make sure we have the 'file' command.
510 $fileCmd = PEAR::getStaticProperty('MIME_Type', 'fileCmd');
511 if (!$cmd->which($fileCmd)) {
513 return PEAR::raiseError("Can't find file command \"{$fileCmd}\"");
516 $cmd->pushCommand($fileCmd, "-bi " . escapeshellarg($file));
517 $res = $cmd->execute();