replace remaining niftyString() occurrences
[racktables] / wwwroot / index.php
1 <?php
2
3 # This file is a part of RackTables, a datacenter and server room management
4 # framework. See accompanying file "COPYING" for the full copyright and
5 # licensing information.
6
7 ob_start();
8 require_once 'inc/pre-init.php';
9 try {
10 // Switch block below is a module request dispatcher.
11 // Dispatches based on module request.
12 // The last string 'interface' is the default.
13 $requestedModule = array_key_exists ('module', $_REQUEST) ? $_REQUEST['module'] : 'interface';
14
15 switch ($requestedModule)
16 {
17 case 'interface':
18 require_once 'inc/interface.php';
19 // init.php has to be included after interface.php, otherwise the bits
20 // set by local.php get lost
21 require_once 'inc/init.php';
22 prepareNavigation();
23 requireExtraFiles ($interface_requires, $pageno, $tabno);
24 // Security context is built on the requested page/tab/bypass data,
25 // do not override.
26 fixContext();
27 redirectIfNecessary();
28 assertPermission();
29 header ('Content-Type: text/html; charset=UTF-8');
30 // call the main handler - page or tab handler.
31 if (isset ($tabhandler[$pageno][$tabno]))
32 {
33 if (! is_callable ($tabhandler[$pageno][$tabno]))
34 throw new RackTablesError ("Missing handler function for node '${pageno}-${tabno}'", RackTablesError::INTERNAL);
35 call_user_func ($tabhandler[$pageno][$tabno], getBypassValue());
36 }
37 elseif (isset ($page[$pageno]['handler']))
38 {
39 if (! is_callable ($page[$pageno]['handler']))
40 throw new RackTablesError ("Missing handler function for node '${pageno}'", RackTablesError::INTERNAL);
41 $page[$pageno]['handler'] ($tabno);
42 }
43 else
44 throw new RackTablesError ("Failed to find handler for page '${pageno}', tab '${tabno}'", RackTablesError::INTERNAL);
45 // Embed the current text in OB into interface layout (the latter also
46 // empties color message buffer).
47 $contents = ob_get_contents();
48 ob_clean();
49 renderInterfaceHTML ($pageno, $tabno, $contents);
50 break;
51
52 case 'chrome':
53 require_once 'inc/init.php';
54 require_once 'inc/solutions.php';
55 proxyStaticURI (genericAssertion ('uri', 'string'));
56 break;
57
58 case 'download':
59 require_once 'inc/init.php';
60 $pageno = 'file';
61 $tabno = 'download';
62 fixContext();
63 assertPermission();
64 $file = getFile (getBypassValue());
65 header("Content-Type: {$file['type']}");
66 header("Content-Length: {$file['size']}");
67 if (! array_key_exists ('asattach', $_REQUEST) || $_REQUEST['asattach'] != 'no')
68 header("Content-Disposition: attachment; filename={$file['name']}");
69 echo $file['contents'];
70 break;
71
72 case 'image':
73 # The difference between "image" and "download" ways to serve the same
74 # picture file is that the former is used in <IMG SRC=...> construct,
75 # and the latter is accessed as a standalone URL and can reply with any
76 # Content-Type. Hence "image" module indicates failures with internally
77 # built images, and "download" can return a full-fledged "permission
78 # denied" or "exception" HTML page instead of the file requested.
79 require_once 'inc/init.php'; // for authentication check
80 require_once 'inc/solutions.php';
81 try
82 {
83 dispatchImageRequest();
84 }
85 catch (Exception $e)
86 {
87 ob_clean();
88 throw ($e instanceof RTImageError) ? $e : new RTImageError;
89 }
90 break;
91
92 case 'svg':
93 require_once 'inc/init.php';
94 require_once 'inc/solutions.php';
95 header ('Content-Type: image/svg+xml');
96 echo '<?xml version="1.0" encoding="iso-8859-1" standalone="no"?>' . "\n";
97 echo '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">' . "\n";
98 try
99 {
100 $view = genericAssertion ('view', 'string');
101 if (! array_key_exists ($view, $svghandler))
102 throw new InvalidRequestArgException ('view', $view, 'undefined view');
103 if (! is_callable ($svghandler[$view]))
104 throw new RackTablesError ('missing handler function', RackTablesError::INTERNAL);
105 call_user_func ($svghandler[$view]);
106 }
107 catch (RTPermissionDenied $e)
108 {
109 ob_clean();
110 printSVGMessageBar ('permission denied', array ('fill' => 'white'), array ('fill' => 'black', 'stroke' => 'gray'));
111 }
112 catch (InvalidRequestArgException $e)
113 {
114 ob_clean();
115 printSVGMessageBar ('malformed HTTP request', array(), array ('fill' => 'yellow', 'stroke' => 'black'));
116 }
117 catch (EntityNotFoundException $e)
118 {
119 ob_clean();
120 printSVGMessageBar ('no such record', array(), array ('fill' => 'yellow', 'stroke' => 'black'));
121 }
122 catch (RackTablesError $e)
123 {
124 ob_clean();
125 printSVGMessageBar ('RT error: ' . $e->getMessage(), array(), array ('fill' => 'red', 'stroke' => 'black'));
126 }
127 catch (Exception $e)
128 {
129 ob_clean();
130 printSVGMessageBar ('unknown error', array(), array ('fill' => 'red', 'stroke' => 'black'));
131 }
132 break;
133
134 case 'progressbar':
135 # Unlike images (and like static content), progress bars are processed
136 # without a permission check, but only for authenticated users.
137 require_once 'inc/init.php';
138 require_once 'inc/solutions.php';
139 try
140 {
141 // 'progressbar's never change, make browser cache the result
142 if (checkCachedResponse (0, CACHE_DURATION))
143 break;
144 renderProgressBarImage (genericAssertion ('done', 'unsigned'));
145 }
146 catch (Exception $e)
147 {
148 ob_clean();
149 throw ($e instanceof RTImageError) ? $e : new RTImageError ('pbar_error');
150 }
151 break;
152
153 case 'progressbar4':
154 # Unlike images (and like static content), progress bars are processed
155 # without a permission check, but only for authenticated users.
156 require_once 'inc/init.php';
157 require_once 'inc/solutions.php';
158 try
159 {
160 renderProgressBar4Image
161 (
162 genericAssertion ('px1', 'unsigned'),
163 genericAssertion ('px2', 'unsigned'),
164 genericAssertion ('px3', 'unsigned')
165 );
166 }
167 catch (Exception $e)
168 {
169 ob_clean();
170 throw ($e instanceof RTImageError) ? $e : new RTImageError ('pbar_error');
171 }
172 break;
173
174 case 'ajax':
175 require_once 'inc/init.php';
176 require_once 'inc/ajax-interface.php';
177 require_once 'inc/solutions.php';
178 try
179 {
180 $ac = genericAssertion ('ac', 'string');
181 if (isset ($ajaxhandler[$ac]))
182 $ajaxhandler[$ac]();
183 else
184 {
185 ob_clean();
186 echo "NAK\nMalformed request";
187 }
188 }
189 catch (RTPermissionDenied $e)
190 {
191 ob_clean();
192 # FIXME: the remote client could be expecting JSON data instead
193 echo "NAK\nPermission denied";
194 }
195 catch (Exception $e)
196 {
197 ob_clean();
198 echo "NAK\nRuntime exception: ". $e->getMessage();
199 }
200 break;
201
202 case 'redirect':
203 // Include init after ophandlers/snmp, not before, so local.php can redefine things.
204 require_once 'inc/ophandlers.php';
205 // snmp.php is an exception, it is treated by a special hack
206 if (isset ($_REQUEST['op']) && $_REQUEST['op'] == 'querySNMPData')
207 require_once 'inc/snmp.php';
208 require_once 'inc/init.php';
209 try
210 {
211 $op = genericAssertion ('op', 'string');
212 prepareNavigation();
213 $location = buildRedirectURL();
214 // FIXME: find a better way to handle this error
215 if ($op == 'addFile' && !isset($_FILES['file']['error']))
216 throw new RackTablesError ('File upload error, check upload_max_filesize in php.ini', RackTablesError::MISCONFIGURED);
217 fixContext();
218 if
219 (
220 ! isset ($ophandler[$pageno][$tabno][$op]) ||
221 ! is_callable ($ophandler[$pageno][$tabno][$op])
222 )
223 throw new RackTablesError ("Invalid navigation data for '${pageno}-${tabno}-${op}'", RackTablesError::INTERNAL);
224 // We have a chance to handle an error before starting HTTP header.
225 if (!isset ($delayauth["${pageno}-${tabno}-${op}"]))
226 assertPermission();
227 # Call below does the job of bypass argument assertion, if such is required,
228 # so the ophandler function doesn't have to re-assert this portion of its
229 # arguments. And it would be even better to pass returned value to ophandler,
230 # so it is not necessary to remember the name of bypass in it.
231 getBypassValue();
232 if ('' != $redirect_to = call_user_func ($ophandler[$pageno][$tabno][$op]))
233 $location = $redirect_to;
234 }
235 // known "soft" failures require a short error message
236 catch (InvalidRequestArgException $e)
237 {
238 ob_clean();
239 showError ($e->getMessage());
240 }
241 catch (RTDatabaseError $e)
242 {
243 ob_clean();
244 showError ('Database error: ' . $e->getMessage());
245 }
246 catch (RTPermissionDenied $e)
247 {
248 ob_clean();
249 showError ('Operation not permitted');
250 }
251 catch (Exception $e)
252 {
253 ob_clean();
254 printException ($e);
255 break;
256 }
257 redirectUser ($location);
258 // any other error requires no special handling and will be caught outside
259 break;
260
261 case 'popup':
262 require_once 'inc/popup.php';
263 require_once 'inc/init.php';
264 prepareNavigation();
265 fixContext();
266 assertPermission();
267 $helper = assertStringArg ('helper');
268
269 header ('Content-Type: text/html; charset=UTF-8');
270 // call the main handler - page or tab handler.
271 if (isset ($popuphandler[$helper]) && is_callable ($popuphandler[$helper]))
272 call_user_func ($popuphandler[$helper], $helper);
273 else
274 throw new RackTablesError ("Missing handler function for node '${handler}'", RackTablesError::INTERNAL);
275 $contents = ob_get_contents();
276 ob_clean();
277 renderPopupHTML ($contents);
278 break;
279
280 case 'upgrade':
281 require_once 'inc/config.php'; // for CODE_VERSION
282 require_once 'inc/database.php';
283 require_once 'inc/dictionary.php';
284 require_once 'inc/functions.php'; // for ip translation functions
285 require_once 'inc/upgrade.php';
286 renderUpgraderHTML();
287 break;
288
289 case 'installer':
290 require_once 'inc/dictionary.php';
291 require_once 'inc/config.php';
292 require_once 'inc/install.php';
293 renderInstallerHTML();
294 break;
295
296 default:
297 throw new InvalidRequestArgException ('module', $requestedModule);
298 }
299 ob_end_flush();
300 }
301 catch (Exception $e)
302 {
303 ob_end_clean();
304 printException ($e);
305 }