summaryrefslogtreecommitdiff
path: root/core/error_handling.php
blob: 95db98c7ca528e41863e7cec2eab9a120b9943a3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
<?php
/** ERROR HANDLING SECTION
 * handles exceptions and errors (even fatal)
 * -----------------------------------------------------------------------------
 * The code...
 * + Catches and handles all Errors and Throwable exceptions;
 * - creates the error messages (for the requester and developer) 
 * ? TODO: routes the error messages to the logging channels
 */


// Global array to save errors
$anom_ERRORS = [];  // ok, Globals are not recommended, but...
    // this one collects only errors (about the application);
    // it is oriented for the developer; not for the request.


/** Error handler,
 * passes flow over the exception logger with new ErrorException.
 */
function handle_error(int $type, string $message, string $file, int $line)
{
    handle_exception( new ErrorException($message, 0, $type, $file, $line) );
}


/** Uncaught exception handler.
*/
function handle_exception(Throwable $e)
{
    global $anom_ERRORS;
    
    // full message description to be logged
    $message = get_class($e) .": ". $e->getMessage()
        . " on file '". $e->getFile() . "' at line {$e->getLine()}";

    $anom_ERRORS[] = $message;      // store the error
}


/**
 * Catch fatal error work-around
 * (set_error_handler not working on fatal errors).
 */
function on_shutdown_check_for_fatal()
{
    global $anom_ERRORS;

    $error = error_get_last();

    if ($error != null) {       // ignore 'normal' system shutdowns [exit|die]() 

        if ( $error["type"] == E_ERROR ) {      // get as much error-info
            handle_error(
                $error["type"] ?? -1,
                $error["message"] ?? 'unknown error',
                $error["file"] ?? 'unknown file',
                $error["line"] ?? -1
            );
        }
    }
    
    if (($anom_ERRORS != [])) {

        // TODO:
        // Implemetnig the design/layout of the error-messages
        // output should not be an error's-handling task, thus
        // shall be assigned to the Rendes/View level;
        // Same about the log service channels

        // TODO:
        // FORWARD ERRORS into LOG-SYSTEM
        // ex. into some file...
        // file_put_contents("logs/thowable.log", $message_template .PHP_EOL, FILE_APPEND);
        // or ...some other channer (Email, Slack, Database etc).
        // Channes can be decided according to error severity;
        // a file-system error loggin for backup is recommended
        // partitioniong of errors onto file-system can be useful

        // TODO:
        // 1st: Log Errors
        // 2nd: Show Errors

        if (PRODUCTION) {
            if (!defined('OUTPUT_STARTED')) {
                // throw a prety-error message
                Render::view('error/general', ['message' => 'Please forgive me, I know not what I do']);
            }

        } else {

            if (!defined('OUTPUT_STARTED')) {
                // no template loaded; render erros in general-error template
                Render::view('error/general', ['message' => implode("<br/>And:<br/>", $anom_ERRORS)]);

            } else {
                 echo '<div style="padding:1em;background:#933;width:100%;color:#fff">
                    Errors:<br />'. implode("<br/>And:<br/>", $anom_ERRORS) .'</div>';
            }
        }
    }
}


// register callback on shutdown
register_shutdown_function( "on_shutdown_check_for_fatal" );

// register custom error handler callback
set_error_handler( "handle_error" );

// set custom exception handler function
set_exception_handler( "handle_exception" );

// send errors to stderr (instead of stdout)
ini_set( "display_errors", "off" );

// thow out all errors
error_reporting( E_ALL );