Skip to content

Commit

Permalink
Improve custom s9y error handling. Will post in issue #399 for details.
Browse files Browse the repository at this point in the history
  • Loading branch information
garvinhicking committed May 9, 2016
1 parent a615ddc commit 98099b6
Show file tree
Hide file tree
Showing 2 changed files with 192 additions and 1 deletion.
173 changes: 173 additions & 0 deletions include/compat.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,179 @@ function memSnap($tshow = '') {
return '[' . date('d.m.Y H:i') . '] ' . number_format($current - $memUsage, 2, ',', '.') . ' label "' . $tshow . '", totalling ' . number_format($current, 2, ',', '.') . '<br />' . "\n";
}


/**
* Make readable error types for debugging error_reporting levels
*
* @access public
* @param int error value
* @return string constant error string
*/
function debug_ErrorLevelType($type)
{
switch($type)
{
case E_ERROR: // 1 //
return 'E_ERROR';
case E_WARNING: // 2 //
return 'E_WARNING';
case E_PARSE: // 4 //
return 'E_PARSE';
case E_NOTICE: // 8 //
return 'E_NOTICE';
case E_CORE_ERROR: // 16 //
return 'E_CORE_ERROR';
case E_CORE_WARNING: // 32 //
return 'E_CORE_WARNING';
case E_COMPILE_ERROR: // 64 //
return 'E_COMPILE_ERROR';
case E_COMPILE_WARNING: // 128 //
return 'E_COMPILE_WARNING';
case E_USER_ERROR: // 256 //
return 'E_USER_ERROR';
case E_USER_WARNING: // 512 //
return 'E_USER_WARNING';
case E_USER_NOTICE: // 1024 //
return 'E_USER_NOTICE';
case E_STRICT: // 2048 //
return 'E_STRICT';
case E_RECOVERABLE_ERROR: // 4096 //
return 'E_RECOVERABLE_ERROR';
case E_DEPRECATED: // 8192 //
return 'E_DEPRECATED';
case E_USER_DEPRECATED: // 16384 //
return 'E_USER_DEPRECATED';
}
return "";
}


/**
* Set our own exeption handler to convert all errors into exeptions automatically
* function_exists() avoids 'cannot redeclare previously declared' fatal errors in XML feed context.
*
* See Notes about returning false
*
* @access public
* @param standard
* @return null
*/
if (!function_exists('errorToExceptionHandler')) {
function errorToExceptionHandler($errNo, $errStr, $errFile = '', $errLine = NULL, $errContext = array()) {
global $serendipity;

// By default, we will continue our process flow, unless:
$exit = false;

switch ($errNo) {
case E_ERROR:
case E_USER_ERROR:
$type = 'Fatal Error';
$exit = true;
break;

case E_USER_WARNING:
case E_WARNING:
$type = 'Warning';
break;

case E_USER_NOTICE:
case E_NOTICE:
case @E_STRICT:
case @E_DEPRECATED:
case @E_USER_DEPRECATED:
$type = 'Notice';
break;

case @E_RECOVERABLE_ERROR:
$type = 'Catchable';
break;

default:
$type = 'Unknown Error';
$exit = true;
break;
}

// NOTE: We do NOT use ini_get('error_reporting'), because that would return the global error reporting,
// and not the one in our current content. @-silenced errors would otherwise never be caught on.
$rep = error_reporting();

// Bypass error processing because it's @-silenced.
if ($rep == 0) {
return false;
}

// if not using Serendipity testing and user or ISP has set PHPs display_errors to show no errors at all, respect this:
if ($serendipity['production'] === true && ini_get('display_errors') == 0) {
return false;
}

// Several plugins might not adapt to proper style. This should not completely kill our execution.
if ($serendipity['production'] !== 'debug' && preg_match('@Declaration.*should be compatible with@i', $args[1])) {
#if (!headers_sent()) echo "<strong>Compatibility warning:</strong> Please upgrade file old '{$args[2]}', it contains incompatible signatures.<br/>Details: {$args[1]}<br/>";
return false;
}

$args = func_get_args();

/*
* $serendipity['production'] can be:
*
* (bool) TRUE: Live-blog, conceal error messages
* (bool) FALSE Beta/alpha builds
* (string) 'debug' Developer build, specifically enabled.
*/

$debug_note = '<br />For more details set $serendipity[\'production\'] = \'debug\' in serendipity_config_local.inc.php to receive a stack-trace.';

// Debug environments shall be verbose...
if ($serendipity['production'] === 'debug') {
echo " == ERROR-REPORT (DEBUGGING ENABLED) == <br />\n";
echo " == (When you copy this debug output to a forum or other places, make sure to remove your username/passwords, as they may be contained within function calls) == \n";
echo '<pre>';
debug_print_backtrace(); // Unlimited output, debugging shall show us everything.
echo "</pre>";
$debug_note = '';
} elseif ($serendipity['production'] === false) {
echo " == ERROR-REPORT (BETA/ALPHA-BUILDS) == \n";
}

if ($serendipity['production'] !== true) {
// Display error (production: FALSE and production: 'debug')
echo '<p><b>' . $type . ':</b> '.$errStr . ' in ' . $errFile . ' on line ' . $errLine . '.' . $debug_note . '</p>';

echo '<pre style="white-space: pre-line;">';
throw new \ErrorException($type . ': ' . $errStr, 0, $errNo, $errFile, $errLine); // tracepath = all, if not ini_set('display_errors', 0);

if (!$serendipity['dbConn'] || $exit) {
exit; // make sure to exit in case of database connection errors or fatal errors.
}
} else {
// Only display error (production blog) if an admin is logged in, else we discard the error.

if ($serendipity['serendipityUserlevel'] >= USERLEVEL_ADMIN) {
$str = " == SERENDIPITY ERROR == ";
$str .= '<p><b>' . $type . ':</b> '.$errStr . ' in ' . $errFile . ' on line ' . $errLine . '.' . $debug_note . '</p>';

if (headers_sent()) {
serendipity_die($str); // case HTTP headers: needs to halt with die() here, else it will path through and gets written underneath blog content, or into streamed js files, which hardly isn't seen by many users
} else {
// see global include of function in plugin_api.inc.php
// this also reacts on non eye-displayed errors with following small javascript,
// while being in tags like <select> to push on top of page, else return non javascript use $str just there
// sadly we can not use HEREDOC notation here, since this does not execute the javascript after finished writing
echo "\n".'<script>
if (typeof errorHandlerCreateDOM == "function") {
var fragment = window.top.errorHandlerCreateDOM("Error redirect: '.addslashes($str).'");
document.body.insertBefore(fragment, document.body.childNodes[0]);
}' . "\n</script>\n<noscript>" . $str . "</noscript>\n";
}
}
}
}
}

