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...
*/

error_reporting(E_ALL E_STRICT E_NOTICE);

$GLOBALS['debug'] = '';

_error();                // initialize on first call
checkbaduser();                // checks banned IPs and Referers
                    //  might exit


/* module support functions - see file MODULES */

function setmodule($file$init NULL) {
    
$GLOBALS['modules'][] = $file;
    if (
$init)
        
$GLOBALS['functions'][] = $init;
}

function 
modules_init() {
    foreach (
$GLOBALS['functions'] as $name)
        
$name();
}

function 
modules_loaded() {
    foreach (
$GLOBALS['modules'] as $name)
        echo 
"\n<!-- $name -->";
}
//register_shutdown_function('modules_loaded');


/* 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 '') {

    switch (
$msg) {                    // specials
    
case 'notfound':
        print 
"'$arg' not found";
        return;
    case 
'last':
        if ((
$t _error('last')))
            echo 
"last error: $t";
        return;
    case 
'caller':
        list(
$file,$line,$func) = caller(2);
        
$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 (debug()) {
        
$bt _backtrace();
        
$msg .= "<div class='e'><pre>$bt</pre></div>";
    }

    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 (
$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 == '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 == && $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($file,$t))
        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 == && config('debugtruncate'))
        
$trunc config('debugtruncate');

    if (
$trunc && $trunc != -&& 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 == -|| $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 (@$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'],$_)) {
                
sleep(30);
                
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;
}
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) */


/* _msglogdump - display the message log (as a shutdown fuction) */

function _msglogdump() {

    
$e _error('error_log');
    if (
$e <= || $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($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

        
ob_start();

        
// 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

        
$out ob_get_contents();
        
ob_end_clean();

        
$error $e;
        
$error['error_log'] = 0;
        
$error['message_log'][] = '<b>message log:</b>';

        if (
$e == FALSE) {
            
$out strip_tags($out);
            
$out str_replace($_SERVER['DOCUMENT_ROOT'],'',$out);
            
$error['message_log'][] = $out;
        }

        if (isset(
$error['maintenance'])) {
            
$file = @$error['messagefile'];
            if (!
$file || !is_file($file))
                
$file 'doc/help/message.html';
            
readfile($file);
            exit;
        }

        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 
'';

}

?>