SIS Tabellengenerator aka. sis-xml-xsl

Bei diesem Projekt ging und es um die Generierung von HTML Tabellen aus XML Daten. Diese Aufgabe lässt sich vergleichsweise trivial mit XSL(T) lösen. (Stylesheet)

Die Tabellen waren also relativ schnell fertig. Nun bin ich aber Overthinker und kam darum auf die Idee dann noch einen Browser für die zugrundeliegende Schnittstelle einzubauen.

Die XML Schnittstelle um die es hier geht ist die der SIS um Handballergebnisse abzurufen. Ursprünglich gab es dafür ein Drop-In-Skript für die Einbettung für den eigenen Verein, das jetzt aber nicht mehr genutzt werden soll, wenn ich mich recht erinnere wird dort jetzt Werbung eingeblendet.

Strukturiert wird die Schnittstelle durch zwei Parameter, die "art", für die, was für ein Zufall, Art, und "auf" für das was ich Entität getauft habe. Die Art ist 1-indizierte, fortlaufende Nummer, die Entität eine numerische ID.

Die Entität kann u.a. ein Verein oder eine Liga sein, immer als numerische ID, wobei die IDs aller Vereine ein gemeinsames Präfix haben, die Ligen gleichermaßen.

Soweit ich herausfinden konnte, hört die Art bei 31 auf, ist aber bereits ab der 20 nicht mehr durchgängig belegt. Die menschenlesbare Art habe ich über Brute Force aus der Schnittstelle extrahiert, indem ich immer die gleiche Entität verwendet, die Art hochgezählt und dann das zurückgegebene XML-Root-Element als Namen verwendet habe, soweit die Antwort kein HTML war. Die Zuordnung von Index und Name habe ich dann "Schema" getauft.

Die Schnittstelle liefert bei einem Fehler eine HTML-Fehlerseite, wobei der scheinbar nur für unbelegte Arten auftritt. Die Unsinnigkeit der Parameterzusammensetzung führt zu keinem Fehler sondern zu einem leeren (selbstschließenden) Root-Element.

Soweit zur Schnittstelle. Um jetzt eine Tabelle generieren zu können, benötige ich nur noch sinnvolle Parameterkombinationen.

Die Schnittstelle ist durch Nutzername und Passwort geschützt. Die Daten sind hierbei äquivalent mit den normalen SIS Login-Daten.

SIS, als Anbieter der Schnittstelle bietet hierzu eine "Linkgenerator" an, mit dem sich ein Link einer XML generieren kann. Anhand des aktuellen Nutzers kann dort auch Verein oder Liga ausgewählt werden. Durch etwas herumprobieren fand ich dann eine Lösung.

Denn mit dem Nutzer als Entität und "Vereinsdaten" (Index 31) als Art liefert die Schnittstelle dort u.a. auch die Ligen in denen der aktuelle Verein spielt. Nutzer sind also anscheinend einem Verein zugeordnet oder entsprechen ihm möglicherweise sogar.

Für das Frontend habe ich mir dann eine einfache Navigation ausgedacht: Entweder der Nutzer steigt mit seiner Nutzer-ID ein und bekommt so dann Liga-IDs. Oder er kennt bereits eine Liga (oder ieine andere Entität), dann kann er die als Entität eintragen, eine Art auswählen und erhält dann seine Tabelle!

In Hintergrund rufen beide Wege einfach nur die XML Schnittstelle an, schicken das Ergebnis mit dem XSL Stylesheet durch den XSLT Prozessor und präsentieren das Ergebnis dem Nutzer. Der einzige Unterschied hier ist, dass der Einstieg mit Nutzer-ID fix "Vereinsdaten" als Art verwendet. (Die Ergebnisse werden übrigens für 1/2h zwischengespeichert.)

Anfangs hatte ich im XSL Stylesheet einen Parameter gesetzt um die Liga-IDs anzuzeigen die dann manuell kopiert werden mussten. Später habe ich das aber durch Links ersetzt, die dann zum vorgefüllten Formular mit der entsprechenden ID umgeleitet hat.

Relativ bald kam dann natürlich die Frage nach dem Einbetten auf. <iframe>s habe ich zügig ausgeschlossen, da die Tabellen keine fixe Größe haben und sie mit solchem Inhalt ungünstig sind. Also blieb es bei einem eingebettetem <script>document.write(...)</script>.

