display MySQL warnings in debug mode
[racktables] / wwwroot / inc / interface-lib.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 // Let's have it here, so extensions can add their own images.
8 $image = array();
9 $image['rackspace']['path'] = 'pix/racks.png';
10 $image['rackspace']['width'] = 218;
11 $image['rackspace']['height'] = 200;
12 $image['objects']['path'] = 'pix/server.png';
13 $image['objects']['width'] = 218;
14 $image['objects']['height'] = 200;
15 $image['depot']['path'] = 'pix/server.png';
16 $image['depot']['width'] = 218;
17 $image['depot']['height'] = 200;
18 $image['files']['path'] = 'pix/files.png';
19 $image['files']['width'] = 218;
20 $image['files']['height'] = 200;
21 $image['ipv4space']['path'] = 'pix/addressspace.png';
22 $image['ipv4space']['width'] = 218;
23 $image['ipv4space']['height'] = 200;
24 $image['ipv6space']['path'] = 'pix/addressspacev6.png';
25 $image['ipv6space']['width'] = 218;
26 $image['ipv6space']['height'] = 200;
27 $image['ipv4slb']['path'] = 'pix/slb.png';
28 $image['ipv4slb']['width'] = 218;
29 $image['ipv4slb']['height'] = 200;
30 $image['config']['path'] = 'pix/configuration.png';
31 $image['config']['width'] = 218;
32 $image['config']['height'] = 200;
33 $image['reports']['path'] = 'pix/report.png';
34 $image['reports']['width'] = 218;
35 $image['reports']['height'] = 200;
36 $image['8021q']['path'] = 'pix/8021q.png';
37 $image['8021q']['width'] = 218;
38 $image['8021q']['height'] = 200;
39 $image['objectlog']['path'] = 'pix/crystal-mimetypes-shellscript-218x200.png';
40 $image['objectlog']['width'] = 218;
41 $image['objectlog']['height'] = 200;
42 $image['virtual']['path'] = 'pix/virtualresources.png';
43 $image['virtual']['width'] = 218;
44 $image['virtual']['height'] = 200;
45 $image['cables']['path'] = 'pix/patch_cables.png';
46 $image['cables']['width'] = 218;
47 $image['cables']['height'] = 200;
48 $image['download']['path'] = 'pix/download.png';
49 $image['download']['width'] = 16;
50 $image['download']['height'] = 16;
51 $image['DOWNLOAD']['path'] = 'pix/download-big.png';
52 $image['DOWNLOAD']['width'] = 32;
53 $image['DOWNLOAD']['height'] = 32;
54 $image['plug']['path'] = 'pix/tango-network-wired.png';
55 $image['plug']['width'] = 16;
56 $image['plug']['height'] = 16;
57 $image['cut']['path'] = 'pix/tango-edit-cut-16x16.png';
58 $image['cut']['width'] = 16;
59 $image['cut']['height'] = 16;
60 $image['Cut']['path'] = 'pix/tango-edit-cut-22x22.png';
61 $image['Cut']['width'] = 22;
62 $image['Cut']['height'] = 22;
63 $image['Cut gray']['path'] = 'pix/tango-edit-cut-22x22-gray.png';
64 $image['Cut gray']['width'] = 22;
65 $image['Cut gray']['height'] = 22;
66 $image['CUT']['path'] = 'pix/tango-edit-cut-32x32.png';
67 $image['CUT']['width'] = 32;
68 $image['CUT']['height'] = 32;
69 $image['CUT gray']['path'] = 'pix/tango-edit-cut-32x32-gray.png';
70 $image['CUT gray']['width'] = 32;
71 $image['CUT gray']['height'] = 32;
72 $image['add']['path'] = 'pix/tango-list-add.png';
73 $image['add']['width'] = 16;
74 $image['add']['height'] = 16;
75 $image['ADD']['path'] = 'pix/tango-list-add-big.png';
76 $image['ADD']['width'] = 32;
77 $image['ADD']['height'] = 32;
78 $image['delete']['path'] = 'pix/tango-list-remove.png';
79 $image['delete']['width'] = 16;
80 $image['delete']['height'] = 16;
81 $image['DELETE']['path'] = 'pix/tango-list-remove-32x32.png';
82 $image['DELETE']['width'] = 32;
83 $image['DELETE']['height'] = 32;
84 $image['destroy']['path'] = 'pix/tango-user-trash-16x16.png';
85 $image['destroy']['width'] = 16;
86 $image['destroy']['height'] = 16;
87 $image['nodestroy']['path'] = 'pix/tango-user-trash-16x16-gray.png';
88 $image['nodestroy']['width'] = 16;
89 $image['nodestroy']['height'] = 16;
90 $image['NODESTROY']['path'] = 'pix/tango-user-trash-32x32-gray.png';
91 $image['NODESTROY']['width'] = 32;
92 $image['NODESTROY']['height'] = 32;
93 $image['DESTROY']['path'] = 'pix/tango-user-trash-32x32.png';
94 $image['DESTROY']['width'] = 32;
95 $image['DESTROY']['height'] = 32;
96 $image['nodelete']['path'] = 'pix/tango-list-remove-shadow.png';
97 $image['nodelete']['width'] = 16;
98 $image['nodelete']['height'] = 16;
99 $image['inservice']['path'] = 'pix/tango-emblem-system.png';
100 $image['inservice']['width'] = 16;
101 $image['inservice']['height'] = 16;
102 $image['notinservice']['path'] = 'pix/tango-dialog-error.png';
103 $image['notinservice']['width'] = 16;
104 $image['notinservice']['height'] = 16;
105 $image['find']['path'] = 'pix/tango-system-search.png';
106 $image['find']['width'] = 16;
107 $image['find']['height'] = 16;
108 $image['next']['path'] = 'pix/tango-go-next.png';
109 $image['next']['width'] = 32;
110 $image['next']['height'] = 32;
111 $image['prev']['path'] = 'pix/tango-go-previous.png';
112 $image['prev']['width'] = 32;
113 $image['prev']['height'] = 32;
114 $image['COMMIT']['path'] = 'pix/tango-go-prev-next-32x32.png';
115 $image['COMMIT']['width'] = 32;
116 $image['COMMIT']['height'] = 32;
117 $image['COMMIT gray']['path'] = 'pix/tango-go-prev-next-gray-32x32.png';
118 $image['COMMIT gray']['width'] = 32;
119 $image['COMMIT gray']['height'] = 32;
120 $image['RECALC']['path'] = 'pix/tango-view-refresh-32x32.png';
121 $image['RECALC']['width'] = 32;
122 $image['RECALC']['height'] = 32;
123 $image['recalc']['path'] = 'pix/tango-view-refresh-16x16.png';
124 $image['recalc']['width'] = 16;
125 $image['recalc']['height'] = 16;
126 $image['clear']['path'] = 'pix/tango-edit-clear.png';
127 $image['clear']['width'] = 16;
128 $image['clear']['height'] = 16;
129 $image['CLEAR']['path'] = 'pix/tango-edit-clear-big.png';
130 $image['CLEAR']['width'] = 32;
131 $image['CLEAR']['height'] = 32;
132 $image['CLEAR gray']['path'] = 'pix/tango-edit-clear-gray-32x32.png';
133 $image['CLEAR gray']['width'] = 32;
134 $image['CLEAR gray']['height'] = 32;
135 $image['save']['path'] = 'pix/tango-document-save-16x16.png';
136 $image['save']['width'] = 16;
137 $image['save']['height'] = 16;
138 $image['SAVE']['path'] = 'pix/tango-document-save-32x32.png';
139 $image['SAVE']['width'] = 32;
140 $image['SAVE']['height'] = 32;
141 $image['NOSAVE']['path'] = 'pix/tango-document-save-32x32-gray.png';
142 $image['NOSAVE']['width'] = 32;
143 $image['NOSAVE']['height'] = 32;
144 $image['create']['path'] = 'pix/tango-document-new.png';
145 $image['create']['width'] = 16;
146 $image['create']['height'] = 16;
147 $image['CREATE']['path'] = 'pix/tango-document-new-big.png';
148 $image['CREATE']['width'] = 32;
149 $image['CREATE']['height'] = 32;
150 $image['DENIED']['path'] = 'pix/tango-dialog-error-big.png';
151 $image['DENIED']['width'] = 32;
152 $image['DENIED']['height'] = 32;
153 $image['node-collapsed']['path'] = 'pix/node-collapsed.png';
154 $image['node-collapsed']['width'] = 16;
155 $image['node-collapsed']['height'] = 16;
156 $image['node-expanded']['path'] = 'pix/node-expanded.png';
157 $image['node-expanded']['width'] = 16;
158 $image['node-expanded']['height'] = 16;
159 $image['node-expanded-static']['path'] = 'pix/node-expanded-static.png';
160 $image['node-expanded-static']['width'] = 16;
161 $image['node-expanded-static']['height'] = 16;
162 $image['dragons']['path'] = 'pix/mitsudragon.png';
163 $image['dragons']['width'] = 195;
164 $image['dragons']['height'] = 33;
165 $image['LB']['path'] = 'pix/loadbalancer.png';
166 $image['LB']['width'] = 32;
167 $image['LB']['height'] = 32;
168 $image['RS pool']['path'] = 'pix/serverpool.png';
169 $image['RS pool']['width'] = 48;
170 $image['RS pool']['height'] = 16;
171 $image['VS']['path'] = 'pix/servicesign.png';
172 $image['VS']['width'] = 39;
173 $image['VS']['height'] = 62;
174 $image['router']['path'] = 'pix/router.png';
175 $image['router']['width'] = 32;
176 $image['router']['height'] = 32;
177 $image['object']['path'] = 'pix/bracket-16x16.png';
178 $image['object']['width'] = 16;
179 $image['object']['height'] = 16;
180 $image['OBJECT']['path'] = 'pix/bracket-32x32.png';
181 $image['OBJECT']['width'] = 32;
182 $image['OBJECT']['height'] = 32;
183 $image['LOCATION']['path'] = 'pix/tango-internet-32x32.png';
184 $image['LOCATION']['width'] = 32;
185 $image['LOCATION']['height'] = 32;
186 $image['attach']['path'] = 'pix/tango-mail-attachment-16x16.png';
187 $image['attach']['width'] = 16;
188 $image['attach']['height'] = 16;
189 $image['Attach']['path'] = 'pix/tango-mail-attachment-22x22.png';
190 $image['Attach']['width'] = 22;
191 $image['Attach']['height'] = 22;
192 $image['ATTACH']['path'] = 'pix/tango-mail-attachment-32x32.png';
193 $image['ATTACH']['width'] = 32;
194 $image['ATTACH']['height'] = 32;
195 $image['favorite']['path'] = 'pix/tango-emblem-favorite.png';
196 $image['favorite']['width'] = 16;
197 $image['favorite']['height'] = 16;
198 $image['computer']['path'] = 'pix/tango-computer.png';
199 $image['computer']['width'] = 16;
200 $image['computer']['height'] = 16;
201 $image['empty file']['path'] = 'pix/crystal-file-empty-32x32.png';
202 $image['empty file']['width'] = 32;
203 $image['empty file']['height'] = 32;
204 $image['text file']['path'] = 'pix/crystal-file-text-32x32.png';
205 $image['text file']['width'] = 32;
206 $image['text file']['height'] = 32;
207 $image['image file']['path'] = 'pix/crystal-file-image-32x32.png';
208 $image['image file']['width'] = 32;
209 $image['image file']['height'] = 32;
210 $image['text']['path'] = 'pix/tango-text-x-generic-16x16.png';
211 $image['text']['width'] = 16;
212 $image['text']['height'] = 16;
213 $image['NET']['path'] = 'pix/crystal-network_local-32x32.png';
214 $image['NET']['width'] = 32;
215 $image['NET']['height'] = 32;
216 $image['net']['path'] = 'pix/crystal-network_local-16x16.png';
217 $image['net']['width'] = 16;
218 $image['net']['height'] = 16;
219 $image['USER']['path'] = 'pix/crystal-edit-user-32x32.png';
220 $image['USER']['width'] = 32;
221 $image['USER']['height'] = 32;
222 $image['setfilter']['path'] = 'pix/pgadmin3-viewfiltereddata.png';
223 $image['setfilter']['width'] = 32;
224 $image['setfilter']['height'] = 32;
225 $image['setfilter gray']['path'] = 'pix/pgadmin3-viewfiltereddata-grayscale.png';
226 $image['setfilter gray']['width'] = 32;
227 $image['setfilter gray']['height'] = 32;
228 $image['resetfilter']['path'] = 'pix/pgadmin3-viewdata.png';
229 $image['resetfilter']['width'] = 32;
230 $image['resetfilter']['height'] = 32;
231 $image['resetfilter gray']['path'] = 'pix/pgadmin3-viewdata-grayscale.png';
232 $image['resetfilter gray']['width'] = 32;
233 $image['resetfilter gray']['height'] = 32;
234 $image['knight']['path'] = 'pix/smiley_knight.png';
235 $image['knight']['width'] = 72;
236 $image['knight']['height'] = 33;
237 $image['Zoom']['path'] = 'pix/tango-system-search-22x22.png';
238 $image['Zoom']['width'] = 22;
239 $image['Zoom']['height'] = 22;
240 $image['Zooming']['path'] = 'pix/tango-view-fullscreen-22x22.png';
241 $image['Zooming']['width'] = 22;
242 $image['Zooming']['height'] = 22;
243 $image['UNLOCK']['path'] = 'pix/crystal-actions-unlock-32x32.png';
244 $image['UNLOCK']['width'] = 32;
245 $image['UNLOCK']['height'] = 32;
246 $image['CLOCK']['path'] = 'pix/tango-appointment-32x32.png';
247 $image['CLOCK']['width'] = 32;
248 $image['CLOCK']['height'] = 32;
249 $image['DQUEUE done']['path'] = 'pix/crystal-ok-32x32.png';
250 $image['DQUEUE done']['width'] = 32;
251 $image['DQUEUE done']['height'] = 32;
252 $image['DQUEUE sync_aging']['path'] = 'pix/tango-appointment-32x32.png';
253 $image['DQUEUE sync_aging']['width'] = 32;
254 $image['DQUEUE sync_aging']['height'] = 32;
255 $image['DQUEUE resync_aging']['path'] = 'pix/tango-appointment-32x32.png';
256 $image['DQUEUE resync_aging']['width'] = 32;
257 $image['DQUEUE resync_aging']['height'] = 32;
258 $image['DQUEUE sync_ready']['path'] = 'pix/tango-emblem-system-32x32.png';
259 $image['DQUEUE sync_ready']['width'] = 32;
260 $image['DQUEUE sync_ready']['height'] = 32;
261 $image['DQUEUE resync_ready']['path'] = 'pix/tango-emblem-important-32x32.png';
262 $image['DQUEUE resync_ready']['width'] = 32;
263 $image['DQUEUE resync_ready']['height'] = 32;
264 $image['DQUEUE failed']['path'] = 'pix/tango-emblem-unreadable-32x32.png';
265 $image['DQUEUE failed']['width'] = 32;
266 $image['DQUEUE failed']['height'] = 32;
267 $image['DQUEUE disabled']['path'] = 'pix/tango-emblem-readonly-32x32.png';
268 $image['DQUEUE disabled']['width'] = 32;
269 $image['DQUEUE disabled']['height'] = 32;
270 $image['copy']['path'] = 'pix/tango-edit-copy-16x16.png';
271 $image['copy']['width'] = 16;
272 $image['copy']['height'] = 16;
273 $image['COPY']['path'] = 'pix/tango-edit-copy-32x32.png';
274 $image['COPY']['width'] = 32;
275 $image['COPY']['height'] = 32;
276 $image['html']['path'] = 'pix/tango-text-html.png';
277 $image['html']['width'] = 16;
278 $image['html']['height'] = 16;
279 $image['pencil']['path'] = 'pix/pencil-icon.png';
280 $image['pencil']['width'] = 12;
281 $image['pencil']['height'] = 12;
282 $image['link up']['path'] = 'pix/link-up.png';
283 $image['link up']['width'] = 16;
284 $image['link up']['height'] = 16;
285 $image['link down']['path'] = 'pix/link-down.png';
286 $image['link down']['width'] = 16;
287 $image['link down']['height'] = 16;
288 $image['link disabled']['path'] = 'pix/link-disabled.png';
289 $image['link disabled']['width'] = 16;
290 $image['link disabled']['height'] = 16;
291 $image['16x16t']['path'] = 'pix/1x1t.gif';
292 $image['16x16t']['width'] = 16;
293 $image['16x16t']['height'] = 16;
294
295 $page_by_realm = array();
296 $page_by_realm['object'] = 'depot';
297 $page_by_realm['rack'] = 'rackspace';
298 $page_by_realm['ipv4net'] = 'ipv4space';
299 $page_by_realm['ipv6net'] = 'ipv6space';
300 $page_by_realm['ipv4vs'] = 'ipv4slb';
301 $page_by_realm['ipv4rspool'] = 'ipv4slb';
302 $page_by_realm['file'] = 'files';
303 $page_by_realm['user'] = 'userlist';
304
305 function getSelectOptions ($options, $selected_id = NULL)
306 {
307 $ret = '';
308 foreach ($options as $key => $value)
309 {
310 $selected = is_array ($selected_id) ? in_array ($key, $selected_id) : $key == $selected_id;
311 $ret .= "<option value='${key}'" . ($selected ? ' selected' : '') . '>';
312 $ret .= stringForOption ($value) . '</option>';
313 }
314 return $ret;
315 }
316
317 function printSelect ($optionList, $select_attrs = array(), $selected_id = NULL)
318 {
319 echo getSelect ($optionList, $select_attrs, $selected_id);
320 }
321
322 // $selected_id can be an array if you want to use multiselect
323 // in order to use multiselect $select_attrs should contain smth like this:
324 // [ 'name' => 'some_name[]', 'multiple' => 'multiple', 'size' => 5 ]
325 // Input array keys are OPTION VALUEs and input array values are OPTION text.
326 function getSelect ($optionList, $select_attrs = array(), $selected_id = NULL, $treat_single_special = TRUE)
327 {
328 $ret = '';
329 if (!array_key_exists ('name', $select_attrs))
330 return '';
331 // handle two corner cases in a specific way
332 if (count ($optionList) == 0)
333 return '(none)';
334 if (count ($optionList) == 1 && $treat_single_special)
335 {
336 foreach ($optionList as $key => $value)
337 break;
338 return "<input type=hidden name=${select_attrs['name']} id=${select_attrs['name']} value=${key}>" .
339 stringForLabel ($value, 64);
340 }
341 if (!array_key_exists ('id', $select_attrs))
342 $select_attrs['id'] = $select_attrs['name'];
343 $ret .= '<select';
344 foreach ($select_attrs as $attr_name => $attr_value)
345 $ret .= " ${attr_name}=${attr_value}";
346 $ret .= '>' . getSelectOptions ($optionList, $selected_id) . '</select>';
347 return $ret;
348 }
349
350 function printNiftySelect ($groupList, $select_attrs = array(), $selected_id = NULL)
351 {
352 echo getNiftySelect ($groupList, $select_attrs, $selected_id);
353 }
354
355 // Input is a cooked list of OPTGROUPs, each with own sub-list of OPTIONs in the same
356 // format as printSelect() expects.
357 // If tree is true, hierarchical drop-boxes are used, otherwise optgroups are used.
358 function getNiftySelect ($groupList, $select_attrs, $selected_id = NULL)
359 {
360 // special treatment for ungrouped data
361 if (count ($groupList) == 1 && isset ($groupList['other']))
362 return getSelect ($groupList['other'], $select_attrs, $selected_id);
363 if (!array_key_exists ('name', $select_attrs))
364 return '';
365 if (!array_key_exists ('id', $select_attrs))
366 $select_attrs['id'] = $select_attrs['name'];
367
368 $ret = '<select';
369 foreach ($select_attrs as $attr_name => $attr_value)
370 $ret .= " ${attr_name}=${attr_value}";
371 $ret .= ">\n";
372 foreach ($groupList as $groupname => $groupdata)
373 {
374 $ret .= "<optgroup label='${groupname}'>\n";
375 foreach ($groupdata as $dict_key => $dict_value)
376 {
377 if (is_array ($selected_id))
378 $is_selected = in_array ($dict_key, $selected_id);
379 else
380 $is_selected = $dict_key == $selected_id;
381 $ret .= "<option value='${dict_key}'" . ($is_selected ? ' selected' : '') . ">${dict_value}</option>\n";
382 }
383 $ret .= "</optgroup>\n";
384 }
385 $ret .= "</select>\n";
386 return $ret;
387 }
388
389 function getOptionTree ($tree_name, $tree_options, $tree_config = array())
390 {
391 $default_config = array
392 (
393 'choose' => 'select...',
394 'empty_value' => '',
395 'indexed' => true,
396 );
397 addJS ('js/jquery.optionTree.js');
398 addJS ("
399 $(function() {
400 var option_tree = " . json_encode ($tree_options) . ";
401 var options = " . json_encode ($tree_config + $default_config) . ";
402 $('input[name=${tree_name}]').optionTree(option_tree, options);
403 });
404 ", TRUE);
405
406 return "<input type=hidden name=${tree_name}>";
407 }
408
409 function printImageHREF ($tag, $title = '', $do_input = FALSE)
410 {
411 echo getImageHREF ($tag, $title, $do_input);
412 }
413
414 // this would be better called mkIMG(), make "IMG" HTML element
415 function getImageHREF ($tag, $title = '', $do_input = FALSE)
416 {
417 global $image;
418 $attrs = array
419 (
420 'src' => array_key_exists ($tag, $image) ?
421 '?module=chrome&uri=' . $image[$tag]['path'] :
422 '?module=image&img=error',
423 'border' => 0,
424 );
425 if ($title != '')
426 $attrs['title'] = $title;
427 if ($do_input)
428 {
429 $element = 'input';
430 $attrs['type'] = 'image';
431 $attrs['name'] = 'submit';
432 $attrs['class'] = 'icon';
433 // Width and height for INPUT only appear in HTML 5.
434 }
435 else
436 {
437 $element = 'img';
438 if (array_key_exists ($tag, $image))
439 {
440 $attrs['width'] = $image[$tag]['width'];
441 $attrs['height'] = $image[$tag]['height'];
442 }
443 }
444 return makeHtmlTag ($element, $attrs);
445 }
446
447 function escapeString ($value, $do_db_escape = FALSE)
448 {
449 $ret = htmlspecialchars ($value, ENT_QUOTES, 'UTF-8');
450 if ($do_db_escape)
451 {
452 global $dbxlink;
453 $ret = substr ($dbxlink->quote ($ret), 1, -1);
454 }
455 return $ret;
456 }
457
458 function transformRequestData()
459 {
460 global $sic;
461 // Magic quotes feature is deprecated, but just in case the local system
462 // still has it activated, reverse its effect.
463 $do_magic_quotes = function_exists ('get_magic_quotes_gpc') && get_magic_quotes_gpc();
464 $seen_keys = array();
465
466 // Escape any globals before we ever try to use them, but keep a copy of originals.
467 $sic = array();
468 // walk through merged GET and POST instead of REQUEST array because it
469 // can contain cookies with data that could not be decoded from UTF-8
470 foreach (($_POST + $_GET) as $key => $value)
471 {
472 if (is_array ($value))
473 $_REQUEST[$key] = $value;
474 else
475 {
476 $value = dos2unix ($value);
477 if ($do_magic_quotes)
478 $value = stripslashes ($value);
479 $_REQUEST[$key] = escapeString ($value);
480 }
481 $sic[$key] = $value;
482 $seen_keys[$key] = 1;
483 }
484
485 // delete cookie information from the $_REQUEST array
486 foreach (array_keys ($_REQUEST) as $key)
487 if (! isset ($seen_keys[$key]))
488 unset ($_REQUEST[$key]);
489
490 if (isset ($_SERVER['PHP_AUTH_USER']))
491 $_SERVER['PHP_AUTH_USER'] = escapeString ($_SERVER['PHP_AUTH_USER']);
492 if (isset ($_SERVER['REMOTE_USER']))
493 $_SERVER['REMOTE_USER'] = escapeString ($_SERVER['REMOTE_USER']);
494 }
495
496 // JS scripts should be included through this function.
497 // They automatically appear in the <head> of your page.
498 // $data is a JS filename, or JS code w/o tags around, if $inline = TRUE
499 // Scripts are included in the order of adding within the same group, and groups are sorted alphabetically.
500 function addJS ($data, $inline = FALSE, $group = 'default')
501 {
502 static $javascript = array();
503 static $seen_data = array();
504
505 if (! isset ($data))
506 {
507 ksort ($javascript);
508 return $javascript;
509 }
510 // Add jquery.js and racktables.js the first time a Javascript file is added.
511 if (! count ($javascript))
512 {
513 $javascript = array
514 (
515 'a_core' => array
516 (
517 array('type' => 'file', 'script' => 'js/jquery-1.4.4.min.js'),
518 array('type' => 'file', 'script' => 'js/racktables.js'),
519 ),
520 );
521
522 // initialize core js filelist
523 foreach ($javascript as $group_name => $group_array)
524 foreach ($group_array as $item)
525 if ($item['type'] == 'file')
526 $seen_data[$item['script']] = 1;
527 }
528
529 if (! isset ($seen_data[$data]))
530 {
531 $javascript[$group][] = array
532 (
533 'type' => $inline ? 'inline' : 'file',
534 'script' => $data,
535 );
536 $seen_data[$data] = 1;
537 }
538 }
539
540 // CSS styles should be included through this function.
541 // They automatically appear in the <head> of your page.
542 // $data is a CSS filename, or CSS code w/o tags around, if $inline = TRUE
543 // Styles are included in the order of adding.
544 function addCSS ($data, $inline = FALSE)
545 {
546 static $styles = array();
547 static $seen_data = array();
548
549 if (! isset ($data))
550 return $styles;
551 if (! isset ($seen_data[$data]))
552 {
553 $styles[] = array
554 (
555 'type' => $inline ? 'inline' : 'file',
556 'style' => $data,
557 );
558 $seen_data[$data] = 1;
559 }
560 }
561
562 function getRenderedIPNetCapacity ($range)
563 {
564 switch (strlen ($range['ip_bin']))
565 {
566 case 4: return getRenderedIPv4NetCapacity ($range);
567 case 16: return getRenderedIPv6NetCapacity ($range);
568 default: throw new InvalidArgException ('range["ip_bin"]', $range['ip_bin'], "Invalid binary IP");
569 }
570 }
571
572 function getRenderedIPv4NetCapacity ($range)
573 {
574 $class = 'net-usage';
575 if (isset ($range['own_addrlist']))
576 {
577 // full mode
578 // $a is "aquamarine zone", $b is "gray zone"
579 $total = ip4_range_size ($range);
580
581 // compute $a_total: own range size, without subranges
582 if (! isset ($range['kidc']) || $range['kidc'] == 0)
583 $a_total = $total;
584 else
585 {
586 $a_total = 0;
587 foreach ($range['spare_ranges'] as $mask => $spare_list)
588 $a_total = bcadd ($a_total, bcmul (count ($spare_list), ip4_mask_size ($mask)), 0);
589 }
590 $a_used = markupIPAddrList ($range['own_addrlist']);
591 $b_total = bcsub ($total, $a_total, 0);
592 $b_used = markupIPAddrList ($range['addrlist']) - $a_used;
593
594 // generate link to progress bar image
595 $width = 100;
596 if ($total != 0)
597 {
598 $px_a = round (bcdiv ($a_total, $total, 4) * $width);
599 $px1 = round (bcdiv ($a_used, $total, 4) * $width);
600 $px2 = $px_a - $px1;
601 $px3 = round (bcdiv ($b_used, $total, 4) * $width);
602 if ($px3 + $px1 + $px2 > $width)
603 $px3 = $width - $px1 - $px2;
604 }
605 else
606 $px1 = $px2 = $px3 = 0;
607
608 $title_items = array();
609 $title2_items = array();
610 if ($a_total != 0)
611 {
612 $title_items[] = "$a_used / $a_total";
613 $title2_items[] = sprintf ("%d%% used", bcdiv ($a_used, $a_total, 4) * 100);
614 }
615 if ($b_total != 0)
616 {
617 $title_items[] = ($b_used ? "$b_used / " : "") . $b_total;
618 $title2_items[] = sprintf ("%d%% sub-allocated", bcdiv ($b_total, $total, 4) * 100);
619 }
620 $title = implode (', ', $title_items);
621 $title2 = implode (', ', $title2_items);
622 $text = "<img width='$width' height=10 border=0 title='$title2' src='?module=progressbar4&px1=$px1&px2=$px2&px3=$px3'>" .
623 " <small class='title'>$title</small>";
624 }
625 else
626 {
627 // fast mode
628 $class .= ' pending';
629 addJS ('js/net-usage.js');
630
631 $free_text = '';
632 if (isset ($range['kidc']) && $range['kidc'] > 0)
633 {
634 $free_masks = array_keys ($range['spare_ranges']);
635 sort ($free_masks, SORT_NUMERIC);
636 if ($mask = array_shift ($free_masks))
637 {
638 $cnt = count ($range['spare_ranges'][$mask]);
639 $free_text = ', ' . ($cnt > 1 ? "<small>${cnt}&times;</small>" : "") . "/$mask free";
640 }
641 }
642 $text = ip4_range_size ($range) . $free_text;
643 }
644
645 $div_id = $range['ip'] . '/' . $range['mask'];
646
647 return "<div class=\"$class\" id=\"$div_id\">" . $text . "</div>";
648 }
649
650 function getRenderedIPv6NetCapacity ($range)
651 {
652 $div_id = $range['ip'] . '/' . $range['mask'];
653 $class = 'net-usage';
654 if (isset ($range['addrlist']))
655 $used = markupIPAddrList ($range['addrlist']);
656 else
657 {
658 $used = NULL;
659 $class .= ' pending';
660 addJS ('js/net-usage.js');
661 }
662
663 static $prefixes = array
664 (
665 0 => '',
666 3 => 'k',
667 6 => 'M',
668 9 => 'G',
669 12 => 'T',
670 15 => 'P',
671 18 => 'E',
672 21 => 'Z',
673 24 => 'Y',
674 );
675
676 if ($range['mask'] <= 64)
677 {
678 $what = 'net';
679 $preposition = 'in';
680 $range['mask'] += 64;
681 }
682 else
683 {
684 $what = 'IP';
685 $preposition = 'of';
686 }
687 $what .= (0 == $range['mask'] % 64 ? '' : 's');
688 $addrc = isset ($used) ? "$used $preposition " : '';
689
690 $dec_order = intval ((128 - $range['mask']) / 10) * 3;
691 $mult = isset ($prefixes[$dec_order]) ? $prefixes[$dec_order] : '??';
692
693 $cnt = 1 << ((128 - $range['mask']) % 10);
694 if ($cnt == 1 && $mult == '')
695 $cnt = '1';
696
697 return "<div class=\"$class\" id=\"$div_id\">" . "{$addrc}${cnt}${mult} ${what}" . "</div>";
698 }
699
700 // print part of HTML HEAD block
701 function printPageHeaders ()
702 {
703 global $pageheaders;
704 ksort ($pageheaders);
705 foreach ($pageheaders as $s)
706 echo $s . "\n";
707 // add tabindex to all input forms
708 addJS ('js/tabindex_auto.js', FALSE);
709
710 // add CSS styles
711 foreach (addCSS (NULL) as $item)
712 if ($item['type'] == 'inline')
713 echo '<style type="text/css">' . "\n" . trim ($item['style'], "\r\n") . "\n</style>\n";
714 elseif ($item['type'] == 'file')
715 echo "<link rel=stylesheet type='text/css' href='?module=chrome&uri=${item['style']}' />\n";
716
717 // add JS scripts
718 foreach (addJS (NULL) as $group_name => $js_list)
719 foreach ($js_list as $item)
720 if ($item['type'] == 'inline')
721 echo '<script type="text/javascript">' . "\n" . trim ($item['script'], "\r\n") . "\n</script>\n";
722 elseif ($item['type'] == 'file')
723 echo "<script type='text/javascript' src='?module=chrome&uri=${item['script']}'></script>\n";
724 }
725
726 function cmpTags ($a, $b)
727 {
728 global $taglist;
729 if (isset ($a['id']) && isset ($b['id']))
730 {
731 $a_root = array_first ($taglist[$a['id']]['trace']);
732 $b_root = array_first ($taglist[$b['id']]['trace']);
733 if ($a_root < $b_root)
734 return -1;
735 elseif ($a_root > $b_root)
736 return 1;
737 }
738 elseif (isset ($a['id']))
739 return -1;
740 elseif (isset ($b['id']))
741 return 1;
742
743 return strcmp ($a['tag'], $b['tag']);
744 }
745
746 function getTagClassName ($tagid)
747 {
748 global $taglist;
749
750 $class = '';
751 foreach ($taglist[$tagid]['trace'] as $parent)
752 $class .= 'tag-' . $parent . ' ';
753 $class .= 'tag-' . $tagid . ' etag-' . $tagid;
754
755 return $class;
756 }
757
758 function serializeTags ($chain, $baseurl = '')
759 {
760 global $taglist;
761 $tmp = array();
762 usort ($chain, 'cmpTags');
763 foreach ($chain as $taginfo)
764 {
765 $title = '';
766 if (isset ($taginfo['user']) && isset ($taginfo['time']))
767 $title = htmlspecialchars ($taginfo['user'] . ', ' . formatAge ($taginfo['time']), ENT_QUOTES);
768 if (isset($taginfo['parent_id']))
769 {
770 $parent_info = array();
771 foreach ($taglist[$taginfo['id']]['trace'] as $tag_id)
772 $parent_info[] = $taglist[$tag_id]['tag'];
773 $parent_info[] = $taginfo['tag'];
774 if ($title != '')
775 $title .= "\n";
776 $title .= implode (" &rarr; ", $parent_info);
777 }
778 if ($title != '')
779 $title = "title='$title'";
780
781 $class = '';
782 if (isset ($taginfo['id']))
783 $class = 'class="' . getTagClassName ($taginfo['id']) . '"';
784
785 $href = '';
786 if ($baseurl == '')
787 $tag = 'span';
788 else
789 {
790 $tag = 'a';
791 $href = "href='${baseurl}cft[]=${taginfo['id']}'";
792 }
793 $tmp[] = "<$tag $href $title $class>" . $taginfo['tag'] . "</$tag>";
794 }
795 return implode (', ', $tmp);
796 }
797
798 function startPortlet ($title = '')
799 {
800 echo "<div class=portlet><h2>${title}</h2>";
801 }
802
803 function finishPortlet ()
804 {
805 echo "</div>\n";
806 }
807
808 function getPageName ($page_code)
809 {
810 global $page;
811 $title = isset ($page[$page_code]['title']) ? $page[$page_code]['title'] : callHook ('dynamic_title_decoder', $page_code);
812 if (is_array ($title))
813 $title = $title['name'];
814 return $title;
815 }
816
817 function printTagTRs ($cell, $baseurl = '')
818 {
819 if (getConfigVar ('SHOW_EXPLICIT_TAGS') == 'yes' && count ($cell['etags']))
820 {
821 echo "<tr><th width='50%' class=tagchain>Explicit tags:</th><td class=tagchain>";
822 echo serializeTags ($cell['etags'], $baseurl) . "</td></tr>\n";
823 }
824 if (getConfigVar ('SHOW_IMPLICIT_TAGS') == 'yes' && count ($cell['itags']))
825 {
826 echo "<tr><th width='50%' class=tagchain>Implicit tags:</th><td class=tagchain>";
827 echo serializeTags ($cell['itags'], $baseurl) . "</td></tr>\n";
828 }
829 if (getConfigVar ('SHOW_AUTOMATIC_TAGS') == 'yes' && count ($cell['atags']))
830 {
831 echo "<tr><th width='50%' class=tagchain>Automatic tags:</th><td class=tagchain>";
832 echo serializeTags ($cell['atags']) . "</td></tr>\n";
833 }
834 }
835
836 // stub function to override it by chain-connected hooks
837 function modifyEntitySummary ($cell, $summary)
838 {
839 return $summary;
840 }
841
842 // renders 'summary' portlet, which persist on default tab of every realm page.
843 // $values is a tricky array.
844 // if its value is a string, it is treated as right td inner html, and the key is treated as left th text, colon appends there automatically.
845 // 'tags' key has a special meaning: instead of value, the result of printTagTRs call is appended to output
846 // if the value is a single-element array, its value rendered as-is instead of <tr> tag and all its contents.
847 // if the value is an array, its first 2 items are treated as left and right contents of row, no colon is appended. Used to enable non-unique titles
848 function renderEntitySummary ($cell, $title, $values = array())
849 {
850 global $page_by_realm;
851 // allow plugins to override summary table
852 $values = callHook ('modifyEntitySummary', $cell, $values);
853
854 startPortlet ($title);
855 echo "<table border=0 cellspacing=0 cellpadding=3 width='100%'>\n";
856 foreach ($values as $name => $value)
857 {
858 if (is_array ($value) && count ($value) == 1)
859 {
860 $value = array_shift ($value);
861 echo $value;
862 continue;
863 }
864 if (is_array ($value))
865 {
866 $name = array_shift ($value);
867 $value = array_shift ($value);
868 }
869 elseif (! is_array ($value))
870 $name .= ':';
871 $class = 'tdright';
872 $m = array();
873 if (preg_match('/^\{(.*?)\}(.*)/', $name, $m))
874 {
875 $class .= ' ' . $m[1];
876 $name = $m[2];
877 }
878 if ($name == 'tags:')
879 {
880 $baseurl = '';
881 if (isset ($page_by_realm[$cell['realm']]))
882 $baseurl = makeHref(array('page'=>$page_by_realm[$cell['realm']], 'tab'=>'default'))."&";
883 printTagTRs ($cell, $baseurl);
884 }
885 else
886 echo "<tr><th width='50%' class='$class'>$name</th><td class=tdleft>$value</td></tr>";
887 }
888 echo "</table>\n";
889 finishPortlet();
890 }
891
892 function getOpLink ($params, $title, $img_name = '', $comment = '', $class = '')
893 {
894 if (isset ($params))
895 {
896 $ret = '<a href="' . makeHrefProcess ($params) . '"';
897 $class .= ' input';
898 }
899 else
900 {
901 $ret = '<a href="#" onclick="return false;"';
902 $class .= ' noclick';
903 }
904 if ($comment != '')
905 $ret .= ' title="' . htmlspecialchars ($comment, ENT_QUOTES) . '"';
906 $class = trim ($class);
907 if ($class != '')
908 $ret .= ' class="' . htmlspecialchars ($class, ENT_QUOTES) . '"';
909 $ret .= '>';
910 if ($img_name != '')
911 {
912 $ret .= getImageHREF ($img_name, $comment);
913 if ($title != '')
914 $ret .= ' ';
915 }
916 if (FALSE !== strpos ($class, 'need-confirmation'))
917 addJS ('js/racktables.js');
918 $ret .= $title . '</a>';
919 return $ret;
920 }
921
922 function getPopupLink ($helper, $params, $window_name = '', $img_name = '', $title = '', $comment = '', $class = '')
923 {
924 $ret = '';
925 $popup_args = 'height=700, width=700, location=no, menubar=no, resizable=yes, scrollbars=yes, status=no, titlebar=no, toolbar=no';
926 $ret .= '<a href="#"';
927 $class = trim ($class);
928 if ($class != '')
929 $ret .= ' class="' . htmlspecialchars ($class, ENT_QUOTES) . '"';
930 if ($comment != '')
931 $ret .= 'title="' . htmlspecialchars ($comment, ENT_QUOTES) . '"';
932 $href = makeHref (array ('module' => 'popup', 'helper' => $helper) + makePageParams ($params));
933 $ret .= " onclick=\"window.open('$href', '$window_name', '$popup_args'); return false\">";
934
935 if ($img_name != '')
936 {
937 $ret .= getImageHREF ($img_name, $comment);
938 if ($title != '')
939 $ret .= ' ';
940 }
941 $ret .= $title;
942 $ret .= '</a>';
943 return $ret;
944 }
945
946 function renderProgressBar ($percentage = 0, $theme = '', $inline = FALSE)
947 {
948 echo getProgressBar ($percentage, $theme, $inline);
949 }
950
951 function getProgressBar ($percentage = 0, $theme = '', $inline = FALSE)
952 {
953 $done = ((int) ($percentage * 100));
954 if (! $inline)
955 $src = "?module=progressbar&done=$done" . (empty ($theme) ? '' : "&theme=${theme}");
956 else
957 {
958 $bk_request = $_REQUEST;
959 $_REQUEST['theme'] = $theme;
960 $src = 'data:image/png;base64,' . chunk_split (base64_encode (getOutputOf ('renderProgressBarImage', $done)));
961 $_REQUEST = $bk_request;
962 }
963 $ret = "<img width=100 height=10 border=0 title='${done}%' src='$src'>";
964 return $ret;
965 }
966
967 function renderNetVLAN ($cell)
968 {
969 echo getRenderedNetVLAN ($cell);
970 }
971
972 function getRenderedNetVLAN ($cell)
973 {
974 if (empty ($cell['8021q']))
975 return;
976 $links = array();
977 foreach ($cell['8021q'] as $vi)
978 {
979 $vlan_info = getVlanRow ("${vi['domain_id']}-${vi['vlan_id']}");
980 $links[] = formatVLANAsShortLink ($vlan_info);
981 }
982 $noun = count ($cell['8021q']) > 1 ? 'VLANs' : 'VLAN';
983 return "<div class='vlan'><strong><small>${noun}</small> " . implode (', ', $links) . '</strong></div>';
984 }
985
986 function includeJQueryUI ($do_css = TRUE)
987 {
988 addJS ('js/jquery-ui-1.8.21.min.js');
989 if ($do_css)
990 addCSS ('css/jquery-ui-1.8.22.redmond.css');
991 }
992
993 function getRenderedIPPortPair ($ip, $port = NULL)
994 {
995 return "<a href=\"" .
996 makeHref (array ('page' => 'ipaddress', 'tab'=>'default', 'ip' => $ip)) .
997 "\">" . $ip . "</a>" .
998 (isset ($port) ? ":" . $port : "");
999 }
1000
1001 // Print common operation form prologue, include bypass argument, if
1002 // appropriate, and some extra hidden inputs, if requested.
1003 // Use special encoding for upload forms
1004 function printOpFormIntro ($opname, $extra = array(), $upload = FALSE)
1005 {
1006 global $pageno, $tabno, $page;
1007
1008 echo "<form method=post id=${opname} name=${opname} action='?module=redirect&page=${pageno}&tab=${tabno}&op=${opname}'";
1009 if ($upload)
1010 echo " enctype='multipart/form-data'";
1011 echo ">";
1012 fillBypassValues ($pageno, $extra);
1013 foreach ($extra as $inputname => $inputvalue)
1014 printf ('<input type=hidden name="%s" value="%s">', htmlspecialchars ($inputname, ENT_QUOTES), htmlspecialchars ($inputvalue, ENT_QUOTES));
1015 }
1016
1017
1018 // Display hrefs for all of a file's parents. If scissors are requested,
1019 // prepend cutting button to each of them.
1020 function serializeFileLinks ($links, $scissors = FALSE)
1021 {
1022 $comma = '';
1023 $ret = '';
1024 foreach ($links as $link_id => $li)
1025 {
1026 $cell = spotEntity ($li['entity_type'], $li['entity_id']);
1027 $ret .= $comma;
1028 if ($scissors)
1029 $ret .= getOpLink (array('op'=>'unlinkFile', 'link_id'=>$link_id), '', 'cut', 'Unlink file') . ' ';
1030 $ret .= mkCellA ($cell);
1031 $comma = '<br>';
1032 }
1033 return $ret;
1034 }
1035
1036 function makeFileDownloadButton ($file_id, $imgname = 'download')
1037 {
1038 $href = makeHref (array ('module' => 'download', 'file_id' => $file_id));
1039 $img = getImageHREF ($imgname, 'download file');
1040 return "<a href='${href}'>${img}</a>";
1041 }
1042
1043 // XXX: in new code please use one of the stringFor... functions below
1044 //
1045 // This is a dual-purpose formating function:
1046 // 1. Replace empty strings with nbsp.
1047 // 2. Cut strings that are too long: append "cut here" indicator and provide a mouse hint.
1048 function niftyString ($string, $maxlen = 30, $usetags = TRUE)
1049 {
1050 $cutind = '&hellip;'; // length is 1
1051 if ($string == '')
1052 return '&nbsp;';
1053 // a tab counts for a space
1054 $string = preg_replace ("/\t/", ' ', $string);
1055 if (! $maxlen || mb_strlen ($string) <= $maxlen)
1056 return htmlspecialchars ($string, ENT_QUOTES, 'UTF-8');
1057 return
1058 ($usetags ? ("<span title='" . htmlspecialchars ($string, ENT_QUOTES, 'UTF-8') . "'>") : '') .
1059 str_replace (' ', '&nbsp;', htmlspecialchars (mb_substr ($string, 0, $maxlen - 1), ENT_QUOTES, 'UTF-8')) .
1060 $cutind .
1061 ($usetags ? '</span>' : '');
1062 }
1063
1064 // "Some text, %s, some more text."
1065 function stringForLabel ($string, $maxlen = 30)
1066 {
1067 // A tab counts for a space.
1068 $string = preg_replace ("/\t/", ' ', $string);
1069 $full = htmlspecialchars ($string, ENT_QUOTES, 'UTF-8');
1070 if ($maxlen == 0 || mb_strlen ($string) <= $maxlen)
1071 return $full;
1072 $trimmed = mb_substr ($string, 0, $maxlen - 1);
1073 $trimmed = htmlspecialchars ($trimmed, ENT_QUOTES, 'UTF-8');
1074 $trimmed = str_replace (' ', '&nbsp;', $trimmed) . '&hellip;';
1075 return "<span title='${full}'>${trimmed}</span>";
1076 }
1077
1078 // "<TD>%s</TD>"
1079 function stringForTD ($string, $maxlen = 30)
1080 {
1081 // The non-breaking space helps the TD to render properly.
1082 return $string == '' ? '&nbsp;' : stringForLabel ($string, $maxlen);
1083 }
1084
1085 // "<INPUT type=text value='%s'>"
1086 function stringForTextInputValue ($string, $maxlen = 30)
1087 {
1088 if ($maxlen != 0)
1089 $string = mb_substr ($string, 0, $maxlen);
1090 return htmlspecialchars ($string, ENT_QUOTES, 'UTF-8');
1091 }
1092
1093 // "<TEXTAREA>%s</TEXTAREA>"
1094 function stringForTextarea ($string)
1095 {
1096 return htmlspecialchars ($string, ENT_QUOTES, 'UTF-8');
1097 }
1098
1099 // <OPTION>%s</OPTION>
1100 function stringForOption ($string, $maxlen = 80)
1101 {
1102 $string = preg_replace ("/\t/", ' ', $string);
1103 if ($maxlen == 0 || mb_strlen ($string) <= $maxlen)
1104 return htmlspecialchars ($string, ENT_QUOTES, 'UTF-8');
1105 $string = mb_substr ($string, 0, $maxlen - 1);
1106 return htmlspecialchars ($string, ENT_QUOTES, 'UTF-8') . '&hellip;';
1107 }
1108
1109 function printTagsPicker ($preselect=NULL)
1110 {
1111 global $taglist;
1112 if (! count ($taglist))
1113 {
1114 printf ('(None exist yet, %s?)', mkA ('configure', 'tagtree', NULL, 'edit'));
1115 return;
1116 }
1117 printTagsPickerInput ();
1118 printTagsPickerUl ($preselect);
1119 enableTagsPicker ();
1120 }
1121
1122 function printTagsPickerInput ($input_name="taglist")
1123 {
1124 # use data-attribute as identifier for tagit
1125 echo "<input type='text' data-tagit-valuename='" . $input_name . "' data-tagit='yes' placeholder='new tags here...' class='ui-autocomplete-input' autocomplete='off' role='textbox' aria-autocomplete='list' aria-haspopup='true'>";
1126 echo "<span title='show tag tree' class='icon-folder-open tagit_input_" . $input_name . "'></span>";
1127 }
1128
1129 function printTagsPickerUl ($preselect=NULL, $input_name="taglist")
1130 {
1131 global $target_given_tags;
1132 if ($preselect === NULL)
1133 $preselect = $target_given_tags;
1134 foreach ($preselect as $key => $value) # readable time format
1135 $preselect[$key]['time_parsed'] = formatAge ($value['time']);
1136 usort ($preselect, 'cmpTags');
1137 $preselect_hidden = "";
1138 foreach ($preselect as $value){
1139 $preselect_hidden .= "<input type=hidden name=" . $input_name . "[] value=" . $value['id'] . ">";
1140 }
1141 echo $preselect_hidden; # print preselected tags id that used in case javascript problems
1142 echo "<ul data-tagit='yes' data-tagit-valuename='" . $input_name . "' data-tagit-preselect='" . json_encode($preselect) . "' class='tagit-vertical'></ul>";
1143 }
1144
1145 function enableTagsPicker ()
1146 {
1147 global $taglist;
1148 static $taglist_inserted;
1149 includeJQueryUI ();
1150 addCSS ('css/tagit.css');
1151 addJS ('js/tag-it.js');
1152 addJS ('js/tag-it-local.js');
1153 if (! $taglist_inserted)
1154 {
1155 $taglist_filtered = array();
1156 foreach ($taglist as $key => $taginfo) # remove unused fields
1157 $taglist_filtered[$key] = array_sub ($taginfo, array("tag", "is_assignable", "trace"));
1158 addJS ('var taglist = ' . json_encode ($taglist_filtered) . ';', TRUE);
1159 $taglist_inserted = TRUE;
1160 }
1161 }
1162
1163 function makeIPAllocLink ($ip_bin, $alloc, $display_ifname = FALSE)
1164 {
1165 $object_name = ! isset ($object_name) || $object_name == '' ?
1166 formatEntityName (spotEntity ('object', $alloc['object_id'])) :
1167 $alloc['object_name'];
1168 $title = $display_ifname ?
1169 '' :
1170 "{$alloc['name']} @ {$object_name}";
1171 return
1172 '<a href="' . makeHref (array ('page' => 'object', 'tab' => 'default', 'object_id' => $alloc['object_id'], 'hl_ip' => ip_format ($ip_bin))) . '"' .
1173 ' title="' . htmlspecialchars ($title, ENT_QUOTES) . '"' .
1174 ">" . ($display_ifname ? $alloc['name'] . '@' : '') . $object_name . "</a>";
1175 }
1176
1177 function makeHtmlTag ($tagname, $attributes = array())
1178 {
1179 $ret = '<' . $tagname;
1180 foreach ($attributes as $key => $value)
1181 $ret .= " $key=\"" . htmlspecialchars($value, ENT_QUOTES) . '"';
1182 $ret .= '>';
1183 return $ret;
1184 }
1185
1186 function showMySQLWarnings()
1187 {
1188 global $debug_mode, $rtdebug_mysql_warnings;
1189 if (! isset ($debug_mode) || ! $debug_mode || ! isset ($rtdebug_mysql_warnings))
1190 return;
1191 foreach ($rtdebug_mysql_warnings as $each)
1192 {
1193 $text = $each['Code'] . ': ' . $each['Message'];
1194 switch ($each['Level'])
1195 {
1196 case 'Warning':
1197 showWarning ($text);
1198 break;
1199 case 'Note':
1200 showNotice ($text);
1201 break;
1202 default:
1203 showError ($text);
1204 break;
1205 }
1206 }
1207 $rtdebug_mysql_warnings = array();
1208 }
1209
1210 ?>