Beispiel #1
0
 * @copyright  2007, Phorum Development Team
 * @license    Phorum License, http://www.phorum.org/license.txt
 */
// This will prevent common.php from loading the extension library.
define('PHORUM_ADMIN', 1);
// Try to load the Phorum PHP extension. Wrap this in output buffering,
// so problems here won't wreck the outputted image code.
ob_start();
if (!extension_loaded('phorum')) {
    @dl('phorum.so');
}
// Load the common Phorum code.
define('phorum_page', 'extension_check');
include_once "./common.php";
// Flush any output so far.
phorum_ob_clean();
// Check if the extension version matches this Phorum version.
if (function_exists('phorum_ext_version')) {
    if (phorum_ext_version() == PHORUM_EXTENSION_VERSION) {
        // All looks okay. Print a green block.
        header("Content-Type: image/gif");
        foreach (array(0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0xf, 0x0, 0xb, 0x0, 0x80, 0x2, 0x0, 0x0, 0x0, 0x0, 0x35, 0xf4, 0x21, 0x21, 0xfe, 0xa, 0x50, 0x68, 0x6f, 0x72, 0x75, 0x6d, 0x2e, 0x6f, 0x72, 0x67, 0x0, 0x2c, 0x0, 0x0, 0x0, 0x0, 0xf, 0x0, 0xb, 0x0, 0x0, 0x2, 0x14, 0x8c, 0x8f, 0xa9, 0xcb, 0x9d, 0x0, 0x2, 0x74, 0x73, 0xba, 0x2b, 0x57, 0x54, 0xfb, 0x74, 0xe, 0x59, 0xd8, 0xc8, 0x14, 0x0, 0x3b) as $byte) {
            print chr($byte);
        }
        exit;
    }
}
// Something went wrong. Print a red block.
header("Content-Type: image/gif");
foreach (array(0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0xf, 0x0, 0xb, 0x0, 0xa1, 0x2, 0x0, 0xbc, 0x12, 0x12, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x21, 0xfe, 0xa, 0x50, 0x68, 0x6f, 0x72, 0x75, 0x6d, 0x2e, 0x6f, 0x72, 0x67, 0x0, 0x21, 0xf9, 0x4, 0x1, 0xa, 0x0, 0x2, 0x0, 0x2c, 0x0, 0x0, 0x0, 0x0, 0xf, 0x0, 0xb, 0x0, 0x0, 0x2, 0x14, 0x84, 0x8f, 0xa9, 0xcb, 0x9d, 0x11, 0x0, 0x74, 0x73, 0xba, 0x7b, 0xa0, 0x6e, 0x11, 0xf5, 0xb7, 0x7c, 0xd8, 0x98, 0x14, 0x0, 0x3b) as $byte) {
    print chr($byte);
Beispiel #2
0
function phorum_mod_event_logging_error_handler($errno, $errstr, $file, $line)
{
    $PHORUM = $GLOBALS["PHORUM"];
    // Check for the use of the silence operator @, in which case
    // this module should not bother with logging the error message.
    if (error_reporting() == 0) {
        return;
    }
    // Check for suspended logging.
    if (!empty($GLOBALS["PHORUM"]["MOD_EVENT_LOGGING"]["SUSPEND"])) {
        return;
    }
    // Prevention against recursive logging calls.
    if (!empty($GLOBALS["PHORUM"]["MOD_EVENT_LOGGING"]["LOOPLOCK"])) {
        return;
    }
    $GLOBALS["PHORUM"]["MOD_EVENT_LOGGING"]["LOOPLOCK"]++;
    // Prepare the event log data.
    $loglevel = NULL;
    $type = NULL;
    switch ($errno) {
        case E_USER_NOTICE:
        case E_NOTICE:
            if ($PHORUM["mod_event_logging"]["do_log_php_notice"]) {
                $loglevel = EVENTLOG_LVL_DEBUG;
                $type = "PHP notice";
            }
            break;
        case E_USER_WARNING:
        case E_WARNING:
            if ($PHORUM["mod_event_logging"]["do_log_php_warning"]) {
                $loglevel = EVENTLOG_LVL_WARNING;
                $type = "PHP warning";
            }
            break;
        case E_USER_ERROR:
        case E_ERROR:
            if ($PHORUM["mod_event_logging"]["do_log_php_error"]) {
                $loglevel = EVENTLOG_LVL_ALERT;
                $type = "PHP error";
            }
            break;
    }
    // Nothing to do? Then return and let PHP handle the problem
    // (works for PHP5, I don't know what PHP4 does here).
    if ($loglevel === NULL) {
        $GLOBALS["PHORUM"]["MOD_EVENT_LOGGING"]["LOOPLOCK"]--;
        return FALSE;
    }
    // Create detailed info.
    $details = "{$type} generated at {$file}:{$line}\n";
    // Construct a back trace and add it to the details info.
    $backtrace = phorum_generate_backtrace(1);
    $details .= $backtrace === NULL ? "" : "\nBack trace:\n\n{$backtrace}\n";
    // Add request info to the details.
    $details .= "Request info:\n\n";
    foreach (array("HTTP_HOST", "HTTP_REFERER", "REQUEST_URI", "REQUEST_PATH", "QUERY_STRING") as $k) {
        if (isset($_SERVER[$k]) and trim($_SERVER[$k]) != '') {
            $details .= "{$k} = {$_SERVER[$k]}\n";
        }
    }
    // Determine the source of the event.
    list($source, $from_module) = event_logging_find_source(0, $file);
    // Because of the way in which the admin interface is programmed,
    // there are a lot of notices coming from that code. We ignore
    // those by default.
    if ($source == 'admin' && !$from_module && $loglevel == EVENTLOG_LVL_DEBUG) {
        if ($PHORUM["mod_event_logging"]["do_log_php_notice_ignore_in_admin"]) {
            $GLOBALS["PHORUM"]["MOD_EVENT_LOGGING"]["LOOPLOCK"]--;
            return FALSE;
        }
    }
    // Log the event.
    if ($loglevel !== NULL) {
        event_logging_writelog(array("message" => "{$type}: {$errstr}", "loglevel" => $loglevel, "category" => $from_module ? EVENTLOG_CAT_MODULE : EVENTLOG_CAT_APPLICATION, "source" => $source, "details" => $details));
    }
    // For fatal errors, we halt the application here and we tell the
    // user that the problem was logged.
    if ($loglevel == EVENTLOG_LVL_ALERT) {
        // Flush any buffered output so far.
        phorum_ob_clean();
        // Notify the user and exit.
        print "An error occurred in the application.<br/>" . "The error was logged to the Phorum event log.<br/>";
        exit(1);
    }
    // Let the normal error handler take over from here
    // (works for PHP5, I don't know what PHP4 does here).
    $GLOBALS["PHORUM"]["MOD_EVENT_LOGGING"]["LOOPLOCK"]--;
    return FALSE;
}
Beispiel #3
0
/**
 * Retrieve a Phorum file.
 *
 * This function can handle Phorum file retrieval in multiple ways:
 * either return the file to the caller or send it directly to the user's
 * browser (based on the $flags parameter). Sending it directly to the
 * browser allows for the implementation of modules that don't have to buffer
 * the full file data before sending it (a.k.a. streaming, which provides the
 * advantage of using less memory for sending files).
 *
 * @param mixed $file
 *     This is either an array containing at least the fields "file_id"
 *     and "filename" or a numerical file_id value. Note that you can
 *     use the return value of the function
 *     {@link phorum_api_file_check_read_access()} as input for this function.
 *
 * @param integer $flags
 *     These are flags which influence aspects of the function call. It is
 *     a bitflag value, so you can OR multiple flags together. Available
 *     flags for this function are: {@link PHORUM_FLAG_IGNORE_PERMS},
 *     {@link PHORUM_FLAG_GET}, {@link PHORUM_FLAG_SEND} and
 *     {@link PHORUM_FLAG_FORCE_DOWNLOAD}. The SEND flag has precedence
 *     over the GET flag.
 *
 * @return mixed
 *     On error, this function will return FALSE.
 *     The functions {@link phorum_api_strerror()} and
 *     {@link phorum_api_errno()} can be used to retrieve information about
 *     the error which occurred.
 *
 *     If the {@link PHORUM_FLAG_SEND} flag is used, then the function will
 *     return NULL.
 *
 *     If the {@link PHORUM_FLAG_GET} flag is used, then the function
 *     will return a file description array, containing the fields "file_id",
 *     "username", "file_data", "mime_type".
 *     If the {@link $file} parameter was an array, then all fields from that
 *     array will be included as well.
 */
function phorum_api_file_retrieve($file, $flags = PHORUM_FLAG_GET)
{
    $PHORUM = $GLOBALS["PHORUM"];
    // Reset error storage.
    $GLOBALS["PHORUM"]["API"]["errno"] = NULL;
    $GLOBALS["PHORUM"]["API"]["error"] = NULL;
    // If $file is not an array, we are handling a numerical file_id.
    // In that case, first retrieve the file data through the access check
    // function. All the function flags are passed on to that function,
    // so the PHORUM_FLAG_IGNORE_PERMS flag can be set for ignoring access
    // permissions.
    if (!is_array($file)) {
        $file_id = (int) $file;
        $file = phorum_api_file_check_read_access($file_id, $flags);
        // Return in case of errors.
        if ($file === FALSE) {
            return FALSE;
        }
    }
    // A small basic check to see if we have a proper $file array.
    if (!isset($file["file_id"])) {
        trigger_error("phorum_api_file_get(): \$file parameter needs a \"file_id\" field.", E_USER_ERROR);
    }
    if (!isset($file["filename"])) {
        trigger_error("phorum_api_file_get(): \$file parameter needs a \"filename\" field.", E_USER_ERROR);
    }
    settype($file["file_id"], "int");
    /*
     * [hook]
     *     file_retrieve
     *
     * [description]
     *     This hook allows modules to handle the file data retrieval.
     *     The hook can use <literal>phorum_api_error_set()</literal>
     *     to return an error. Hooks should be aware that their input might
     *     not be <literal>$file</literal>, but <literal>FALSE</literal>
     *     instead, in which case they should immediately return
     *     <literal>FALSE</literal> themselves.
     *
     * [category]
     *     File storage
     *
     * [when]
     *     In <filename>include/api/file_storage.php</filename>,
     *     right before a file attachment is retrieved from the database.
     *
     * [input]
     *     Two part array where the first element is an empty file array
     *     and the second element is the flags variable.
     *
     * [output]
     *     Same as input with file_data filled in.
     */
    $file["result"] = 0;
    $file["mime_type"] = NULL;
    $file["file_data"] = NULL;
    if (isset($PHORUM["hooks"]["file_retrieve"])) {
        list($file, $flags) = phorum_hook("file_retrieve", array($file, $flags));
        if ($file === FALSE) {
            return FALSE;
        }
        // If a module sent the file data to the browser, then we are done.
        if ($file["result"] == PHORUM_FLAG_SEND) {
            return NULL;
        }
    }
    // If no module handled file retrieval, we will retrieve the
    // file from the Phorum database.
    if ($file["file_data"] === NULL) {
        $dbfile = phorum_db_file_get($file["file_id"], TRUE);
        if (empty($dbfile)) {
            return phorum_api_error_set(PHORUM_ERRNO_NOTFOUND, "Phorum file (id {$file["file_id"]}) could not be " . "retrieved from the database.");
        }
        // Phorum stores the files in base64 format in the database, to
        // prevent problems with dumping and restoring databases.
        $file["file_data"] = base64_decode($dbfile["file_data"]);
    }
    $mime_type_verified = FALSE;
    // Set the MIME type information if it was not set by a module.
    if ($file["mime_type"] === NULL) {
        $extension_mime_type = phorum_api_file_get_mimetype($file["filename"]);
        // mime magic file in case its needed
        if (!empty($PHORUM['mime_magic_file'])) {
            $mime_magic_file = $PHORUM['mime_magic_file'];
        } else {
            $mime_magic_file = NULL;
        }
        // retrieve the mime-type using the fileinfo extension if its available and enabled
        if (function_exists("finfo_open") && (!isset($PHORUM['file_fileinfo_ext']) || !empty($PHORUM['file_fileinfo_ext'])) && ($finfo = @finfo_open(FILEINFO_MIME, $mime_magic_file))) {
            $file["mime_type"] = finfo_buffer($finfo, $file['file_data']);
            finfo_close($finfo);
            if ($file["mime_type"] === FALSE) {
                return phorum_api_error_set(PHORUM_ERRNO_ERROR, "The mime-type of file {$file["file_id"]} couldn't be determined through the" . "fileinfo-extension");
            }
            // extension mime-type doesn't fit the signature mime-type
            // make it a download then
            if ($extension_mime_type != $file["mime_type"]) {
                $flags = $flags | PHORUM_FLAG_FORCE_DOWNLOAD;
            }
            $mime_type_verified = TRUE;
        } else {
            $file["mime_type"] = $extension_mime_type;
        }
    }
    // If the file is not requested for downloading, then check if it is
    // safe for the browser to view this file. If it is not, then
    // enable the force download flag to make sure that the browser will
    // download the file.
    $safe_to_cache = TRUE;
    $safe_to_view = TRUE;
    if (!($flags & PHORUM_FLAG_FORCE_DOWNLOAD) && !$mime_type_verified) {
        list($safe_to_view, $safe_to_cache) = phorum_api_file_safe_to_view($file);
        if (!$safe_to_view) {
            $flags = $flags | PHORUM_FLAG_FORCE_DOWNLOAD;
        }
    }
    // Allow for post processing on the retrieved file.
    list($file, $flags) = phorum_hook("file_after_retrieve", array($file, $flags));
    // In "send" mode, we directly send the file contents to the browser.
    if ($flags & PHORUM_FLAG_SEND) {
        // Get rid of any buffered output so far.
        phorum_ob_clean();
        // Avoid using any output compression or handling on the sent data.
        ini_set("zlib.output_compression", "0");
        ini_set("output_handler", "");
        $time = (int) $file['add_datetime'];
        // Handle client side caching.
        if ($safe_to_cache) {
            if (!empty($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
                $header = preg_replace('/;.*$/', '', $_SERVER['HTTP_IF_MODIFIED_SINCE']);
                $modified_since = strtotime($header);
                if ($modified_since >= $time) {
                    $proto = empty($_SERVER['SERVER_PROTOCOL']) ? 'HTTP/1.0' : $_SERVER['SERVER_PROTOCOL'];
                    header("{$proto} 304 Not Modified");
                    header('Status: 304');
                    exit(0);
                }
            }
            header("Last-Modified: " . gmdate('D, d M Y H:i:s \\G\\M\\T', $time));
            header('Cache-Control: max-age=5184000');
            // 60 days
            header('Expires: ' . gmdate('D, d M Y H:i:s \\G\\M\\T', time() + 5184000));
        } else {
            // Expire in the past.
            header('Expires: ' . gmdate('D, d M Y H:i:s \\G\\M\\T', time() - 99999));
            // Always modified.
            header('Last-Modified: ' . gmdate('D, d M Y H:i:s \\G\\M\\T', time()));
            // HTTP/1.1
            header('cache-Control: no-store, no-cache, must-revalidate');
            header('cache-Control: post-check=0, pre-check=0', FALSE);
            // HTTP/1.0
            header('Pragma: no-cache');
        }
        if ($flags & PHORUM_FLAG_FORCE_DOWNLOAD) {
            header("Content-Type: application/octet-stream");
            header("Content-Disposition: attachment; filename=\"{$file["filename"]}\"");
        } else {
            header("Content-Type: " . $file["mime_type"]);
            header("Content-Disposition: filename=\"{$file["filename"]}\"");
        }
        header('Content-Length: ' . strlen($file['file_data']));
        print $file["file_data"];
        return NULL;
    } elseif ($flags & PHORUM_FLAG_GET) {
        return $file;
    } else {
        trigger_error("phorum_api_file_retrieve(): no retrieve mode specified in the " . "flags (either use PHORUM_FLAG_GET or PHORUM_FLAG_SEND).", E_USER_ERROR);
    }
}
Beispiel #4
0
/**
 * Retrieve a Phorum file.
 *
 * This function can handle Phorum file retrieval in multiple ways:
 * either return the file to the caller or send it directly to the user's
 * browser (based on the $flags parameter). Sending it directly to the
 * browser allows for the implementation of modules that don't have to buffer
 * the full file data before sending it (a.k.a. streaming, which provides the
 * advantage of using less memory for sending files).
 *
 * @param mixed $file
 *     This is either an array containing at least the fields "file_id"
 *     and "filename" or a numerical file_id value. Note that you can
 *     use the return value of the function
 *     {@link phorum_api_file_check_read_access()} as input for this function.
 *
 * @param integer $flags
 *     These are flags which influence aspects of the function call. It is
 *     a bitflag value, so you can OR multiple flags together. Available
 *     flags for this function are: {@link PHORUM_FLAG_IGNORE_PERMS},
 *     {@link PHORUM_FLAG_GET}, {@link PHORUM_FLAG_SEND} and
 *     {@link PHORUM_FLAG_FORCE_DOWNLOAD}. The SEND flag has precedence
 *     over the GET flag.
 *
 * @return mixed
 *     On error, this function will return FALSE.
 *     The functions {@link phorum_api_strerror()} and
 *     {@link phorum_api_errno()} can be used to retrieve information about
 *     the error which occurred.
 *
 *     If the {@link PHORUM_FLAG_SEND} flag is used, then the function will
 *     return NULL.
 *
 *     If the {@link PHORUM_FLAG_GET} flag is used, then the function
 *     will return a file description array, containing the fields "file_id",
 *     "username", "file_data", "mime_type".
 *     If the {@link $file} parameter was an array, then all fields from that
 *     array will be included as well.
 */
function phorum_api_file_retrieve($file, $flags = PHORUM_FLAG_GET)
{
    $PHORUM = $GLOBALS["PHORUM"];
    // Reset error storage.
    $GLOBALS["PHORUM"]["API"]["errno"] = NULL;
    $GLOBALS["PHORUM"]["API"]["error"] = NULL;
    // If $file is not an array, we are handling a numerical file_id.
    // In that case, first retrieve the file data through the access check
    // function. All the function flags are passed on to that function,
    // so the PHORUM_FLAG_IGNORE_PERMS flag can be set for ignoring access
    // permissions.
    if (!is_array($file)) {
        $file_id = (int) $file;
        $file = phorum_api_file_check_read_access($file_id, $flags);
        // Return in case of errors.
        if ($file === FALSE) {
            return FALSE;
        }
    }
    // A small basic check to see if we have a proper $file array.
    if (!isset($file["file_id"])) {
        trigger_error("phorum_api_file_get(): \$file parameter needs a \"file_id\" field.", E_USER_ERROR);
    }
    if (!isset($file["filename"])) {
        trigger_error("phorum_api_file_get(): \$file parameter needs a \"filename\" field.", E_USER_ERROR);
    }
    settype($file["file_id"], "int");
    // Allow modules to handle the file data retrieval. The hook can use
    // phorum_api_error_set() to return an error. Hooks should be aware
    // that their input might not be $file, but FALSE instead, in which
    // case they should immediately return FALSE themselves.
    $file["result"] = 0;
    $file["mime_type"] = NULL;
    $file["file_data"] = NULL;
    if (isset($PHORUM["hooks"]["file_retrieve"])) {
        list($file, $flags) = phorum_hook("file_retrieve", array($file, $flags));
        if ($file === FALSE) {
            return FALSE;
        }
        // If a module sent the file data to the browser, then we are done.
        if ($file["result"] == PHORUM_FLAG_SEND) {
            return NULL;
        }
    }
    // If no module handled file retrieval, we will retrieve the
    // file from the Phorum database.
    if ($file["file_data"] === NULL) {
        $dbfile = phorum_db_file_get($file["file_id"], TRUE);
        if (empty($dbfile)) {
            return phorum_api_error_set(PHORUM_ERRNO_NOTFOUND, "Phorum file (id {$file["file_id"]}) could not be " . "retrieved from the database.");
        }
        // Phorum stores the files in base64 format in the database, to
        // prevent problems with dumping and restoring databases.
        $file["file_data"] = base64_decode($dbfile["file_data"]);
    }
    // Set the MIME type information if it was not set by a module.
    if ($file["mime_type"] === NULL) {
        $file["mime_type"] = phorum_api_file_get_mimetype($file["filename"]);
    }
    // Allow for post processing on the retrieved file.
    list($file, $flags) = phorum_hook("file_after_retrieve", array($file, $flags));
    // In "send" mode, we directly send the file contents to the browser.
    if ($flags & PHORUM_FLAG_SEND) {
        // Avoid using any output compression or handling on the sent data.
        ini_set("zlib.output_compression", "0");
        ini_set("output_handler", "");
        // Get rid of any buffered output so far.
        phorum_ob_clean();
        if ($flags & PHORUM_FLAG_FORCE_DOWNLOAD) {
            header("Content-Type: application/octet-stream");
        } else {
            header("Content-Type: " . $file["mime_type"]);
        }
        header("Content-Disposition: filename=\"{$file["filename"]}\"");
        print $file["file_data"];
        return NULL;
    } elseif ($flags & PHORUM_FLAG_GET) {
        return $file;
    } else {
        trigger_error("phorum_api_file_retrieve(): no retrieve mode specified in the " . "flags (either use PHORUM_FLAG_GET or PHORUM_FLAG_SEND).", E_USER_ERROR);
    }
}
Beispiel #5
0
/**
 * Database error handling function.
 *
 * @param $error - The error message.
 */
function phorum_database_error($error)
{
    $PHORUM = $GLOBALS["PHORUM"];
    // Flush output that we buffered so far (for displaying a
    // clean page in the admin interface).
    phorum_ob_clean();
    /*
     * [hook]
     *     database_error
     *
     * [description]
     *     Give modules a chance to handle or process database errors.
     *     This can be useful to implement addional logging backends and/or
     *     alerting mechanisms. Another option is to fully override Phorum's
     *     default database error handling by handling the error and then
     *     calling exit() from the hook to prevent the default Phorum code
     *     from running.<sbr/>
     *     <sbr/>
     *     Note: If you decide to use the full override scenario, then
     *     it is best to make your module run the database_error hook
     *     last, so other modules can still run their hook handling
     *     before the script exits. To accomplish this, add this to your
     *     module info:
     *     <programlisting>
     *     priority: run hook database_error after *
     *     </programlisting>
     *
     * [category]
     *     Miscellaneous
     *
     * [when]
     *     At the start of the function
     *     <literal>phorum_database_error</literal> (which you can find in
     *     <filename>common.php</filename>). This function is called from
     *     the database layer when some database error occurs.
     *
     * [input]
     *     The error message that was returned from the database layer.
     *     This error is not HTML escaped, so if you send it to the browser,
     *     be sure to preprocess it using <phpfunc>htmlspecialchars</phpfunc>.
     *
     * [output]
     *     Same as input.
     *
     * [example]
     *     <hookcode>
     *     function phorum_mod_foo_database_error($error)
     *     {
     *         // Log database errors to syslog facility "LOCAL0".
     *         openlog("Phorum", LOG_PID | LOG_PERROR, LOG_LOCAL0);
     *         syslog(LOG_ERR, $error);
     *
     *         return $error;
     *     }
     *     </hookcode>
     */
    if (isset($PHORUM["hooks"]["database_error"])) {
        phorum_hook("database_error", $error);
    }
    // Find out what type of error handling is required.
    $logopt = isset($PHORUM["error_logging"]) ? $PHORUM["error_logging"] : 'screen';
    // Create a backtrace report, so it's easier to find out where a problem
    // is coming from.
    $backtrace = phorum_generate_backtrace(0);
    // Start the error page.
    ?>
    <html>
    <head><title>Phorum database error</title></head>
    <body>
    <h1>Phorum Database Error</h1>

    Sorry, a Phorum database error occurred.<br/>
    <?php 
    // In admin scripts, we will always include the
    // error message inside a comment in the page.
    if (defined("PHORUM_ADMIN")) {
        print "<!-- " . htmlspecialchars($error, ENT_COMPAT, $PHORUM["DATA"]["HCHARSET"]) . " -->";
    }
    switch ($logopt) {
        // Log the database error to a logfile.
        case "file":
            $cache_dir = $PHORUM["cache"];
            $fp = fopen($cache_dir . "/phorum-sql-errors.log", "a");
            fputs($fp, "Time: " . time() . "\n" . "Error: {$error}\n" . ($backtrace !== NULL ? "Back trace:\n{$backtrace}\n\n" : ""));
            fclose($fp);
            print "The error message has been written<br/>" . "to the phorum-sql-errors.log error log.<br/>" . "Please try again later!";
            break;
            // Display the database error on screen.
        // Display the database error on screen.
        case "screen":
            $htmlbacktrace = $backtrace === NULL ? NULL : nl2br(htmlspecialchars($backtrace, ENT_COMPAT, $PHORUM["DATA"]["HCHARSET"]));
            print "Please try again later!" . "<h3>Error:</h3>" . htmlspecialchars($error, ENT_COMPAT, $PHORUM["DATA"]["HCHARSET"]) . ($backtrace !== NULL ? "<h3>Backtrace:</h3>\n{$htmlbacktrace}" : "");
            break;
            // Send a mail to the administrator about the database error.
        // Send a mail to the administrator about the database error.
        case "mail":
        default:
            require_once "./include/email_functions.php";
            $data = array("mailmessage" => "A database error occured in your Phorum installation.\n" . "\n" . "Error message:\n" . "--------------\n" . "\n" . "{$error}\n" . "\n" . ($backtrace !== NULL ? "Backtrace:\n----------\n\n{$backtrace}" : ""), "mailsubject" => "Phorum: A database error occured");
            $adminmail = $PHORUM["system_email_from_address"];
            phorum_email_user(array($adminmail), $data);
            print "The administrator of this forum has been<br/>" . "notified by email about the error.<br/>" . "Please try again later!";
            break;
    }
    // Finish the error page.
    ?>
    </body>
    </html>
    <?php 
    exit;
}