Ich habe außerdem beschlossen die Einbettung noch mit einem Embed-Key zu schützen, um den im System hinterlegten Zugang zur Schnittstelle vor Missbrauch zu schützen.

Soweit zur Theorie, jetzt noch etwas zur praktischen Umsetzung und den Problemchen dabei.

Da die Schnittstelle durch Nutzername und Passwort geschützt ist und diese Daten nicht clientseitig auftauchen sollen (eine SIS-Vorgabe), muss mindestens für diesen Teil der Anfrage etwas serverseitiges her. Da derzeit schon ein PHP CMS im Einsatz ist, fiel die Wahl auf PHP. Nach kurzer Recherche schloss ich dann eine Erweiterung für jenes CMS aus. (Kein WordPress oder Joomla btw.) Die Wahl fiel also auf eine eigenständige Lösung.

Nachdem ich mich dann in XML und XSL(T) in Kombination mit PHP eingearbeitet hatte, stand das Backend dann somit auch, nur das Frontend war absolut grässlich hässlich (á la ungestylten HTML Formularen).

Nachdem ich dann mein Quick'n'Dirty HTML im PHP mit einem Mustache-Template ersetzt habe, ging die Frontend-"Gestaltung" dann auch besser von der Hand. (PHP-Logik vermischt mit HTML kann mein Vim nicht brauchbar einrücken.) Das Gestalten beschränkt sich dank Bootstrap aber auf das Umschachteln der Tags und vergeben von CSS-Klassen.

Um dann noch einen einheitlichen Stil mit den generierten Tabellen einzuhalten (die beim Einbetten mit Absicht kein CSS enthalten), habe ich dann noch einen zusätzlichen Stylesheet erstellt, der Bootstrap hinzufügt und ein paar Standarts für Parameter setzt, die ich zum Stylen in den Einbett-Stylesheet hinzugefügt habe.

Da ich vermeiden wollte, das der Embed-Key über das Frontend ausgehebelt wird, habe ich zwischenzeitlich im Frontend über JWT eine Sitzung erstellt und einen POST-Ablauf implementiert und bin von reinem PHP zum Slim-Framework gewechselt, u.a. um nicht selbst die JWT-Verifizierung und -Authentifizierung übernehmen zu müssen. Dafür habe ich die slim-jwt-middleware verwendet. Nachdem aber JWT durch den POST-Ablauf überflüssig wurde, wurde somit auch das Middleware-Problem obsolet und somit auch Slim. Des Weiteren ist Slim eher für die Erstellung von Schnittstellen gedacht und eignet sich somit für meinen Zweck nur mäßig. Ich habe hier etwas recherchiert und werde wohl zum "Klein"-Router wechseln. Dazu gibt es schon einen Issue, aber ich werde im Anschluss nochmal berichten :)

Die Einbettung inklusive der Embed-Keys funktioniert soweit über eine REST Schnittstelle. (Es gibt aber nur eine Resource embed, und die kann auch nur GET.) Das generieren des document.write-Skripts geschieht im PHP und entspricht dem Ergebnis aus dem XSLT Prozessor, nur das die Leerzeile entfernt wurden.

Die Embed-Keys sind momentan über ein assoziatives Array in der Konfiguration und array_key_exists realisiert. Key hat hier jetzt eine doppelte Bedeutung, da der Embed-Key einerseits als Schlüssel im Array fungiert als auch als Schlüssel zur Authentifizieren beim Einbetten. Die Autorisierung finden über den Wert im Array statt, welcher ein Domain-Name ist, der im eingebetteten Skript überprüft wird.

Momentan sind meine Formular-Workflows aber absolut Back-Button-unfreundlich, da ich ausschließlich POST verwende. Ich werde diesen Workflow in ein POST-Redirect-GET umwandeln, mit einem (H)MAC, damit der Embed-Key nicht durch das Frontend ausgehebelt wird.

Und hier noch eine kleine Liste mit Werkzeugen und Frameworks die ich erwähnt habe und sonstigen Links:

Christoph Schulz

Christoph Schulz
I am Dev. Maybe.

Blog

In this post I would like to write about how I would like to change the functionand design of my blog.While I do not dislike the current ...… Continue reading

Malware-Protection without App Stores

Published on August 05, 2018