page: include scripts from placeholders
[minimedit.git] / page.php
1 <?php
2 error_reporting(E_ALL);
3 ini_set('display_errors', TRUE);
4
5 function abort($body, $status = NULL) {
6         if ($status) header("HTTP/1.1 $status");
7         print "$body\n";
8         exit;
9 }
10
11 function getoutput($blocks = [])
12 {
13         $doc = ob_get_clean();
14
15         if (!empty($blocks['warn'])) {
16                 $warn = '<p class="warn">[[warn]]</p>';
17                 if ($offset = strpos($doc, '</h2>')) {
18                         $doc = substr_replace($doc, "\n\n".$warn, $offset + 5, 0);
19                 }
20                 else {
21                         $doc = $warn . "\n\n" . $doc;
22                 }
23         }
24
25         return preg_replace_callback(
26                 '< \[\[ ([^]/]+) ([^]]*) \]\] >x',
27                 function ($sub) use ($blocks) {
28                         list ($placeholder, $name, $params) = $sub;
29                         if (isset($blocks[$name])) {
30                                 $html = $blocks[$name];
31                         }
32                         elseif (file_exists("$name.php")) {
33                                 ob_start();
34                                 $Page = $GLOBALS['Page'];
35                                 $Args = $GLOBALS['Args'] . $params;
36                                 include "$name.php";
37                                 $html = ob_get_clean();
38                         }
39                         else {
40                                 $html = '<strong class="warn"><em>'.$name.'</em> ontbreekt</strong>';
41                         }
42                         return sprintf('<!--BLOCK:%s-->%s<!--/-->',
43                                 is_numeric($name) ? '' : $placeholder, # edit replacement
44                                 preg_replace('{<!--[^-]*-->}', '', $html) # contents
45                         );
46                 },
47                 $doc
48         );
49 }
50
51 # custom error handling
52
53 define('DOCROOT', getcwd().'/');
54
55 function fail($error)
56 {
57         http_response_code(500);
58         include_once 'page.inc.php';
59         ob_start();
60         require_once DOCROOT.'500.html';
61         print getoutput(['debug' => $error]);
62 }
63
64 set_exception_handler('fail');
65
66 define('E_FATAL', E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR);
67
68 set_error_handler(function ($level, $error, $file, $line) {
69         if ($level & E_FATAL) {
70                 fail($error);
71                 return;
72         }
73         return FALSE;
74 });
75
76 register_shutdown_function(function () {
77         # display failure page for fatal exceptions
78         $error = error_get_last();
79         if (!($error['type'] & E_FATAL)) return;
80         fail("Fatal: $error[message] in $error[file]:$error[line]");
81 });
82
83 error_reporting(error_reporting() & ~E_FATAL);
84
85 # user login and control
86
87 include_once 'auth.inc.php';
88 $Edit = isset($_GET['edit']);
89
90 # distinguish subpage Args from topmost Page script
91
92 $Args = '';
93 $Page = preg_replace('/\?.*/', '', @$_SERVER['PATH_INFO'] ?: $_SERVER['REQUEST_URI']);
94 $Page = urldecode(trim($Page, '/')) ?: 'index';
95 while (TRUE) {
96         if (file_exists("$Page/.private")) {
97                 # access restriction
98                 if (empty($User)) {
99                         http_response_code(303);
100                         $target = urlencode($_SERVER['REQUEST_URI']);
101                         header("Location: /login?goto=$target");
102                         exit;
103                 }
104                 $PageAccess = $Page;
105         }
106
107         if (file_exists("$Page/index.php")) {
108                 break;
109         }
110
111         $up = strrpos($Page, '/');
112         $Args = substr($Page, $up) . $Args;
113         $Page = substr($Page, 0, $up);
114         if ($up === FALSE) {
115                 break;
116         }
117 }
118
119 # load static contents
120
121 ob_start(); # page body
122 ob_start(); # inner html
123 print '<div class="static">'."\n\n";
124
125 $found = FALSE;
126 if (file_exists("$Page$Args.html")) {
127         $found = include "./$Page$Args.html";
128 }
129 elseif (file_exists("$Page$Args/index.html")) {
130         $found = include "./$Page$Args/index.html";
131 }
132 elseif (!empty($User['admin'])) {
133         $found = include (file_exists("$Page/template.html") ? "$Page/template.html" : './template.html');
134 }
135
136 print "</div>\n\n";
137
138 # execute dynamic code
139
140 $Place = [
141         'user'  => $User['name'],
142         'url'   => htmlspecialchars($_SERVER['REQUEST_URI']),
143 ];
144
145 if ($Page) {
146         $found |= require "./$Page/index.php";
147 }
148
149 # global html
150
151 if (!$found) {
152         # no resulting output
153         http_response_code(404);
154         @require "./404.html";
155 }
156
157 include_once 'page.inc.php';
158