index.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. <?php
  2. //-
  3. // Copyright (c) 2011-2016 Joe Clarke <jclarke@cisco.com>
  4. // All rights reserved.
  5. // Redistribution and use in source and binary forms, with or without
  6. // modification, are permitted provided that the following conditions
  7. // are met:
  8. // 1. Redistributions of source code must retain the above copyright
  9. // notice, this list of conditions and the following disclaimer.
  10. // 2. Redistributions in binary form must reproduce the above copyright
  11. // notice, this list of conditions and the following disclaimer in the
  12. // documentation and/or other materials provided with the distribution.
  13. // THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  14. // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  15. // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  16. // ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  17. // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  18. // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  19. // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  20. // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  21. // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  22. // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  23. // SUCH DAMAGE.
  24. include_once 'db.inc.php';
  25. include_once 'swreg/swreg.inc.php';
  26. require_once 'Log.php';
  27. require_once 'functions.php';
  28. $dsn = "$db_driver:host=$db_host;dbname=$db_name";
  29. $options = [
  30. PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
  31. PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
  32. PDO::ATTR_EMULATE_PREPARES => false,
  33. ];
  34. try {
  35. $dbh = new PDO($dsn, $db_user, $db_pass, $options);
  36. } catch (PDOException $e) {
  37. die($e->getMessage());
  38. }
  39. $logger = Log::singleton('file', LOGFILE, TOOL_NAME.' : Physical Switches');
  40. if ($logger === false) {
  41. die("Failed to open logfile.\n");
  42. }
  43. $mask = Log::UPTO(LOG_LEVEL);
  44. $logger->setMask($mask);
  45. $base = get_base($_SERVER['SCRIPT_NAME']);
  46. $ruser = '<AUTHENTICATION NOT ENABLED>';
  47. if (isset($_SERVER['REMOTE_USER'])) {
  48. $ruser = $_SERVER['REMOTE_USER'];
  49. }
  50. $errors = array();
  51. if (isset($_REQUEST['prev_checked'])) {
  52. $pc = $_REQUEST['prev_checked'];
  53. $pas = $_REQUEST['prev_assigned_switch'];
  54. $c = (isset($_REQUEST['checked'])) ? $_REQUEST['checked'] : array();
  55. $as = $_REQUEST['assigned_switch'];
  56. $d = (isset($_REQUEST['delete'])) ? $_REQUEST['delete'] : array();
  57. foreach ($pc as $swsn => $value) {
  58. $curr_del = (isset($d[$swsn])) ? $d[$swsn] : 0;
  59. if ($curr_del == 1) {
  60. $sql = "DELETE FROM DEVICE_MAP WHERE serial_number='{$swsn}'";
  61. try {
  62. $dbh->query($sql);
  63. $logger->info("User {$ruser} deleted physical switch {$swsn}");
  64. } catch (PDOException $e) {
  65. array_push($errors, "Failed to delete switch {$swsn}: {$e->getMessage()}");
  66. }
  67. continue;
  68. }
  69. $curr_checked = (isset($c[$swsn])) ? $c[$swsn] : 0;
  70. if ($value != $curr_checked || $pas[$swsn] != $as[$swsn]) {
  71. $nc = $curr_checked;
  72. $additional = '';
  73. if ($nc == 1 && $as == '__BOGUS__') {
  74. array_push($errors, "You must select a logical switch assignment for $swsn");
  75. } else {
  76. if ($nc == 0 || $as == '__BOGUS__') {
  77. $nas = 'NULL';
  78. $additional = ", provisioned_status = '".PROVISION_UNKNOWN."', device_status = '".REACHABILITY_NEVER_REACHABLE."'";
  79. } else {
  80. $nas = "'{$as[$swsn]}'";
  81. }
  82. $sql = "UPDATE DEVICE_MAP SET checked_out='{$nc}', assigned_switch = {$nas} {$additional} WHERE serial_number='{$swsn}'";
  83. try {
  84. $dbh->query($sql);
  85. $logger->info("User {$ruser} updated physical switches, checked_out={$nc}, assigned_switch={$nas} for serial_number={$swsn}");
  86. } catch (PDOException $e) {
  87. array_push($errors, "Failed to update $swsn: '{$e->getMessage()}'");
  88. }
  89. }
  90. }
  91. }
  92. }
  93. $wc = '';
  94. if (isset($_REQUEST['filter'])) {
  95. switch ($_REQUEST['filter']) {
  96. case 'a':
  97. $wc = '';
  98. break;
  99. case 'p':
  100. $wc = 'WHERE assigned_switch IS NOT NULL';
  101. break;
  102. case 'up':
  103. $wc = 'WHERE assigned_switch IS NULL';
  104. break;
  105. case 'vu':
  106. $wc = 'WHERE provisioned_status=\''.PROVISION_UNKNOWN.'\'';
  107. break;
  108. case 'vi':
  109. $wc = 'WHERE provisioned_status=\''.PROVISION_IN_PROGRESS.'\'';
  110. break;
  111. case 'vf':
  112. $wc = 'WHERE provisioned_status=\''.PROVISION_FAIL.'\'';
  113. break;
  114. case 'vs':
  115. $wc = 'WHERE provisioned_status=\''.PROVISION_SUCCESS.'\'';
  116. break;
  117. case 'r':
  118. $wc = 'WHERE device_status=\''.REACHABILITY_REACHABLE.'\'';
  119. break;
  120. case 'ur':
  121. $wc = 'WHERE provisioned_status=\''.PROVISION_SUCCESS.'\' AND (device_status=\''.REACHABILITY_NEVER_REACHABLE.'\' OR device_status=\''.REACHABILITY_NOW_UNREACHABLE.'\')';
  122. break;
  123. default:
  124. if (preg_match("/^pid:([\w\d-]+)/", $_REQUEST['filter'], $match)) {
  125. $wc = "WHERE pid = '{$match[1]}'";
  126. } else {
  127. $wc = '';
  128. }
  129. break;
  130. }
  131. }
  132. $res = null;
  133. if (isset($_REQUEST['switch_name'])) {
  134. $sql = "SELECT * FROM DEVICE_MAP WHERE serial_number LIKE '%{$_REQUEST['switch_name']}%' OR assigned_switch LIKE '%{$_REQUEST['switch_name']}%'";
  135. try {
  136. $res = $dbh->query($sql);
  137. } catch (PDOException $e) {
  138. echo "<p><font color=\"red\">Error querying for physical switches: {$e->getMessage()}</font></p>\r\n";
  139. exit(1);
  140. }
  141. } else {
  142. $sql = 'SELECT * FROM DEVICE_MAP '.$wc.' ORDER BY serial_number';
  143. try {
  144. $res = $dbh->query($sql);
  145. } catch (PDOException $e) {
  146. echo "<p><font color=\"red\">Error querying for physical switches: {$e->getMessage()}</font></p>\r\n";
  147. exit(1);
  148. }
  149. }
  150. $sql = 'SELECT name, pid FROM SWITCHES ORDER BY name';
  151. $ls_res = null;
  152. try {
  153. $ls_res = $dbh->query($sql);
  154. } catch (PDOException $e) {
  155. echo "<p><font color=\"red\">Error querying for logical switches: {$e->getMessage()}</font></p>\r\n";
  156. exit(1);
  157. }
  158. $lswitches = array();
  159. while ($row = $ls_res->fetch()) {
  160. if (!isset($lswitches[$row['pid']])) {
  161. $lswitches[$row['pid']] = array('__BOGUS__', $row['name']);
  162. } else {
  163. array_push($lswitches[$row['pid']], $row['name']);
  164. }
  165. }
  166. $switches = array();
  167. while ($row = $res->fetch()) {
  168. array_push($switches, $row);
  169. }
  170. $sql = 'SELECT DISTINCT(pid) AS pid FROM DEVICE_MAP';
  171. try {
  172. $res = $dbh->query($sql);
  173. } catch (PDOException $e) {
  174. echo "<p><font color=\"red\">Error querying for PIDs: {$e->getMessage()}</font></p>\r\n";
  175. exit(1);
  176. }
  177. $pids = array();
  178. while ($row = $res->fetch()) {
  179. $pids[$row['pid']] = true;
  180. }
  181. $sql = 'SELECT assigned_switch FROM DEVICE_MAP WHERE assigned_switch IS NOT NULL';
  182. try {
  183. $res = $dbh->query($sql);
  184. } catch (PDOException $e) {
  185. echo "<p><font color=\"red\">Error querying for assigned switches: {$e->getMessage()}</font></p>\r\n";
  186. exit(1);
  187. }
  188. $used = array();
  189. while ($row = $res->fetch()) {
  190. $used[$row['assigned_switch']] = true;
  191. }
  192. $filt = null;
  193. if (!isset($_REQUEST['filter'])) {
  194. $filt = '';
  195. } else {
  196. $filt = $_REQUEST['filter'];
  197. }
  198. print_header(TOOL_NAME.': Physical Switches');
  199. ?>
  200. <body class="flex">
  201. <script language="javascript">
  202. var deletes = 0;
  203. var PROVISION_UNKNOWN = <?=PROVISION_UNKNOWN?>;
  204. var PROVISION_IN_PROGRESS = <?=PROVISION_IN_PROGRESS?>;
  205. var PROVISION_FAIL = <?=PROVISION_FAIL?>;
  206. var PROVISION_SUCCESS = <?=PROVISION_SUCCESS?>;
  207. var REACHABILITY_NEVER_REACHABLE = <?=REACHABILITY_NEVER_REACHABLE?>;
  208. var REACHABILITY_NOW_UNREACHABLE = <?=REACHABILITY_NOW_UNREACHABLE?>;
  209. var REACHABILITY_REACHABLE = <?=REACHABILITY_REACHABLE?>;
  210. var row_intervals = {};
  211. function refresh() {
  212. $.ajax({
  213. url: '<?=$base?>/get_dev_stats.php',
  214. dataType: 'json',
  215. success: function(data) {
  216. $.each(data.response, function(k, v) {
  217. var rtext = '&nbsp;';
  218. var color = '#FFFFFF';
  219. var rtitle = 'Not yet assigned';
  220. var prs = v.provisioned_status;
  221. var ds = v.device_status;
  222. if (prs == PROVISION_SUCCESS) {
  223. color = '#00FF00';
  224. rtitle = 'Bootstrap validated successfully';
  225. rtext += '&nbsp;&nbsp;&nbsp;';
  226. } else if (prs == PROVISION_UNKNOWN || prs == PROVISION_IN_PROGRESS) {
  227. color = '#919191';
  228. rtitle = 'Not yet bootstrapped';
  229. if (prs == PROVISION_IN_PROGRESS) {
  230. rtitle = 'Bootstrapping in progress';
  231. rtext += '&nbsp;';
  232. }
  233. } else {
  234. color = '#FF0000';
  235. rtitle = 'Bootstrap validation failed';
  236. rtext += '&nbsp;&nbsp;';
  237. }
  238. rtext += '<input type="hidden" id="pros'+k+'" value="'+prs+'">';
  239. if (prs != PROVISION_IN_PROGRESS) {
  240. if ('undefined' !== typeof row_intervals[k]) {
  241. $('#psr_'+k).stop(true, true);
  242. clearInterval(row_intervals[k]);
  243. $('#psr_'+k).stop(true, true);
  244. }
  245. }
  246. $('#psr_'+k).css('background', color);
  247. $('#psr_'+k).html('<span style="display: none">' + prs + '</span>' + rtext);
  248. $('#psr_'+k).attr('title', rtitle);
  249. if (prs == PROVISION_IN_PROGRESS) {
  250. if ('undefined' !== typeof row_intervals[k]) {
  251. clearInterval(row_intervals[k]);
  252. $('#psr_'+k).stop(true, true);
  253. }
  254. var pulseint = setInterval(function() {
  255. $('#psr_'+k).animate({
  256. backgroundColor : '#919191',
  257. }, 1000).animate({
  258. backgroundColor : '#f5f5f5',
  259. }, 1000);
  260. }, 1500);
  261. row_intervals[k] = pulseint;
  262. }
  263. color = '#FFFFFF';
  264. rtext = '&nbsp;';
  265. rtitle = 'Not yet assigned';
  266. if (ds == REACHABILITY_NEVER_REACHABLE && prs == PROVISION_SUCCESS) {
  267. color = '#FF0000';
  268. rtitle = 'Device was never reachable';
  269. } else if (ds == REACHABILITY_NEVER_REACHABLE) {
  270. color = '#919191';
  271. rtitle = 'Not yet bootstrapped';
  272. rtext += '&nbsp;';
  273. } else if (ds == REACHABILITY_NOW_UNREACHABLE) {
  274. color = '#FFFF00';
  275. rtitle = 'Device has been reachable, but is not reachable now';
  276. rtext += '&nbsp;&nbsp;';
  277. } else {
  278. color = '#00FF00';
  279. rtitle = 'Device is reachable';
  280. rtext += '&nbsp;&nbsp;&nbsp;';
  281. }
  282. $('#dsr_'+k).css('background', color);
  283. $('#dsr_'+k).html('<span style="display: none">' + ds + '</span>' + rtext);
  284. $('#dsr_'+k).attr('title', rtitle);
  285. });
  286. },
  287. complete: function(xhr, message) {
  288. setTimeout(refresh, 30000);
  289. }
  290. });
  291. }
  292. $(document).ready(function() {
  293. $('#devtable').DataTable( {
  294. "scrollY": "400px",
  295. "scrollCollapse": true,
  296. "paging":false
  297. } );
  298. refresh();
  299. } );
  300. </script>
  301. <div id="headswreg">
  302. <div class="apage">
  303. <div id="header">
  304. <h1><?=TOOL_NAME?>: Physical Switches</h1>
  305. </div>
  306. <br/>
  307. </div>
  308. </div>
  309. <div class="apage">
  310. <form method="POST" name="search_form" action="<?=$_SERVER['PHP_SELF']?>">
  311. <table class="noborder" summary="Filter Table">
  312. <tr>
  313. <td class="left_act">Show Only:
  314. <select name="filter" onChange="MM_jumpMenu('parent', this, 0)">
  315. <option value="<?=$_SERVER['PHP_SELF']?>?filter=a" <?=($filt == 'a') ? 'selected' : ''?>>All</option>
  316. <option value="<?=$_SERVER['PHP_SELF']?>?filter=p" <?=($filt == 'p') ? 'selected' : ''?>>Assigned</option>
  317. <option value="<?=$_SERVER['PHP_SELF']?>?filter=up" <?=($filt == 'up') ? 'selected' : ''?>>Unassigned</option>
  318. <option value="<?=$_SERVER['PHP_SELF']?>?filter=vu" <?=($filt == 'vu') ? 'selected' : ''?>>Not Yet Bootstrapped</option>
  319. <option value="<?=$_SERVER['PHP_SELF']?>?filter=vi" <?=($filt == 'vi') ? 'selected' : ''?>>Bootstrapping In Progress</option>
  320. <option value="<?=$_SERVER['PHP_SELF']?>?filter=vf" <?=($filt == 'vf') ? 'selected' : ''?>>Verification Failed</option>
  321. <option value="<?=$_SERVER['PHP_SELF']?>?filter=vs" <?=($filt == 'vs') ? 'selected' : ''?>>Verification Succeeded</option>
  322. <option value="<?=$_SERVER['PHP_SELF']?>?filter=r" <?=($filt == 'r') ? 'selected' : ''?>>Reachable</option>
  323. <option value="<?=$_SERVER['PHP_SELF']?>?filter=ur" <?=($filt == 'ur') ? 'selected' : ''?>>Unreachable</option>
  324. <?php
  325. foreach ($pids as $lsp => $value) {
  326. $selected = ($filt == "pid:$lsp") ? 'selected' : ''; ?>
  327. <option value="<?=$_SERVER['PHP_SELF']?>?filter=pid:<?=$lsp?>" <?=$selected?>><?=$lsp?></option>
  328. <?php
  329. }
  330. ?>
  331. </select></td>
  332. <td class="right">Switch Search:
  333. <input type="text" size="16" name="switch_name" value="<?=(isset($_REQUEST['switch_name'])) ? $_REQUEST['switch_name'] : ''?>">
  334. <input type="image" value="Submit" name="search" src="/images/submit_button.png">
  335. </td>
  336. </tr>
  337. </table>
  338. </form>
  339. <br/>
  340. <table class="noborder" summary="Control Table">
  341. <tr>
  342. <td class="left"><a href="<?=$base?>/add_phys.php">Add Physical Switch</a> |
  343. <a href="#" onClick="window.open('<?=$base?>/export.php')">Export to Prime / DNS</a> |
  344. <a href="<?=$base?>/logicsw.php">Logical Switches</a></td>
  345. </tr>
  346. </table>
  347. <form name="mod_phys_switch_form" method="POST" action="<?=$_SERVER['PHP_SELF']?>" onSubmit='if (deletes > 0) { return confirm("Are you sure you want to delete these " + deletes + " physical switch(es)?"); }'>
  348. <?php
  349. foreach (array_merge($_GET, $_POST) as $name => $value) {
  350. if (!is_array($value)) {
  351. ?>
  352. <input type="hidden" name="<?=$name?>" value="<?=$value?>">
  353. <?php
  354. }
  355. }
  356. ?>
  357. <div class="btable">
  358. <table summary="Button Table" width="100%" cellspacing="0">
  359. <tr>
  360. <td><input type="reset" value="Reset" name="reset">
  361. <input type="submit" value="Submit" name="submit"></td>
  362. </tr>
  363. </table>
  364. </div>
  365. <br/>
  366. <div align="center">
  367. <?php
  368. foreach ($errors as $error) {
  369. ?>
  370. <p class="error"><?=$error?></p>
  371. <?php
  372. }
  373. ?>
  374. </div>
  375. <div class="maintable">
  376. <table id="devtable" class="cell-border compact" width="100%" cellspacing="0" summary="Physical Switch Table">
  377. <thead>
  378. <tr>
  379. <th class="headlink">Row No.</th>
  380. <th class="headlink">Delete?</th>
  381. <th class="headlink">Assigned?</th>
  382. <th class="headlink">Serial Number</th>
  383. <th class="headlink">Product ID</th>
  384. <th class="headlink">MAC Address</th>
  385. <th class="headlink">Max Ports</th>
  386. <th class="headlink">Assigned Logical<br/>Switch</th>
  387. <th class="headlink">Provision<br/>Status</th>
  388. <th class="headlink">Reachability</th>
  389. </tr>
  390. </thead>
  391. <tbody>
  392. <?php
  393. $i = 0;
  394. foreach ($switches as $row) {
  395. $sn = $row['serial_number'];
  396. $checked = false;
  397. if ($row['checked_out'] == 1) {
  398. $checked = true;
  399. } ?>
  400. <tr>
  401. <td><?=$i + 1?>.</td>
  402. <td><input type="checkbox" name="delete[<?=$sn?>]" value="1" onClick="if (this.checked == true) { deletes++; } else { deletes--; }"></td>
  403. <td><input type="hidden" name="prev_checked[<?=$sn?>]" value="<?=$row['checked_out']?>">
  404. <input id="checked_<?=$i?>" type="checkbox" name="checked[<?=$sn?>]" value="1" <?=($checked) ? 'checked' : ''?>></td>
  405. <td><?=$row['serial_number']?></td>
  406. <td><?=$row['pid']?></td>
  407. <td><?=$row['mac']?></td>
  408. <td><?=$row['max_ports']?></td>
  409. <td><input type="hidden" name="prev_assigned_switch[<?=$sn?>]" value="<?=$row['assigned_switch']?>">
  410. <select id="asw<?=$i?>" name="assigned_switch[<?=$sn?>]" onChange='var elem = document.getElementById("checked_<?=$i?>"); if (this.value == "__BOGUS__") { elem.checked = false; } else { elem.checked = true; }'>
  411. <?php
  412. $has_avail = false;
  413. foreach ($lswitches[$row['pid']] as $lsw) {
  414. $selected = ($row['assigned_switch'] == $lsw) ? 'selected' : '';
  415. if ($selected == '' && isset($used[$lsw]) && $used[$lsw] === true) {
  416. continue;
  417. }
  418. if ($lsw == '__BOGUS__') {
  419. ?>
  420. <option value="__BOGUS__" <?=$selected?>>--Please Select--</option>
  421. <?php
  422. } else {
  423. $has_avail = true; ?>
  424. <option value="<?=$lsw?>" <?=$selected?>><?=$lsw?></option>
  425. <?php
  426. }
  427. }
  428. if (!$has_avail) {
  429. ?>
  430. <option value="__BOGUS__" <?=$selected?>>--Please Select--</option>
  431. <?php
  432. } ?>
  433. </select>
  434. &nbsp;<a href="#" onClick='var lsw = document.getElementById("asw<?=$i?>"); if (lsw.value == "__BOGUS__") { alert("There is no logical switch associated to this device."); return false; } else { window.open("<?=$base?>/logicsw.php?switch_name=" + lsw.value, "Logical switch " + lsw.value, "height=480,width=1048"); return false; }'><img src="/images/switch.gif" border="0" title="View logical switch"></a>&nbsp;<a href="#" onClick='var pros = document.getElementById("pros<?=$row['serial_number']?>"); var lsw = document.getElementById("asw<?=$i?>"); if (pros.value < PROVISION_FAIL) { alert("This switch config has not yet been generated."); return false; } else { window.open("<?=$base?>/show_config.php?cfg=" + lsw.value + "-config.txt&dname=" + lsw.value, "Config for switch " + lsw.value, "height=650,width=980"); return false; }'><img src="/images/mag.gif" border="0" title="View switch config"></a>
  435. </td>
  436. <?php
  437. $color = '#FFFFFF';
  438. $rtext = 'N/A';
  439. $rtitle = 'Not yet assigned'; ?>
  440. <td id="psr_<?=$row['serial_number']?>" style="background: <?=$color?>;" title="<?=$rtitle?>"><input type="hidden" id="pros<?=$row['serial_number']?>" value="<?=$row['provisioned_status']?>"><span style="display: none"><?=$row['provisioned_status']?></span><?=$rtext?></td>
  441. <?php
  442. $color = '#FFFFFF';
  443. $rtext = 'N/A';
  444. $rtitle = 'Not yet assigned'; ?>
  445. <td id="dsr_<?=$row['serial_number']?>" style="background: <?=$color?>;" title="<?=$rtitle?>"><span style="display: none"><?=$row['device_status']?></span><?=$rtext?></td>
  446. </tr>
  447. <?php
  448. ++$i;
  449. }
  450. ?>
  451. </tbody>
  452. </table>
  453. </div>
  454. <br/>
  455. <div class="btable">
  456. <table summary="Button Table" width="100%" cellspacing="0">
  457. <tr>
  458. <td><input type="reset" value="Reset" name="reset">
  459. <input type="submit" value="Submit" name="submit"></td>
  460. </tr>
  461. </table>
  462. </div>
  463. </form>
  464. </div>
  465. </body>
  466. </html>
  467. <?php
  468. cleanup();
  469. ?>