<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Aukyla PHP Framework</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="StyleSheet" href="auton.css" type="text/css" media="screen">
</head>
<body>
<div id="mainmenu">
<a href="http://www.auton.nl/" class="home">Home</a>
</div>
<div id="submenu">
<a class="logo" href="http://www.auton.nl/"></a>
<div class="head">Ads</div>
<a href="http://sourceforge.net/"><img src="http://sourceforge.net/sflogo.php?group_id=116358&type=1" alt="SourceForge.net Logo" style="padding: 2px 4px; width: 88px; height: 31px; border: 0px"></a>
<a href="http://getfirefox.com/" title="Get Firefox - The Browser, Reloaded."><img src="http://www.mozilla.org/products/firefox/buttons/getfirefox_small.png" alt="Get Firefox" style="width: 110px; height: 32px; border: 0px"></a>
</div>
<div id="main">
<!-- Generated by Doxygen 1.3.9.1 -->
<div class="qindex"><a class="qindex" href="index.html">Main Page</a> | <a class="qindex" href="hierarchy.html">Class Hierarchy</a> | <a class="qindex" href="classes.html">Alphabetical List</a> | <a class="qindex" href="annotated.html">Class List</a> | <a class="qindex" href="files.html">File List</a> | <a class="qindex" href="functions.html">Class Members</a> | <a class="qindex" href="pages.html">Related Pages</a></div>
<div class="nav">
<a class="el" href="dir_000000.html">base</a></div>
<h1>MIME.php</h1><div class="fragment"><pre class="fragment">00001 <?php
00002 <span class="comment">/*</span>
00003 <span class="comment"> MIME.php, provides functions for determining MIME types and getting info</span>
00004 <span class="comment"> about MIME types</span>
00005 <span class="comment"> Copyright (C) 2003-2004 Arend van Beelen, Auton Rijnsburg</span>
00006 <span class="comment"></span>
00007 <span class="comment"> This program is free software; you can redistribute it and/or modify it</span>
00008 <span class="comment"> under the terms of the GNU General Public License as published by the Free</span>
00009 <span class="comment"> Software Foundation; either version 2 of the License, or (at your option)</span>
00010 <span class="comment"> any later version.</span>
00011 <span class="comment"></span>
00012 <span class="comment"> This program is distributed in the hope that it will be useful, but WITHOUT</span>
00013 <span class="comment"> ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or</span>
00014 <span class="comment"> FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for</span>
00015 <span class="comment"> more details.</span>
00016 <span class="comment"></span>
00017 <span class="comment"> You should have received a copy of the GNU General Public License along</span>
00018 <span class="comment"> with this program; if not, write to the Free Software Foundation, Inc.,</span>
00019 <span class="comment"> 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA</span>
00020 <span class="comment"></span>
00021 <span class="comment"> For any questions, comments or whatever, you may mail me at: hide@address.com</span>
00022 <span class="comment">*/</span>
00023
00024 require_once('<a class="code" href="a00119.html">Locale</a>.php');
00025 require_once('<a class="code" href="a00129.html">Messages</a>.php');
00026 require_once('<a class="code" href="a00163.html">URI</a>.php');
00027
00031 <span class="keyword">class </span>MIME
00032 {
00033 function __construct()
00034 {
00035 $this->XDG_DATA_DIRS = explode(<span class="charliteral">':'</span>, (isset($_ENV['XDG_DATA_DIRS']) ? $_ENV['XDG_DATA_DIRS'] : '/usr/local/share/:/usr/share/'));
00036 }
00037
00056 <span class="keyword">static</span> function type($uri, $openFile = <span class="keyword">true</span>, $useMetaData = <span class="keyword">true</span>)
00057 {
00058 global $MIME;
00059
00060 <span class="keywordflow">if</span>($useMetaData == <span class="keyword">true</span> && $openFile == <span class="keyword">true</span>)
00061 {
00062 $mimetype = <a class="code" href="a00163.html#e33">URI::metaData</a>($uri, 'mime-type');
00063
00064 <span class="keywordflow">if</span>($mimetype !== <span class="keyword">false</span> && $mimetype !== '')
00065 {
00066 <span class="keywordflow">return</span> $mimetype;
00067 }
00068 }
00069
00070 $mimetype = '';
00071 $matchlen = 0;
00072
00073 $basename = basename($uri);
00074
00075 $MIME->loadGlobFile();
00076
00077 <span class="comment">// check the globs twice (both case sensitive and insensitive)</span>
00078 <span class="keywordflow">for</span>($i = 0; $i < 2; $i++)
00079 {
00080 <span class="comment">// walk through the file line by line</span>
00081 foreach($MIME->globFileLines as $line)
00082 {
00083 <span class="comment">// check whether the line is a comment and is valid</span>
00084 <span class="keywordflow">if</span>($line{0} == <span class="charliteral">'#'</span> || strstr($line, <span class="charliteral">':'</span>) === <span class="keyword">false</span>)
00085 {
00086 <span class="keywordflow">continue</span>;
00087 }
00088
00089 <span class="comment">// strip the newline character, but leave any spaces</span>
00090 $line = substr($line, 0, strlen($line) - 1);
00091
00092 list($mime, $glob) = explode(<span class="charliteral">':'</span>, $line, 2);
00093
00094 <span class="comment">// check for a possible direct match</span>
00095 <span class="keywordflow">if</span>($basename == $glob)
00096 {
00097 <span class="keywordflow">return</span> $mime;
00098 }
00099
00100 <span class="comment">// match the globs</span>
00101 $flag = ($i > 0 ? FNM_CASEFOLD : 0);
00102 <span class="keywordflow">if</span>(fnmatch($glob, $basename, $flag) == <span class="keyword">true</span> && strlen($glob) > $matchlen)
00103 {
00104 $mimetype = $mime;
00105 $matchlen = strlen($glob);
00106 }
00107 }
00108 }
00109
00110 <span class="comment">// check for hits</span>
00111 <span class="keywordflow">if</span>($mimetype != '')
00112 {
00113 <span class="keywordflow">return</span> $mimetype;
00114 }
00115
00116 <span class="comment">// if globbing didn't return any results we're going to do some magic</span>
00117 <span class="comment">// quit now if we may not or cannot open the file</span>
00118 <span class="keywordflow">if</span>($openFile == <span class="keyword">false</span> || ($fp = <a class="code" href="a00163.html#e2">URI::fopen</a>($uri, <span class="charliteral">'r'</span>)) == <span class="keyword">false</span>)
00119 {
00120 <span class="keywordflow">return</span> '';
00121 }
00122
00123 <span class="comment">// load the magic files if they weren't loaded yet</span>
00124 <span class="keywordflow">if</span>(!isset($MIME->magicRules))
00125 {
00126 $MIME->magicRules = array();
00127
00128 <span class="comment">// go through the data dirs to search for the magic files</span>
00129 foreach(array_reverse($MIME->XDG_DATA_DIRS) as $dir)
00130 {
00131 <span class="comment">// read the file</span>
00132 <span class="keywordflow">if</span>(!file_exists(<span class="stringliteral">"$dir/mime/magic"</span>) ||
00133 ($buffer = file_get_contents(<span class="stringliteral">"$dir/mime/magic"</span>)) === <span class="keyword">false</span>)
00134 {
00135 <span class="keywordflow">continue</span>;
00136 }
00137
00138 <span class="comment">// check the file type</span>
00139 <span class="keywordflow">if</span>(substr($buffer, 0, 12) != <span class="stringliteral">"MIME-Magic\0\n"</span>)
00140 {
00141 <span class="keywordflow">continue</span>;
00142 }
00143
00144 $buffer = substr($buffer, 12);
00145
00146 <span class="comment">// go through the entire file</span>
00147 <span class="keywordflow">while</span>($buffer != '')
00148 {
00149 <span class="keywordflow">if</span>($buffer{0} != <span class="charliteral">'['</span> && $buffer{0} != <span class="charliteral">'>'</span> &&
00150 ($buffer{0} < <span class="charliteral">'0'</span> || $buffer{0} > <span class="charliteral">'9'</span>))
00151 {
00152 <span class="keywordflow">break</span>;
00153 }
00154
00155 <span class="keywordflow">switch</span>($buffer{0})
00156 {
00157 <span class="comment">// create an entry for a new mimetype</span>
00158 <span class="keywordflow">case</span> <span class="charliteral">'['</span>:
00159 $mime = substr($buffer, 1, strpos($buffer, <span class="charliteral">']'</span>) - 1);
00160 $MIME->magicRules[$mime] = array();
00161 $parents[0] =& $MIME->magicRules[$mime];
00162 $buffer = substr($buffer, strlen($mime) + 3);
00163 <span class="keywordflow">break</span>;
00164
00165 <span class="comment">// add a new rule to the current mimetype</span>
00166 <span class="keywordflow">case</span> <span class="charliteral">'>'</span>:
00167 <span class="keywordflow">default</span>:
00168 $indent = ($buffer{0} == <span class="charliteral">'>'</span> ? 0 : intval($buffer));
00169 $buffer = substr($buffer, strpos($buffer, <span class="charliteral">'>'</span>) + 1);
00170 $parents[$indent][] = <span class="keyword">new</span> MIME_MagicRule;
00171 $rulenum = <span class="keyword">sizeof</span>($parents[$indent]) - 1;
00172 $parents[$indent][$rulenum]->start_offset = intval($buffer); $buffer = substr($buffer, strpos($buffer, <span class="charliteral">'='</span>) + 1);
00173 $value_length = 256 * ord($buffer{0}) + ord($buffer{1}); $buffer = substr($buffer, 2);
00174 $parents[$indent][$rulenum]->value = substr($buffer, 0, $value_length); $buffer = substr($buffer, $value_length);
00175 $parents[$indent][$rulenum]->mask = ($buffer{0} != <span class="charliteral">'&'</span> ? str_repeat(<span class="stringliteral">"\xff"</span>, $value_length) : substr($buffer, 1, $value_length)); <span class="keywordflow">if</span>($buffer{0} == <span class="charliteral">'&'</span>) $buffer = substr($buffer, $value_length + 1);
00176 $parents[$indent][$rulenum]->word_size = ($buffer{0} != <span class="charliteral">'~'</span> ? 1 : intval(substr($buffer, 1))); <span class="keywordflow">while</span>($buffer{0} != <span class="charliteral">'+'</span> && $buffer{0} != <span class="stringliteral">"\n"</span> && $buffer != '') $buffer = substr($buffer, 1);
00177 $parents[$indent][$rulenum]->range_length = ($buffer{0} != <span class="charliteral">'+'</span> ? 1 : intval($buffer)); $buffer = substr($buffer, strpos($buffer, <span class="stringliteral">"\n"</span>) + 1);
00178 $parents[$indent][$rulenum]->children = array();
00179 $parents[$indent + 1] =& $parents[$indent][$rulenum]->children;
00180 <span class="keywordflow">break</span>;
00181 }
00182 }
00183 }
00184
00185 <span class="comment">// sort the array so items with high priority will get on top</span>
00186 ksort($MIME->magicRules);
00187 $magicRules = array_reverse($MIME->magicRules);
00188 reset($MIME->magicRules);
00189 }
00190
00191 <span class="comment">// call the recursive function for all mime types</span>
00192 foreach($MIME->magicRules as $mime => $rules)
00193 {
00194 foreach($rules as $rule)
00195 {
00196 <span class="keywordflow">if</span>($MIME->applyRecursiveMagic($rule, $fp) == <span class="keyword">true</span>)
00197 {
00198 list($priority, $mimetype) = explode(<span class="charliteral">':'</span>, $mime, 2);
00199 <a class="code" href="a00163.html#e10">URI::fclose</a>($fp);
00200 <span class="keywordflow">return</span> $mimetype;
00201 }
00202 }
00203 }
00204
00205 <span class="comment">// nothing worked, I will now only determine whether the file is binary or text</span>
00206 <a class="code" href="a00163.html#e7">URI::fseek</a>($fp, 0);
00207 $length = (<a class="code" href="a00163.html#e14">URI::fileSize</a>($uri) > 50 ? 50 : <a class="code" href="a00163.html#e14">URI::fileSize</a>($uri));
00208 $data = <a class="code" href="a00163.html#e3">URI::fread</a>($fp, $length);
00209 <a class="code" href="a00163.html#e10">URI::fclose</a>($fp);
00210 <span class="keywordflow">for</span>($i = 0; $i < strlen($data); $i++)
00211 {
00212 <span class="keywordflow">if</span>($data{$i} < <span class="stringliteral">"\x20"</span> && $data{$i} != <span class="stringliteral">"\x09"</span> && $data{$i} != <span class="stringliteral">"\x0a"</span> && $data{$i} != <span class="stringliteral">"\x0d"</span>)
00213 {
00214 <span class="keywordflow">return</span> 'application/octet-stream';
00215 }
00216 }
00217 <span class="keywordflow">return</span> 'text/plain';
00218 }
00219
00225 <span class="keyword">private</span> function applyRecursiveMagic(MIME_MagicRule $rule, $fp)
00226 {
00227 global $MIME;
00228
00229 <a class="code" href="a00163.html#e7">URI::fseek</a>($fp, $rule->start_offset);
00230 $data = <a class="code" href="a00163.html#e3">URI::fread</a>($fp, strlen($rule->value) + $rule->range_length);
00231 <span class="keywordflow">if</span>(strstr($data, $rule->value) !== <span class="keyword">false</span>)
00232 {
00233 <span class="keywordflow">if</span>(<span class="keyword">sizeof</span>($rule->children) == 0)
00234 {
00235 <span class="keywordflow">return</span> <span class="keyword">true</span>;
00236 }
00237 <span class="keywordflow">else</span>
00238 {
00239 foreach($rule->children as $child)
00240 {
00241 <span class="keywordflow">if</span>($MIME->applyRecursiveMagic($child, $fp) == <span class="keyword">true</span>)
00242 {
00243 <span class="keywordflow">return</span> <span class="keyword">true</span>;
00244 }
00245 }
00246 }
00247 }
00248 <span class="keywordflow">return</span> <span class="keyword">false</span>;
00249 }
00250
00264 <span class="keyword">static</span> function description($mimetype, $language = '')
00265 {
00266 global $MIME;
00267
00268 $MIME->description = i18n('Unknown filetype');
00269 <span class="keywordflow">if</span>($language == '')
00270 {
00271 $MIME->lang = <a class="code" href="a00119.html#e1">Locale::language</a>();
00272 }
00273 <span class="keywordflow">else</span>
00274 {
00275 $MIME->lang = $language;
00276 }
00277 $MIME->read = <span class="keyword">false</span>;
00278
00279 <span class="comment">// go through the data dirs to search for the XML file for the specified mime type</span>
00280 foreach($MIME->XDG_DATA_DIRS as $dir)
00281 {
00282 $filename = <span class="stringliteral">"$dir/mime/$mimetype.xml"</span>;
00283
00284 <span class="comment">// open the XML file</span>
00285 <span class="keywordflow">if</span>(!file_exists($filename) ||
00286 ($fp = fopen($filename, <span class="charliteral">'r'</span>)) == <span class="keyword">false</span>)
00287 {
00288 <span class="keywordflow">continue</span>;
00289 }
00290
00291 <span class="comment">// initialize XML parser</span>
00292 $xml_parser = xml_parser_create();
00293 xml_set_element_handler($xml_parser, array($MIME, 'description_StartElement'), array($MIME, 'description_EndElement'));
00294 xml_set_character_data_handler($xml_parser, array($MIME, 'description_Data'));
00295
00296 <span class="comment">// read the file and parse</span>
00297 <span class="keywordflow">while</span>($data = str_replace(<span class="stringliteral">"\n"</span>, <span class="stringliteral">""</span>, fread($fp, 4096)))
00298 {
00299 <span class="keywordflow">if</span>(!xml_parse($xml_parser, $data, feof($fp)))
00300 {
00301 error_log(<span class="stringliteral">"ERROR: Couldn't parse $filename: "</span>.
00302 xml_error_string(xml_get_error_code($xml_parser)));
00303 <span class="keywordflow">break</span>;
00304 }
00305 }
00306 fclose($fp);
00307 }
00308
00309 <span class="keywordflow">return</span> $MIME->description;
00310 }
00311
00315 <span class="keyword">private</span> function description_StartElement($parser, $name, $attrs)
00316 {
00317 $this->read = <span class="keyword">false</span>;
00318 <span class="keywordflow">if</span>($name == 'COMMENT')
00319 {
00320 <span class="keywordflow">if</span>(!isset($attrs['XML:LANG']) || $attrs['XML:LANG'] == $this->lang)
00321 {
00322 $this->read = <span class="keyword">true</span>;
00323 }
00324 }
00325 }
00326
00330 <span class="keyword">private</span> function description_EndElement($parser, $name)
00331 {
00332 $this->read = <span class="keyword">false</span>;
00333 }
00334
00338 <span class="keyword">private</span> function description_Data($parser, $data)
00339 {
00340 <span class="keywordflow">if</span>($this->read == <span class="keyword">true</span>)
00341 {
00342 $this->description = $data;
00343 }
00344 }
00345
00353 <span class="keyword">static</span> function extension($mimetype)
00354 {
00355 global $MIME;
00356
00357 $MIME->loadGlobFile();
00358
00359 foreach($MIME->globFileLines as $line)
00360 {
00361 <span class="keywordflow">if</span>(strstr($line, <span class="charliteral">':'</span>) === <span class="keyword">false</span>)
00362 {
00363 <span class="keywordflow">continue</span>;
00364 }
00365 $line = trim($line);
00366 list($mime, $glob) = explode(<span class="charliteral">':'</span>, $line, 2);
00367 <span class="keywordflow">if</span>($mime == $mimetype)
00368 {
00369 <span class="keywordflow">if</span>(substr($glob, 0, 2) == '*.')
00370 {
00371 <span class="keywordflow">return</span> substr($glob, 1);
00372 }
00373 }
00374 }
00375
00376 <span class="keywordflow">return</span> '';
00377 }
00378
00379 <span class="keyword">private</span> function loadGlobFile()
00380 {
00381 <span class="comment">// load the glob files if they haven't been loaded already</span>
00382 <span class="keywordflow">if</span>(!isset($this->globFileLines))
00383 {
00384 $this->globFileLines = array();
00385
00386 <span class="comment">// go through the data dirs to search for the globbing files</span>
00387 foreach($this->XDG_DATA_DIRS as $dir)
00388 {
00389 <span class="comment">// read the file</span>
00390 <span class="keywordflow">if</span>(file_exists(<span class="stringliteral">"$dir/mime/globs"</span>) &&
00391 ($lines = file(<span class="stringliteral">"$dir/mime/globs"</span>)) !== <span class="keyword">false</span>)
00392 {
00393 $this->globFileLines = array_merge($this->globFileLines, $lines);
00394 }
00395 }
00396 }
00397 }
00398
00399 <span class="keyword">private</span> $XDG_DATA_DIRS;
00400 <span class="keyword">private</span> $globFileLines;
00401 <span class="keyword">private</span> $magicRules;
00402 <span class="keyword">private</span> $description;
00403 <span class="keyword">private</span> $lang;
00404 <span class="keyword">private</span> $read;
00405 }
00406
00412 <span class="keyword">class </span>MIME_MagicRule
00413 {
00414 <span class="keyword">public</span> $start_offset;
00415 <span class="keyword">public</span> $value;
00416 <span class="keyword">public</span> $mask;
00417 <span class="keyword">public</span> $word_size;
00418 <span class="keyword">public</span> $range_length;
00419 <span class="keyword">public</span> $children;
00420 }
00421
00422 <span class="comment">// create one global instance of the class</span>
00423 global $MIME;
00424 $MIME = <span class="keyword">new</span> MIME;
00425
00426 ?>
</pre></div> </div>
</body>
</html>