r4178 bugfix: PHP warnings were appearing before rackspace on SLB object page, defaul...
[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 = HTTPDateToUnixTime ($_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 HTTPDateToUnixTime ($string)
70 {
71 //Written per RFC 2616 3.3.1 - Full Date
72 //http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html
73 $month_number = array
74 (
75 'Jan' => 1,
76 'Feb' => 2,
77 'Mar' => 3,
78 'Apr' => 4,
79 'May' => 5,
80 'Jun' => 6,
81 'Jul' => 7,
82 'Aug' => 8,
83 'Sep' => 9,
84 'Oct' => 10,
85 'Nov' => 11,
86 'Dec' => 12,
87 );
88
89 $formats = array();
90 $formats['rfc1123'] = '/^(Sun|Mon|Tue|Wed|Thu|Fri|Sat), (\d{2}) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) (\d{4}) (\d{2}):(\d{2}):(\d{2}) GMT$/';
91 $formats['rfc850'] = '/^(Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday), (\d{2})-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-(\d{2}) (\d{2}):(\d{2}):(\d{2}) GMT$/';
92 $formats['asctime'] = '/^(Sun|Mon|Tue|Wed|Thu|Fri|Sat) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) (\d{2}|\d{1}) (\d{2}):(\d{2}):(\d{2}) (\d{4})$/';
93
94 $matches = array();
95 if (preg_match ($formats['rfc1123'], $string, $matches)) {
96 $hours = $matches[5];
97 $minutes = $matches[6];
98 $seconds = $matches[7];
99 $month = $month_number[$matches[3]];
100 $day = $matches[2];
101 $year = $matches[4];
102 } elseif (preg_match ($formats['rfc850'], $string, $matches)) {
103 $hours = $matches[5];
104 $minutes = $matches[6];
105 $seconds = $matches[7];
106 $month = $month_number[substr($matches[3],0,3)];
107 $day = $matches[2];
108 $year = $matches[4];
109 } elseif (preg_match ($formats['asctime'], $string, $matches)) {
110 $hours = $matches[4];
111 $minutes = $matches[5];
112 $seconds = $matches[6];
113 $month = $month_number[$matches[2]];
114 $day = $matches[3];
115 $year = $matches[7];
116 } else
117 return false;
118 return gmmktime ($hours, $minutes, $seconds, $month, $day, $year);
119 }
120
121 function renderError ()
122 {
123 header("Content-type: image/png");
124 // "ERROR", 76x17, red on white
125 echo base64_decode
126 (
127 'iVBORw0KGgoAAAANSUhEUgAAAEwAAAARCAYAAAB3h0oCAAAAAXNSR0IArs4c6QAAALBJREFUWMPt' .
128 'WFsOwCAIG4v3vzL7WEyWxQdVwM1A4l/F2iHVETPzESGOMyTAInURRP0suUhb2FIho/jWXO38w4KN' .
129 'LPDGEt2jlgPBZxFKc2o8UT7Lj6SkAmfw1nx+28MkVWQlcjT9EOwjLqnpaNImi+I1j/YSl5RY/gx+' .
130 'VCCF/MnkCz4JZQtvEUXx1nyW9jCUlPVLbTJ/3MO2dsnWRq2Nwl2wTarM51rhsVEnDhT/w7C4APaJ' .
131 'ZhkIGYaUAAAAAElFTkSuQmCC'
132 );
133 }
134
135 // Having a local caching array speeds things up. A little.
136 function colorFromHex ($image, $hex)
137 {
138 static $colorcache = array ();
139 if (isset ($colorcache[$hex]))
140 return $colorcache[$hex];
141 $r = hexdec ('0x' . substr ($hex, 0, 2));
142 $g = hexdec ('0x' . substr ($hex, 2, 2));
143 $b = hexdec ('0x' . substr ($hex, 4, 2));
144 $c = imagecolorallocate ($image, $r, $g, $b);
145 $colorcache[$hex] = $c;
146 return $c;
147 }
148
149 function renderRackThumb ($rack_id = 0)
150 {
151 // Don't call DB extra times, hence we are most probably not the
152 // only script wishing to access the same data now.
153 if (NULL !== ($thumbcache = loadThumbCache ($rack_id)))
154 {
155 header("Content-type: image/png");
156 echo $thumbcache;
157 return;
158 }
159 ob_start();
160 if (FALSE !== generateMiniRack ($rack_id))
161 {
162 $capture = ob_get_clean();
163 header("Content-type: image/png");
164 echo $capture;
165 usePreparedUpdateBlade ('Rack', array ('thumb_data' => base64_encode ($capture)), array ('id' => $rack_id));
166 return;
167 }
168 // error text in the buffer
169 ob_end_flush();
170 }
171
172 // Output a binary string containing the PNG minirack. Indicate error with return code.
173 function generateMiniRack ($rack_id)
174 {
175 if (NULL === ($rackData = spotEntity ('rack', $rack_id)))
176 return FALSE;
177 amplifyCell ($rackData);
178 markupObjectProblems ($rackData);
179 global $rtwidth;
180 $rtdepth = 9;
181 $offset[0] = 3;
182 $offset[1] = 3 + $rtwidth[0];
183 $offset[2] = 3 + $rtwidth[0] + $rtwidth[1];
184 $totalheight = 3 + 3 + $rackData['height'] * 2;
185 $totalwidth = $offset[2] + $rtwidth[2] + 3;
186 $img = @imagecreatetruecolor ($totalwidth, $totalheight)
187 or die("Cannot Initialize new GD image stream");
188 // cache our palette as well
189 $color = array();
190 foreach (array ('F', 'A', 'U', 'T', 'Th', 'Tw', 'Thw') as $statecode)
191 $color[$statecode] = colorFromHex ($img, getConfigVar ('color_' . $statecode));
192 $color['black'] = colorFromHex ($img, '000000');
193 $color['gray'] = colorFromHex ($img, 'c0c0c0');
194 imagerectangle ($img, 0, 0, $totalwidth - 1, $totalheight - 1, $color['black']);
195 imagerectangle ($img, 1, 1, $totalwidth - 2, $totalheight - 2, $color['gray']);
196 imagerectangle ($img, 2, 2, $totalwidth - 3, $totalheight - 3, $color['black']);
197 for ($unit_no = 1; $unit_no <= $rackData['height']; $unit_no++)
198 {
199 for ($locidx = 0; $locidx < 3; $locidx++)
200 {
201 $colorcode = $rackData[$unit_no][$locidx]['state'];
202 if (isset ($rackData[$unit_no][$locidx]['hl']))
203 $colorcode = $colorcode . $rackData[$unit_no][$locidx]['hl'];
204 imagerectangle
205 (
206 $img,
207 $offset[$locidx],
208 3 + ($rackData['height'] - $unit_no) * 2,
209 $offset[$locidx] + $rtwidth[$locidx] - 1,
210 3 + ($rackData['height'] - $unit_no) * 2 + 1,
211 $color[$colorcode]
212 );
213 }
214 }
215 imagepng ($img);
216 imagedestroy ($img);
217 return TRUE;
218 }
219
220 function renderProgressBarImage ($done)
221 {
222 $img = @imagecreatetruecolor (100, 10);
223 switch (isset ($_REQUEST['theme']) ? $_REQUEST['theme'] : 'rackspace')
224 {
225 case 'sparenetwork':
226 $color['T'] = colorFromHex ($img, '808080');
227 $color['F'] = colorFromHex ($img, 'c0c0c0');
228 break;
229 case 'rackspace': // teal
230 default:
231 $color['T'] = colorFromHex ($img, getConfigVar ('color_T'));
232 $color['F'] = colorFromHex ($img, getConfigVar ('color_F'));
233 }
234 imagefilledrectangle ($img, 0, 0, $done, 10, $color['T']);
235 imagefilledrectangle ($img, $done, 0, 100, 10, $color['F']);
236 for ($x = 20; $x <= 80; $x += 20)
237 {
238 $cc = $x > $done ? $color['T'] : $color['F'];
239 imagesetpixel ($img, $x, 0, $cc);
240 imagesetpixel ($img, $x, 1, $cc);
241 imagesetpixel ($img, $x, 4, $cc);
242 imagesetpixel ($img, $x, 5, $cc);
243 imagesetpixel ($img, $x, 8, $cc);
244 imagesetpixel ($img, $x, 9, $cc);
245 }
246 header("Content-type: image/png");
247 imagepng ($img);
248 imagedestroy ($img);
249 }
250
251 function renderAccessDeniedImage ()
252 {
253 $img = @imagecreatetruecolor (1, 1);
254 imagefilledrectangle ($img, 0, 0, 1, 1, colorFromHex ($img, '000000'));
255 header("Content-type: image/png");
256 imagepng ($img);
257 imagedestroy ($img);
258 die;
259 }
260
261 function renderFilePreview ($file_id = 0, $mode = 'view')
262 {
263 switch ($mode)
264 {
265 case 'view':
266 // GFX files can become really big, if we uncompress them in memory just to
267 // provide a PNG version of a file. To keep things working, just send the
268 // contents as is for known MIME types.
269 $file = getFile ($file_id);
270 if (!in_array ($file['type'], array ('image/jpeg', 'image/png', 'image/gif')))
271 {
272 renderError();
273 break;
274 }
275 header("Content-type: ${file['type']}");
276 echo $file['contents'];
277 break;
278 case 'preview':
279 if ($image = getFileCache ($file_id)) //Cache Hit
280 {
281 header("Content-type: image/jpeg");
282 echo $image;
283 break;
284 }
285 //Cache Miss
286 $file = getFile ($file_id);
287 $image = imagecreatefromstring ($file['contents']);
288 unset ($file['contents']);
289 $width = imagesx ($image);
290 $height = imagesy ($image);
291 header ('Content-type: image/jpeg');
292 if ($width > getConfigVar ('PREVIEW_IMAGE_MAXPXS') or $height > getConfigVar ('PREVIEW_IMAGE_MAXPXS'))
293 {
294 $ratio = getConfigVar ('PREVIEW_IMAGE_MAXPXS') / max ($width, $height);
295 $newwidth = $width * $ratio;
296 $newheight = $height * $ratio;
297 $resampled = imagecreatetruecolor ($newwidth, $newheight);
298 imagecopyresampled ($resampled, $image, 0, 0, 0, 0, $newwidth, $newheight, $width, $height);
299 imagedestroy ($image);
300 $image = $resampled;
301
302 //TODO: Find a better way to save the stream of the image... Output buffer seems silly.
303 ob_start();
304 imagejpeg ($image);
305 commitAddFileCache ($file_id, ob_get_flush());
306 imagedestroy ($image);
307 unset ($file);
308 unset ($resampled);
309 }
310 break;
311 default:
312 renderError();
313 break;
314 }
315 }
316
317 ?>