if (!function_exists('file_get_contents')) {
function file_get_contents($filename, $use_include_path = 0) {
$file = fopen($filename, 'rb', $use_include_path);
Expand Down
20 changes: 19 additions & 1 deletion serendipity_config.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,10 @@

if ($serendipity['production'] !== true) {
@ini_set('display_errors', 'on');
};
}

// The serendipity errorhandler string
$serendipity['errorhandler'] = 'errorToExceptionHandler';

// Default rewrite method
$serendipity['rewrite'] = 'none';
Expand Down Expand Up @@ -273,6 +276,21 @@
error_reporting(E_ALL & ~(E_NOTICE|E_STRICT)); // is 30711 with 5.4+
}

$errLevel = error_reporting();

/* [DEBUG] Helper to display current error levels, meant for developers.
echo $errLevel."<br>\n";
for ($i = 0; $i < 15; $i++ ) {
print debug_ErrorLevelType($errLevel & pow(2, $i)) . "<br>\n";
}
*/

// [internal callback function]: errorToExceptionHandler()
if (is_callable($serendipity['errorhandler'], false, $callable_name)) {
// set serendipity global error to exeption handler
set_error_handler($serendipity['errorhandler'], $errLevel); // See error_reporting() earlier to see which errors are passed to the handler, deending on $serendipity['production'].
}

define('IS_up2date', version_compare($serendipity['version'], $serendipity['versionInstalled'], '<='));

// Include main functions
Expand Down

7 comments on commit 98099b6

@onli
Copy link
Member

@onli onli commented on 98099b6 May 10, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@garvinhicking I updated my devblog to the current alpha to be able to test especially this commit. It does not seem to work, I see no change with the stacktrace in http://onli.columba.uberspace.de/s9y_dev/, while the code says he would also update " == ERROR-REPORT (BETA/ALPHA-BUILDS) == \n"; and wrap the stacktrace in a pre-trag.

@garvinhicking
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@onli Don't know, works for me. Can you debug? Does the errorhandler get called at all, add a die('blabla') as the first line in the function? If not, does set_error_handler() get called? Did you set $serendipity['production']=true in serendipity_config_local.inc.php?!

@onli
Copy link
Member

@onli onli commented on 98099b6 May 10, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you debug?

Sure. You ran this on PHP7, but not on uberspace?

Does the errorhandler get called at all, add a die('blabla') as the first line in the function?

No, it does not get called.

If not, does set_error_handler() get called?

Yes, at least the line is reached, I added an echo there in serendipity_config.inc.php.

Did you set $serendipity['production']=true in serendipity_config_local.inc.php?!

No, and I wrapped it in an if at the point of where the error is in the index.php and it is not true.

@onli
Copy link
Member

@onli onli commented on 98099b6 May 10, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is echo "error"->is_array(); a type of error he should catch?

@garvinhicking
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@onli Yes I ran this on my own Debian machine with mod-PHP and Apache2.

You might be onto something, it could be that Fatal Errors cannot be caught by us. Try with something that raises a warning, like file_get_contents('file/that/does/not/exist.txt'), I tried it with that...

@onli
Copy link
Member

@onli onli commented on 98099b6 May 10, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bingo. Now it gets triggered. Good to know! :)

It leads me to another issue: Is stopping s9y really what we want here? This is what happens with the error handler:

2016-05-10_1920x1080_25081

This without:

2016-05-10_1920x1080_18169

The warning gets written on top. I take it that is the wanted behaviour on alpha/beta to see the stacktrace?

@garvinhicking
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly, it's so that we definitely get warnings reported - on release versions this would not happen

Please sign in to comment.