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; }
#!/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";
/** * 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); } }
/** * @deprecated Replaced by {@link phorum_api_buffer_clear()}. */ function phorum_ob_clean() { return phorum_api_buffer_clear(); }
/** * 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; }