c1735e6caa3d256278b7149f410e74f2a71165a3
[racktables] / render_image.php
1 <?php
2
3 define ('CACHE_DURATION', 604800); // 7 * 24 * 3600
4 if ( // 'progressbar's never change, force cache hit before loading init.php
5 isset ($_SERVER['HTTP_IF_MODIFIED_SINCE'])
6 && $_REQUEST['img'] == 'progressbar'
7 )
8 {
9 $client_time = strtotime ($_SERVER['HTTP_IF_MODIFIED_SINCE']);
10 if ($client_time !== FALSE && $client_time !== -1) // readable
11 {
12 $server_time = time();
13 // not in future and not yet expired
14 if ($client_time <= $server_time && $client_time + CACHE_DURATION >= $server_time)
15 {
16 header ('Last-Modified: ' . $_SERVER['HTTP_IF_MODIFIED_SINCE'], TRUE, 304);
17 exit;
18 }
19 }
20 }
21
22 ob_start();
23 try {
24 require 'inc/init.php';
25
26 assertStringArg ('img');
27 switch ($_REQUEST['img'])
28 {
29 case 'minirack': // rack security context
30 assertUIntArg ('rack_id');
31 $pageno = 'rack';
32 $tabno = 'default';
33 fixContext();
34 if (!permitted())
35 renderAccessDeniedImage();
36 else
37 renderRackThumb ($_REQUEST['rack_id']);
38 break;
39 case 'progressbar': // no security context
40 assertUIntArg ('done', TRUE);
41 // 'progressbar's never change, make browser cache the result
42 header ('Cache-Control: private, max-age=' . CACHE_DURATION . ', pre-check=' . CACHE_DURATION);
43 header ('Last-Modified: ' . gmdate (DATE_RFC1123));
44 renderProgressBarImage ($_REQUEST['done']);
45 break;
46 case 'preview': // file security context
47 assertUIntArg ('file_id');
48 $pageno = 'file';
49 $tabno = 'download';
50 fixContext();
51 if (!permitted())
52 renderAccessDeniedImage();
53 else
54 renderFilePreview ($_REQUEST['file_id'], $_REQUEST['img']);
55 break;
56 default:
57 renderError();
58 }
59
60 ob_end_flush();
61 }
62 catch (Exception $e)
63 {
64 ob_end_clean();
65 renderError();
66 }
67
68 //------------------------------------------------------------------------
69 function renderError ()
70 {
71 // A hardcoded value is worth of saving lots of code here.
72 $img = imagecreatefrompng ('pix/error.png');
73 header("Content-type: image/png");
74 imagepng ($img);
75 imagedestroy ($img);
76 }
77
78 // Having a local caching array speeds things up. A little.
79 function colorFromHex ($image, $hex)
80 {
81 static $colorcache = array ();
82 if (isset ($colorcache[$hex]))
83 return $colorcache[$hex];
84 $r = hexdec ('0x' . substr ($hex, 0, 2));
85 $g = hexdec ('0x' . substr ($hex, 2, 2));
86 $b = hexdec ('0x' . substr ($hex, 4, 2));
87 $c = imagecolorallocate ($image, $r, $g, $b);
88 $colorcache[$hex] = $c;
89 return $c;
90 }
91
92 function renderRackThumb ($rack_id = 0)
93 {
94 // Don't call DB extra times, hence we are most probably not the
95 // only script wishing to acces the same data now.
96 if (NULL !== ($thumbcache = loadThumbCache ($rack_id)))
97 {
98 header("Content-type: image/png");
99 echo $thumbcache;
100 return;
101 }
102 ob_start();
103 if (FALSE !== generateMiniRack ($rack_id))
104 {
105 $capture = ob_get_clean();
106 header("Content-type: image/png");
107 echo $capture;
108 saveThumbCache ($rack_id, $capture);
109 return;
110 }
111 // error text in the buffer
112 ob_end_flush();
113 }
114
115 // Output a binary string containing the PNG minirack. Indicate error with return code.
116 function generateMiniRack ($rack_id)
117 {
118 if (NULL === ($rackData = spotEntity ('rack', $rack_id)))
119 return FALSE;
120 amplifyCell ($rackData);
121 markupObjectProblems ($rackData);
122 global $rtwidth;
123 $rtdepth = 9;
124 $offset[0] = 3;
125 $offset[1] = 3 + $rtwidth[0];
126 $offset[2] = 3 + $rtwidth[0] + $rtwidth[1];
127 $totalheight = 3 + 3 + $rackData['height'] * 2;
128 $totalwidth = $offset[2] + $rtwidth[2] + 3;
129 $img = @imagecreatetruecolor ($totalwidth, $totalheight)
130 or die("Cannot Initialize new GD image stream");
131 // cache our palette as well
132 $color = array();
133 foreach (array ('F', 'A', 'U', 'T', 'Th', 'Tw', 'Thw') as $statecode)
134 $color[$statecode] = colorFromHex ($img, getConfigVar ('color_' . $statecode));
135 $color['black'] = colorFromHex ($img, '000000');
136 $color['gray'] = colorFromHex ($img, 'c0c0c0');
137 imagerectangle ($img, 0, 0, $totalwidth - 1, $totalheight - 1, $color['black']);
138 imagerectangle ($img, 1, 1, $totalwidth - 2, $totalheight - 2, $color['gray']);
139 imagerectangle ($img, 2, 2, $totalwidth - 3, $totalheight - 3, $color['black']);
140 for ($unit_no = 1; $unit_no <= $rackData['height']; $unit_no++)
141 {
142 for ($locidx = 0; $locidx < 3; $locidx++)
143 {
144 $colorcode = $rackData[$unit_no][$locidx]['state'];
145 if (isset ($rackData[$unit_no][$locidx]['hl']))
146 $colorcode = $colorcode . $rackData[$unit_no][$locidx]['hl'];
147 imagerectangle
148 (
149 $img,
150 $offset[$locidx],
151 3 + ($rackData['height'] - $unit_no) * 2,
152 $offset[$locidx] + $rtwidth[$locidx] - 1,
153 3 + ($rackData['height'] - $unit_no) * 2 + 1,
154 $color[$colorcode]
155 );
156 }
157 }
158 imagepng ($img);
159 imagedestroy ($img);
160 return TRUE;
161 }
162
163 function renderProgressBarImage ($done)
164 {
165 $img = @imagecreatetruecolor (100, 10);
166 switch (isset ($_REQUEST['theme']) ? $_REQUEST['theme'] : 'rackspace')
167 {
168 case 'sparenetwork':
169 $color['T'] = colorFromHex ($img, '808080');
170 $color['F'] = colorFromHex ($img, 'c0c0c0');
171 break;
172 case 'rackspace': // teal
173 default:
174 $color['T'] = colorFromHex ($img, getConfigVar ('color_T'));
175 $color['F'] = colorFromHex ($img, getConfigVar ('color_F'));
176 }
177 imagefilledrectangle ($img, 0, 0, $done, 10, $color['T']);
178 imagefilledrectangle ($img, $done, 0, 100, 10, $color['F']);
179 for ($x = 20; $x <= 80; $x += 20)
180 {
181 $cc = $x > $done ? $color['T'] : $color['F'];
182 imagesetpixel ($img, $x, 0, $cc);
183 imagesetpixel ($img, $x, 1, $cc);
184 imagesetpixel ($img, $x, 4, $cc);
185 imagesetpixel ($img, $x, 5, $cc);
186 imagesetpixel ($img, $x, 8, $cc);
187 imagesetpixel ($img, $x, 9, $cc);
188 }
189 header("Content-type: image/png");
190 imagepng ($img);
191 imagedestroy ($img);
192 }
193
194 function renderAccessDeniedImage ()
195 {
196 $img = @imagecreatetruecolor (1, 1);
197 imagefilledrectangle ($img, 0, 0, 1, 1, colorFromHex ($img, '000000'));
198 header("Content-type: image/png");
199 imagepng ($img);
200 imagedestroy ($img);
201 die;
202 }
203
204 function renderFilePreview ($file_id = 0, $mode = 'view')
205 {
206 switch ($mode)
207 {
208 case 'view':
209 // GFX files can become really big, if we uncompress them in memory just to
210 // provide a PNG version of a file. To keep things working, just send the
211 // contents as is for known MIME types.
212 $file = getFile ($file_id);
213 if (!in_array ($file['type'], array ('image/jpeg', 'image/png', 'image/gif')))
214 {
215 showError ('Invalid MIME type on file', 'inline');
216 break;
217 }
218 header("Content-type: ${file['type']}");
219 echo $file['contents'];
220 break;
221 case 'preview':
222 if($image = getFileCache($file_id)){ //Cache Hit
223 header("Content-type: image/jpeg");
224 echo $image;
225 break;
226 }
227
228 //Cache Miss
229 $file = getFile ($file_id);
230 $image = imagecreatefromstring ($file['contents']);
231 unset ($file['contents']);
232 $width = imagesx ($image);
233 $height = imagesy ($image);
234 header ('Content-type: image/jpeg');
235 if ($width > getConfigVar ('PREVIEW_IMAGE_MAXPXS') or $height > getConfigVar ('PREVIEW_IMAGE_MAXPXS'))
236 {
237 $ratio = getConfigVar ('PREVIEW_IMAGE_MAXPXS') / max ($width, $height);
238 $newwidth = $width * $ratio;
239 $newheight = $height * $ratio;
240 $resampled = imagecreatetruecolor ($newwidth, $newheight);
241 imagecopyresampled ($resampled, $image, 0, 0, 0, 0, $newwidth, $newheight, $width, $height);
242 imagedestroy ($image);
243 $image = $resampled;
244
245 //TODO: Find a better way to save the stream of the image... Output buffer seems silly.
246 ob_start();
247 imagejpeg ($image);
248 commitAddFileCache ($file_id, ob_get_flush());
249 imagedestroy ($image);
250 unset ($file);
251 unset ($resampled);
252 }
253 break;
254 default:
255 showError ('Invalid argument', 'inline');
256 break;
257 }
258 }
259
260 ?>