Rev 277 | Rev 289 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 277 | Rev 288 | ||
---|---|---|---|
Line 18... | Line 18... | ||
18 | */ |
18 | */ |
19 | 19 | ||
20 | class OIDplusLogger { |
20 | class OIDplusLogger { |
21 | 21 | ||
22 | private static function split_maskcodes($maskcodes) { |
22 | private static function split_maskcodes($maskcodes) { |
- | 23 | // This function splits a mask code containing multiple components |
|
- | 24 | // (delimited by '+' or '/') in single components |
|
- | 25 | // It takes care that '+' and '/' inside brackets won't be used to split the codes |
|
- | 26 | // Also, brackets can be escaped. |
|
- | 27 | // The severity block (optional, must be standing in front of a component) |
|
- | 28 | // is handled too. Inside the severity block, you may only use '/' to split components. |
|
- | 29 | // The severity block will be implicitly repeated from the previous components if a component |
|
- | 30 | // does not feature one. |
|
- | 31 | // |
|
- | 32 | // "[S]AAA(BBB)+CCC(DDD)" ==> array( |
|
- | 33 | // array(array("S"),"AAA(BBB)"), |
|
- | 34 | // array(array("S"),"CCC(DDD)") |
|
- | 35 | // ) |
|
- | 36 | // "[S]AAA(B+BB)+CCC(DDD)" ==> array( |
|
- | 37 | // array(array("S"),"AAA(B+BB)"), |
|
- | 38 | // array(array("S"),"CCC(DDD)") |
|
- | 39 | // ) |
|
- | 40 | // "[S]AAA(B\)BB)+CCC(DDD)" ==> array( |
|
- | 41 | // array(array("S"),"AAA(B\)BB)"), |
|
- | 42 | // array(array("S"),"CCC(DDD)") |
|
- | 43 | // ) |
|
- | 44 | ||
23 | $out = array(); |
45 | $out = array(); |
- | 46 | $sevs = array(); // Note: The severity block will repeat for the next components if not changed explicitly |
|
24 | 47 | ||
25 | $code = ''; |
48 | $code = ''; |
- | 49 | $sev = ''; |
|
26 | $bracket_level = 0; |
50 | $bracket_level = 0; |
- | 51 | $is_escaping = false; |
|
- | 52 | $inside_severity_block = false; |
|
27 | for ($i=0; $i<strlen($maskcodes); $i++) { |
53 | for ($i=0; $i<strlen($maskcodes); $i++) { |
28 | $char = $maskcodes[$i]; |
54 | $char = $maskcodes[$i]; |
- | 55 | ||
- | 56 | if ($inside_severity_block) { |
|
- | 57 | // Severity block (optional) |
|
- | 58 | // e.g. [?WARN/!OK] ==> $sevs = array("?WARN", "!OK") |
|
- | 59 | if ($char == '\\') { |
|
- | 60 | if ($is_escaping) { |
|
- | 61 | $is_escaping = false; |
|
- | 62 | $sev .= $char; |
|
- | 63 | } else { |
|
- | 64 | $is_escaping = true; |
|
- | 65 | } |
|
- | 66 | } |
|
- | 67 | else if ($char == '[') { |
|
- | 68 | if ($is_escaping) { |
|
- | 69 | $is_escaping = false; |
|
- | 70 | } else { |
|
- | 71 | $bracket_level++; |
|
- | 72 | } |
|
- | 73 | $sev .= $char; |
|
- | 74 | } |
|
- | 75 | else if ($char == ']') { |
|
- | 76 | if ($is_escaping) { |
|
- | 77 | $is_escaping = false; |
|
- | 78 | $sev .= $char; |
|
- | 79 | } else { |
|
- | 80 | $bracket_level--; |
|
- | 81 | if ($bracket_level < 0) return false; |
|
- | 82 | if ($bracket_level == 0) { |
|
- | 83 | $inside_severity_block = false; |
|
- | 84 | if ($sev != '') $sevs[] = $sev; |
|
- | 85 | $sev = ''; |
|
- | 86 | } else { |
|
- | 87 | $sev .= $char; |
|
- | 88 | } |
|
- | 89 | } |
|
- | 90 | } |
|
29 | if ($char == '(') $bracket_level++; |
91 | else if ((($char == '/')) && ($bracket_level == 1)) { |
- | 92 | if ($is_escaping) { |
|
- | 93 | $is_escaping = false; |
|
- | 94 | $sev .= $char; |
|
- | 95 | } else { |
|
- | 96 | if ($sev != '') $sevs[] = $sev; |
|
- | 97 | $sev = ''; |
|
- | 98 | } |
|
- | 99 | } else { |
|
- | 100 | if ($is_escaping) { |
|
- | 101 | // This would actually be an error, because we cannot escape this |
|
- | 102 | $is_escaping = false; |
|
- | 103 | $sev .= '\\' . $char; |
|
- | 104 | } else { |
|
- | 105 | $sev .= $char; |
|
- | 106 | } |
|
- | 107 | } |
|
- | 108 | } else { |
|
- | 109 | // Normal data (after the severity block) |
|
- | 110 | if (($char == '[') && ($code == '')) { |
|
- | 111 | $inside_severity_block = true; |
|
- | 112 | $bracket_level++; |
|
- | 113 | $sevs = array(); |
|
- | 114 | } |
|
- | 115 | else if ($char == '\\') { |
|
- | 116 | if ($is_escaping) { |
|
- | 117 | $is_escaping = false; |
|
- | 118 | $code .= $char; |
|
- | 119 | } else { |
|
- | 120 | $is_escaping = true; |
|
- | 121 | } |
|
- | 122 | } |
|
- | 123 | else if ($char == '(') { |
|
- | 124 | if ($is_escaping) { |
|
- | 125 | $is_escaping = false; |
|
- | 126 | } else { |
|
- | 127 | $bracket_level++; |
|
- | 128 | } |
|
- | 129 | $code .= $char; |
|
- | 130 | } |
|
30 | if ($char == ')') { |
131 | else if ($char == ')') { |
- | 132 | if ($is_escaping) { |
|
- | 133 | $is_escaping = false; |
|
- | 134 | } else { |
|
31 | $bracket_level--; |
135 | $bracket_level--; |
32 | if ($bracket_level < 0) return false; |
136 | if ($bracket_level < 0) return false; |
33 | } |
137 | } |
- | 138 | $code .= $char; |
|
- | 139 | } |
|
34 | if ((($char == '+') || ($char == '/')) && ($bracket_level == 0)) { |
140 | else if ((($char == '+') || ($char == '/')) && ($bracket_level == 0)) { |
- | 141 | if ($is_escaping) { |
|
- | 142 | $is_escaping = false; |
|
35 | $out[] = $code; |
143 | $code .= $char; |
- | 144 | } else { |
|
- | 145 | if ($code != '') $out[] = array($sevs,$code); |
|
36 | $code = ''; |
146 | $code = ''; |
- | 147 | } |
|
- | 148 | } else { |
|
- | 149 | if ($is_escaping) { |
|
- | 150 | // This would actually be an error, because we cannot escape this |
|
- | 151 | $is_escaping = false; |
|
- | 152 | $code .= '\\' . $char; |
|
37 | } else { |
153 | } else { |
38 | $code .= $char; |
154 | $code .= $char; |
39 | } |
155 | } |
40 | } |
156 | } |
- | 157 | } |
|
- | 158 | } |
|
41 | if ($code != '') $out[] = $code; |
159 | if ($code != '') $out[] = array($sevs,$code); |
- | 160 | if ($inside_severity_block) return false; |
|
42 | 161 | ||
43 | return $out; |
162 | return $out; |
44 | } |
163 | } |
45 | 164 | ||
46 | public static function log($maskcodes, $event) { |
165 | public static function log($maskcodes, $event) { |
- | 166 | // What is a mask code? |
|
- | 167 | // A mask code gives information about the log event: |
|
- | 168 | // 1. The severity (info, warning, error) |
|
- | 169 | // 2. In which logbook(s) the event shall be placed |
|
- | 170 | // Example: |
|
- | 171 | // The event would be: |
|
- | 172 | // "Person 'X' moves from house 'A' to house 'B'" |
|
- | 173 | // This event would affect the person X and the two houses, |
|
- | 174 | // so, instead of logging into 3 logbooks separately, |
|
- | 175 | // you would create a mask code that tells the system |
|
- | 176 | // to put the message into the logbooks of person X, |
|
- | 177 | // house A and house B. |
|
47 | 178 | ||
48 | $users = array(); |
179 | $users = array(); |
49 | $objects = array(); |
180 | $objects = array(); |
50 | 181 | ||
- | 182 | // A mask code with multiple components is split into single codes |
|
- | 183 | // using '+' or '/', e.g. "OID(x)+RA(x)" would be split to "OID(x)" and "RA(x)" |
|
- | 184 | // which would result in the message being placed in the logbook of OID x, |
|
- | 185 | // and the logbook of the RA owning OID x. |
|
51 | $maskcodes_ary = self::split_maskcodes($maskcodes); |
186 | $maskcodes_ary = self::split_maskcodes($maskcodes); |
52 | if ($maskcodes_ary === false) { |
187 | if ($maskcodes_ary === false) { |
53 | throw new OIDplusException("Invalid maskcode '$maskcodes'"); |
188 | throw new OIDplusException("Invalid maskcode '$maskcodes' (failed to split)"); |
54 | } |
189 | } |
55 | foreach ($maskcodes_ary as $maskcode) { |
190 | foreach ($maskcodes_ary as list($sevs,$maskcode)) { |
- | 191 | // At the beginning of each mask code, you can define a severity. |
|
- | 192 | // If you have a mask code with multiple components, you don't have to place the |
|
- | 193 | // severity for each component. You can just leave it at the beginning. |
|
- | 194 | // e.g. "[WARN]OID(x)+RA(x)" is equal to "[WARN]OID(x)+[WARN]RA(x)" |
|
- | 195 | // You can also put different severities for the components: |
|
- | 196 | // e.g. "[INFO]OID(x)+[WARN]RA(x)" would be a info for the OID, but a warning for the RA. |
|
- | 197 | // If you want to make the severity dependent on wheather the user is logged in or not, |
|
- | 198 | // prepend "?" or "!" and use '/' as delimiter |
|
- | 199 | // Example: "[?WARN/!OK]RA(x)" means: If RA is not logged in, it is a warning; if it is logged in, it is an success |
|
- | 200 | $severity = 0; // default severity = none |
|
- | 201 | foreach ($sevs as $sev) { |
|
- | 202 | switch (strtoupper($sev)) { |
|
- | 203 | // [OK] = Success |
|
- | 204 | // Numeric value: 1 |
|
- | 205 | // Rule of thumb: YOU have done something and it was successful |
|
- | 206 | case '?OK': |
|
- | 207 | $severity_online = 1; |
|
- | 208 | break; |
|
- | 209 | case '!OK': |
|
- | 210 | case 'OK': |
|
- | 211 | $severity = 1; |
|
- | 212 | break; |
|
- | 213 | // [INFO] = Informational |
|
- | 214 | // Numeric value: 2 |
|
- | 215 | // Rule of thumb: Someone else has done something (that affects you) and it was successful |
|
- | 216 | case '?INFO': |
|
- | 217 | $severity_online = 2; |
|
- | 218 | break; |
|
- | 219 | case '!INFO': |
|
- | 220 | case 'INFO': |
|
- | 221 | $severity = 2; |
|
- | 222 | break; |
|
- | 223 | // [WARN] = Warning |
|
- | 224 | // Numeric value: 3 |
|
- | 225 | // Rule of thumb: Something happened (probably someone did something) and it affects you |
|
- | 226 | case '?WARN': |
|
- | 227 | $severity_online = 3; |
|
- | 228 | break; |
|
- | 229 | case '!WARN': |
|
- | 230 | case 'WARN': |
|
- | 231 | $severity = 3; |
|
- | 232 | break; |
|
- | 233 | // [ERR] = Error |
|
- | 234 | // Numeric value: 4 |
|
- | 235 | // Rule of thumb: Something failed (probably someone did something) and it affects you |
|
- | 236 | case '?ERR': |
|
- | 237 | $severity_online = 4; |
|
- | 238 | break; |
|
- | 239 | case '!ERR': |
|
- | 240 | case 'ERR': |
|
- | 241 | $severity = 4; |
|
- | 242 | break; |
|
- | 243 | // [CRIT] = Critical |
|
- | 244 | // Numeric value: 5 |
|
- | 245 | // Rule of thumb: Something happened (probably someone did something) which is not an error, |
|
- | 246 | // but some critical situation (e.g. hardware failure), and it affects you |
|
- | 247 | case '?CRIT': |
|
- | 248 | $severity_online = 5; |
|
- | 249 | break; |
|
- | 250 | case '!CRIT': |
|
- | 251 | case 'CRIT': |
|
- | 252 | $severity = 5; |
|
- | 253 | break; |
|
- | 254 | default: |
|
- | 255 | throw new OIDplusException("Invalid maskcode '$maskcodes' (Unknown severity '$sev')"); |
|
- | 256 | } |
|
- | 257 | } |
|
- | 258 | ||
56 | // OID(x) Save log entry into the logbook of: Object "x" |
259 | // OID(x) Save log entry into the logbook of: Object "x" |
57 | if (preg_match('@^OID\((.+)\)$@ismU', $maskcode, $m)) { |
260 | if (preg_match('@^OID\((.+)\)$@ismU', $maskcode, $m)) { |
58 | $object_id = $m[1]; |
261 | $object_id = $m[1]; |
59 | $objects[] = $object_id; |
262 | $objects[] = array($severity, $object_id); |
60 | if ($object_id == '') throw new OIDplusException("OID logger mask requires OID"); |
263 | if ($object_id == '') throw new OIDplusException("OID logger mask requires OID"); |
61 | } |
264 | } |
62 | 265 | ||
- | 266 | // SUPOID(x) Save log entry into the logbook of: Parent of object "x" |
|
- | 267 | else if (preg_match('@^SUPOID\((.+)\)$@ismU', $maskcode, $m)) { |
|
- | 268 | $object_id = $m[1]; |
|
- | 269 | if ($object_id == '') throw new OIDplusException("SUPOID logger mask requires OID"); |
|
- | 270 | $obj = OIDplusObject::parse($object_id); |
|
- | 271 | if ($obj) { |
|
- | 272 | $parent = $obj->getParent()->nodeId(); |
|
- | 273 | $objects[] = array($severity, $parent); |
|
- | 274 | } else { |
|
- | 275 | throw new OIDplusException("SUPOID logger mask: Invalid object '$object_id'"); |
|
- | 276 | } |
|
- | 277 | } |
|
- | 278 | ||
63 | // OIDRA(x)? Save log entry into the logbook of: Logged in RA of object "x" |
279 | // OIDRA(x)? Save log entry into the logbook of: Logged in RA of object "x" |
64 | // Replace ? by ! if the entity does not need to be logged in |
280 | // Remove or replace "?" by "!" if the entity does not need to be logged in |
65 | else if (preg_match('@^OIDRA\((.+)\)([\?\!])$@ismU', $maskcode, $m)) { |
281 | else if (preg_match('@^OIDRA\((.+)\)([\?\!])$@ismU', $maskcode, $m)) { |
66 | $object_id = $m[1]; |
282 | $object_id = $m[1]; |
67 | $ra_need_login = $m[2] == '?'; |
283 | $ra_need_login = $m[2] == '?'; |
68 | if ($object_id == '') throw new OIDplusException("OIDRA logger mask requires OID"); |
284 | if ($object_id == '') throw new OIDplusException("OIDRA logger mask requires OID"); |
69 | $obj = OIDplusObject::parse($object_id); |
285 | $obj = OIDplusObject::parse($object_id); |
70 | if ($obj) { |
286 | if ($obj) { |
71 | if ($ra_need_login) { |
287 | if ($ra_need_login) { |
72 | foreach (OIDplus::authUtils()->loggedInRaList() as $ra) { |
288 | foreach (OIDplus::authUtils()->loggedInRaList() as $ra) { |
73 | if ($obj->userHasWriteRights($ra)) $users[] = $ra->raEmail(); |
289 | if ($obj->userHasWriteRights($ra)) $users[] = array($severity_online, $ra->raEmail()); |
74 | } |
290 | } |
75 | } else { |
291 | } else { |
76 | // $users[] = $obj->getRa()->raEmail(); |
292 | // $users[] = array($severity, $obj->getRa()->raEmail()); |
77 | foreach (OIDplusRA::getAllRAs() as $ra) { |
293 | foreach (OIDplusRA::getAllRAs() as $ra) { |
78 | if ($obj->userHasWriteRights($ra)) $users[] = $ra->raEmail(); |
294 | if ($obj->userHasWriteRights($ra)) $users[] = array($severity, $ra->raEmail()); |
79 | } |
295 | } |
80 | } |
296 | } |
- | 297 | } else { |
|
- | 298 | throw new OIDplusException("OIDRA logger mask: Invalid object '$object_id'"); |
|
81 | } |
299 | } |
82 | } |
300 | } |
83 | 301 | ||
84 | // SUPOIDRA(x)? Save log entry into the logbook of: Logged in RA that owns the superior object of "x" |
302 | // SUPOIDRA(x)? Save log entry into the logbook of: Logged in RA that owns the superior object of "x" |
85 | // Replace ? by ! if the entity does not need to be logged in |
303 | // Remove or replace "?" by "!" if the entity does not need to be logged in |
86 | else if (preg_match('@^SUPOIDRA\((.+)\)([\?\!])$@ismU', $maskcode, $m)) { |
304 | else if (preg_match('@^SUPOIDRA\((.+)\)([\?\!])$@ismU', $maskcode, $m)) { |
87 | $object_id = $m[1]; |
305 | $object_id = $m[1]; |
88 | $ra_need_login = $m[2] == '?'; |
306 | $ra_need_login = $m[2] == '?'; |
89 | if ($object_id == '') throw new OIDplusException("SUPOIDRA logger mask requires OID"); |
307 | if ($object_id == '') throw new OIDplusException("SUPOIDRA logger mask requires OID"); |
90 | $obj = OIDplusObject::parse($object_id); |
308 | $obj = OIDplusObject::parse($object_id); |
91 | if ($obj) { |
309 | if ($obj) { |
92 | if ($ra_need_login) { |
310 | if ($ra_need_login) { |
93 | foreach (OIDplus::authUtils()->loggedInRaList() as $ra) { |
311 | foreach (OIDplus::authUtils()->loggedInRaList() as $ra) { |
94 | if ($obj->userHasParentalWriteRights($ra)) $users[] = $ra->raEmail(); |
312 | if ($obj->userHasParentalWriteRights($ra)) $users[] = array($severity_online, $ra->raEmail()); |
95 | } |
313 | } |
96 | } else { |
314 | } else { |
97 | // $users[] = $obj->getParent()->getRa()->raEmail(); |
315 | // $users[] = array($severity, $obj->getParent()->getRa()->raEmail()); |
98 | foreach (OIDplusRA::getAllRAs() as $ra) { |
316 | foreach (OIDplusRA::getAllRAs() as $ra) { |
99 | if ($obj->userHasParentalWriteRights($ra)) $users[] = $ra->raEmail(); |
317 | if ($obj->userHasParentalWriteRights($ra)) $users[] = array($severity, $ra->raEmail()); |
100 | } |
318 | } |
101 | } |
319 | } |
- | 320 | } else { |
|
- | 321 | throw new OIDplusException("SUPOIDRA logger mask: Invalid object '$object_id'"); |
|
102 | } |
322 | } |
103 | } |
323 | } |
104 | 324 | ||
105 | // RA(x)? Save log entry into the logbook of: Logged in RA "x" |
325 | // RA(x)? Save log entry into the logbook of: Logged in RA "x" |
106 | // Replace ? by ! if the entity does not need to be logged in |
326 | // Remove or replace "?" by "!" if the entity does not need to be logged in |
107 | else if (preg_match('@^RA\((.+)\)([\?\!])$@ismU', $maskcode, $m)) { |
327 | else if (preg_match('@^RA\((.*)\)([\?\!])$@ismU', $maskcode, $m)) { |
108 | $ra_email = $m[1]; |
328 | $ra_email = $m[1]; |
109 | $ra_need_login = $m[2] == '?'; |
329 | $ra_need_login = $m[2] == '?'; |
- | 330 | if (!empty($ra_email)) { |
|
110 | if ($ra_need_login && OIDplus::authUtils()->isRaLoggedIn($ra_email)) { |
331 | if ($ra_need_login && OIDplus::authUtils()->isRaLoggedIn($ra_email)) { |
111 | $users[] = $ra_email; |
332 | $users[] = array($severity_online, $ra_email); |
112 | } else if (!$ra_need_login) { |
333 | } else if (!$ra_need_login) { |
113 | $users[] = $ra_email; |
334 | $users[] = array($severity, $ra_email); |
- | 335 | } |
|
114 | } |
336 | } |
115 | } |
337 | } |
116 | 338 | ||
117 | // A? Save log entry into the logbook of: A logged in admin |
339 | // A? Save log entry into the logbook of: A logged in admin |
118 | // Replace ? by ! if the entity does not need to be logged in |
340 | // Remove or replace "?" by "!" if the entity does not need to be logged in |
119 | else if (preg_match('@^A([\?\!])$@ismU', $maskcode, $m)) { |
341 | else if (preg_match('@^A([\?\!])$@ismU', $maskcode, $m)) { |
120 | $admin_need_login = $m[1] == '?'; |
342 | $admin_need_login = $m[1] == '?'; |
121 | if ($admin_need_login && OIDplus::authUtils()->isAdminLoggedIn()) { |
343 | if ($admin_need_login && OIDplus::authUtils()->isAdminLoggedIn()) { |
122 | $users[] = 'admin'; |
344 | $users[] = array($severity_online, 'admin'); |
123 | } else if (!$admin_need_login) { |
345 | } else if (!$admin_need_login) { |
124 | $users[] = 'admin'; |
346 | $users[] = array($severity, 'admin'); |
125 | } |
347 | } |
126 | } |
348 | } |
127 | 349 | ||
128 | // Unexpected |
350 | // Unexpected |
129 | else { |
351 | else { |
130 | throw new OIDplusException("Unexpected logger mask code '$maskcode'"); |
352 | throw new OIDplusException("Unexpected logger component '$maskcode' in mask code '$maskcodes'"); |
131 | } |
353 | } |
132 | } |
354 | } |
133 | 355 | ||
134 | // Now write the log message |
356 | // Now write the log message |
135 | 357 | ||
Line 139... | Line 361... | ||
139 | if ($log_id === false) { |
361 | if ($log_id === false) { |
140 | $res = OIDplus::db()->query("select max(id) as last_id from ###log"); |
362 | $res = OIDplus::db()->query("select max(id) as last_id from ###log"); |
141 | if ($res->num_rows() == 0) throw new OIDplusException("Could not log event"); |
363 | if ($res->num_rows() == 0) throw new OIDplusException("Could not log event"); |
142 | $row = $res->fetch_array(); |
364 | $row = $res->fetch_array(); |
143 | $log_id = $row['last_id']; |
365 | $log_id = $row['last_id']; |
- | 366 | if ($log_id == 0) throw new OIDplusException("Could not log event"); |
|
144 | } |
367 | } |
145 | 368 | ||
- | 369 | $object_dupe_check = array(); |
|
146 | foreach ($objects as $object) { |
370 | foreach ($objects as list($severity, $object)) { |
- | 371 | if (in_array($object, $object_dupe_check)) continue; |
|
- | 372 | $object_dupe_check[] = $object; |
|
147 | OIDplus::db()->query("insert into ###log_object (log_id, object) values (?, ?)", array($log_id, $object)); |
373 | OIDplus::db()->query("insert into ###log_object (log_id, severity, object) values (?, ?, ?)", array($log_id, $severity, $object)); |
148 | } |
374 | } |
149 | 375 | ||
- | 376 | $user_dupe_check = array(); |
|
150 | foreach ($users as $username) { |
377 | foreach ($users as list($severity, $username)) { |
- | 378 | if (in_array($username, $user_dupe_check)) continue; |
|
- | 379 | $user_dupe_check[] = $username; |
|
151 | OIDplus::db()->query("insert into ###log_user (log_id, username) values (?, ?)", array($log_id, $username)); |
380 | OIDplus::db()->query("insert into ###log_user (log_id, severity, username) values (?, ?, ?)", array($log_id, $severity, $username)); |
152 | } |
381 | } |
153 | 382 | ||
154 | } |
383 | } |
155 | } |
384 | } |