* @package api * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @version $Id$ */ use EGroupware\Api; /** * Translate message only if translation object is already loaded * * This function is usefull for exception handlers or early stages of the initialisation of the egw object, * as calling lang would try to load the translations, evtl. cause more errors, eg. because there's no db-connection. * * @param string $key message in englich with %1, %2, ... placeholders * @param string $vars =null multiple values to replace the placeholders * @return string translated message with placeholders replaced */ function try_lang($key,$vars=null) { static $varnames = array('%1','%2','%3','%4'); if(!is_array($vars)) { $vars = func_get_args(); array_shift($vars); // remove $key } return class_exists('EGroupware\Api\Translations',false) ? Api\Translation::translate($key,$vars) : str_replace($varnames,$vars,$key); } /** * Clasify exception for a headline and log it to error_log, if not running as cli * * @param Exception|Error $e * @param string &$headline */ function _egw_log_exception($e,&$headline=null) { $trace = explode("\n", $e->getTraceAsString()); if ($e instanceof Api\Exception\NoPermission) { $headline = try_lang('Permission denied!'); } elseif ($e instanceof Api\Db\Exception) { $headline = try_lang('Database error'); } elseif ($e instanceof Api\Exception\WrongUserinput) { $headline = ''; // message contains the whole message, it's usually no real error but some input validation } elseif ($e instanceof egw_exception_warning) { $headline = 'PHP Warning'; array_shift($trace); } else { $headline = try_lang('An error happened'); } // log exception to error log, if not running as cli, // which outputs the error_log to stderr and therefore output it twice to the user if(isset($_SERVER['HTTP_HOST']) || $GLOBALS['egw_info']['flags']['no_exception_handler'] !== 'cli') { error_log($headline.($e instanceof egw_exception_warning ? ': ' : ' ('.get_class($e).'): ').$e->getMessage()); foreach($trace as $line) { error_log($line); } error_log('# Instance='.$GLOBALS['egw_info']['user']['domain'].', User='.$GLOBALS['egw_info']['user']['account_lid']. ', Request='.$_SERVER['REQUEST_METHOD'].' '.($_SERVER['HTTPS']?'https://':'http://').$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']. ', User-agent='.$_SERVER['HTTP_USER_AGENT']); } } /** * Fail a little bit more gracefully then an uncought exception * * Does NOT return * * @param Exception|Error $e */ function egw_exception_handler($e) { // handle redirects without logging if ($e instanceof Api\Exception\Redirect) { Api\Egw::redirect($e->url, $e->app); } // logging all exceptions to the error_log (if not cli) and get headline $headline = null; _egw_log_exception($e,$headline); // exception handler for cli (command line interface) clients, no html, no logging if(!isset($_SERVER['HTTP_HOST']) || $GLOBALS['egw_info']['flags']['no_exception_handler'] == 'cli') { echo ($headline ? $headline.': ' : '').$e->getMessage()."\n"; if ($GLOBALS['egw_info']['server']['exception_show_trace']) { echo $e->getTraceAsString()."\n"; } exit($e->getCode() ? $e->getCode() : 9999); // allways give a non-zero exit code } // regular GUI exception if (!isset($GLOBALS['egw_info']['flags']['no_exception_handler'])) { header('HTTP/1.1 500 '.$headline); $message = '

'.Api\Html::htmlspecialchars($headline)."

\n". '
'.Api\Html::htmlspecialchars($e->getMessage())."\n\n";

		// only show trace (incl. function arguments) if explicitly enabled, eg. on a development system
		if ($GLOBALS['egw_info']['server']['exception_show_trace'])
		{
			$message .= Api\Html::htmlspecialchars($e->getTraceAsString());
		}
		$message .= "
\n"; if (is_a($e, 'EGroupware\Api\Db\Exception\Setup')) { $setup_dir = str_replace(array('home/index.php','index.php'),'setup/',$_SERVER['PHP_SELF']); $message .= 'Run setup to install or configure EGroupware.'; } elseif (is_object($GLOBALS['egw']) && isset($GLOBALS['egw']->session) && method_exists($GLOBALS['egw'],'link')) { $message .= '

'.try_lang('Click here to resume your eGroupWare Session.').'

'; } if (is_object($GLOBALS['egw']) && isset($GLOBALS['egw']->framework)) { $GLOBALS['egw']->framework->render($message,$headline); } else { echo "\n\n".Api\Html::htmlspecialchars($headline)."\n\n\n$message\n\n\n"; } } // exception handler sending message back to the client as basic auth message elseif($GLOBALS['egw_info']['flags']['no_exception_handler'] == 'basic_auth') { $error = str_replace(array("\r", "\n"), array('', ' | '), $e->getMessage()); header('WWW-Authenticate: Basic realm="'.$headline.' '.$error.'"'); header('HTTP/1.1 401 Unauthorized'); header('X-WebDAV-Status: 401 Unauthorized', true); } exit; } if (!isset($GLOBALS['egw_info']['flags']['no_exception_handler']) || $GLOBALS['egw_info']['flags']['no_exception_handler'] !== true) { set_exception_handler('egw_exception_handler'); } /** * Fail a little bit more gracefully then a catchable fatal error, by throwing an exception * * @param int $errno level of the error raised: E_* constants * @param string $errstr error message * @param string $errfile filename that the error was raised in * @param int $errline line number the error was raised at * @link http://www.php.net/manual/en/function.set-error-handler.php * @throws ErrorException */ function egw_error_handler ($errno, $errstr, $errfile, $errline) { switch ($errno) { case E_RECOVERABLE_ERROR: case E_USER_ERROR: throw new ErrorException($errstr, $errno, 0, $errfile, $errline); case E_WARNING: case E_USER_WARNING: // skip message for warnings supressed via @-error-control-operator (eg. @is_dir($path)) // can be commented out to get suppressed warnings too! if ((error_reporting() & $errno) && // silence "Declaration of $class::$method should be compatible with $parent::$method" warning !(substr($errstr, 0, 15) === 'Declaration of ' && strpos($errstr, ' should be compatible with ') !== false)) { _egw_log_exception(new egw_exception_warning($errstr.' in '.$errfile.' on line '.$errline)); } break; } } /** * Used internally to trace warnings */ class egw_exception_warning extends Exception {} // install our error-handler only for catchable fatal errors and warnings // following error types cannot be handled with a user defined function: E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING set_error_handler('egw_error_handler', E_RECOVERABLE_ERROR|E_USER_ERROR|E_WARNING|E_USER_WARNING);