THIS source compiler<?php
/*
"NCSA httpd 1.3 would return some boring old error/problem message
which would often be meaningless to the user, and would provide no
means of logging the symptoms which caused it."
-- Apache, 'Custom Error Responses'
*/
/*
"Once you are ready for deployment, you should either disable error
reporting completely by setting error_reporting() to 0, or turn off
the error display using the php.ini option display_errors, to insulate
your code from probing. If you choose to do the latter, you should also
define the path to your log file using the error_log ini directive, and
turn log_errors on."
-- PHP.NET
*/
/* ERROR.PHP - error and debug message handling
This gets included by INDEX.PHP and ADMIN.PHP (the two sole entry points)
as the very first include; it provides two main things:
Error and informational messages, both fatal and notices.
Detailed debug/runtime message logging and displaying.
A few server "error" functions.
Well, that's three. But we never said we could count...
*/
$GLOBALS['debug'] = '';
//ini_set('display_errors',1);
error_reporting(0); // when upgrading use E_ERROR|E_PARSE
_error(); // initialize on first call
checkbaduser(); // checks banned IPs and Referers
// might exit
/* module support functions - see file MODULES */
function setmodule($file) {
$GLOBALS['modules'][] = $file;
$init = '_config_'.str_replace('.php','',$file);
if (function_exists($init))
$GLOBALS['functions'][] = $init;
}
function modules_init() {
foreach ($GLOBALS['functions'] as $name) {
debug($name);
$name();
}
}
function modules_loaded() {
foreach ($GLOBALS['modules'] as $name)
echo "\n<!-- $name -->";
}
//register_shutdown_function('modules_loaded');
// that will interfere with redirects and file downloads if registered
/* errorlog - set the errorlog level */
// called by CONFIG *if* logged in as Admin and 'debug =' is non-zero
function errorlog($log) {
_error('error_log',$log);
if ($log)
register_shutdown_function('_msglogdump');
}
/* error - display a formated error message */
// we still only have a very clumsy way of handling errors...
function error($msg = '', $arg = '') {
list($file,$line,$func) = caller(1);
$func = caller(2,'function');
if ($msg == '')
$msg = "(empty message passed to error from: $file,$func)";
switch ($msg) { // specials
case 'notfound':
print "'$arg' not found";
return;
case 'last':
if (($t = _error('last')))
echo "last error: '$t'";
return;
case 'caller':
$func = caller(3,'function');
echo "called: $file,$line,$func $arg ";
return;
case -1:
return _error();
}
if ($html = geterror($msg)) // special message?
$msg = $html;
_error('last',$msg); // save message
if ($arg === FALSE) { // log message?
if (_error('error_log'))
_error('addmsg',$msg);
return;
}
if ($arg === TRUE) // return message?
return $msg;
if ($arg === -1) {
$msg = obcomments($msg);
echo "<!-- $msg -->";
return;
}
if (debug()) {
$bt = _backtrace();
$msg .= "<div class='e'>(backtrace)<pre>$bt</pre></div>";
}
if ($arg == 'fatal') { // early errors may be
if (!function_exists('displayhtml')) // before display.php
exit($msg); // is loaded
$t = 'fatalerror';
if (headers_sent())
$t = 'error';
displayhtml($t,'$error',$msg);
exit;
}
if ($arg == 'error') {
displayhtml($arg,'$error',$msg);
return;
}
if ($arg == 'html')
$msg = "\n<!--\n".strip_htmlcomments($msg)."\n-->\n";
print $msg;
}
/* debug - display message or add to message queue */
function debug($msg = NULL, $trunc = 0) {
$error_log = _error('error_log');
if ($msg === NULL)
return $error_log;
if ($error_log == 0 && $trunc != -1)
return;
list($file,$line,$func) = caller(1);
$func = caller(2,'function');
if (($t = config('debugmod')) && $t != $file)
return;
if (($t = config('debugnomod')) && strstr($t,$file))
return;
if ($msg === TRUE)
$msg = '(true)';
else
if ($msg === FALSE)
$msg = '(false)';
else
if (is_resource($msg))
$msg = 'Resource: '. get_resource_type($msg);
else
if (is_object($msg))
$msg = 'Object: '. get_class($msg);
else
if (is_array($msg))
$msg = 'Array: {'. flatten($msg). '}';
if ($trunc == 0 && config('debugtruncate'))
$trunc = config('debugtruncate');
if ($trunc && $trunc != -1 && strlen($msg) > $trunc)
$msg = substr($msg,0,$trunc). ' ...';
if (!config('nodebugentities'))
$msg = htmlentities($msg);
if (config('debugconvertnl'))
$msg = str_replace("\n",'\n',$msg);
$c = '';
if (config('debugcaller')) {
list($f,$l,$nu) = caller(2);
$c = "($f,$l)";
}
if (!config('nodebugfunc'))
$msg = "$c($file,$line,$func) $msg";
else
$msg = "$c($file,$line) $msg";
if ($error_log == -1 || $trunc == -1)
print $msg . '<br>';
else
if ($error_log == 100)
print '<!-- '.$msg.' -->'.THIS_EOL;
else
if ($error_log == 200)
$GLOBALS['debug'] .= $msg.'<br>'.THIS_EOL;
else
_error('addmsg',$msg);
}
/* redirect - send browser to a new location */
// assumes $url starts with a '?' or that path/file is valid
function redirect($url) {
$host = 'http://'.$_SERVER['HTTP_HOST'].dirname($_SERVER['PHP_SELF']);
$host = rtrim($host,'/').'/';
if (headers_sent($file,$line)) {
debug("headers already sent by $file, line $line");
debug(implode('<br>',headers_list()));
print("Location: <a href='$url'>$url</a>");
exit;
}
if (config('noredirect'))
print("Location: <a href='$url'>$url</a>");
else {
// if debugging is on redirects fail with Opera, but we
// can just turn it off as the data would get lost anyway
errorlog(0);
header("Location: $host$url");
}
exit;
}
/* HTML error handler stuff */
/* htmlseterror - set globally accessible error message */
// this sets the "global" error message to one of the defined error messages
// see ERROR.INI - yes, it is a little odd
function htmlseterror($name, $id = NULL) {
$error = _error();
if (!$error) return FALSE;
if ($id && strpos($error['id_list'],$id) !== FALSE) {
$GLOBALS[$id] = $name;
return;
}
if (!isset($error[$name]))
$name = 'DEFAULT';
if (!is_array($error[$name])) {
$id = $error['default_id'];
$ms = $error[$name];
}
else {
$id = $error[$name]['id'];
$ms = $error[$name]['msg'];
}
$GLOBALS[$id] = $ms;
return $ms;
}
/* htmlgeterror - get a global error message based on ID/name lookup */
function htmlgeterror($name = NULL) {
$error = _error();
if (!$error) return FALSE;
if ($name == NULL)
$id = $error['default_id']; // default "global" message
if (strpos($error['id_list'],$name) !== FALSE)
$id = $name; // one of the "global" messages
if (isset($id)) // did we get one
return (isset($GLOBALS[$id])) ? $GLOBALS[$id] : "";
if (!isset($error[$name])) // no message?
return "error '$name' error!"; // oh no, an error error!
if (is_array($error[$name])) // one of comment/system
return $error[$name]['msg']; // messages
return $error[$name]; // an other message
}
/* geterror - just get the error message or not */
function geterror($name) {
return _error($name);
}
/*
These are the "banning" check functions. checkbaduser() is always called early
in the start process and checkbadinput() for each comment POST.
*/
/* checkbaduser - look for match of banned ip or user agent */
// right now a 404 is sent for the spammers so maybe they'll go away, but
// that does not seem to works as some never stop trying; we want all of this
// configurable, through Admin, who they are: agents, addresses, refers; and
// what to do with them: 404, 403, redirect, send them megabytes of garbage...
function checkbaduser() {
$e = _error();
if (isset($e['HTTP_USER_AGENT']))
foreach ($e['HTTP_USER_AGENT'] as $_)
if (strstr($_SERVER['HTTP_USER_AGENT'],$_))
notfound();
if (isset($e['REMOTE_ADDR']))
foreach ($e['REMOTE_ADDR'] as $_)
if (strstr($_SERVER['REMOTE_ADDR'],$_))
notfound();
// some referers also suck
if (isset($e['HTTP_REFERER']) && isset($_SERVER['HTTP_REFERER']))
foreach ($e['HTTP_REFERER'] as $_)
if (strstr($_SERVER['HTTP_REFERER'],$_))
notfound();
}
/* checkbadinput - look for "banned words" */
// Comment spammers use the "[link=" and "[url=" strings. Those are the two
// default "ban words" and the code stops if detected.
function checkbadinput($data) {
if ($words = _error('BAN_WORDS'))
foreach ($words as $k => $v)
if (stristr($data,$v))
forbidden();
}
function notfound($arg = NULL, $place = NULL) {
if ($arg && !preg_match('/^http:/',$arg))
$arg = "http://$arg";
header('HTTP/1.1 404 Not Found');
echo "<!DOCTYPE HTML>
<html><head><title>404 Not Found</title></head><body>
<h1>Not Found</h1>
<p>The requested URL was not found on this server.</p>
<hr>
<ADDRESS>
Web Server at <a href='$arg'>$place</a>
</ADDRESS>
</body>
</html>
";
exit;
}
function forbidden() {
header("HTTP/1.1 403 Forbidden");
echo '<!DOCTYPE HTML>
<HTML><HEAD><TITLE>403 Forbidden</TITLE>
</HEAD><BODY>
<H1>That is Forbidden</H1>
You have done something wrong.
</BODY>
</HTML>
';
exit;
}
/* "internal" functions (used here and nowhere else) */
/* _msglogdump - display the message log (as a shutdown fuction) */
function _msglogdump() {
$e = _error('error_log');
if ($e <= 0 || $e >= 100) return; // special cases
print THIS_EOL.
"<div style='font-size:13px;background:white;color:black;'><pre>";
foreach (_error('message_log') as $msg)
print THIS_EOL.$msg;
print "</pre></div>";
}
/* _backtrace - this version is vastly better than the last one! sheesh */
function _backtrace() {
if (config('errorfullbacktrace'))
return print_r(debug_backtrace(),1);
ob_start();
if (defined('DEBUG_BACKTRACE_IGNORE_ARGS'))
debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
else
debug_print_backtrace();
$out = ob_get_contents();
ob_end_clean();
if (config('errorbacktrace'))
return $out;
$out = explode(PHP_EOL,$out);
if (isset($out[3]))
$bt[] = substr($out[3],2);
$bt[] = substr($out[2],2);
$s = '';
foreach ($bt as $t) {
$t = str_replace($_SERVER['DOCUMENT_ROOT'],'',$t);
$t = str_replace(array('[',']'),'',$t);
$s .= $t . '<br>';
}
return $s;
}
/* this module's config */
function _error($var = NULL, $val = NULL) {
static $error = array();
if ($error == array()) {
// this reads the error messages, but let's do it nicely
// it's an INI file that can be edited by Admin so if it
// errs we can continue
// this is how to read a PHP format
$e = @eval(file_get_contents('error.dat'));
// this is the INI file format
//$e = @parse_ini_file('error.ini',TRUE);
// tests show that reading the PHP file format is faster -- eventually this
// code will just: include 'error.dat';
if ($e) $error = $e;
$error['error_log'] = 0;
$error['message_log'][] = '<b>message log:</b>';
if ($e == FALSE) {
$e = error_get_last();
$e['file'] = basename($e['file']);
$m = "{$e['message']} ({$e['file']},{$e['line']})";
$error['message_log'][] = $m;
}
$error['handler'] = set_error_handler('error_handler');
return;
}
if ($var === NULL)
return $error;
// special case:
if ($var == 'addmsg')
return $error['message_log'][] = $val;
// config values:
if ($val !== NULL)
return $error[$var] = $val;
// caller must make sure to not override special keys
if (isset($error[$var]))
return $error[$var];
return '';
}
/* error_handler - our error handler */
/*
PHP.NET: "The following error types cannot be handled with a user defined
function: E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR,
E_COMPILE_WARNING..."
*/
function error_handler($errno, $errstr, $errfile, $errline) {
$errfile = basename($errfile);
$error = "$errstr ($errfile, $errline)";
if ($errno == E_USER_ERROR)
exit($error);
if ($errno == E_NOTICE) {
if (config('shownotices'))
echo($error.'<br>');
if (config('debugnotices'))
debug($error);
return TRUE;
}
if (config('showerrors'))
echo($error.'<br>');
debug($error);
return TRUE;
}
?>
Source Code Index