DIR : /home/kozerus/public_html/ko_center/ko_center_admin.html

/home/kozerus/public_html/ko_center

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <title>ko_center System Administrator Documentation</title>
  <style type="text/css">
    body { font-family: Arial, sans-serif; margin: 20px; background-color: #f0f0f0; }
    h1 { color: #333; border-bottom: 2px solid #cc0000; padding-bottom: 5px; }
    h2 { color: #cc0000; margin-top: 30px; }
    h3 { color: #333; }
    h4 { color: #555; }
    code { background-color: #eee; padding: 2px 4px; border-radius: 3px; font-size: 14px; }
    pre { background-color: #f8f8f8; border: 1px solid #ddd; padding: 10px; border-radius: 4px; overflow-x: auto; }
    table { border-collapse: collapse; margin: 10px 0; }
    th, td { border: 1px solid #ccc; padding: 6px 10px; text-align: left; }
    th { background-color: #cc0000; color: white; }
    tr:nth-child(even) { background-color: #f9f9f9; }
    .note { background-color: #fff3cd; border: 1px solid #ffc107; padding: 10px; margin: 10px 0; border-radius: 4px; }
    .warning { background-color: #f8d7da; border: 1px solid #dc3545; padding: 10px; margin: 10px 0; border-radius: 4px; }
    .info { background-color: #d1ecf1; border: 1px solid #17a2b8; padding: 10px; margin: 10px 0; border-radius: 4px; }
    .admin { background-color: #e2e3e5; border: 1px solid #6c757d; padding: 10px; margin: 10px 0; border-radius: 4px; }
    a { color: #cc0000; text-decoration: none; }
    a:hover { text-decoration: underline; }
    .toc { margin: 20px 0; padding: 15px; background: white; border: 1px solid #ddd; border-radius: 4px; }
    .toc ul { list-style-type: none; padding-left: 10px; }
    .toc li { margin: 4px 0; }
    .cmd { font-family: monospace; background: #2d2d2d; color: #f8f8f2; padding: 10px; border-radius: 4px; }
  </style>
</head>
<body>

<h1>ko_center System Administrator Documentation</h1>

<p><strong>Version:</strong> v0.70 (2026-08-01)<br />
<strong>Type:</strong> PHP/Perl Web Application (Single-File Architecture)<br />
<strong>Primary File:</strong> <code>/os/ai/io/ko_center.php</code> (16,322 lines, 205 functions)<br />
<strong>Database:</strong> SQLite 3 (<code>ko_center.db3</code>, ~39.6 MB)<br />
<strong>Web Server:</strong> Apache (with PHP) or Python Flask (equivalent: <code>ko_center.py</code>)<br />
<strong>Document Type:</strong> System Administrator Guide</p>

<div class="toc">
<h2>Table of Contents</h2>
<ul>
  <li><a href="#arch">1. System Architecture</a></li>
  <li><a href="#install">2. Installation &amp; Setup</a></li>
  <li><a href="#config">3. Configuration</a></li>
  <li><a href="#db">4. Database Administration</a></li>
  <li><a href="#users">5. User &amp; Role Management</a></li>
  <li><a href="#security">6. Security</a></li>
  <li><a href="#logging">7. Logging &amp; Debugging</a></li>
  <li><a href="#backup">8. Backup &amp; Recovery</a></li>
  <li><a href="#maintenance">9. Maintenance Tasks</a></li>
  <li><a href="#troubleshoot">10. Troubleshooting</a></li>
  <li><a href="#files">11. File Structure &amp; Assets</a></li>
  <li><a href="#functions">12. PHP Function Reference</a></li>
  <li><a href="#deploy">13. Deployment</a></li>
  <li><a href="#python">14. Python Flask Equivalent</a></li>
  <li><a href="#api">15. API Endpoints</a></li>
</ul>
</div>

<!-- ================================================================== -->
<h2 id="arch">1. System Architecture</h2>
<!-- ================================================================== -->

<h3>1.1 Overview</h3>
<p>ko_center is a <strong>single-file PHP web application</strong> that provides a
centralized dashboard for managing LED indicators, database grids, knowledge
base articles, hardware inventory, and various system monitoring tools.</p>

<p>The application follows a traditional LAMP-style architecture:</p>
<ul>
  <li><strong>Web Server:</strong> Apache with PHP module (or Python Flask for the
    equivalent Python port)</li>
  <li><strong>Backend:</strong> PHP 5.x+ (uses <code>$GLOBALS</code>, <code>$_SESSION</code>,
    <code>$_REQUEST</code>, <code>$_SERVER</code>)</li>
  <li><strong>Database:</strong> SQLite 3 via PDO</li>
  <li><strong>Frontend:</strong> XHTML 1.0 Strict with inline CSS and JavaScript</li>
  <li><strong>JavaScript Libraries:</strong> jQuery 1.7.2, jQuery UI 1.7.2, jqGrid 4.4.0,
    fg-menu</li>
</ul>

<h3>1.2 Request Flow</h3>
<pre>
Browser Request
    |
    v
Apache/PHP (ko_center.php)
    |
    +--> startup()          [Initialize session, globals, paths]
    |
    +--> Parse ?q= parameter
    |       Split by "/" into options[] array
    |       options[0] = page, options[1] = action, options[2] = id, etc.
    |
    +--> Route to handler function
            |
            +--> leds_show()     - Display LED indicators
            +--> pdo_grid()      - Database grid view
            +--> leds_kb()       - Knowledge Base
            +--> leds_reports_*  - Reports (SQL, CSV, XML)
            +--> leds_config()   - Configuration
            +--> leds_login_*    - Authentication
            +--> trigger()       - Broadcast refresh
            +--> iperms()        - System utilities
            +--> ko_upload*      - File uploads
            +--> pdo_cr_*        - Table creation
            +--> pdo_insert_*    - Data insertion
            +--> ... (205 functions total)
    |
    +--> Generate HTML output
    |       html_header()   - <head> section
    |       html_btn_squares() - Navigation buttons
    |       [page content]
    |       html_footer()   - </body></html>
    |
    v
Browser renders HTML
</pre>

<h3>1.3 Key Design Patterns</h3>
<ul>
  <li><strong>Single-file architecture:</strong> All functionality is in one PHP file
    (no MVC framework, no separate controllers)</li>
  <li><strong>Global state:</strong> Uses <code>$GLOBALS</code> for database file path,
    table name, log file, user info</li>
  <li><strong>Session-based auth:</strong> <code>$_SESSION['user']</code>,
    <code>$_SESSION['role']</code>, <code>$_SESSION['preview']</code></li>
  <li><strong>URL-based routing:</strong> <code>?q=page/action/id</code> parsed into
    <code>$options[]</code> array</li>
  <li><strong>Procedural with functions:</strong> No classes, all functions are
    global</li>
  <li><strong>Inline HTML generation:</strong> Functions return HTML strings that are
    concatenated and printed</li>
</ul>

<!-- ================================================================== -->
<h2 id="install">2. Installation &amp; Setup</h2>
<!-- ================================================================== -->

<h3>2.1 Prerequisites</h3>
<table>
<tr><th>Component</th><th>Requirement</th></tr>
<tr><td>Web Server</td><td>Apache 2.x with mod_php, or Python 3.x with Flask</td></tr>
<tr><td>PHP</td><td>PHP 5.3+ (uses PDO, sessions, $_REQUEST)</td></tr>
<tr><td>SQLite</td><td>SQLite 3 with PHP PDO extension</td></tr>
<tr><td>ImageMagick</td><td>Required for LED GIF generation (cr_leds.py)</td></tr>
<tr><td>Perl</td><td>Required for iperms utility functions</td></tr>
<tr><td>Disk Space</td><td>~50 MB minimum (database + images + logs)</td></tr>
</table>

<h3>2.2 Installation Steps</h3>

<h4>Step 1: Deploy files</h4>
<pre>
cp ko_center.php /var/www/html/ko_center/
cp ko_center.db3 /var/www/html/ko_center/db3/
mkdir -p /var/www/html/ko_center/images/btn
mkdir -p /var/www/html/ko_center/images/ani
mkdir -p /var/www/html/ko_center/images/fpb
mkdir -p /var/www/html/ko_center/kb
mkdir -p /var/www/html/ko_center/db3
</pre>

<h4>Step 2: Set permissions</h4>
<pre>
chown -R www-data:www-data /var/www/html/ko_center/
chmod 666 /var/www/html/ko_center/db3/ko_center.db3
chmod 666 /var/www/html/ko_center/ko_trigger.dat  # if using trigger feature
</pre>

<h4>Step 3: Configure hosts.allow</h4>
<p>Create or edit <code>/var/www/html/../safer/hosts.allow</code>:</p>
<pre>
allow all
# or format: allow user role
</pre>

<h4>Step 4: Initialize database (if new install)</h4>
<p>Access <code>http://&lt;host&gt;/ko_center/ko_center.php</code> in a browser.
If the database file doesn't exist, the <code>leds_install("new")</code> function
is called automatically, creating all core tables.</p>

<h4>Step 5: Verify installation</h4>
<p>Navigate to <code>?q=about</code> or <code>?q=pdo</code> to verify the database
connection and table creation.</p>

<h3>2.3 First-Time Install (leds_install)</h3>
<p>The <code>leds_install()</code> function (line 9707) creates all database tables
and inserts default data:</p>

<table>
<tr><th>Table</th><th>Function</th><th>Description</th></tr>
<tr><td><code>leds</code></td><td><code>pdo_cr_leds()</code> + <code>pdo_insert_leds()</code></td><td>LED indicator records</td></tr>
<tr><td><code>nodes</code></td><td><code>pdo_cr_nodes()</code> + <code>pdo_insert_nodes()</code></td><td>Network nodes</td></tr>
<tr><td><code>roles</code></td><td><code>pdo_cr_roles()</code> + <code>pdo_insert_roles()</code></td><td>User roles</td></tr>
<tr><td><code>users</code></td><td><code>pdo_cr_users()</code> + <code>pdo_insert_users()</code></td><td>User accounts</td></tr>
<tr><td><code>fp</code></td><td><code>pdo_cr_fp()</code> + <code>pdo_insert_fp()</code></td><td>Floor plan data</td></tr>
<tr><td><code>grid</code></td><td><code>pdo_cr_grid()</code> + <code>pdo_insert_grid()</code></td><td>Grid configuration</td></tr>
<tr><td><code>us</code></td><td><code>pdo_cr_us()</code> + <code>pdo_insert_us()</code></td><td>User-specific data</td></tr>
<tr><td><code>hw</code></td><td><code>pdo_cr_hw()</code> + <code>pdo_insert_hw()</code></td><td>Hardware inventory</td></tr>
<tr><td><code>n11</code></td><td><code>pdo_cr_n11()</code> + <code>pdo_insert_n11()</code></td><td>N11 monitoring</td></tr>
<tr><td><code>obj</code></td><td><code>pdo_cr_obj()</code> + <code>pdo_insert_obj()</code></td><td>Object data</td></tr>
<tr><td><code>pano</code></td><td><code>pdo_cr_pano()</code> + <code>pdo_insert_pano()</code></td><td>Panorama data</td></tr>
<tr><td><code>dbs</code></td><td><code>pdo_cr_dbs()</code> + <code>pdo_insert_dbs()</code></td><td>Database registry</td></tr>
<tr><td><code>menus</code></td><td><code>pdo_cr_menus()</code> + <code>pdo_insert_menus()</code></td><td>Menu definitions</td></tr>
<tr><td><code>ko_plans</code></td><td>Created via pdo_cr</td><td>Project plans</td></tr>
<tr><td><code>ko_hw</code></td><td>Created via pdo_cr</td><td>Hardware details</td></tr>
<tr><td><code>koaac_kb</code></td><td><code>pdo_cr_kb()</code></td><td>Knowledge Base</td></tr>
<tr><td><code>ko_center_certs</code></td><td>Created via pdo_cr</td><td>Certificates</td></tr>
</table>

<!-- ================================================================== -->
<h2 id="config">3. Configuration</h2>
<!-- ================================================================== -->

<h3>3.1 Global Configuration Variables</h3>
<p>All configuration is set in the <code>startup()</code> function (line 101) via
<code>$GLOBALS</code>:</p>

<table>
<tr><th>Variable</th><th>Default Value</th><th>Description</th></tr>
<tr><td><code>$GLOBALS['dbfile']</code></td><td><code>$document_root/ko_center/db3/ko_center.db3</code></td><td>Path to SQLite database</td></tr>
<tr><td><code>$GLOBALS['kbfile']</code></td><td><code>$document_root/ko_center/db3/koaac_kb.db3</code></td><td>Path to KB database</td></tr>
<tr><td><code>$GLOBALS['kb_rootpath']</code></td><td><code>$document_root/ko_center/kb</code></td><td>KB file storage path</td></tr>
<tr><td><code>$GLOBALS['kbpath']</code></td><td><code>$document_root/ko_center/kb</code></td><td>KB path (alias of kb_rootpath)</td></tr>
<tr><td><code>$GLOBALS['hosts_allow']</code></td><td><code>$document_root/../safer/hosts.allow</code></td><td>Authentication file</td></tr>
<tr><td><code>$GLOBALS['ko_center_certsfile']</code></td><td><code>$document_root/ko_center/db3/ko_center_certs.db3</code></td><td>Certificates database</td></tr>
<tr><td><code>$GLOBALS['logfil']</code></td><td><code>$logfil_rootpath/ko_center_YYYYMM.log</code></td><td>Log file path</td></tr>
<tr><td><code>$GLOBALS['progid']</code></td><td><code>"ko_center"</code></td><td>Program identifier</td></tr>
<tr><td><code>$GLOBALS['tblname']</code></td><td><code>"leds"</code></td><td>Default table name for LED operations</td></tr>
<tr><td><code>$GLOBALS['dbfiles']</code></td><td>Array of database configs</td><td>Multi-database registry for role-based access</td></tr>
<tr><td><code>$GLOBALS['roles']</code></td><td>Array of role definitions</td><td>Role-based access control</td></tr>
<tr><td><code>$GLOBALS['themes']</code></td><td>Array of jQuery UI theme names</td><td>Available UI themes</td></tr>
<tr><td><code>$GLOBALS['allowflag']</code></td><td>From hosts.allow file</td><td>Access control flag</td></tr>
<tr><td><code>$GLOBALS['kb_user']</code></td><td>From hosts.allow field 2</td><td>KB user identifier</td></tr>
<tr><td><code>$GLOBALS['screenshots_pcharts']</code></td><td>"" (empty)</td><td>pChart screenshot path</td></tr>
<tr><td><code>$GLOBALS['js_output']</code></td><td>false</td><td>JavaScript output flag</td></tr>
</table>

<h3>3.2 Configuration Settings</h3>
<table>
<tr><th>Setting</th><th>Location</th><th>Description</th></tr>
<tr><td><code>path_btn</code></td><td>startup() line 130</td><td>Button images path: <code>/ko_center/images/btn</code></td></tr>
<tr><td><code>path_ani</code></td><td>startup() line 131</td><td>Animated GIF path: <code>/ko_center/images/ani</code></td></tr>
<tr><td><code>path_fpb</code></td><td>leds_show() line 6905</td><td>Floor plan button images: <code>/ko_center/images/fpb</code></td></tr>
<tr><td><code>theme</code></td><td>Session variable</td><td>jQuery UI theme: redmond, humanity, frog, swanky, etc.</td></tr>
<tr><td><code>preview</code></td><td>Session variable</td><td>Preview mode on/off</td></tr>
<tr><td><code>grid_zoom</code></td><td>Session variable</td><td>Grid zoom toggle</td></tr>
<tr><td><code>hs_type</code></td><td>Session variable</td><td>Hotspot type filter</td></tr>
<tr><td><code>org_type</code></td><td>Session variable</td><td>Organization type filter</td></tr>
</table>

<!-- ================================================================== -->
<h2 id="db">4. Database Administration</h2>
<!-- ================================================================== -->

<h3>4.1 Database File</h3>
<table>
<tr><th>Property</th><th>Value</th></tr>
<tr><td>File</td><td><code>/os/ai/io/ko_center.db3</code></td></tr>
<tr><td>Type</td><td>SQLite 3</td></tr>
<tr><td>Size</td><td>~39.6 MB</td></tr>
<tr><td>Tables</td><td>30+ tables</td></tr>
<tr><td>Access</td><td>Via PHP PDO (<code>newpdo()</code> function)</td></tr>
</table>

<h3>4.2 Database Connection</h3>
<p>The <code>newpdo()</code> function (line 6595) creates SQLite connections:</p>
<pre>
function newpdo( $dbfile ) {
    $pdo = new PDO("sqlite:$dbfile");
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    return $pdo;
}
</pre>

<h3>4.3 Key Database Tables</h3>
<table>
<tr><th>Table</th><th>Purpose</th><th>Key Columns</th></tr>
<tr><td><code>leds</code></td><td>LED indicator records</td><td>led_id, led_name, led_color, led_speed, led_type, led_dttm, led_cmd, led_desc</td></tr>
<tr><td><code>randomus</code></td><td>Random user data</td><td>gender, title, fname, lname_last, email, login_user, login_pass, etc.</td></tr>
<tr><td><code>leds_randomus</code></td><td>Combined LED + randomus</td><td>All leds columns (NULL) + all randomus columns</td></tr>
<tr><td><code>ko_plans</code></td><td>Project plans</td><td>id, name, status, steps, items</td></tr>
<tr><td><code>ko_hw</code></td><td>Hardware inventory</td><td>led_name, cab, item, model, sn, ip, hrctag, hostname, machinename, amps, btu</td></tr>
<tr><td><code>koaac_kb</code></td><td>Knowledge Base</td><td>kb_id, kb_title, kb_body, kb_dttm, kb_user, kb_type</td></tr>
<tr><td><code>nodes</code></td><td>Network nodes</td><td>node_id, node_code, node_name, node_status, node_city, node_bldg</td></tr>
<tr><td><code>roles</code></td><td>User roles</td><td>role definitions and permissions</td></tr>
<tr><td><code>users</code></td><td>User accounts</td><td>user credentials and role assignments</td></tr>
<tr><td><code>cabs</code></td><td>Cabinet/rack data</td><td>Cabinet information</td></tr>
<tr><td><code>cfg</code></td><td>Configuration</td><td>System configuration key-value pairs</td></tr>
<tr><td><code>dbs</code></td><td>Database registry</td><td>Multi-database connection configs</td></tr>
<tr><td><code>menus</code></td><td>Menu definitions</td><td>Navigation menu structure</td></tr>
<tr><td><code>fp</code></td><td>Floor plan data</td><td>Floor plan references</td></tr>
<tr><td><code>grid</code></td><td>Grid configuration</td><td>Grid view settings</td></tr>
<tr><td><code>us</code></td><td>User-specific data</td><td>Per-user preferences</td></tr>
<tr><td><code>n11</code></td><td>N11 monitoring</td><td>N11 alert data</td></tr>
<tr><td><code>pano</code></td><td>Panorama data</td><td>Panorama/tour references</td></tr>
<tr><td><code>obj</code></td><td>Object data</td><td>Object references</td></tr>
<tr><td><code>zoom</code></td><td>Zoom configuration</td><td>Zoom viewer settings</td></tr>
<tr><td><code>zoomxml</code></td><td>Zoom XML data</td><td>Hotspot XML configurations</td></tr>
<tr><td><code>shelves</code></td><td>Shelf data</td><td>Shelf/rack shelf data</td></tr>
<tr><td><code>hallo</code></td><td>Hallo data</td><td>Hallo records</td></tr>
<tr><td><code>halo</code></td><td>Halo data</td><td>Halo records</td></tr>
<tr><td><code>nimbus</code></td><td>Nimbus data</td><td>Nimbus records</td></tr>
<tr><td><code>aureole</code></td><td>Aureole data</td><td>Aureole records</td></tr>
<tr><td><code>leds_defaults</code></td><td>LED defaults</td><td>Default LED settings</td></tr>
<tr><td><code>leds_racks</code></td><td>LED rack mappings</td><td>LED-to-rack mappings</td></tr>
<tr><td><code>periods</code></td><td>Time periods</td><td>Reporting periods</td></tr>
<tr><td><code>rpts</code></td><td>Report definitions</td><td>Report SQL and metadata</td></tr>
<tr><td><code>hrc_datacenters_equipment</code></td><td>DC equipment</td><td>Datacenter equipment inventory</td></tr>
<tr><td><code>defrag_plan</code></td><td>Defrag plans</td><td>Defragmentation plans</td></tr>
<tr><td><code>defrag_plansum</code></td><td>Defrag plan summaries</td><td>Summary data for defrag plans</td></tr>
<tr><td><code>hrc_dc_*</code></td><td>Various DC tables</td><td>Datacenter-specific data</td></tr>
<tr><td><code>es_ip</code></td><td>IP data</td><td>IP address tracking</td></tr>
<tr><td><code>es_hw</code></td><td>Extended HW data</td><td>Extended hardware info</td></tr>
<tr><td><code>kohw_*</code></td><td>Hardware variants</td><td>Hardware table variants</td></tr>
<tr><td><code>kocab</code></td><td>Cabinet data</td><td>Cabinet details</td></tr>
<tr><td><code>kohw</code></td><td>Hardware data</td><td>Hardware records</td></tr>
<tr><td><code>koplans</code></td><td>Plan data</td><td>Plan records</td></tr>
</table>

<h3>4.4 Database Maintenance Commands</h3>
<pre>
# Check database integrity
sqlite3 /os/ai/io/ko_center.db3 "PRAGMA integrity_check;"

# List all tables
sqlite3 /os/ai/io/ko_center.db3 ".tables"

# Get table row counts
sqlite3 /os/ai/io/ko_center.db3 "SELECT name, (SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name=m.name) FROM sqlite_master m WHERE type='table';"

# Vacuum the database (reclaim space)
sqlite3 /os/ai/io/ko_center.db3 "VACUUM;"

# Backup the database
cp /os/ai/io/ko_center.db3 /os/ai/io/ko_center.db3.backup.$(date +%Y%m%d)

# Export a table to CSV
sqlite3 -header -csv /os/ai/io/ko_center.db3 "SELECT * FROM leds LIMIT 100;" &gt; leds_export.csv
</pre>

<h3>4.5 Creating New Tables</h3>
<p>Use the <code>pdo_create()</code> function (line 9785) or the <code>pdo_cr_*()</code>
functions for table creation:</p>
<pre>
function pdo_create( $dbfile, $tblname, $sql ) {
    $pdo = newpdo( $dbfile );
    $pdo->exec("DROP TABLE IF EXISTS $tblname");
    $pdo->exec($sql);
    $pdo = null;
}
</pre>

<!-- ================================================================== -->
<h2 id="users">5. User &amp; Role Management</h2>
<!-- ================================================================== -->

<h3>5.1 Authentication Flow</h3>
<ol>
  <li>User accesses <code>?q=login</code> → <code>leds_login_form()</code></li>
  <li>User submits credentials → <code>leds_login_validate()</code></li>
  <li>Credentials checked against <code>hosts.allow</code> file</li>
  <li>On success: <code>$_SESSION['user']</code> and <code>$_SESSION['role']</code> set</li>
  <li>On failure: Login form redisplayed</li>
</ol>

<h3>5.2 Role-Based Access</h3>
<p>The system supports the following roles (from the PHP code):</p>
<table>
<tr><th>Role</th><th>Description</th><th>Access Level</th></tr>
<tr><td><code>guest</code></td><td>Unauthenticated user</td><td>Read-only, limited features</td></tr>
<tr><td><code>user</code></td><td>Standard authenticated user</td><td>View LED status, basic navigation</td></tr>
<tr><td><code>qc</code></td><td>Quality control</td><td>View + QC-specific features</td></tr>
<tr><td><code>manager</code></td><td>Manager</td><td>View + management features</td></tr>
<tr><td><code>operator</code></td><td>Operator</td><td>View + operational features</td></tr>
<tr><td><code>admin</code></td><td>Administrator</td><td>Full access, all features</td></tr>
</table>

<h3>5.3 Session Variables</h3>
<table>
<tr><th>Variable</th><th>Set By</th><th>Description</th></tr>
<tr><td><code>$_SESSION['user']</code></td><td>leds_login_validate()</td><td>Username</td></tr>
<tr><td><code>$_SESSION['role']</code></td><td>leds_login_validate()</td><td>User role</td></tr>
<tr><td><code>$_SESSION['preview']</code></td><td>User toggle</td><td>Preview mode (on/off)</td></tr>
<tr><td><code>$_SESSION['theme']</code></td><td>User selection</td><td>UI theme</td></tr>
<tr><td><code>$_SESSION['grid_zoom']</code></td><td>User toggle</td><td>Grid zoom state</td></tr>
<tr><td><code>$_SESSION['hs_type']</code></td><td>User selection</td><td>Hotspot type</td></tr>
<tr><td><code>$_SESSION['org_type']</code></td><td>User selection</td><td>Organization type</td></tr>
<tr><td><code>$_SESSION['gridimgpath']</code></td><td>js_scripts()</td><td>Theme image path</td></tr>
</table>

<!-- ================================================================== -->
<h2 id="security">6. Security</h2>
<!-- ================================================================== -->

<div class="warning">
<strong>Security Warning:</strong> ko_center.php is a legacy application with
several known security concerns. Review and address these before deploying
in a production environment.
</div>

<h3>6.1 Known Security Issues</h3>
<table>
<tr><th>Issue</th><th>Location</th><th>Risk</th><th>Mitigation</th></tr>
<tr>
  <td>SQL Injection</td>
  <td>leds_show() line 6939, multiple grid functions</td>
  <td>High</td>
  <td>Use prepared statements instead of string interpolation in SQL queries</td>
</tr>
<tr>
  <td>No CSRF Protection</td>
  <td>All form submissions</td>
  <td>Medium</td>
  <td>Add CSRF tokens to all forms</td>
</tr>
<tr>
  <td>No XSS Filtering</td>
  <td>All user input displayed</td>
  <td>Medium</td>
  <td>Use <code>htmlspecialchars()</code> on all user-supplied output</td>
</tr>
<tr>
  <td>Plain Text Passwords</td>
  <td>randomus table (login_pass column)</td>
  <td>High</td>
  <td>Hash passwords with bcrypt or Argon2</td>
</tr>
<tr>
  <td>No Rate Limiting</td>
  <td>Login form, all endpoints</td>
  <td>Medium</td>
  <td>Implement rate limiting on authentication endpoints</td>
</tr>
<tr>
  <td>Directory Traversal</td>
  <td>File operations in kb, upload</td>
  <td>High</td>
  <td>Sanitize all file paths, restrict to allowed directories</td>
</tr>
<tr>
  <td>Error Reporting Disabled</td>
  <td>startup() line 107: <code>error_reporting(0)</code></td>
  <td>Low</td>
  <td>Enable error logging to file in production; disable display</td>
</tr>
<tr>
  <td>Shell Command Injection</td>
  <td>leds_process(), iperms(), localcmds()</td>
  <td>Critical</td>
  <td>Avoid passing user input to shell commands; use escapeshellarg()</td>
</tr>
</table>

<h3>6.2 Authentication</h3>
<p>The authentication system uses a simple hosts.allow file check:</p>
<pre>
$allowflag = file_get_contents($GLOBALS['hosts_allow']);
$allowflag_fields = explode(" ", $allowflag);
$user = $allowflag_fields[2];
</pre>
<p>This is a very basic authentication mechanism. For production use,
consider implementing proper password hashing and database-based
authentication.</p>

<h3>6.3 Session Security</h3>
<p>The PHP session configuration is minimal. Consider adding:</p>
<ul>
  <li><code>session_regenerate_id(true)</code> after login</li>
  <li>Session timeout configuration</li>
  <li>Secure cookie flags (HttpOnly, Secure, SameSite)</li>
</ul>

<!-- ================================================================== -->
<h2 id="logging">7. Logging &amp; Debugging</h2>
<!-- ================================================================== -->

<h3>7.1 Log File Configuration</h3>
<p>Log files are created in the <code>ko_safer</code> directory with a monthly
naming convention:</p>
<pre>
Log file: /os/ai/io/../ko_safer/ko_center_YYYYMM.log
Example: /os/ai/io/../ko_safer/ko_center_202608.log
</pre>

<p>The log file path is constructed in <code>startup()</code> (line 145-148):</p>
<pre>
$yyyymm = date('Ym');
$logfil_basename = $progid . "_" . $yyyymm . ".log";
$logfil_rootpath = $document_root . "/../ko_safer";
$logfil = $logfil_rootpath . "/" . $logfil_basename;
</pre>

<h3>7.2 Logging Functions</h3>
<table>
<tr><th>Function</th><th>Line</th><th>Description</th></tr>
<tr><td><code>logwrite($logfil, $logrec)</code></td><td>4673</td><td>Write a record to the log file</td></tr>
<tr><td><code>logdump($logfil)</code></td><td>4683</td><td>Dump entire log file contents</td></tr>
<tr><td><code>bugfile($options)</code></td><td>10993</td><td>Write debug info to fp_bugs.txt (dbfile, url_table, page, etc.)</td></tr>
</table>

<h3>7.3 Debugging</h3>
<p>Debug output is controlled by commented-out print statements throughout the
code. To enable debugging:</p>
<ol>
  <li>Remove the <code>//</code> comment markers from debug print statements</li>
  <li>Set <code>error_reporting(E_ALL)</code> in startup() (currently set to 0)</li>
  <li>Check the log file: <code>/os/ai/io/../ko_safer/ko_center_YYYYMM.log</code></li>
  <li>Use <code>?q=about</code> or <code>?q=pdo</code> for basic diagnostics</li>
</ol>

<h3>7.4 Error Handling</h3>
<p>The PHP error reporting is disabled (<code>error_reporting(0)</code> at line 107).
Errors are silently suppressed. The application uses custom error messages
embedded in HTML output rather than PHP exceptions.</p>

<!-- ================================================================== -->
<h2 id="backup">8. Backup &amp; Recovery</h2>
<!-- ================================================================== -->

<h3>8.1 Backup Strategy</h3>
<pre>
# Daily backup script
#!/bin/bash
DB="/os/ai/io/ko_center.db3"
BACKUP_DIR="/os/ai/io/backups"
DATE=$(date +%Y%m%d_%H%M%S)

mkdir -p $BACKUP_DIR
cp $DB "$BACKUP_DIR/ko_center_$DATE.db3"
gzip "$BACKUP_DIR/ko_center_$DATE.db3"

# Keep only last 30 days
find $BACKUP_DIR -name "ko_center_*.db3.gz" -mtime +30 -delete
</pre>

<h3>8.2 Recovery Procedure</h3>
<ol>
  <li>Stop the web server</li>
  <li>Copy backup file to database location:
    <pre>cp /os/ai/io/backups/ko_center_YYYYMMDD_HHMMSS.db3.gz /os/ai/io/ko_center.db3.gz</pre></li>
  <li>Decompress: <code>gunzip /os/ai/io/ko_center.db3.gz</code></li>
  <li>Verify integrity: <code>sqlite3 /os/ai/io/ko_center.db3 "PRAGMA integrity_check;"</code></li>
  <li>Set correct permissions: <code>chown www-data:www-data /os/ai/io/ko_center.db3</code></li>
  <li>Start the web server</li>
</ol>

<h3>8.3 Important Files to Backup</h3>
<table>
<tr><th>File</th><th>Description</th></tr>
<tr><td><code>/os/ai/io/ko_center.db3</code></td><td>Main SQLite database</td></tr>
<tr><td><code>/os/ai/io/ko_center_certs.db3</code></td><td>Certificates database</td></tr>
<tr><td><code>/os/ai/io/koaac_kb.db3</code></td><td>Knowledge Base database</td></tr>
<tr><td><code>/os/ai/io/safer/hosts.allow</code></td><td>Authentication/authorization file</td></tr>
<tr><td><code>/os/ai/io/ko_center.php</code></td><td>Application source code</td></tr>
<tr><td><code>/os/ai/io/images/</code></td><td>Button, animation, and floor plan images</td></tr>
<tr><td><code>/os/ai/io/ko_center/kb/</code></td><td>Knowledge Base file attachments</td></tr>
<tr><td><code>/os/ai/io/../ko_safer/</code></td><td>Log files</td></tr>
</table>

<!-- ================================================================== -->
<h2 id="maintenance">9. Maintenance Tasks</h2>
<!-- ================================================================== -->

<h3>9.1 Routine Maintenance</h3>
<table>
<tr><th>Task</th><th>Frequency</th><th>Command/Action</th></tr>
<tr><td>Database backup</td><td>Daily</td><td>Copy ko_center.db3 to backup directory</td></tr>
<tr><td>Log rotation</td><td>Monthly</td><td>Compress old log files, delete logs older than 90 days</td></tr>
<tr><td>Database vacuum</td><td>Monthly</td><td><code>sqlite3 ko_center.db3 "VACUUM;"</code></td></tr>
<tr><td>Disk space check</td><td>Weekly</td><td><code>df -h /os/ai/io/</code></td></tr>
<tr><td>File permissions check</td><td>Weekly</td><td>Verify db3 file is writable by web server</td></tr>
<tr><td>Image asset check</td><td>Monthly</td><td>Verify btn/, ani/, fpb/ directories have expected images</td></tr>
<tr><td>KB cleanup</td><td>Monthly</td><td>Remove old or unused KB entries</td></tr>
<tr><td>LED record cleanup</td><td>Monthly</td><td>Archive or delete old LED records (led_dttm != 'current')</td></tr>
</table>

<h3>9.2 LED Record Management</h3>
<p>LED records use <code>led_dttm = 'current'</code> to mark active records.
Historical records can be archived or deleted:</p>
<pre>
-- Archive old LED records
INSERT INTO leds_archive SELECT * FROM leds WHERE led_dttm != 'current';
DELETE FROM leds WHERE led_dttm != 'current';
</pre>

<h3>9.3 Database Optimization</h3>
<pre>
# Rebuild indexes
sqlite3 /os/ai/io/ko_center.db3 "REINDEX;"

# Analyze tables for query optimization
sqlite3 /os/ai/io/ko_center.db3 "ANALYZE;"

# Check database size
ls -lh /os/ai/io/ko_center.db3

# Check for fragmentation
sqlite3 /os/ai/io/ko_center.db3 "PRAGMA freelist_count;"
</pre>

<!-- ================================================================== -->
<h2 id="troubleshoot">10. Troubleshooting</h2>
<!-- ================================================================== -->

<h3>10.1 Common Issues</h3>

<table>
<tr><th>Symptom</th><th>Cause</th><th>Solution</th></tr>
<tr>
  <td>Blank page</td>
  <td>PHP error suppressed by <code>error_reporting(0)</code></td>
  <td>Enable error reporting temporarily: change <code>error_reporting(0)</code> to <code>error_reporting(E_ALL)</code> in startup()</td>
</tr>
<tr>
  <td>Database not found error</td>
  <td><code>ko_center.db3</code> missing or wrong path</td>
  <td>Verify <code>$GLOBALS['dbfile']</code> path in startup(); run <code>leds_install("new")</code></td>
</tr>
<tr>
  <td>Permission denied</td>
  <td>Web server user cannot write to db3 file or directories</td>
  <td><code>chown www-data:www-data ko_center.db3</code>; <code>chmod 666 ko_center.db3</code></td>
</tr>
<tr>
  <td>LED images not showing</td>
  <td>Missing <code>ani_*.gif</code> files in <code>images/ani/</code></td>
  <td>Run <code>python3 cr_leds.py</code> to generate LED GIF images</td>
</tr>
<tr>
  <td>Button images not showing</td>
  <td>Missing <code>btn_*.gif</code> files in <code>images/btn/</code></td>
  <td>Verify button images exist in <code>/os/ai/io/images/btn/</code></td>
</tr>
<tr>
  <td>Login fails</td>
  <td><code>hosts.allow</code> file missing or wrong format</td>
  <td>Check <code>/os/ai/io/../safer/hosts.allow</code> exists and has correct format</td>
</tr>
<tr>
  <td>Trigger not working</td>
  <td><code>ko_trigger.dat</code> file not writable</td>
  <td><code>touch /os/ai/io/ko_trigger.dat &amp;&amp; chmod 666 /os/ai/io/ko_trigger.dat</code></td>
</tr>
<tr>
  <td>Grid view empty</td>
  <td>Table doesn't exist or has no data</td>
  <td>Verify table exists in database; check SQL query</td>
</tr>
<tr>
  <td>Report export fails</td>
  <td>CSV/XML export path issues</td>
  <td>Check file write permissions in report output directory</td>
</tr>
<tr>
  <td>Slow page loads</td>
  <td>Large database (39.6 MB), complex queries</td>
  <td>Run <code>VACUUM</code> and <code>ANALYZE</code>; add indexes to frequently queried columns</td>
</tr>
</table>

<h3>10.2 Debug Checklist</h3>
<ol>
  <li>Check if PHP is running: <code>php -v</code></li>
  <li>Check if database exists: <code>ls -la /os/ai/io/ko_center.db3</code></li>
  <li>Check database integrity: <code>sqlite3 ko_center.db3 "PRAGMA integrity_check;"</code></li>
  <li>Check web server error log: <code>tail -f /var/log/apache2/error.log</code></li>
  <li>Check application log: <code>ls -la /os/ai/io/../ko_safer/</code></li>
  <li>Verify file permissions on all directories</li>
  <li>Test with <code>?q=about</code> to verify basic functionality</li>
  <li>Test with <code>?q=pdo</code> to verify database connectivity</li>
</ol>

<!-- ================================================================== -->
<h2 id="files">11. File Structure &amp; Assets</h2>
<!-- ================================================================== -->

<h3>11.1 Directory Layout</h3>
<pre>
/os/ai/io/
├── ko_center.php          # Main application (16,322 lines)
├── ko_center.db3          # SQLite database (39.6 MB)
├── ko_center.md           # Documentation (markdown)
├── ko_center.txt          # Documentation (text)
├── ko_center.py           # Python Flask equivalent
├── new_leds.py            # Create leds_randomus table
├── new_leds_tbl.py        # Generalized table creation script
├── cr_leds.py             # LED GIF generation script
├── ko_trigger.dat         # Trigger timestamp file (runtime)
├── prompt_*.txt           # Original task prompts
├── response_*.txt         # Response documents
├── images/
│   ├── btn/               # Button images (btn_black.gif, btn_white.gif, etc.)
│   ├── ani/               # Animated LED GIFs (ani_red0.gif, etc.)
│   ├── fpb/               # Floor plan button images
│   └── cab/               # Cabinet images
├── ko_center/
│   ├── db3/               # Additional database files
│   │   ├── ko_center_certs.db3
│   │   └── koaac_kb.db3
│   └── kb/                # Knowledge Base file storage
├── ../safer/
│   └── hosts.allow        # Authentication/authorization file
├── ../ko_safer/
│   └── ko_center_YYYYMM.log  # Monthly log files
├── js/
│   ├── jquery-1.7.2.min.js
│   ├── jquery-ui-1.7.2.custom.min.js
│   ├── fg-menu/           # fg-menu JavaScript and CSS
│   ├── jqgrid-4.4.0/      # jqGrid library
│   └── tooltip/           # Tooltip JavaScript
└── css/
    └── (theme CSS files)
</pre>

<h3>11.2 Image Assets</h3>
<table>
<tr><th>Directory</th><th>Content</th><th>Generated By</th></tr>
<tr><td><code>images/btn/</code></td><td>Button GIFs (btn_black.gif, btn_white.gif, btn_red.gif, etc.)</td><td>Manual creation</td></tr>
<tr><td><code>images/ani/</code></td><td>LED animated GIFs (ani_red0.gif through ani_trans3.gif)</td><td><code>cr_leds.py</code></td></tr>
<tr><td><code>images/fpb/</code></td><td>Floor plan button images and thumbnails</td><td>Manual creation</td></tr>
<tr><td><code>images/cab/</code></td><td>Cabinet/rack images</td><td>Manual creation</td></tr>
</table>

<!-- ================================================================== -->
<h2 id="functions">12. PHP Function Reference</h2>
<!-- ================================================================== -->

<h3>12.1 Core Functions</h3>
<table>
<tr><th>Function</th><th>Line</th><th>Purpose</th></tr>
<tr><td><code>startup()</code></td><td>101</td><td>Application initialization: session, globals, paths, config</td></tr>
<tr><td><code>html_header()</code></td><td>8395</td><td>Generate HTML <code>&lt;head&gt;</code> section with CSS/JS includes</td></tr>
<tr><td><code>html_footer()</code></td><td>10987</td><td>Generate HTML <code>&lt;/body&gt;&lt;/html&gt;</code> closing tags</td></tr>
<tr><td><code>html_page()</code></td><td>6635</td><td>Generate complete HTML page (header + buttons + content + footer)</td></tr>
<tr><td><code>html_btn_squares()</code></td><td>7331</td><td>Generate navigation button squares</td></tr>
<tr><td><code>js_scripts()</code></td><td>14337</td><td>Generate JavaScript includes (jQuery, jqGrid, fg-menu)</td></tr>
<tr><td><code>leds_show()</code></td><td>6895</td><td>Main LED display function - queries DB and renders LED grid</td></tr>
<tr><td><code>leds_detail()</code></td><td>7759</td><td>LED detail view with associated hardware items</td></tr>
<tr><td><code>leds_about()</code></td><td>6323</td><td>About page</td></tr>
<tr><td><code>leds_login_form()</code></td><td>8450</td><td>Login form HTML</td></tr>
<tr><td><code>leds_login_validate()</code></td><td>8568</td><td>Login credential validation</td></tr>
<tr><td><code>leds_logout()</code></td><td>8739</td><td>Session cleanup and redirect</td></tr>
<tr><td><code>leds_config()</code></td><td>6653</td><td>Configuration page with theme/org/role/preview buttons</td></tr>
<tr><td><code>leds_install()</code></td><td>9707</td><td>Database initialization - creates all tables and default data</td></tr>
</table>

<h3>12.2 Database Functions</h3>
<table>
<tr><th>Function</th><th>Line</th><th>Purpose</th></tr>
<tr><td><code>newpdo($dbfile)</code></td><td>6595</td><td>Create SQLite PDO connection</td></tr>
<tr><td><code>pdo_create($dbfile, $tblname, $sql)</code></td><td>9785</td><td>Create a new database table</td></tr>
<tr><td><code>pdo_insert($dbfile, $tblname, $data)</code></td><td>9799</td><td>Insert a row into a table</td></tr>
<tr><td><code>pdo_cr_leds()</code></td><td>9929</td><td>Create the leds table</td></tr>
<tr><td><code>pdo_cr_kb()</code></td><td>9981</td><td>Create the KB table</td></tr>
<tr><td><code>pdo_cr_nodes()</code></td><td>10132</td><td>Create the nodes table</td></tr>
<tr><td><code>pdo_cr_roles()</code></td><td>10166</td><td>Create the roles table</td></tr>
<tr><td><code>pdo_cr_users()</code></td><td>10178</td><td>Create the users table</td></tr>
<tr><td><code>pdo_cr_grid()</code></td><td>10220</td><td>Create the grid table</td></tr>
<tr><td><code>pdo_cr_hw()</code></td><td>10261</td><td>Create the hw table</td></tr>
<tr><td><code>pdo_cr_n11()</code></td><td>10282</td><td>Create the n11 table</td></tr>
<tr><td><code>pdo_cr_dbs()</code></td><td>15641</td><td>Create the dbs (database registry) table</td></tr>
<tr><td><code>pdo_cr_flds()</code></td><td>15728</td><td>Create the flds (fields) table</td></tr>
<tr><td><code>pdo_insert_leds()</code></td><td>10305</td><td>Insert default LED records</td></tr>
<tr><td><code>pdo_insert_nodes()</code></td><td>10423</td><td>Insert default node records</td></tr>
<tr><td><code>pdo_insert_roles()</code></td><td>10474</td><td>Insert default role records</td></tr>
<tr><td><code>pdo_insert_users()</code></td><td>10491</td><td>Insert default user records</td></tr>
<tr><td><code>pdo_grid($options)</code></td><td>10686</td><td>Generate sortable/filterable database grid view</td></tr>
<tr><td><code>pdo_gridxml($options)</code></td><td>11021</td><td>Export grid data as XML</td></tr>
<tr><td><code>pdo_unload($options)</code></td><td>11693</td><td>Unload/export table data</td></tr>
<tr><td><code>pdo_list($options)</code></td><td>11786</td><td>List all database tables</td></tr>
<tr><td><code>pdo_update($options)</code></td><td>11790</td><td>Update table data</td></tr>
<tr><td><code>pdo_load($options)</code></td><td>11794</td><td>Load table data</td></tr>
</table>

<h3>12.3 Report Functions</h3>
<table>
<tr><th>Function</th><th>Line</th><th>Purpose</th></tr>
<tr><td><code>leds_reports_sql($options)</code></td><td>3681</td><td>SQL query interface for reports</td></tr>
<tr><td><code>leds_reports_csv($dbfile, $sql, $csvfil)</code></td><td>3841</td><td>Export report data as CSV</td></tr>
<tr><td><code>leds_reports_rpt($options)</code></td><td>3931</td><td>Generate formatted report</td></tr>
<tr><td><code>rptsxml($options)</code></td><td>16043</td><td>XML report generation</td></tr>
<tr><td><code>rpts($options)</code></td><td>16134</td><td>Report listing and management</td></tr>
</table>

<h3>12.4 KB Functions</h3>
<table>
<tr><th>Function</th><th>Line</th><th>Purpose</th></tr>
<tr><td><code>leds_kb($options)</code></td><td>12401</td><td>Knowledge Base listing</td></tr>
<tr><td><code>leds_kb_rpts($options)</code></td><td>12594</td><td>KB reports</td></tr>
<tr><td><code>koaac_kb_new_form($options)</code></td><td>4844</td><td>New KB entry form</td></tr>
<tr><td><code>koaac_kb_add_form($options)</code></td><td>5436</td><td>Add KB entry form</td></tr>
<tr><td><code>koaac_kb_upload($kbid)</code></td><td>5690</td><td>KB file upload</td></tr>
<tr><td><code>kbwrite($kbfil, $kbrec)</code></td><td>4661</td><td>Write KB record to file</td></tr>
<tr><td><code>kb_ls($options, $path)</code></td><td>4701</td><td>List KB files</td></tr>
<tr><td><code>kb_mkdir($kbpath, $kbid)</code></td><td>6031</td><td>Create KB directory</td></tr>
</table>

<h3>12.5 Utility Functions</h3>
<table>
<tr><th>Function</th><th>Line</th><th>Purpose</th></tr>
<tr><td><code>logwrite($logfil, $logrec)</code></td><td>4673</td><td>Write to log file</td></tr>
<tr><td><code>logdump($logfil)</code></td><td>4683</td><td>Dump log file contents</td></tr>
<tr><td><code>bugfile($options)</code></td><td>10993</td><td>Write debug info to file</td></tr>
<tr><td><code>ko_unique()</code></td><td>14904</td><td>Generate UUID</td></tr>
<tr><td><code>ko_unique1()</code></td><td>14909</td><td>Generate short unique ID</td></tr>
<tr><td><code>pc_encode($data)</code></td><td>14918</td><td>PC encoding (obfuscation)</td></tr>
<tr><td><code>pc_decode($data, $hash)</code></td><td>14923</td><td>PC decoding</td></tr>
<tr><td><code>datediff($interval, $date1, $date2)</code></td><td>14939</td><td>Calculate date difference</td></tr>
<tr><td><code>datediff_leds($diffdays)</code></td><td>14951</td><td>LED-specific date difference (color/speed calculation)</td></tr>
<tr><td><code>iperms($options)</code></td><td>6425</td><td>System permissions/utility functions</td></tr>
<tr><td><code>localcmds($options)</code></td><td>15887</td><td>Local command execution</td></tr>
<tr><td><code>telnet($options)</code></td><td>15939</td><td>Telnet connection utility</td></tr>
<tr><td><code>ko_imap($options)</code></td><td>14700</td><td>IMAP email functions</td></tr>
<tr><td><code>email_headers()</code></td><td>16117</td><td>Email header generation</td></tr>
<tr><td><code>leds_process($title, $cmd, $cwd)</code></td><td>6485</td><td>Execute shell process and display output</td></tr>
<tr><td><code>leds_process_psv($title, $cmd, $cwd)</code></td><td>6519</td><td>Execute Perl script process</td></tr>
<tr><td><code>leds_process_value($title, $cmd, $cwd)</code></td><td>6560</td><td>Execute command and return value</td></tr>
</table>

<h3>12.6 AJAX Functions</h3>
<table>
<tr><th>Function</th><th>Line</th><th>Purpose</th></tr>
<tr><td><code>ko_ajax($options)</code></td><td>2508</td><td>AJAX request handler</td></tr>
<tr><td><code>ko_ajax_controller($options)</code></td><td>2532</td><td>Generate AJAX controller JavaScript</td></tr>
<tr><td><code>ko_ajax_listener($options)</code></td><td>2555</td><td>Generate AJAX listener JavaScript</td></tr>
<tr><td><code>ko_ajax_app($options)</code></td><td>2580</td><td>Generate AJAX app JavaScript (includes refreshPage handler)</td></tr>
<tr><td><code>ko_ajax_complete($options)</code></td><td>2599</td><td>Generate AJAX complete handler</td></tr>
<tr><td><code>ko_ajax_result($options)</code></td><td>2616</td><td>Generate ServiceResult class JavaScript</td></tr>
</table>

<!-- ================================================================== -->
<h2 id="deploy">13. Deployment</h2>
<!-- ================================================================== -->

<h3>13.1 Apache Configuration</h3>
<pre>
&lt;VirtualHost *:80&gt;
    ServerName ko_center.example.com
    DocumentRoot /os/ai/io

    &lt;Directory /os/ai/io&gt;
        Options +FollowSymLinks
        AllowOverride None
        Require all granted
    &lt;/Directory&gt;

    # PHP configuration
    php_value upload_max_filesize 50M
    php_value post_max_size 50M
    php_value max_execution_time 300
    php_value memory_limit 256M

    # SQLite configuration
    php_value sqlite.assoc_case 0

    ErrorLog /var/log/apache2/ko_center_error.log
    CustomLog /var/log/apache2/ko_center_access.log combined
&lt;/VirtualHost&gt;
</pre>

<h3>13.2 Python Flask Deployment</h3>
<p>The Python Flask equivalent (<code>ko_center.py</code>) can be deployed with:</p>
<pre>
# Development server
python3 /os/ai/io/ko_center.py

# Production with Gunicorn
gunicorn -w 4 -b 0.0.0.0:5000 ko_center:app

# Production with systemd service
# Create /etc/systemd/system/ko_center.service:
[Unit]
Description=ko_center Python Web Application
After=network.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/os/ai/io
ExecStart=/usr/bin/python3 /os/ai/io/ko_center.py
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
</pre>

<h3>13.3 Environment Variables</h3>
<table>
<tr><th>Variable</th><th>Default</th><th>Description</th></tr>
<tr><td><code>KO_THEME</code></td><td><code>redmond</code></td><td>jQuery UI theme name</td></tr>
<tr><td><code>KO_DB_FILE</code></td><td><code>/os/ai/io/ko_center.db3</code></td><td>Database file path</td></tr>
<tr><td><code>KO_HOSTS_ALLOW</code></td><td><code>/os/ai/io/../safer/hosts.allow</code></td><td>Authentication file path</td></tr>
<tr><td><code>KO_LOG_DIR</code></td><td><code>/os/ai/io/../ko_safer</code></td><td>Log file directory</td></tr>
<tr><td><code>KO_TRIGGER_FILE</code></td><td><code>/os/ai/io/ko_trigger.dat</code></td><td>Trigger timestamp file</td></tr>
</table>

<!-- ================================================================== -->
<h2 id="python">14. Python Flask Equivalent</h2>
<!-- ================================================================== -->

<p>A Python Flask equivalent of ko_center.php has been created at
<code>/os/ai/io/ko_center.py</code>. Key differences from the PHP version:</p>

<table>
<tr><th>Aspect</th><th>PHP Version</th><th>Python Version</th></tr>
<tr><td>Web Framework</td><td>Apache + mod_php</td><td>Flask (built-in development server)</td></tr>
<tr><td>Routing</td><td><code>?q=page/action/id</code> parsed manually</td><td>Flask <code>@app.route</code> decorators</td></tr>
<tr><td>Database</td><td>PDO SQLite</td><td>Python <code>sqlite3</code> module</td></tr>
<tr><td>Sessions</td><td><code>$_SESSION</code></td><td>Flask <code>session</code></td></tr>
<tr><td>HTML Generation</td><td>String concatenation in functions</td><td>String concatenation in functions</td></tr>
<tr><td>Authentication</td><td>hosts.allow file check</td><td>Same hosts.allow file check</td></tr>
<tr><td>AJAX</td><td>jQuery AJAX + custom ko_ajax functions</td><td>Flask <code>jsonify()</code> + jQuery AJAX</td></tr>
<tr><td>File Upload</td><td><code>$_FILES</code> superglobal</td><td>Flask <code>request.files</code></td></tr>
<tr><td>Process Execution</td><td><code>system()</code>, <code>exec()</code>, <code>passthru()</code></td><td><code>subprocess</code> module</td></tr>
</table>

<p><strong>Running the Python version:</strong></p>
<pre>python3 /os/ai/io/ko_center.py</pre>

<!-- ================================================================== -->
<h2 id="api">15. API Endpoints</h2>
<!-- ================================================================== -->

<h3>15.1 Query Parameter Routes</h3>
<table>
<tr><th>Route</th><th>Method</th><th>Description</th></tr>
<tr><td><code>?q=leds</code></td><td>GET</td><td>Display LED indicators</td></tr>
<tr><td><code>?q=leds/detail/&lt;name&gt;</code></td><td>GET</td><td>LED detail view</td></tr>
<tr><td><code>?q=login</code></td><td>GET</td><td>Login form</td></tr>
<tr><td><code>?q=login_validate</code></td><td>POST</td><td>Process login</td></tr>
<tr><td><code>?q=logout</code></td><td>GET</td><td>Logout</td></tr>
<tr><td><code>?q=trigger</code></td><td>GET</td><td>Broadcast trigger (JSON response)</td></tr>
<tr><td><code>?q=grid?dbcode=&lt;db&gt;&amp;table=&lt;tbl&gt;</code></td><td>GET</td><td>Database grid view</td></tr>
<tr><td><code>?q=reports/sql</code></td><td>GET</td><td>SQL query interface</td></tr>
<tr><td><code>?q=reports/rpt/&lt;code&gt;</code></td><td>GET</td><td>Run named report</td></tr>
<tr><td><code>?q=kb</code></td><td>GET</td><td>Knowledge Base listing</td></tr>
<tr><td><code>?q=kb/new</code></td><td>GET</td><td>New KB entry form</td></tr>
<tr><td><code>?q=kb/view/&lt;id&gt;</code></td><td>GET</td><td>View KB entry</td></tr>
<tr><td><code>?q=certs</code></td><td>GET</td><td>Certificate listing</td></tr>
<tr><td><code>?q=nodes</code></td><td>GET</td><td>Node listing</td></tr>
<tr><td><code>?q=hw</code></td><td>GET</td><td>Hardware inventory</td></tr>
<tr><td><code>?q=hw?cab=&lt;cab&gt;</code></td><td>GET</td><td>Hardware filtered by cabinet</td></tr>
<tr><td><code>?q=hw?sn=&lt;sn&gt;</code></td><td>GET</td><td>Hardware filtered by serial number</td></tr>
<tr><td><code>?q=hw?ip=&lt;ip&gt;</code></td><td>GET</td><td>Hardware filtered by IP address</td></tr>
<tr><td><code>?q=hw?hrctag=&lt;tag&gt;</code></td><td>GET</td><td>Hardware filtered by HRC tag</td></tr>
<tr><td><code>?q=plans</code></td><td>GET</td><td>Plan listing</td></tr>
<tr><td><code>?q=config</code></td><td>GET</td><td>Configuration page</td></tr>
<tr><td><code>?q=zoom/&lt;code&gt;/&lt;type&gt;/&lt;rowid&gt;</code></td><td>GET</td><td>Zoom viewer</td></tr>
<tr><td><code>?q=zview/&lt;file&gt;/&lt;xml&gt;</code></td><td>GET</td><td>Full-screen zoom view</td></tr>
<tr><td><code>?q=ptviewer</code></td><td>GET</td><td>Panorama viewer</td></tr>
<tr><td><code>?q=ptobject</code></td><td>GET</td><td>Panorama object viewer</td></tr>
<tr><td><code>?q=scrub</code></td><td>GET</td><td>Scrub/data cleanup</td></tr>
<tr><td><code>?q=upload</code></td><td>GET/POST</td><td>File upload</td></tr>
<tr><td><code>?q=sql</code></td><td>GET</td><td>SQL query interface</td></tr>
<tr><td><code>?q=about</code></td><td>GET</td><td>About page</td></tr>
<tr><td><code>?q=konet</code></td><td>GET</td><td>Contact information</td></tr>
<tr><td><code>?q=form_request_access</code></td><td>GET</td><td>Access request form</td></tr>
<tr><td><code>?q=pdo_cr_kb</code></td><td>GET</td><td>Create KB table</td></tr>
<tr><td><code>?q=pdo_cr_leds</code></td><td>GET</td><td>Create leds table</td></tr>
<tr><td><code>?q=pdo_insert_leds</code></td><td>GET</td><td>Insert LED record</td></tr>
<tr><td><code>?q=pdo_list</code></td><td>GET</td><td>List database tables</td></tr>
<tr><td><code>?q=pdo_unload?dbcode=&lt;db&gt;&amp;table=&lt;tbl&gt;</code></td><td>GET</td><td>Unload/export table</td></tr>
<tr><td><code>?q=pdo_update</code></td><td>GET</td><td>Update table data</td></tr>
<tr><td><code>?q=pdo_load</code></td><td>GET</td><td>Load table data</td></tr>
<tr><td><code>?q=pdo_gridxml?dbcode=&lt;db&gt;&amp;table=&lt;tbl&gt;</code></td><td>GET</td><td>Grid XML export</td></tr>
</table>

<h3>15.2 Trigger API</h3>
<p>The trigger endpoint provides a JSON API for browser refresh coordination:</p>

<h4>Request</h4>
<pre>GET /ko_center/ko_center.php?q=trigger[&amp;last_check=&lt;timestamp&gt;]</pre>

<h4>Response</h4>
<pre>{
  "triggered": true|false,
  "timestamp": "2026-08-01 07:05:00",
  "since": "2026-08-01 07:00:00"
}</pre>

<h4>Example</h4>
<pre>
# First call (no last_check)
GET /ko_center/ko_center.php?q=trigger
→ {"triggered": true, "timestamp": "2026-08-01 07:05:00", "since": ""}

# Subsequent call (no new trigger)
GET /ko_center/ko_center.php?q=trigger&amp;last_check=2026-08-01 07:05:00
→ {"triggered": false, "timestamp": "2026-08-01 07:05:00", "since": "2026-08-01 07:05:00"}

# Another browser calls trigger
GET /ko_center/ko_center.php?q=trigger
→ Writes new timestamp to ko_trigger.dat

# First browser's poll detects the change
GET /ko_center/ko_center.php?q=trigger&amp;last_check=2026-08-01 07:05:00
→ {"triggered": true, "timestamp": "2026-08-01 07:06:00", "since": "2026-08-01 07:05:00"}
# Browser reloads the page
</pre>

<!-- ================================================================== -->
<h2>Appendix A: Version History</h2>
<!-- ================================================================== -->

<table>
<tr><th>Version</th><th>Date</th><th>Changes</th></tr>
<tr><td>v0.70</td><td>2026-08-01</td><td>Current version: q=leds_context, ranks, randomus, actions</td></tr>
<tr><td>v0.67</td><td>2025-03-25</td><td>q=login debug</td></tr>
<tr><td>v0.66</td><td>2025-03-25</td><td>ERR_210 /etc/hosts.allow fix</td></tr>
<tr><td>v0.65</td><td>2020-10-14</td><td>fpbimg support</td></tr>
<tr><td>v0.64</td><td>2020-09-25</td><td>sql3_insert_hallo, sql3_select_hallo</td></tr>
<tr><td>v0.64</td><td>2020-09-23</td><td>Bug fixes, blank page fixes</td></tr>
<tr><td>v0.64</td><td>2019-08-27</td><td>leds_dragdrop support</td></tr>
<tr><td>v0.64</td><td>2012-12-10</td><td>leds_dragdrop initial</td></tr>
<tr><td>v0.64</td><td>2012-12-07</td><td>ko_ajax, ko_dragdrop, ko_im added</td></tr>
<tr><td>v0.62</td><td>2012-11-09</td><td>defrag/report support</td></tr>
<tr><td>v0.60</td><td>2012-10-27</td><td>passthru() support</td></tr>
<tr><td>v0.52</td><td>2012-08-29</td><td>?q=kb/rpts/rpt_id&fmt=xml &amp; fmt=csv</td></tr>
<tr><td>v0.50</td><td>2012-08-28</td><td>jqgrid-4.4.0 integration</td></tr>
<tr><td>v0.48</td><td>2012-08-24</td><td>ko_center.db3 nodes tables &amp; reports</td></tr>
<tr><td>v0.32</td><td>2012-07-30</td><td>pdo_cr_kb, pdo_cr_flds, new/add/mod/upd/view</td></tr>
<tr><td>v0.10</td><td>2012-05-16</td><td>refresh to kohpx_vg.php kohpx_us.php kohpx_sw.php</td></tr>
<tr><td>v0.01</td><td>2012-02-05</td><td>Initial version</td></tr>
</table>

<!-- ================================================================== -->
<h2>Appendix B: Python Scripts Reference</h2>
<!-- ================================================================== -->

<table>
<tr><th>Script</th><th>Purpose</th><th>Usage</th></tr>
<tr><td><code>ko_center.py</code></td><td>Python Flask equivalent of ko_center.php</td><td><code>python3 ko_center.py</code></td></tr>
<tr><td><code>new_leds.py</code></td><td>Create leds_randomus table from leds + randomus</td><td><code>python3 new_leds.py</code></td></tr>
<tr><td><code>new_leds_tbl.py</code></td><td>Generalized: create leds_&lt;tbl2&gt; from leds + any table</td><td><code>python3 new_leds_tbl.py &lt;tbl2&gt;</code></td></tr>
<tr><td><code>cr_leds.py</code></td><td>Create blinking LED GIF images with ImageMagick</td><td><code>python3 cr_leds.py &lt;static.png&gt; &lt;dynamic.png&gt;</code></td></tr>
</table>

</body>
</html>
//


koh5_pano



Your browser does not support the HTML5 canvas element.


Drag mouse to navigate.

Navigation





17.Aug.2010, Martin Wengenmayer