@@ -24,85 +24,118 @@ public static function die($x = null, $show_user = false)
24
24
}
25
25
}
26
26
27
- public static function redirect ($ destination )
27
+ public static function redirect ($ dest )
28
28
{
29
- header ("Location: $ destination " );
30
- self ::die ("Redirect failed, click <a href=' $ destination'>here</a> to continue. " , true );
29
+ header ("Location: $ dest " );
30
+ self ::errorToUser ("Redirect failed, click <a href=' $ dest'>here</a> to continue. " , 302 );
31
+ self ::die ();
31
32
}
32
33
33
- private static function headerResponseCode (int $ code , string $ reason )
34
- {
35
- $ protocol = $ _SERVER ["SERVER_PROTOCOL " ] ?? "HTTP/1.1 " ;
36
- $ msg = $ protocol . " " . strval ($ code ) . " " . $ reason ;
37
- header ($ msg , true , $ code );
34
+ // $data must be JSON serializable
35
+ public static function errorLog (
36
+ string $ title ,
37
+ string $ message ,
38
+ string |null $ errorid = null ,
39
+ Throwable |null $ error = null ,
40
+ mixed $ data = null ,
41
+ ) {
42
+ if (!CONFIG ["site " ]["enable_verbose_error_log " ]) {
43
+ error_log ("$ title: $ message " );
44
+ return ;
45
+ }
46
+ $ output = [
47
+ "message " => $ message ,
48
+ "REMOTE_USER " => $ _SERVER ["REMOTE_USER " ] ?? null ,
49
+ "REMOTE_ADDR " => $ _SERVER ["REMOTE_ADDR " ] ?? null ,
50
+ ];
51
+ if (!is_null ($ errorid )) {
52
+ $ output ["errorid " ] = $ errorid ;
53
+ }
54
+ if (!is_null ($ error )) {
55
+ $ output ["error " ] = throwableToArray ($ error );
56
+ } else {
57
+ // newlines are bad for error log, but getTrace() is too verbose
58
+ $ output ["trace " ] = explode ("\n" , (new \Exception ())->getTraceAsString ());
59
+ }
60
+ if (!is_null ($ data )) {
61
+ $ output ["data " ] = $ data ;
62
+ }
63
+ error_log ("$ title: " . json_encode ($ output , JSON_UNESCAPED_SLASHES ));
38
64
}
39
65
40
- public static function errorLog (string $ title , string $ message )
66
+ // recursive on $t->getPrevious()
67
+ private static function throwableToArray (Throwable $ t ): array
41
68
{
42
- if (CONFIG ["site " ]["enable_verbose_error_log " ] == false ) {
43
- error_log ("$ title: $ message " );
69
+ $ output = [
70
+ "type " => gettype ($ t ),
71
+ "msg " => $ t ->getMessage (),
72
+ // newlines are bad for error log, but getTrace() is too verbose
73
+ "trace " => explode ("\n" , $ t ->getTraceAsString ()),
74
+ ];
75
+ $ previous = $ t ->getPrevious ();
76
+ if (!is_null ($ previous )) {
77
+ $ output ["previous " ] = throwableToArray ($ previous );
78
+ }
79
+ return $ output ;
80
+ }
81
+
82
+ private static function errorToUser (
83
+ string $ msg ,
84
+ int $ http_response_code ,
85
+ string |null $ errorid = null
86
+ ) {
87
+ if (!CONFIG ["site " ]["enable_error_to_user " ]) {
44
88
return ;
45
89
}
46
- error_log (
47
- " $ title : " . json_encode (
48
- [
49
- " message " => $ message ,
50
- " REMOTE_USER " => @ $ _SERVER [ " REMOTE_USER " ],
51
- " REMOTE_ADDR " => @ $ _SERVER [ " REMOTE_ADDR " ],
52
- " trace " => ( new \ Exception ())-> getTraceAsString ()
53
- ]
54
- )
55
- ) ;
90
+ $ notes = " Please notify a Unity admin at " . CONFIG [ " mail " ][ " support " ] . " . " ;
91
+ if (! is_null ( $ errorid )) {
92
+ $ notes = $ notes . " Error ID: $ errorid . " ;
93
+ }
94
+ if (! headers_sent ()) {
95
+ http_response_code ( $ http_response_code );
96
+ }
97
+ // text may not be shown in the webpage in an obvious way, so make a popup
98
+ self :: alert ( " $ msg $ notes " );
99
+ echo " <h1> $ msg </h1><p> $ notes </p> " ;
56
100
}
57
101
58
- public static function badRequest ($ message )
102
+ public static function badRequest ($ message, $ error = null , $ data = null )
59
103
{
60
- self :: headerResponseCode ( 400 , " bad request " );
61
- self ::errorLog ( " bad request " , $ message );
62
- error_clear_last ( );
104
+ $ errorid = uniqid ( );
105
+ self ::errorToUser ( " Invalid requested action or submitted data. " , 400 , $ errorid );
106
+ self :: errorLog ( " bad request " , $ message , $ errorid , $ error , $ data );
63
107
self ::die ($ message );
64
108
}
65
109
66
- public static function forbidden ($ message )
110
+ public static function forbidden ($ message, $ error = null , $ data = null )
67
111
{
68
- self ::headerResponseCode (403 , "forbidden " );
69
- self ::errorLog ("forbidden " , $ message );
70
- error_clear_last ();
112
+ $ errorid = uniqid ();
113
+ self ::errorToUser ("Permission denied. " , 403 , $ errorid );
114
+ self ::errorLog ("forbidden " , $ message , $ errorid , $ error , $ data );
115
+ self ::die ($ message );
116
+ }
117
+
118
+ public static function internalServerError ($ message , $ error = null , $ data = null )
119
+ {
120
+ $ errorid = uniqid ();
121
+ self ::errorToUser ("An internal server error has occurred. " , 500 , $ errorid );
122
+ self ::errorLog ("internal server error " , $ message , $ errorid , $ error , $ data );
71
123
self ::die ($ message );
72
124
}
73
125
74
126
// https://www.php.net/manual/en/function.register-shutdown-function.php
75
127
public static function shutdown ()
76
128
{
77
- if (CONFIG ["site " ]["enable_shutdown_msg " ] == false ) {
78
- return ;
79
- }
80
129
$ e = error_get_last ();
81
130
if (is_null ($ e ) || $ e ["type " ] !== E_ERROR ) {
82
131
return ;
83
132
}
84
- if (!headers_sent ()) {
85
- self ::headerResponseCode (500 , "internal server error " );
133
+ // newlines are bad for error log
134
+ if (!is_null ($ e ) && array_key_exists ("message " , $ e ) && str_contains ($ e ["message " ], "\n" )) {
135
+ $ e ["message " ] = explode ("\n" , $ e ["message " ]);
86
136
}
87
- $ errorid = uniqid ();
88
- $ e ["unity_error_id " ] = $ errorid ;
89
- self ::errorLog ("internal server error " , json_encode ($ e ));
90
- echo "
91
- <h1>An internal server error has occurred.</h1>
92
- <p>
93
- Please notify a Unity admin at "
94
- . CONFIG ["mail " ]["support " ]
95
- . ". Error ID: $ errorid.
96
- </p>
97
- " ;
98
- // if content already printed, status code will be ignored and alert text may not be
99
- // shown in the webpage in an obvious way, so make a popup
100
- self ::alert (
101
- "An internal server error has occurred. "
102
- . "Please notify a Unity admin at "
103
- . CONFIG ["mail " ]["support " ]
104
- . ". Error ID: $ errorid. "
105
- );
137
+ // error_get_last is an array, not a Throwable
138
+ self ::internalServerError ("An internal server error has occurred. " , data: ["error " => $ e ]);
106
139
}
107
140
108
141
public static function arrayGetOrBadRequest (array $ array , ...$ keys )
0 commit comments