Example #1
0
function phorum_mod_event_logging_error_handler($errno, $errstr, $file, $line)
{
    global $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($PHORUM["MOD_EVENT_LOGGING"]["SUSPEND"])) {
        return;
    }
    // Prevention against recursive logging calls.
    if (!empty($PHORUM["MOD_EVENT_LOGGING"]["LOOPLOCK"])) {
        return;
    }
    $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) {
        $PHORUM["MOD_EVENT_LOGGING"]["LOOPLOCK"]--;
        return FALSE;
    }
    // Create detailed info.
    $details = "{$type} generated at {$file}:{$line}\n";
    // Construct a backtrace and add it to the details info.
    require_once PHORUM_PATH . '/include/api/error/backtrace.php';
    $backtrace = phorum_api_error_backtrace(2);
    $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"]) {
            $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) {
        // Clear any buffered output so far.
        require_once PHORUM_PATH . '/include/api/buffer.php';
        phorum_api_buffer_clear();
        // 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).
    $PHORUM["MOD_EVENT_LOGGING"]["LOOPLOCK"]--;
    return FALSE;
}
Example #2
0
#!/usr/bin/php
<?php 
// rebuild search-table
// this script rebuilds the search-table
// this needs some time, please make sure that its really needed
// i.e. in case of errors, required updates etc.
define('phorum_page', 'rebuild_search_table');
// if we are running in the webserver, bail out
if ('cli' != php_sapi_name()) {
    echo "This script cannot be run from a browser.";
    return;
}
define("PHORUM_ADMIN", 1);
require_once dirname(__FILE__) . '/../include/api.php';
// Make sure that the output is not buffered.
phorum_api_buffer_clear();
if (!ini_get('safe_mode')) {
    set_time_limit(0);
    ini_set("memory_limit", "64M");
}
echo "\nRebuilding search-table ...\n";
$PHORUM['DB']->rebuild_search_data();
echo "If no errors were logged above,\n" . "then the search table was successfully rebuilt.\n\n";
Example #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 that 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_error_message()} and
 *     {@link phorum_api_error_code()} can be used to retrieve information
 *     about the error that 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)
{
    global $PHORUM;
    // Reset error storage.
    $PHORUM["API"]["errno"] = NULL;
    $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()</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.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_api_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(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.
    $mime_type_verified = FALSE;
    if ($file["mime_type"] === NULL) {
        // Determine the MIME type based on the file extension using
        // the MIME types as defined in the Phorum API code.
        $extension_mime_type = phorum_api_file_get_mimetype($file["filename"]);
        // The MIME magic file to use for the fileinfo extension.
        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
        // it is 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(PHORUM_ERRNO_ERROR, "The mime-type of file {$file["file_id"]} couldn't be " . "determined through the fileinfo-extension");
            }
            // The MIME-type for the file extension doesn't fit the
            // MIME-type as determined by the file's magic signature.
            // Because it is not safe to view this file in a browser,
            // we force a download.
            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 the file inline. If it is not, then
    // enable the force download flag to make sure that the browser will
    // download the file instead.
    $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.
    /**
     * @todo document the file_after_retrieve hook.
     */
    if (!empty($PHORUM['hooks']['file_after_retrieve'])) {
        list($file, $flags) = phorum_api_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 (there shouldn't be any).
        phorum_api_buffer_clear();
        $time = (int) $file['add_datetime'];
        // Handle client side caching.
        if ($safe_to_cache) {
            // Check if an If-Modified-Since header is in the request. If yes,
            // then check if the file has changed, based on the date from
            // the file data. If nothing changed, then we return a 304 header,
            // to tell the browser to use the cached data.
            phorum_api_output_last_modify_time($time);
            // Send caching headers, so files can be cached by the browser.
            phorum_api_output_cache_max_age(3600 * 24 * 60);
        } else {
            phorum_api_output_cache_disable();
        }
        if ($flags & PHORUM_FLAG_FORCE_DOWNLOAD) {
            $disposition = 'attachment; ';
            $type = 'application/octet-stream';
        } else {
            $disposition = '';
            $type = $file['mime_type'];
        }
        header("Content-Disposition: " . "{$disposition}filename=\"{$file['filename']}\"");
        header("Content-Type: {$type}");
        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);
    }
}
Example #4
0
/**
 * @deprecated Replaced by {@link phorum_api_buffer_clear()}.
 */
function phorum_ob_clean()
{
    return phorum_api_buffer_clear();
}
Example #5
0
/**
 * Database error handling function.
 *
 * @param string $error
 *     The database error message.
 */
function phorum_api_error_database($error)
{
    global $PHORUM;
    $hcharset = $PHORUM['DATA']['HCHARSET'];
    // Clear any output that we buffered so far (e.g. in the admin interface,
    // we might already have sent the page header).
    phorum_api_buffer_clear();
    /*
     * [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_api_error_database</literal> (which you can find in
     *     <filename>include/api/error.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_api_hook("database_error", $error);
    }
    // Find out what type of error handling is configured.
    // If no type if set, then we use "screen" by default.
    $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_api_error_backtrace(2);
    // Error page header.
    if (PHP_SAPI != "cli") {
        // 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, $hcharset) . " -->";
        }
    } else {
        // In CLI mode, we always show the error message on screen.
        // No need to be hiding this info from a user that can run CLI code.
        print "Sorry, a Phorum database error occurred:\n";
        print "------------------------------------------------------\n";
        print "Error: {$error}\n";
        if ($backtrace !== NULL) {
            print "------------------------------------------------------\n";
            print "Backtrace:\n" . $backtrace . "\n";
        }
        print "------------------------------------------------------\n";
    }
    switch ($logopt) {
        // Log the database error to a logfile.
        case "file":
            $cache_dir = $PHORUM['CACHECONFIG']['directory'];
            $logfile = $cache_dir . '/phorum-sql-errors.log';
            if ($fp = @fopen($logfile, "a")) {
                fputs($fp, "Time: " . time() . "\n" . "Error: {$error}\n" . ($backtrace !== NULL ? "Back trace:\n{$backtrace}\n\n" : ""));
                fclose($fp);
                if (PHP_SAPI != 'cli') {
                    print "The error message has been logged<br/>" . "to the phorum-sql-errors.log error log.<br/>" . "Please, try again later!";
                } else {
                    print "The error message has been logged to the db error log:\n";
                    print "{$logfile}\n";
                }
            } else {
                trigger_error("phorum_api_error_database(): cannot write to {$logfile}", E_USER_ERROR);
            }
            break;
            // Display the database error on screen.
        // Display the database error on screen.
        case "screen":
            // For CLI scripts, the error was already shown on screen.
            if (PHP_SAPI != 'cli') {
                $htmlbacktrace = $backtrace === NULL ? NULL : nl2br(htmlspecialchars($backtrace, ENT_COMPAT, $hcharset));
                print "Please try again later!" . "<h3>Error:</h3>" . htmlspecialchars($error, ENT_COMPAT, $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 PHORUM_PATH . '/include/api/mail.php';
            $data = array('mailmessage' => "A database error occured in your Phorum installation\n" . htmlspecialchars($PHORUM['http_path']) . ":\n" . "\n" . "Error message:\n" . (require_once "--------------\n" . "\n" . "{$error}\n" . "\n" . ($backtrace !== NULL ? "Backtrace:\n" . "----------\n" . "\n" . "{$backtrace}\n" : "")), 'mailsubject' => 'Phorum: A database error occured');
            $adminmail = $PHORUM['system_email_from_address'];
            phorum_api_mail($adminmail, $data);
            if (PHP_SAPI != 'cli') {
                print "The administrator of this forum has been<br/>" . "notified by email about the error.<br/>" . "Please, try again later!";
            } else {
                print "The error message was sent by mail to {$adminmail}\n";
            }
            break;
    }
    // Error page footer.
    if (PHP_SAPI != "cli") {
        print '</body></html>';
    }
    exit;
}