Im letzten Teil dieser Serie hatte ich beschrieben, wie man die IP-Steckdosenleiste unter PHP per SNMP anspricht und dafür einige PHP-Klassen vorgestellt. In diesem Teil geht es nun darum, ein PHP-Backend zu entwickeln. Erinnern wir uns: Die Applikation soll alle Ports der Steckdosenleiste grafisch mit ihrem Schaltzustand anzeigen. Neben den Ports soll die Grafik mit den angeschlossenen Geräten beschriftet werden. Ein Klick auf das jeweilige Steckdosensymbol soll einen Schaltvorgang auslösen. Aus dieser kurzen Funktionsbeschreibung folgt, welche Funktionalität unser Backend bereitstellen muss:

  • HTML-Grundgerüst für das HTML-Frontend ausliefern
  • Portbeschriftungen per SNMP aus der Steckdosenleiste auslesen
  • mittels Ajax aktuelle Portzustände per SNMP auslesen
  • mittels Ajax Portzustand per SNMP setzen

Beginnen wir also mit dem einfachen Teil, den Ajax-Funktionen:

$apc = new APCPDU( new SNMPv3_Agent( '10.10.99.1', 
                                     'apc snmp profile1', 'AuthenticationPassphrase', 'authPriv', 'MD5',
                                     'PrivacyPassphrase', 'DES'
                                   )
                 );

// set the outlet state
function setOutlet( $apc, $port, $mode ) {
        $result = [
                'result' => $apc->setOutlet( $port, $mode ) ? '1' : '0'
        ];
        header( 'Content-Type: application/json; charset=utf-8' );
        echo json_encode( $result );
}

// get the outlet state as JSON
function getOutletStates( $apc ) {
        $outletStates = [];
        $result = $apc->getOutletStates();
	foreach ( $result as $index => $status ) {
                $outletStates[ $index ] = strpos( $status, 'outletStatusOn' ) !== false ? 1 : 0;
        }
        header( 'Content-Type: application/json; charset=utf-8' );
        echo json_encode( $outletStates );
}

// get the outlet state as JSON
function getOutletNames( $apc ) {
        $outletNames = [];
        $result = $apc->getOutletNames();
	foreach ( $result as $index => $portName ) {
                $portNr = $index+1;
                $outletNames[ $index ] = [
                        name => $portName,
                        port => $portNr
                ];

        }
        header( 'Content-Type: application/json; charset=utf-8' );
        echo json_encode( $outletNames );
}

setOutlet() nimmt die Device-Instanz $apc, die Portnummer $port und den Schaltzustand $mode entgegen und ruft damit die gleichnamige Funktion des Device auf. Daraus generiert es ein Ergebnis-JSON-Objekt und liefert es aus. getOutletStates ruft ebenfalls die gleichnamige Device-Funktion auf. Als Ergebnis liefert es ein Array, wobei es es die SNMP-Zustandscodierung in numerische Werte 0 und 1 übersetzt. Nun braucht die index.php noch einen Funktionsdispatcher:

if ( $_GET[ 'command' ] == 'setOutlet' ) {
	$port = intval( $_GET[ 'port' ] );
	$mode = intval( $_GET[ 'mode' ] );
        setOutlet( $apc, $port, $mode );
}
elseif ( $_GET[ 'command' ] == 'getOutletStates' ) {
        getOutletStates( $apc );
}
elseif ( $_GET[ 'command' ] == 'getOutletNames' ) {
        getOutletNames( $apc );
}
else {
        showTemplate( $apc );
}

Dazu prüft die index.php den Kommandozeilenparameter command. Entsprechend des gesetzten Werts werden die jeweiligen Backendfunktionen aufgerufen. Dabei werden übergebene Parameter ggf. umgewandelt (wie bei setOutlet). Wenn kein Parameter angegeben ist, wird das HTML-Grundgerüst über die Funktion showTemplate() ausgeliefert.

Dieser Beispielapplikation fehlt selbstverständlich noch eine Autorisierung und Authentifizierung, denn man möchte sicherlich nicht, dass jede Person, die auf das Netzwerk Zugriff hat, auch die Steckdosen schalten kann. Dieser Teil ist aus Gründen der Vereinfachung hier weggelassen.

PHP war ursprünglich dazu gedacht, dynamische Webseiten serverseitig zu erzeugen. Dazu schrieb man früher HTML-Code und streute die bekannten PHP-Tags <?php ?> an den Stellen ein, wo PHP den HTML-Code erzeugen sollte. Das ergab dann ein wildes Durcheinander von HTML und PHP, der schlecht zu warten war. Heute trennt man die Logik in PHP von der Darstellung in HTML. Dies gelingt z. B. mit Template-Engines, von denen es zahlreiche gibt. Dieses Projekt verwendet die Lightweight Template Engine with PHP von David Adams. Mit ihr lassen sich Werte aus PHP ausgeben, indem man sie mit 2 geschweiften Klammern umschließt:

{{ $output }}

Setzt man 3 geschweifte Klammern, wird vor der Ausgabe htmlspecialchars() aufgerufen, um die Ausgabe zu escapen:

{{{ $output }}}

Um die Template-Engine zu nutzen, kopiert man sie in das lokale Verzeichnis und bindet sie mit include ein. Dann kann man mit Template::view() den Dateinamen einer Templatedatei übergeben sowie ein Array mit Variablen, die innerhalb des Templates ausgegeben werden können. Unsere Funktion showTemplate() sieht damit wie folgt aus:

function showTemplate( $apc ) {
        $outlets = [];
        $result = $apc->getOutletNames();
        foreach ( $result as $index => $portName ) {
                $portNr = $index+1;
                $outlets[ $index ] = [
                        name => $portName,
                        port => $portNr
                ];
        }

        // https://codeshack.io/lightweight-template-engine-php/
        include 'template.php';
        Template::view( 'index.tmpl', [
                pduName => $apc->getPDUName(),
                pduIdentModelNumber => $apc->getPDUIdentModelNumber(),
                identFirmwareRev => $apc->getIdentFirmwareRev(),
                outlets => $outlets
        ] );
}

Zunächst liest showTemplate die Portbeschreibungen über die SNMP-Funktion getOutletNames aus und speichert sie in einem Array mit Name und Portnummer. Dann instanziiert sie das Template index.tmpl und übergibt den Namen der Steckdose, die Modellbezeichnung und die Firmwareversion. Diese Informationen liest showTemplate ebenfalls per SNMP aus. Die Template-Engine setzt diese Werte in das Template ein und liefert es an den Browser zur Darstellung aus. Wie das Template genau aussieht und was der Browser damit anstellt, das beschreibt Teil 3 dieser Serie.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert