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