error.php -
index
<?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'] = '';
error_reporting(E_ALL | E_STRICT | E_NOTICE);
// some hosts will turn this off which can be annoying if there is an error
//ini_set('display_errors',1);
// the following is very useful to locate start-up errors, but we can't
// use it based on a configuration setting as config may not be available
// what I do if a "blank screen" happens is to uncomment it and then it will
// display the modules that successfully loaded -- the one that does not is
// the one that has the error
//register_shutdown_function('modules_loaded');
_error_config();
checkbaduser(); // checks banned IPs and Referers
// might exit
/* setmodule - each module calls this first, INDEX.PHP calls last */
function setmodule() {
$GLOBALS['modules'][] = caller(1,'file');
}
// see file MODULES
/* modules_loaded - display loaded modules list */
function modules_loaded() {
foreach ($GLOBALS['modules'] as $name)
echo "\n<!-- $name -->";
}
/* errorlog - set the errorlog level */
// called by CONFIG *if* logged in as Admin and 'debug =' is non-zero
function errorlog($log) {
global $error;
$error['error_log'] = $log;
register_shutdown_function('_msglogdump');
}
/* error - display a formated error message */
// we still only have a very clumsy way of handling errors...
// fatal errors are handled stupidly, as they just "fart"... just some stinky
// error message that is offensive -- we HAVE to do something different, like
// continue loading the program and, once we get to the start, THEN display a
// really informative message with links to the HTML compiled documentation!
function error($msg = '', $arg = '') {
global $error;
switch ($msg) { // specials
case 'notfound':
print "'$arg' not found";
return;
case 'last':
if (isset($error['last']))
echo "last error: ".$error['last'];
return;
case 'caller':
list($file,$line,$func) = caller(2);
$func = caller(3,'function');
echo "called: $file,$line,$func$arg";
return;
case -1:
return $error;
}
$error['last'] = $msg;
// two calls are here to displayhtml() and I am inclined to remove them and
// have the caller do it instead...
if ($html = geterror($msg)) {
if (!function_exists('displayhtml'))
echo $html;
else
displayhtml('message','$error',$html);
return;
}
if (debug()) {
$bt = _backtrace();
$msg .= "<div class='e'><pre>$bt</pre></div>";
}
if ($arg === FALSE) { // log message?
if ($error['error_log'])
_msglog($msg);
return;
}
if ($arg === TRUE) // return message?
return $msg;
if ($arg === -1) {
$msg = obcomments($msg);
echo "<!-- $msg -->";
return;
}
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;
}
print $msg;
}
/* debug - display message or add to message queue */
function debug($msg = NULL, $trunc = 0) {
global $error;
$error_log = $error['error_log'];
if ($msg === NULL)
return $error_log;
if ($error_log == 0)
return;
list($file,$line,$func) = caller(1);
$func = caller(2,'function');
if (function_exists('config'))
if (($t = config('debugmod')) && $t != $file)
return;
if ($msg === TRUE)
$msg = '(true)';
if ($msg === FALSE)
$msg = '(false)';
if (is_resource($msg))
$msg = 'Resource: '.get_resource_type($msg);
if (is_object($msg))
$msg = 'Object: '.get_class($msg);
if (is_array($msg))
$msg = "Array: {".rtrim(implode(',',$msg),','). "}";
if ($trunc == 0)
if (function_exists('config') && config('debugtruncate'))
$trunc = config('debugtruncate');
if ($trunc && $trunc != -1 && strlen($msg) > $trunc)
$msg = substr($msg,0,$trunc).' ...';
if (function_exists('config') && config('debugentities'))
$msg = htmlentities($msg);
if (function_exists('config') && config('debugconvertnl'))
$msg = str_replace("\n",'\n',$msg);
$c = '';
if (function_exists('config') && config('debugcaller')) {
list($f,$l,$nu) = caller(2);
$c = "($f,$l)";
}
if (function_exists('config') && !config('nodebugfunc'))
$msg = "$c($file,$line,$func) $msg";
else
$msg = "$c($file,$line) $msg";
if ($error_log == -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
_msglog($msg);
}
/* redirect - send browser to a new location */
// assumes $url starts with a '?'
function redirect($url) {
$host = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'];
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
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
function htmlseterror($name, $id = NULL) {
global $error;
$error =& $error['error_msgs'];
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) {
global $error;
$error =& $error['error_msgs'];
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 (@$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) {
global $error;
return @$error['error_msgs'][$name];
}
/* 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.
function checkbaduser() {
global $error;
$e =& $error['error_msgs'];
if (isset($e['HTTP_USER_AGENT']))
foreach ($e['HTTP_USER_AGENT'] as $_)
if (strstr($_SERVER['HTTP_USER_AGENT'],$_)) {
sleep(30);
notfound();
exit;
}
if (isset($e['REMOTE_ADDR']))
foreach ($e['REMOTE_ADDR'] as $_)
if (strstr($_SERVER['REMOTE_ADDR'],$_)) {
notfound();
exit;
}
}
/* checkbadinput - look for "banned words" */
// Comment spammers use the "[link=" and "[url=" strings. Those are the two
// default "ban words" and the code stops and logs the IP and UA string if
// detected. the logging is experimental and to gather statistics
function checkbadinput($data) {
global $error;
$e =& $error['error_msgs'];
if (!isset($e['BAN_WORDS']))
return;
foreach ($e['BAN_WORDS'] as $k => $v)
if (stristr($data,$v))
forbidden();
}
function notfound() {
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="">where are we?</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;
}
function servererror() {
header('HTTP/1.1 500 Internal Server Error');
echo '<!DOCTYPE HTML>
<HTML><HEAD><TITLE>500 Internal Server Error</TITLE>
</HEAD><BODY>
<H1>Internal Server Error</H1>
<P>The server encountered an internal error or misconfiguration and was unable to complete your request.</P>
<P>Please contact the server administrator to inform of the time the error occurred and of anything you might have done that may have caused the error.</P>
<P>More information about this error may be available in the server error log.</P>
</BODY>
</HTML>
';
exit;
}
/* "internal" functions (used here and nowhere else) */
// _msglog - place a string into the message log
function _msglog($msg) {
global $error;
$error['message_log'][] = $msg;
}
// _msglogdump - display the message log (as a shutdown fuction)
function _msglogdump() {
global $error;
$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(THIS_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_config() {
global $error;
// we have an INI to PHP array tool now and are going to slowly convert
// some INI files to PHP files - that will make this code load much faster
/* going to delay this
if (file_exists('dat/error_dat.php')) {
include 'dat/error_dat.php';
return;
}
*/
$error['error_log'] = 0;
$error['message_log'] = array("<b>message log:</b>");
// this reads the error messages "database" into memory
$error['error_msgs'] = parse_ini_file("error.ini",TRUE);
}
?>