page: catch triggered php errors
[minimedit.git] / page.php
1 <?php
2 error_reporting(E_ALL);
3 ini_set('display_errors', TRUE);
4
5 function getoutput($blocks = [])
6 {
7         $rep = [];
8         foreach ($blocks as $name => $html) {
9                 $rep["[[$name]]"] = sprintf('<!--BLOCK:%s-->%s<!--/-->',
10                         is_numeric($name) ? '' : "[[$name]]",
11                         preg_replace('{<!--[^-]*-->}', '', $html)
12                 );
13         }
14         return str_replace(array_keys($rep), array_values($rep), ob_get_clean());
15 }
16
17 # custom error handling
18
19 function fail($error)
20 {
21         http_response_code(500);
22         include_once 'page.inc.php';
23         ob_start();
24         require_once './500.html';
25         print getoutput(['debug' => $error]);
26 }
27
28 set_exception_handler('fail');
29
30 define('E_FATAL', E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR);
31
32 set_error_handler(function ($level, $error, $file, $line) {
33         if ($level & E_FATAL) {
34                 fail($error);
35                 return;
36         }
37         return FALSE;
38 });
39
40 register_shutdown_function(function () {
41         # display failure page for fatal exceptions
42         $error = error_get_last();
43         if (!($error['type'] & E_FATAL)) return;
44         fail("Fatal: $error[message] in $error[file]:$error[line]");
45 });
46
47 error_reporting(error_reporting() & ~E_FATAL);
48
49 # user login and control
50
51 include_once 'auth.inc.php';
52 $Edit = isset($_GET['edit']);
53
54 # distinguish subpage Args from topmost Page script
55
56 $Args = '';
57 $Page = preg_replace('/\?.*/', '', $_SERVER['REQUEST_URI']);
58 $Page = urldecode(trim($Page, '/')) ?: 'index';
59 while (TRUE) {
60         if (file_exists("$Page/.private")) {
61                 # access restriction
62                 if (!isset($User)) {
63                         http_response_code(403);
64                         include_once 'page.inc.php';
65                         ob_start();
66                         @require_once './403.html';
67                         exit;
68                 }
69         }
70
71         if (file_exists("$Page.php")) {
72                 break;
73         }
74
75         $up = strrpos($Page, '/');
76         $Args = substr($Page, $up) . $Args;
77         $Page = substr($Page, 0, $up);
78         if ($up === FALSE) {
79                 break;
80         }
81 }
82
83 # load static contents
84
85 ob_start(); # page body
86 ob_start(); # inner html
87 print '<div class="static">'."\n\n";
88
89 $found = FALSE;
90 if (file_exists("$Page$Args/index.html")) {
91         $found = include "./$Page$Args/index.html";
92 }
93 elseif (file_exists("$Page$Args.html")) {
94         $found = include "./$Page$Args.html";
95 }
96 elseif (isset($User) and $User['admin']) {
97         $found = include (file_exists("$Page/template.html") ? "$Page/template.html" : './template.html');
98 }
99
100 print "</div>\n\n";
101
102 # execute dynamic code
103
104 if ($Page) {
105         $found |= @require "./$Page.php";
106 }
107
108 # global html
109
110 include_once 'page.inc.php';
111
112 if (!$found) {
113         # no resulting output
114         http_response_code(404);
115         ob_start();
116         @require "./404.html";
117         print getoutput([ 'url' => htmlspecialchars($_SERVER['REQUEST_URI']) ]);
118 }
119