final move of files
[web.mtrack] / MTrack / web.php
1 <?php # vim:ts=2:sw=2:et:
2 /* For licensing and copyright terms, see the file named LICENSE */
3
4 die("web.php not used any more");
5 /* Simplistic pathinfo parsing - could optionally have additional features such
6   as validation added */
7 function mtrack_parse_pathinfo($vars) {
8   $pi = isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : '';
9   $data = explode('/', $pi);
10   $i = 0;
11   $return_vars = array();
12   array_shift($data);
13   foreach($vars as $name => $value) {
14     if (isset($data[$i])) {
15       $return_vars[$name] = $data[$i];
16       $i++;
17     } else {
18       $return_vars[$name] = $value;
19     }
20   }
21   return $return_vars;
22 }
23
24 /* Pathinfo retrieval minus starting slash */
25 function mtrack_get_pathinfo($no_strip = false) {
26   $pi = isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : NULL;
27   if ($pi !== NULL && strlen($pi) && $no_strip == false) {
28     $pi = substr($pi, 1);
29   }
30   return $pi;
31 }
32
33 function mtrack_calc_root()
34 {
35   /* ABSWEB: the absolute URL to the base of the web app */
36   global $ABSWEB;
37
38   /* if they have one, use the weburl config value for this */
39   $ABSWEB = MTrackConfig::get('core', 'weburl');
40   if (strlen($ABSWEB)) {
41     return;
42   }
43
44   /* otherwise, determine the root of the app.
45    * This is complicated because the DOCUMENT_ROOT may refer to an area that
46    * is completely unrelated to the actual root of the web application, for
47    * instance, in the case that the user has a public_html dir where they
48    * are running mtrack */
49
50   /* determine the root of the app */
51   $sdir = dirname($_SERVER['SCRIPT_FILENAME']);
52   $idir = dirname(dirname(__FILE__)) . '/web';
53   $diff = substr($sdir, strlen($idir)+1);
54   $rel = preg_replace('@[^/]+@', '..', $diff);
55   if (strlen($rel)) {
56     $rel .= '/';
57   }
58   /* $rel is now the relative path to the root of the web app, from the current
59    * page */
60
61   if (isset($_SERVER['HTTP_HOST'])) {
62     $ABSWEB = ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ?
63               'https' : 'http') . '://' .  $_SERVER['HTTP_HOST'];
64   } else {
65     $ABSWEB = 'http://localhost';
66   }
67
68   $bits = explode('/', $rel);
69   $base = $_SERVER['SCRIPT_NAME'];
70   foreach ($bits as $b) {
71     $base = dirname($base);
72   }
73   if ($base == '/') {
74     $ABSWEB .= '/';
75   } else {
76     $ABSWEB .= $base . '/';
77   }
78 }
79 mtrack_calc_root();
80
81 function mtrack_head($title, $navbar = true)
82 {
83   global $ABSWEB;
84   static $mtrack_did_head;
85
86   $whoami = mtrack_username(MTrackAuth::whoami(),
87     array(
88       'no_image' => true
89     )
90   );
91
92   if ($mtrack_did_head) {
93     return;
94   }
95   $mtrack_did_head = true;
96
97   $projectname = htmlentities(MTrackConfig::get('core', 'projectname'),
98     ENT_QUOTES, 'utf-8');
99   $logo = MTrackConfig::get('core', 'projectlogo');
100   if (strlen($logo)) {
101     $projectname = "<img alt='$projectname' src='$logo'>";
102   }
103   $fav = MTrackConfig::get('core', 'favicon');
104   if (strlen($fav)) {
105     $fav = <<<HTML
106 <link rel="icon" href="$fav" type="image/x-icon" />
107 <link rel="shortcut icon" href="$fav" type="image/x-icon" />
108 HTML;
109   } else {
110     $fav = '';
111   }
112
113   $title = htmlentities($title, ENT_QUOTES, 'utf-8');
114
115   $userinfo = "Logged in as $whoami";
116   MTrackNavigation::augmentUserInfo($userinfo);
117   
118   echo "<!DOCTYPE html>
119 <html>
120     <head>
121         <meta http-equiv=\"Content-Type\" value=\"text/html; charset=utf-8\">
122         <meta http-equiv=\"X-UA-Compatible\" content=\"IE=8\">
123         <title>$title</title>
124         $fav
125 ";
126
127 /* For licensing and copyright terms, see the file named LICENSE */
128
129     $scripts = array(
130       'css/smoothness/jquery-ui-1.7.2.custom.css',
131       'mtrack.css',
132       'css/ticket.css',
133       'css/markitup/markitup-simple.css',
134       'css/markitup/wiki.css',
135       'css/hyperlight/plain.css',
136       'css/hyperlight/vibrant-ink.css',
137       'css/hyperlight/zenburn.css',
138       'css/hyperlight/wezterm.css',
139     );
140
141     foreach ($scripts as $name) {
142       
143       echo "<link rel=\"stylesheet\" href=\"${ABSWEB}$name\" type=\"text/css\" />";
144       
145     }
146
147  
148     $scripts = array(
149       'excanvas.pack.js',
150       'jquery-1.4.2.min.js',
151       'jquery-ui-1.8.2.custom.min.js',
152       'jquery.asmselect.js',
153       'jquery.flot.pack.js',
154       'jquery.MultiFile.pack.js',
155       'jquery.cookie.js',
156       'jquery.treeview.js',
157       'jquery.tablesorter.js',
158       'jquery.metadata.js',
159       'jquery.markitup.js',
160       'jquery.timeago.js',
161       'json2.js',
162       'mtrack.js',
163        'mtrack.ticket.js',
164         'mtrack.watch.js',
165     );
166     
167     echo '
168     <script type="text/javascript"> 
169     var ABSWEB = "'. $ABSWEB . '";
170     </script>
171     ';
172
173     foreach ($scripts as $name) {
174       echo "<script type=\"text/javascript\" src=\"$ABSWEB/js/$name\"></script>\n";
175     }
176
177
178     $PRI_SWITCH = '';
179     foreach (MTrackDB::q('select priorityname, value from priorities')
180         ->fetchAll() as $row) {
181       $PRI_SWITCH .= "case '$row[0]': return $row[1];\n";
182     }
183     $SEV_SWITCH = '';
184     foreach (MTrackDB::q('select sevname, ordinal from severities')
185         ->fetchAll() as $row) {
186       $SEV_SWITCH .= "case '$row[0]': return $row[1];\n";
187     }
188
189     echo <<<JAVASCRIPT
190
191     <script type="text/javsacript">
192
193     $(document).ready(function() {
194          
195       $.tablesorter.addParser({
196         id: 'priority',
197         is: function(s) {
198           // don't auto-detect
199           return false;
200         },
201         format: function(s) {
202           switch (s) {
203             $PRI_SWITCH
204           }
205           return s;
206         },
207         type: 'numeric'
208       });
209       $.tablesorter.addParser({
210         id: 'severity',
211         is: function(s) {
212           // don't auto-detect
213           return false;
214         },
215         format: function(s) {
216           switch (s) {
217             $SEV_SWITCH
218           }
219           return s;
220         },
221         type: 'numeric'
222       });
223       
224     </script>
225
226 JAVASCRIPT;
227   
228   
229   echo <<<HTML
230 </head>
231 <body>
232 HTML;
233
234   if ($navbar) {
235     echo <<<HTML
236 <div id="banner-back">
237   <form id="mainsearch" action="${ABSWEB}search.php">
238     $userinfo
239     <input type="text" class="search" title="Type and press enter to Search"
240         name="q" accesskey="f">
241   </form>
242   <div id="banner">
243     $projectname
244   </div>
245 HTML;
246
247     echo <<<HTML
248 <div id="header">
249 HTML;
250
251   $nav = array();
252   if (MTrackAuth::whoami() !== 'anonymous') {
253   //  $nav['/'] = 'Today';
254   }
255   $navcandidates = array(
256     "/Browse.php" => array("Browse", 'read', 'Browser'),
257    // "/wiki.php" => array("Wiki", 'read', 'Wiki'),
258     "/timeline.php" => array("Timeline", 'read', 'Timeline'),
259    // "/roadmap.php" => array("Roadmap", 'read', 'Roadmap'),
260     "/report.php/1" => array("Active Tickets", 'read', 'Reports'),
261     "/report.php/3" => array("Pending Review", 'read', 'Reports'),
262     "/Ticket.php/new" => array("New Ticket", 'create', 'Tickets'),
263    // "/snippet.php" => array("Snippets", 'read', 'Snippets'),
264     "/admin/" => array("Administration", 'modify', 'Enumerations', 'Components', 'Projects', 'Browser'),
265   );
266   foreach ($navcandidates as $url => $data) {
267     $label = array_shift($data);
268     $right = array_shift($data);
269     $ok = false;
270     foreach ($data as $object) {
271       if (MTrackACL::hasAllRights($object, $right)) {
272         $ok = true;
273         break;
274       }
275     }
276     if ($ok) {
277       $nav[$url] = $label;
278     }
279   }
280
281   echo mtrack_nav('mainnav', $nav);
282   echo <<<HTML
283   </div>
284 HTML;
285   }
286   if (MTrackConfig::get('core', 'admin_party') == 1 &&
287       MTrackAuth::whoami() == 'adminparty' &&
288       ($_SERVER['REMOTE_ADDR'] == '127.0.0.1' ||
289           $_SERVER['REMOTE_ADDR'] == '::1')) {
290     echo <<<HTML
291 <div class='ui-state-error ui-corner-all'>
292     <span class='ui-icon ui-icon-alert'></span>
293   <b>Welcome to the admin party!</b> Authentication is not yet configured;
294   while it is in this state, any user connecting from the localhost
295   address is treated as having admin rights (that includes you, and this
296   is why you are seeing this message). All other users are treated
297   as anonymous users.<br>
298   <b><a href="{$ABSWEB}admin/auth.php">Click here to Configure Authentication</a></b>
299 </div>
300 HTML;
301   } elseif (!MTrackAuth::isAuthConfigured() &&
302       MTrackConfig::get('core', 'admin_party') == 1)
303   {
304     $localaddr = preg_replace('@^(https?://)([^/]+)/(.*)$@',
305       "\\1localhost/\\3", $ABSWEB);
306
307     echo <<<HTML
308 <div class='ui-state-highlight ui-corner-all'>
309     <span class='ui-icon ui-icon-info'></span>
310   <b>Authentication is not yet configured</b>.  If you are the admin,
311   you should use the <b><a href="$localaddr">localhost address</a></b>
312   to reach the system and configure it.
313 </div>
314 HTML;
315   } elseif (!MTrackAuth::isAuthConfigured()) {
316     echo <<<HTML
317 <div class='ui-state-highlight ui-corner-all'>
318     <span class='ui-icon ui-icon-info'></span>
319   <b>Authentication is not yet configured</b>.  If you are the admin,
320   you will need to edit the config.ini file to configure authentication.
321 </div>
322 HTML;
323   }
324
325   if (ini_get('magic_quotes_gpc') === true ||
326       !strcasecmp(ini_get('magic_quotes_gpc'), 'on')) {
327     echo <<<HTML
328 <div class='ui-state-error ui-corner-all'>
329     <span class='ui-icon ui-icon-alert'></span>
330   <b>magic_quotes_gpc</b> is enabled.  This causes mtrack not to work.
331   Please disable this setting in your server configuration.
332 </div>
333 HTML;
334
335   }
336
337   echo <<<HTML
338 </div>
339 <div id="content">
340 HTML;
341 }
342
343 function mtrack_foot($visible_markup = true)
344 {
345   echo <<<HTML
346 </div>
347 HTML;
348   if ($visible_markup) {
349     echo <<<HTML
350 <div id="footer">
351 <div class="navfoot">
352   Powered by <a href="http://bitbucket.org/wez/mtrack/">mtrack</a>
353 </div>
354 </div>
355 </body>
356 <script>
357 \$(document).ready(function () {
358   window.mtrack_footer_position();
359 });
360 </script>
361 </html>
362 HTML;
363     if (MTrackConfig::get('core', 'debug.footer')) {
364       global $FORKS;
365
366       echo "<!-- " . MTrackDB::$queries . " queries\n";
367       var_export(MTrackDB::$query_strings);
368       echo "\n\nforks\n\n";
369       var_export($FORKS);
370       echo "-->";
371     }
372   }
373 }
374
375 interface IMTrackExtensionPage {
376   /** called to dispatch a page render */
377   function dispatchRequest();
378 }
379
380 class MTrackExtensionPage {
381   static $locations = array();
382   static function registerLocation($location, IMTrackExtensionPage $page) {
383     self::$locations[$location] = $page;
384   }
385   static function locationToURL($location) {
386     global $ABSWEB;
387     return $ABSWEB . 'ext.php/' . $location;
388   }
389   static function bindToPage($location) {
390     while (strlen($location)) {
391       if (isset(self::$locations[$location])) {
392         return self::$locations[$location];
393       }
394       if (strpos($location, '/') === false) {
395         return null;
396       }
397       $location = dirname($location);
398     }
399   }
400 }
401  
402 function mtrack_date($tstring, $show_full = false)
403 {
404   /* database time is always relative to UTC */
405   $d = date_create($tstring, new DateTimeZone('UTC'));
406   if (!is_object($d)) {
407     throw new Exception("could not represent $tstring as a datetime object");
408   }
409   $iso8601 = $d->format(DateTime::W3C);
410   /* but we want to render relative to user prefs */
411   date_timezone_set($d, new DateTimeZone(date_default_timezone_get()));
412   $full = $d->format('D, M d Y H:i');
413
414   if (!$show_full) {
415     return "<abbr title=\"$iso8601\" class='timeinterval'>$full</abbr>";
416   }
417
418   return "<abbr title='$iso8601' class='timeinterval'>$full</abbr> <span class='fulldate'>$full</span>";
419 }
420
421 function mtrack_rmdir($dir)
422 {
423   foreach (scandir($dir) as $ent) {
424     if ($ent == '.' || $ent == '..') {
425       continue;
426     }
427     $full = $dir . DIRECTORY_SEPARATOR . $ent;
428     if (is_dir($full)) {
429       mtrack_rmdir($full);
430     } else {
431       unlink($full);
432     }
433   }
434   rmdir($dir);
435 }
436
437 function mtrack_make_temp_dir($do_make = true)
438 {
439   $tempdir = sys_get_temp_dir();
440   $base = $tempdir . DIRECTORY_SEPARATOR . "mtrack." . uniqid();
441   for ($i = 0; $i < 1024; $i++) {
442     $candidate = $base . sprintf("%04x", $i);
443     if ($do_make) {
444       if (mkdir($candidate)) {
445         return $candidate;
446       }
447     } else {
448       /* racy */
449       if (!file_exists($candidate) && !is_dir($candidate)) {
450         return $candidate;
451       }
452     }
453   }
454   throw new Exception("unable to make temp dir based on path $candidate");
455 }
456 /// moved to mtrack_dataobjects_event (currently)
457 //function mtrack_diff_strings($before, $now)
458
459
460 function mtrack_last_chance_saloon($e)
461 {
462   // adding headers on exceptions here causes nightmares for dynamic content..
463   
464   if ($e instanceof MTrackAuthorizationException) {
465     if (MTrackAuth::whoami() == 'anonymous') {
466       MTrackAuth::forceAuthenticate();
467     }
468   //  mtrack_head('Insufficient Privilege');
469     echo '<h1>Insufficient Privilege</h1>';
470     $rights = is_array($e->rights) ? join(', ', $e->rights) : $e->rights;
471     echo "You do not have the required set of rights ($rights) to access this page<br>";
472     //mtrack_foot();
473     exit;
474   }
475
476   $msg = $e->getMessage();
477
478   try {
479   //  mtrack_head('Whoops: ' . $msg);
480   } catch (Exception $doublefault) {
481   }
482
483   echo "<h1>An error occurred!</h1>";
484
485   echo htmlentities($msg, ENT_QUOTES, 'utf-8');
486
487   echo "<br>";
488
489   echo nl2br(htmlentities($e->getTraceAsString(), ENT_QUOTES, 'utf-8'));
490
491   try {
492   //  mtrack_foot();
493   } catch (Exception $doublefault) {
494   }
495 }
496  
497
498  
499 function mtrack_gravatar($email, $size = 24)
500 {
501   // d=identicon
502   // d=monsterid
503   // d=wavatar
504   return "<img class='gravatar' width='$size' height='$size' src='http://www.gravatar.com/avatar/" .  md5(strtolower($email)) . "?s=$size&amp;d=wavatar'>";
505 }
506 // mtrack_defrepo ==> MTrackRepo::defaultRepo($cfg); 
507 // mtrack_changeset_url ==> MTrackRepo::loadByChangeSet = see  linkhandler::changeset
508  
509
510 // basically outputs 
511 // <a class='wikilink' href=\"{$ABSWEB}wiki.php/$pagename#$anchor\">NAME</a> 
512 function mtrack_wiki_link($pagename, $extras = array())
513 {
514     global $ABSWEB;
515     if ($pagename instanceof MTrack_Wiki_Item) {
516         $wiki = $pagename;
517     } else if (is_string($pagename)) {
518         $wiki = null;//MTrackWikiItem::loadByPageName($pagename);
519     } else {
520         // FIXME: hinted data from reports
521         throw new Exception("FIXME: wiki");
522     }
523     
524     if ($wiki) {
525         $pagename = $wiki->pagename;
526     }
527     $html = "<a class='wikilink'";
528     if (isset($extras['#'])) {
529         $anchor = '#' . $extras['#'];
530     } else {
531         $anchor = '';
532     }
533     $html .= " href=\"{$ABSWEB}wiki.php/$pagename$anchor\">";
534     if (isset($extras['display'])) {
535         $html .= htmlentities($extras['display'], ENT_QUOTES, 'utf-8');
536     } else {
537         $html .= htmlentities($pagename, ENT_QUOTES, 'utf-8');
538     }
539     $html .= "</a>";
540     return $html;
541 }
542
543 function mtrack_tag($tag, $repo = null)
544 {
545   return "<span class='tagname'>$tag</span>";
546 }
547
548 function mtrack_keyword($keyword)
549 {
550   global $ABSWEB;
551   $kw = urlencode($keyword);
552   return "<a class='keyword' href='{$ABSWEB}search.php?q=keyword%3A$kw'>$keyword</span>";
553 }
554
555 function mtrack_multi_select_box($name, $title, $items, $values = null)
556 {
557   $title = htmlentities($title, ENT_QUOTES, 'utf-8');
558   $html = "<select id='$name' name='{$name}[]' multiple='multiple' title='$title'>";
559   foreach ($items as $k => $v) {
560     $html .= "<option value='" .
561       htmlspecialchars($k, ENT_QUOTES, 'utf-8') .
562       "'";
563     if (isset($values[$k])) {
564       $html .= ' selected';
565     }
566     $html .= ">" . htmlentities($v, ENT_QUOTES, 'utf-8') . "</option>\n";
567   }
568   return $html . "</select>";
569 }
570
571 function mtrack_select_box($name, $items, $value = null, $keyed = true)
572 {
573   $html = "<select id='$name' name='$name'>";
574   foreach ($items as $k => $v) {
575     $html .= "<option value='" .
576       htmlspecialchars($k, ENT_QUOTES, 'utf-8') .
577       "'";
578     if (($keyed && $value == $k) || (!$keyed && $value == $v)) {
579       $html .= ' selected';
580     }
581     $html .= ">" . htmlentities($v, ENT_QUOTES, 'utf-8') . "</option>\n";
582   }
583   return $html . "</select>";
584 }
585
586 function mtrack_radio($name, $value, $curval)
587 {
588   $checked = $curval == $value ? " checked='checked'": '';
589   return "<input type='radio' id='$value' name='$name' value='$value'$checked>";
590 }
591
592 function mtrack_diff($diffstr)
593 {
594   $nlines = 0;
595
596   if (is_resource($diffstr)) {
597     $lines = array();
598     while (($line = fgets($diffstr)) !== false) {
599       $lines[] = rtrim($line, "\r\n");
600     }
601     $diffstr = $lines;
602   }
603
604   if (is_string($diffstr)) {
605     $abase = md5($diffstr);
606     $diffstr = preg_split("/\r?\n/", $diffstr);
607   } else {
608     $abase = md5(join("\n", $diffstr));
609   }
610
611   /* we could use toggle() below, but it is much faster to determine
612    * if we are hiding or showing based on a single variable than evaluating
613    * that for each possible cell */
614   $html = <<<HTML
615 <button class='togglediffcopy' type='button'>Toggle Diff Line Numbers</button>
616 HTML;
617   $html .= "<table class='code diff'>";
618   //$html = "<pre class='code diff'>";
619
620   while (true) {
621     if (!count($diffstr)) {
622       break;
623     }
624     $line = array_shift($diffstr);
625     $nlines++;
626     if (!strncmp($line, '@@ ', 3)) {
627       /* done with preamble */
628       break;
629     }
630     $line = htmlspecialchars($line, ENT_QUOTES, 'utf-8');
631     $line = "<tr class='meta'><td class='lineno'></td><td class='lineno'></td><td class='lineno'></td><td width='100%'>$line</tr>";
632     $html .= $line . "\n";
633   }
634
635   $lines = array(0, 0);
636   $first = false;
637   while (true) {
638     $class = 'unmod';
639
640     if (preg_match("/^@@\s+-(\pN+)(?:,\pN+)?\s+\+(\pN+)(?:,\pN+)?\s*@@/",
641         $line, $M)) {
642       $lines[0] = (int)$M[1] - 1;
643       $lines[1] = (int)$M[2] - 1;
644       $class = 'meta';
645       $first = true;
646     } elseif (strlen($line)) {
647       if ($line[0] == '-') {
648         $lines[0]++;
649         $class = 'removed';
650       } elseif ($line[0] == '+') {
651         $lines[1]++;
652         $class = 'added';
653       } else {
654         $lines[0]++;
655         $lines[1]++;
656       }
657     } else {
658       $lines[0]++;
659       $lines[1]++;
660     }
661     $row = "<tr class='$class";
662     if ($first) {
663       $row .= ' first';
664     }
665     if ($class != 'meta' && $first) {
666       $first = false;
667     }
668     $row .= "'>";
669
670     switch ($class) {
671       case 'meta':
672         $line_info = '';
673         $row .= "<td class='lineno'></td><td class='lineno'></td>";
674         break;
675       case 'added':
676         $row .= "<td class='lineno'></td><td class='lineno'>" . $lines[1] . "</td>";
677         break;
678       case 'removed':
679         $row .= "<td class='lineno'>" . $lines[0] . "</td><td class='lineno'></td>";
680         break;
681       default:
682         $row .= "<td class='lineno'>" . $lines[0] . "</td><td class='lineno'>" . $lines[1] . "</td>";
683     }
684     $anchor = $abase . '.' . $nlines;
685     $row .= "<td class='linelink'><a name='$anchor'></a><a href='#$anchor' title='link to this line'>#</a></td>";
686
687     $line = htmlspecialchars($line, ENT_QUOTES, 'utf-8');
688     $row .= "<td class='line' width='100%'>$line</td></tr>\n";
689     $html .= $row;
690
691     if (!count($diffstr)) {
692       break;
693     }
694     $line = array_shift($diffstr);
695     $nlines++;
696   }
697
698   if ($nlines == 0) {
699     return null;
700   }
701
702   $html .= "</table>";
703   return $html;
704 }
705
706 function mtrack_mime_detect($filename, $namehint = null)
707 {
708   /* does config tell us how to decide mimetype */
709   $detector = MTrackConfig::get('core', 'mimetype_detect');
710
711   /* if detector is blank, we'll try to figure out which one to use */
712   if (empty($detector)) {
713     if (function_exists('finfo_open')) {
714       $detector = 'fileinfo';
715     } elseif (function_exists('mime_content_type')) {
716       $detector = 'mime_magic';
717     } else {
718       $detector = 'file';
719     }
720   }
721
722   /* use detector or all mimetypes will be blank */
723   if ($detector === 'fileinfo') {
724     if (defined('FILEINFO_MIME_TYPE')) {
725       $fileinfo = finfo_open(FILEINFO_MIME_TYPE);
726     } else {
727       $magic = MTrackConfig::get('core', 'mime.magic');
728       if (strlen($magic)) {
729         $fileinfo = finfo_open(FILEINFO_MIME, $magic);
730       } else {
731         $fileinfo = finfo_open(FILEINFO_MIME);
732       }
733     }
734     $mimetype = finfo_file($fileinfo, $filename);
735     finfo_close($fileinfo);
736   } elseif ($detector === 'mime_magic') {
737     $mimetype = mime_content_type($filename);
738   } elseif (PHP_OS != 'SunOS') {
739     $mimetype = shell_exec("file -b --mime " . escapeshellarg($filename));
740   } else {
741     $mimetype = 'application/octet-stream';
742   }
743   $mimetype = trim(preg_replace("/\s*;.*$/", '', $mimetype));
744   if (empty($mimetype)) {
745     $mimetype = 'application/octet-stream';
746   }
747   if ($mimetype == 'application/octet-stream') {
748     if ($namehint === null) {
749       $namehint = $filename;
750     }
751     $pi = pathinfo($namehint);
752     switch (strtolower($pi['extension'])) {
753       case 'bin': return 'application/octet-stream';
754       case 'exe': return 'application/octet-stream';
755       case 'dll': return 'application/octet-stream';
756       case 'iso': return 'application/octet-stream';
757       case 'so': return 'application/octet-stream';
758       case 'a': return 'application/octet-stream';
759       case 'lib': return 'application/octet-stream';
760       case 'pdf': return 'application/pdf';
761       case 'ps': return 'application/postscript';
762       case 'ai': return 'application/postscript';
763       case 'eps': return 'application/postscript';
764       case 'ppt': return 'application/vnd.ms-powerpoint';
765       case 'xls': return 'application/vnd.ms-excel';
766       case 'tiff': return 'image/tiff';
767       case 'tif': return 'image/tiff';
768       case 'wbmp': return 'image/vnd.wap.wbmp';
769       case 'png': return 'image/png';
770       case 'gif': return 'image/gif';
771       case 'jpg': return 'image/jpeg';
772       case 'jpeg': return 'image/jpeg';
773       case 'ico': return 'image/x-icon';
774       case 'bmp': return 'image/bmp';
775       case 'css': return 'text/css';
776       case 'htm': return 'text/html';
777       case 'html': return 'text/html';
778       case 'txt': return 'text/plain';
779       case 'xml': return 'text/xml';
780       case 'eml': return 'message/rfc822';
781       case 'asc': return 'text/plain';
782       case 'rtf': return 'application/rtf';
783       case 'wml': return 'text/vnd.wap.wml';
784       case 'wmls': return 'text/vnd.wap.wmlscript';
785       case 'gtar': return 'application/x-gtar';
786       case 'gz': return 'application/x-gzip';
787       case 'tgz': return 'application/x-gzip';
788       case 'tar': return 'application/x-tar';
789       case 'zip': return 'application/zip';
790       case 'sql': return 'text/plain';
791     }
792     // if the file is ascii, then treat it as text/plain
793     $fp = fopen($filename, 'rb');
794     $mimetype = 'text/plain';
795     do {
796       $x = fread($fp, 8192);
797       if (!strlen($x)) break;
798       if (preg_match('/([\x80-\xff])/', $x, $M)) {
799         $mimetype = 'application/octet-stream';
800         break;
801       }
802     } while (true);
803     $fp = null;
804   }
805   return $mimetype;
806 }
807  
808
809 if (php_sapi_name() != 'cli') {
810   set_exception_handler('mtrack_last_chance_saloon');
811   error_reporting(E_NOTICE|E_ERROR|E_WARNING);
812  // ini_set('display_errors', false);
813   set_time_limit(300);
814 }
815
816