r4998 Added a reference to COPYING into every file with meaningful PHP, Perl or
[racktables] / wwwroot / inc / solutions.php
CommitLineData
b325120a 1<?php
cddbb9fd
DO
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
5c42f907
DO
7/*
8
9The purpose of this file is to contain functions, which generate a complete
10HTTP response body and are either "dead ends" or depend on just a small
11amount of other code (which should eventually be placed in a sort of
12"first order" library file).
13
14*/
15
16define ('RE_STATIC_URI', '#^([[:alpha:]]+)/(?:[[:alpha:]]+/)*[[:alnum:]\._-]+\.([[:alpha:]]+)$#');
e673ee24 17
4afb4c10 18function dispatchImageRequest()
d15b2330 19{
4afb4c10
DO
20 genericAssertion ('img', 'string');
21 global $pageno, $tabno;
22 switch ($_REQUEST['img'])
23 {
da958e52 24 case 'minirack': // rack security context
da958e52 25 $pageno = 'rack';
d15b2330 26 $tabno = 'default';
da958e52 27 fixContext();
46422e6f 28 assertPermission();
3ec33017 29 renderRackThumb (getBypassValue());
d15b2330 30 break;
0df8c52b 31 case 'preview': // file security context
37e59768 32 $pageno = 'file';
0df8c52b 33 $tabno = 'download';
37e59768 34 fixContext();
3ec33017
DO
35 assertPermission();
36 renderFilePreview (getBypassValue());
37e59768 37 break;
bfbdd78b
DO
38 case 'cactigraph':
39 $pageno = 'object';
c62bbd4c 40 $tabno = 'cacti';
bfbdd78b
DO
41 fixContext();
42 assertPermission();
43 genericAssertion ('graph_id', 'uint');
44 if (! array_key_exists ($_REQUEST['graph_id'], getCactiGraphsForObject (getBypassValue())))
45 throw new InvalidRequestArgException ('graph_id', $_REQUEST['graph_id']);
46 proxyCactiRequest ($_REQUEST['graph_id']);
47 break;
d15b2330 48 default:
11566bd6 49 renderErrorImage();
4afb4c10 50 }
90a3d6d8
DY
51}
52
11566bd6 53function renderErrorImage ()
e673ee24 54{
e673ee24 55 header("Content-type: image/png");
d5f8fa19
DO
56 // "ERROR", 76x17, red on white
57 echo base64_decode
58 (
59 'iVBORw0KGgoAAAANSUhEUgAAAEwAAAARCAYAAAB3h0oCAAAAAXNSR0IArs4c6QAAALBJREFUWMPt' .
60 'WFsOwCAIG4v3vzL7WEyWxQdVwM1A4l/F2iHVETPzESGOMyTAInURRP0suUhb2FIho/jWXO38w4KN' .
61 'LPDGEt2jlgPBZxFKc2o8UT7Lj6SkAmfw1nx+28MkVWQlcjT9EOwjLqnpaNImi+I1j/YSl5RY/gx+' .
62 'VCCF/MnkCz4JZQtvEUXx1nyW9jCUlPVLbTJ/3MO2dsnWRq2Nwl2wTarM51rhsVEnDhT/w7C4APaJ' .
63 'ZhkIGYaUAAAAAElFTkSuQmCC'
64 );
da958e52
DO
65}
66
9077fd0e
DO
67function renderAccessDeniedImage()
68{
69 header ('Content-type: image/png');
70 // 1x1, single black pixel
71 echo base64_decode
72 (
73 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAAXNSR0IArs4c6QAAAAxJREFUCNdj' .
74 'YGBgAAAABAABJzQnCgAAAABJRU5ErkJggg=='
75 );
76}
77
9c0b0016 78// Having a local caching array speeds things up. A little.
e673ee24
DO
79function colorFromHex ($image, $hex)
80{
9c0b0016
DO
81 static $colorcache = array ();
82 if (isset ($colorcache[$hex]))
83 return $colorcache[$hex];
e673ee24
DO
84 $r = hexdec ('0x' . substr ($hex, 0, 2));
85 $g = hexdec ('0x' . substr ($hex, 2, 2));
86 $b = hexdec ('0x' . substr ($hex, 4, 2));
9c0b0016
DO
87 $c = imagecolorallocate ($image, $r, $g, $b);
88 $colorcache[$hex] = $c;
89 return $c;
e673ee24
DO
90}
91
92function renderRackThumb ($rack_id = 0)
35ee7bd0
DO
93{
94 // Don't call DB extra times, hence we are most probably not the
6b06a019 95 // only script wishing to access the same data now.
61a1d996
DO
96 if (NULL !== ($thumbcache = loadThumbCache ($rack_id)))
97 {
98 header("Content-type: image/png");
35ee7bd0 99 echo $thumbcache;
61a1d996
DO
100 return;
101 }
102 ob_start();
103 if (FALSE !== generateMiniRack ($rack_id))
35ee7bd0 104 {
61a1d996
DO
105 $capture = ob_get_clean();
106 header("Content-type: image/png");
107 echo $capture;
9b8174d7
AD
108 usePreparedExecuteBlade
109 (
110 'REPLACE INTO RackThumbnail SET rack_id=?, thumb_data=?',
111 array ($rack_id, base64_encode ($capture))
112 );
61a1d996 113 return;
35ee7bd0 114 }
61a1d996
DO
115 // error text in the buffer
116 ob_end_flush();
35ee7bd0
DO
117}
118
61a1d996
DO
119// Output a binary string containing the PNG minirack. Indicate error with return code.
120function generateMiniRack ($rack_id)
e673ee24 121{
61a1d996
DO
122 if (NULL === ($rackData = spotEntity ('rack', $rack_id)))
123 return FALSE;
124 amplifyCell ($rackData);
e673ee24 125 markupObjectProblems ($rackData);
529eac25 126 global $rtwidth;
d5157018 127 $rtdepth = 9;
e673ee24
DO
128 $offset[0] = 3;
129 $offset[1] = 3 + $rtwidth[0];
130 $offset[2] = 3 + $rtwidth[0] + $rtwidth[1];
131 $totalheight = 3 + 3 + $rackData['height'] * 2;
132 $totalwidth = $offset[2] + $rtwidth[2] + 3;
aa0e4c55
DO
133 $img = @imagecreatetruecolor ($totalwidth, $totalheight)
134 or die("Cannot Initialize new GD image stream");
a4c50c50
DO
135 # It was measured, that caching palette in an array is faster, than
136 # calling colorFromHex() multiple times. It matters, when user's
137 # browser is trying to fetch many minirack images in parallel.
138 $color = array
139 (
140 'F' => colorFromHex ($img, '8fbfbf'),
141 'A' => colorFromHex ($img, 'bfbfbf'),
142 'U' => colorFromHex ($img, 'bf8f8f'),
143 'T' => colorFromHex ($img, '408080'),
144 'Th' => colorFromHex ($img, '80ffff'),
145 'Tw' => colorFromHex ($img, '804040'),
146 'Thw' => colorFromHex ($img, 'ff8080'),
147 'black' => colorFromHex ($img, '000000'),
148 'gray' => colorFromHex ($img, 'c0c0c0'),
149 );
9b8174d7 150 $border_color = ($rackData['has_problems'] == 'yes') ? $color['Thw'] : $color['gray'];
d5157018 151 imagerectangle ($img, 0, 0, $totalwidth - 1, $totalheight - 1, $color['black']);
9b8174d7 152 imagerectangle ($img, 1, 1, $totalwidth - 2, $totalheight - 2, $border_color);
d5157018
DO
153 imagerectangle ($img, 2, 2, $totalwidth - 3, $totalheight - 3, $color['black']);
154 for ($unit_no = 1; $unit_no <= $rackData['height']; $unit_no++)
e673ee24
DO
155 {
156 for ($locidx = 0; $locidx < 3; $locidx++)
157 {
158 $colorcode = $rackData[$unit_no][$locidx]['state'];
159 if (isset ($rackData[$unit_no][$locidx]['hl']))
160 $colorcode = $colorcode . $rackData[$unit_no][$locidx]['hl'];
161 imagerectangle
162 (
163 $img,
164 $offset[$locidx],
165 3 + ($rackData['height'] - $unit_no) * 2,
166 $offset[$locidx] + $rtwidth[$locidx] - 1,
167 3 + ($rackData['height'] - $unit_no) * 2 + 1,
d1adb55a 168 $color[$colorcode]
e673ee24
DO
169 );
170 }
171 }
e673ee24
DO
172 imagepng ($img);
173 imagedestroy ($img);
61a1d996 174 return TRUE;
e673ee24
DO
175}
176
d15b2330
DO
177function renderProgressBarImage ($done)
178{
4487fd91
DO
179 if ($done > 100)
180 throw new InvalidArgException ('done', $done);
d1adb55a 181 $img = @imagecreatetruecolor (100, 10);
fec0c8da
DO
182 switch (isset ($_REQUEST['theme']) ? $_REQUEST['theme'] : 'rackspace')
183 {
184 case 'sparenetwork':
185 $color['T'] = colorFromHex ($img, '808080');
186 $color['F'] = colorFromHex ($img, 'c0c0c0');
187 break;
188 case 'rackspace': // teal
189 default:
a4c50c50
DO
190 $color['T'] = colorFromHex ($img, '408080');
191 $color['F'] = colorFromHex ($img, '8fbfbf');
fec0c8da 192 }
d1adb55a
DO
193 imagefilledrectangle ($img, 0, 0, $done, 10, $color['T']);
194 imagefilledrectangle ($img, $done, 0, 100, 10, $color['F']);
074106cf
DO
195 for ($x = 20; $x <= 80; $x += 20)
196 {
197 $cc = $x > $done ? $color['T'] : $color['F'];
198 imagesetpixel ($img, $x, 0, $cc);
199 imagesetpixel ($img, $x, 1, $cc);
200 imagesetpixel ($img, $x, 4, $cc);
201 imagesetpixel ($img, $x, 5, $cc);
202 imagesetpixel ($img, $x, 8, $cc);
203 imagesetpixel ($img, $x, 9, $cc);
204 }
d15b2330
DO
205 header("Content-type: image/png");
206 imagepng ($img);
207 imagedestroy ($img);
d15b2330
DO
208}
209
4487fd91
DO
210function renderProgressBarError()
211{
212 header ('Content-type: image/png');
213 // 100x10, red on pink, "progr. bar error"
214 echo base64_decode
215 (
216 'iVBORw0KGgoAAAANSUhEUgAAAGQAAAAKCAYAAABCHPt+AAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A' .
217 '/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sDERYTJrBhF8sAAACvSURBVEjH' .
218 '7VdRDoAgCMXmQbz/qbhJfdnMQQiDTZ3vL6MHvEA03Yg3rIRSABBhV1xwMBXyp/JatFVYq7La1Hft' .
219 'N709xcXxWLqE4tbGr+GXdNDqw8STxSS0z9S695ZD+e05pXhHt8RRHqtebIdoRPASM2K+ePi18Gjz' .
220 'Yuwz7AKpM2cpmjPUVx3qf0OIqyLKvl+POMp6+R3Jy9oxnD4C0nsPiTrfb35viO2QiOF6foYKD57g' .
221 'f1uXQb2mAAAAAElFTkSuQmCC'
222 );
223}
224
4afb4c10 225function renderFilePreview ($file_id)
37e59768 226{
4afb4c10 227 if ($image = getFileCache ($file_id)) //Cache Hit
37e59768 228 {
4afb4c10
DO
229 header("Content-type: image/jpeg");
230 echo $image;
231 return;
37e59768 232 }
4afb4c10
DO
233 //Cache Miss
234 $file = getFile ($file_id);
235 $image = imagecreatefromstring ($file['contents']);
236 unset ($file);
237 $width = imagesx ($image);
238 $height = imagesy ($image);
239 if ($width > getConfigVar ('PREVIEW_IMAGE_MAXPXS') or $height > getConfigVar ('PREVIEW_IMAGE_MAXPXS'))
240 {
241 $ratio = getConfigVar ('PREVIEW_IMAGE_MAXPXS') / max ($width, $height);
242 $newwidth = $width * $ratio;
243 $newheight = $height * $ratio;
244 $resampled = imagecreatetruecolor ($newwidth, $newheight);
245 imagecopyresampled ($resampled, $image, 0, 0, 0, 0, $newwidth, $newheight, $width, $height);
246 imagedestroy ($image);
247 $image = $resampled;
248 unset ($resampled);
249 }
250 header ('Content-type: image/jpeg');
251 ob_start();
252 imagejpeg ($image);
253 imagedestroy ($image);
254 commitAddFileCache ($file_id, ob_get_flush());
37e59768 255}
f537da2f 256
5c42f907
DO
257function printStatic404()
258{
259 header ('404 Not Found');
260?><!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
261<html><head>
262<title>404 Not Found</title>
263</head><body>
264<h1>Not Found</h1>
265<p>The requested file was not found in this instance.</p>
266<hr>
267<address>RackTables static content proxy</address>
268</body></html><?php
269 exit;
270}
271
272function proxyStaticURI ($URI)
273{
274 $content_type = array
275 (
276 'css' => 'text/css',
277 'js' => 'text/javascript',
278 'html' => 'text/html',
279 'png' => 'image/png',
280 'gif' => 'image/gif',
281 'jpg' => 'image/jpeg',
282 'jpeg' => 'image/jpeg',
283 'ico' => 'image/x-icon',
284 );
285 $matches = array();
286 if
287 (
288 ! preg_match (RE_STATIC_URI, $URI, $matches)
289 or ! in_array ($matches[1], array ('pix', 'css', 'js'))
290 or ! array_key_exists (strtolower ($matches[2]), $content_type)
291 )
292 printStatic404();
93fbb578
AA
293 global $local_staticdir, $racktables_staticdir;
294 if (isset ($local_staticdir))
99c1a2a0 295 $fh = @fopen ("${local_staticdir}/${URI}", 'r');
6f8192f6 296 if (! isset ($fh) or FALSE === $fh)
99c1a2a0 297 $fh = @fopen ("${racktables_staticdir}/${URI}", 'r');
93fbb578 298 if (FALSE === $fh)
5c42f907
DO
299 printStatic404();
300 if (FALSE !== $stat = fstat ($fh))
301 if (checkCachedResponse (max ($stat['mtime'], $stat['ctime']), 0))
302 exit;
303 header ('Content-type: ' . $content_type[$matches[2]]);
304 fpassthru ($fh);
6f8192f6 305 fclose ($fh);
5c42f907
DO
306}
307
bfbdd78b
DO
308function proxyCactiRequest ($graph_id)
309{
310 $ret = array();
311 $cacti_url = getConfigVar('CACTI_URL');
312 $cacti_user = getConfigVar('CACTI_USERNAME');
313 $cacti_pass = getConfigVar('CACTI_USERPASS');
9a377178 314 $url = $cacti_url . "/graph_image.php?action=view&local_graph_id=" . $graph_id;
bfbdd78b
DO
315 $postvars = "action=login&login_username=" . $cacti_user . "&login_password=" . $cacti_pass;
316
317 $session = curl_init();
9a377178 318// curl_setopt ($session, CURLOPT_VERBOSE, TRUE);
bfbdd78b
DO
319
320 // Initial options up here so a specific type can override them
321 curl_setopt ($session, CURLOPT_FOLLOWLOCATION, FALSE);
322 curl_setopt ($session, CURLOPT_TIMEOUT, 10);
323 curl_setopt ($session, CURLOPT_RETURNTRANSFER, TRUE);
bfbdd78b 324 curl_setopt ($session, CURLOPT_URL, $url);
bfbdd78b 325
9a377178
JT
326 if (isset($_SESSION['CACTICOOKIE'][$cacti_url]))
327 curl_setopt ($session, CURLOPT_COOKIE, $_SESSION['CACTICOOKIE'][$cacti_url]);
bfbdd78b 328
9a377178 329 // Request the image
bfbdd78b 330 $ret['contents'] = curl_exec ($session);
bfbdd78b 331 $ret['type'] = curl_getinfo ($session, CURLINFO_CONTENT_TYPE);
9a377178
JT
332 $ret['size'] = curl_getinfo ($session, CURLINFO_SIZE_DOWNLOAD);
333
334 // Not an image, probably the login page
335 if (preg_match('/^text\/html.*/i', $ret['type'])) {
336 // Request to set the cookies
337 curl_setopt ($session, CURLOPT_HEADER, TRUE);
338 curl_setopt ($session, CURLOPT_COOKIE, ""); // clear the old cookie
339 $headers = curl_exec ($session);
340
341 // Get the cookies from the headers
342 preg_match('/Set-Cookie: ([^;]*)/i', $headers, $cookies);
343 array_shift($cookies); // Remove 'Set-Cookie: ...' value
344 $cookie_header = implode(";", $cookies);
345 $_SESSION['CACTICOOKIE'][$cacti_url] = $cookie_header; // store for later use by this user
346
347 // POST Login
348 curl_setopt ($session, CURLOPT_COOKIE, $cookie_header);
349 curl_setopt ($session, CURLOPT_HEADER, FALSE);
350 curl_setopt ($session, CURLOPT_POST, TRUE);
351 curl_setopt ($session, CURLOPT_POSTFIELDS, $postvars);
352 curl_exec ($session);
353
354 // Request the image
355 curl_setopt ($session, CURLOPT_HTTPGET, TRUE);
356 $ret['contents'] = curl_exec ($session);
357 $ret['type'] = curl_getinfo ($session, CURLINFO_CONTENT_TYPE);
dda93df7 358 $ret['size'] = curl_getinfo ($session, CURLINFO_SIZE_DOWNLOAD);
9a377178 359 }
bfbdd78b
DO
360
361 curl_close ($session);
362
9a377178
JT
363 if ($ret['type'] != NULL)
364 header("Content-Type: {$ret['type']}");
365 if ($ret['size'] > 0)
366 header("Content-Length: {$ret['size']}");
367
bfbdd78b
DO
368 echo $ret['contents'];
369}
370
fa7634c7
DO
371function printSVGMessageBar ($text = 'lost message', $textattrs = array(), $rectattrs = array())
372{
373 $mytextattrs = array
374 (
375 'fill' => 'black',
376 'x' => '85',
377 'y' => '15',
378 'font-size' => '100%',
379 'text-anchor' => 'middle',
380 'font-family' => 'monospace',
381 'font-weight' => 'bold',
382 );
383 $myrectattrs = array
384 (
385 'fill' => 'white',
386 'stroke' => 'black',
387 'x' => '0',
388 'y' => '0',
389 'width' => '170px',
390 'height' => '20px',
391 'stroke-width' => '1px',
392 );
393 foreach ($textattrs as $k => $v)
394 $mytextattrs[$k] = $v;
395 foreach ($rectattrs as $k => $v)
396 $myrectattrs[$k] = $v;
397 echo "<svg width='" . $myrectattrs['width'] . "' height='" . $myrectattrs['height'] . "' version='1.1' ";
398 echo "xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'>\n";
399 echo '<rect';
400 foreach ($myrectattrs as $k => $v)
401 echo " ${k}='${v}'";
402 echo " />\n<text";
403 foreach ($mytextattrs as $k => $v)
404 echo " ${k}='${v}'";
405 echo ">${text}</text>\n";
406 echo "</svg>\n";
407}
408
e673ee24 409?>