From 793eb160822860ebc78777f4397c224c06d1f0d4 Mon Sep 17 00:00:00 2001 From: svollbehr Date: Sat, 12 Apr 2008 19:07:31 +0000 Subject: [PATCH] Add support to Mime Magic git-svn-id: http://php-reader.googlecode.com/svn/trunk@73 51a70ab9-7547-0410-9469-37e369ee0574 --- src/Magic.php | 177 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 src/Magic.php diff --git a/src/Magic.php b/src/Magic.php new file mode 100644 index 0000000..21a3c27 --- /dev/null +++ b/src/Magic.php @@ -0,0 +1,177 @@ +1 -- byte number to begin checking from. ">" indicates a dependency + * upon the previous non-">" line + * o 2 -- type of data to match. Can be one of following + * - byte (single character) + * - short (machine-order 16-bit integer) + * - long (machine-order 32-bit integer) + * - string (arbitrary-length string) + * - date (long integer date (seconds since Unix epoch/1970)) + * - beshort (big-endian 16-bit integer) + * - belong (big-endian 32-bit integer) + * - bedate (big-endian 32-bit integer date) + * - leshort (little-endian 16-bit integer) + * - lelong (little-endian 32-bit integer) + * - ledate (little-endian 32-bit integer date) + * o 3 -- contents of data to match + * o 4 -- file description/MIME type if matched + * o 5 -- optional MIME encoding if matched and if above was a MIME type + * + * @package php-reader + * @author Sven Vollbehr + * @copyright Copyright (c) 2006-2008 PHP Reader Project Workgroup + * @license http://code.google.com/p/php-reader/wiki/License New BSD License + * @version $Rev$ + */ +final class Magic +{ + /** @var string */ + private $_magic; + + /** + * Reads the magic information from given magic file. + * + * @param string $filename The path to the magic file. + */ + public function __construct($filename) + { + $reader = new Reader($filename); + $this->_magic = $reader->read($reader->getSize()); + } + + /** + * Returns the recognized MIME type/description of the given file. The type + * is determined by the content using magic bytes characteristic for the + * particular file type. + * + * If the type could not be found, the function returns the default value, or + * false. + * + * @param string $filename The file path whose type to determine. + * @param string $default The default value. + * @return string|false + */ + public function getType($filename, $default = false) + { + $reader = new Reader($filename); + + $parentOffset = 0; + foreach (preg_split("/^/m", $this->_magic) as $line) { + $chunks = array(); + if (!preg_match("/^(?P>?)(?P\d+)\s+(?P\S+)" . + "\s+(?P\S+)(?:\s+(?P[a-z]+\/[a-z-" . + "0-9]+)?(?:\s+(?P.+))?)?$/", $line, $chunks)) + continue; + + if ($chunks["Dependant"]) { + $reader->setOffset($parentOffset); + $reader->skip($chunks["Byte"]); + } else + $reader->setOffset($parentOffset = $chunks["Byte"]); + + $matchType = strtolower($chunks["MatchType"]); + $matchData = preg_replace + (array("/\\\\ /", "/\\\\\\\\/", "/\\\\([0-7]{1,3})/e", + "/\\\\x([0-9A-Fa-f]{1,2})/e", "/0x([0-9A-Fa-f]+)/e"), + array(" ", "\\\\", "pack(\"H*\", base_convert(\"$1\", 8, 16));", + "pack(\"H*\", \"$1\");", "hexdec(\"$1\");"), + $chunks["MatchData"]); + + switch ($matchType) { + case "byte": // single character + $data = $reader->readInt8(); + break; + case "short": // machine-order 16-bit integer + $data = $reader->readInt16(); + break; + case "long": // machine-order 32-bit integer + $data = $reader->readInt32(); + break; + case "string": // arbitrary-length string + $data = $reader->readString8(strlen($matchData)); + break; + case "date": // long integer date (seconds since Unix epoch/1970) + $data = $reader->readInt64BE(); + break; + case "beshort": // big-endian 16-bit integer + $data = $reader->readUInt16BE(); + break; + case "belong": // big-endian 32-bit integer + case "bedate": // big-endian 32-bit integer date + $data = $reader->readUInt32BE(); + break; + case "leshort": // little-endian 16-bit integer + $data = $reader->readUInt16LE(); + break; + case "lelong": // little-endian 32-bit integer + case "ledate": // little-endian 32-bit integer date + $data = $reader->readUInt32LE(); + break; + default: + $data = null; + break; + } + + if (strcmp($data, $matchData) == 0) { + if (!empty($chunks["MIMEType"])) + return $chunks["MIMEType"]; + if (!empty($chunks["Description"])) + return $chunks["Description"]; + } + } + return $default; + } +}