Die visionapp GmbH [1] plant, implementiert und betreibt serverbasierte Infrastruktur- und Portal-Lösungen auf Basis von Microsoft- und Citrix-Technologien. Ihr Produkt „visionapp Platform Management Suite“ ermöglicht die automatisierte Installation von Citrix-Serverfarmen, wozu applikationsspezifische Installationspakete zur Verfügung gestellt werden.
Im August 2005 wurde erstmals ein Download-Center für die seit langem mit TYPO3 verwaltete Website angefragt, da auf dem Markt kein entsprechendes fertiges Produkt vorhanden war. Begonnen wurde mit einigen Dutzend Dateien, in erster Linie Dokumentationen und Tools in mehreren Sprachen. Inzwischen werden mehr als 3.000 Dateien auf der Website zum Download angeboten und die Anzahl wächst stetig.
Bei einer solchen Steigerung des Umfangs bleiben Anpassungen des
Software-Designs nicht aus, neue Funktionalitäten zur Verwaltung und
auch zum Download wurden hinzugefügt. Im Folgenden wird der Weg
dieses Projekts skizziert und einige der
Problemstellungen auf diesem Weg mit den gefundenen
Lösungsmöglichkeiten aufgezeigt.
Für eine Handvoll Dateien
Grundlage des Download-Centers war die Erweiterung „mit_download“,
die inzwischen im TER nicht mehr existiert. Aufgrund der Anforderungen
von visionapp wurde das Datenmodell um einige n:m-Relationen (z. B.
Betriebssysteme, Sprachen, Citrix-Versionen) erweitert und die
Suchfunktionen angepasst. Wegen der vergleichsweise geringen
Datenmengen waren die resultierenden JOINS über viele Tabellen beim
Suchen und Sortieren kein Problem.
Bereits damals sollten manche Dateien nur von authentifizierten und
autorisierten Benutzern heruntergeladen werden können, für einen
eingeschränkten Zugang konnten Besucher sich selbst registrieren. Der
unautorisierte Download wurde verhindert, indem Dateien in einem
geschützten Verzeichnis abgelegt und per PHP-Skript als Stream an den
Browser gesendet wurden. Die Anforderung, auch nicht angemeldeten Besuchern die geschützten Dateien anzuzeigen, wurde durch Manipulation des TCA erreicht:
$TCA["tx_mitdownload_files"] = Array ( "ctrl" => Array ( "enablecolumns" => Array ( "disabled" => "hidden" ), [...] ), [...] );
Listing 1
Im Plugin-Code wurde dieser Wert bei Bedarf geändert, wie das folgende Listing zeigt.
$GLOBALS['TCA']['tx_mitdownload_files']['ctrl']['enablecolumns']['fe_group'] = 'fe_group';
Listing 2
Für ein paar Dateien mehr
Mit zunehmender Anzahl der Dateien wurde die Suche und das Sortieren zum Problem, weil die SQL-Abfragen, in denen die Dateitabelle, die Attributtabellen und pro Attribut noch eine Verknüpfungstabelle enthalten waren, zu lange dauerten. Die JOINS in der Suchabfrage wurden daher im ersten Schritt zugunsten von EXISTS abgelöst. Das folgende Beispiel zeigt die Einschränkung auf bestimmte Kategorien:
($filter['cat']?' AND EXISTS (SELECT * FROM tx_mitdownload_cat_mm WHERE uid_local = tx_mitdownload_files.uid AND uid_foreign IN ('.$filter['cat'].'))':'')
Listing 3
Um dennoch nach dem Namen der Attribute – bisher werden nur die IDs, aber keine Bezeichnungen verwendet – sortieren zu können, wurden die Attributtabellen nur bei Bedarf hinzugezogen:
$sortfield = 'tx_mitdownload_file_cat.title'; $joinTables = ', tx_mitdownload_file_cat, tx_mitdownload_cat_mm'; $joinWhere = 'AND tx_mitdownload_cat_mm.uid_local = tx_mitdownload_files.uid AND tx_mitdownload_cat_mm.uid_foreign = tx_mitdownload_file_cat.uid';
Listing 4
Nach diesem Umbau liefen die Suchabfragen wieder ausreichend schnell und mussten seitdem auch nicht mehr überarbeitet werden. Neben dem Suchen ist jedoch das Herunterladen der gefundenen Dateien das wesentliche Merkmal eines Download-Centers. Häufig wollten Nutzer viele Installationspakete auf einmal laden. Deshalb sollte es möglich sein, Dateien zu einem Zip-Archiv zusammenfassen zu lassen und so gebündelt herunterzuladen.
Hierzu wurde noch in PHP4 das PEAR-Package „Archive_Zip“ eingebunden, welches einen in PHP notierten Zip-Algorithmus enthält. Als Interimslösung taugte diese Variante, doch waren die nächsten Performance-Engpässe vorprogrammiert.
Die Faust im Nacken
Neben dem bereits absehbaren Flaschenhals der Archiverstellung in PHP stellte sich heraus, dass das Streaming der Dateien keine konstant hohe Download-Rate bereitstellte. Stattdessen sank die Transfergeschwindigkeit mit der Zeit, was sich erstmalig bei der 144 MB großen Freeware „visionapp Express Edition 2006“ ernsthaft bemerkbar machte.
Der radikale Schnitt erfolgte deshalb mit einem Update der TYPO3-Version auf 4.0 und dem Umstieg auf PHP5, weil letzteres eine native Unterstützung für Zip-Kompression mitbringt. Während früher zum Streaming der Dateien immer das gesamte Website-Frontend geladen werden musste, konnte jetzt das eID-Feature [2] von TYPO3 4.0 genutzt werden. Mit dessen Hilfe wird TYPO3 angewiesen, das Frontend-Rendering früh abzubrechen und die Ausgabe einem eigenen Skript zu überlassen.
Außerdem wurde das Streaming optimiert, indem anstelle des selbstgeschriebenen Codes PEAR::HTTP_Download eingebunden wurde. Das Ergebnis ist ein stabiler Download-Prozess auch bei großen Dateien, der konstant hohe Transferraten ermöglicht.
require_once("HTTP/Download.php"); function send_file($path, $sendmime) { $dl = &new HTTP_Download(); $dl->setFile($path); $dl->setContentType($sendmime); $dl->setContentDisposition(HTTP_DOWNLOAD_ATTACHMENT, basename($path)); return $dl->send(false); }
Listing 5
Nachdem die Zip-Erstellung auf die PHP5-internen Funktionen umgestellt wurde, war Performance kein Thema mehr – jedoch die Integrität der erstellten Archive. Bei mehr als 500 Dateien pro Zip-Datei enthielt das Archiv nämlich kein Verzeichnis mehr, der Benutzer lud eine „leere“ Datei herunter. Deshalb war es notwendig, mehrere Archive zu erstellen, wenn mehr als 500 Dateien zum Download angefordert wurden. Dem Benutzer werden in diesem Fall mehrere Links zu den erzeugten Archiven angezeigt. Die Fortschrittsanzeige verwendet die in der Datenbank gepufferten Dateigrößen und berechnet daraus den Fertigstellungsgrad.
Damit der Festplattenspeicher des Webservers trotz der Erstellung
vieler Zip-Archive täglich nicht vor temporären Dateien überläuft,
werden diese regelmäßig gelöscht. Dazu wird der TYPO3-Scheduler
„Gabriel“ [3] verwendet, der acht Stunden nach der Zip-Erstellung alte Dateien entfernt:
require_once(t3lib_extMgm::extPath('gabriel').'class.tx_gabriel_event.php'); $notification = t3lib_div::getUserObj('EXT:[...]/class.tx_[...]_scheduler.php:tx_[...]_scheduler'); $notification->registerSingleExecution(time()+8*3600); $gabriel = t3lib_div::getUserObj('EXT:gabriel/class.tx_gabriel.php:&tx_gabriel'); $gabriel->addEvent($notification,'scheduled cleanup @' .time());
Listing 6
Wie verwaltet man eine Million?
Nachdem das Frontend nun schnell und stabil lief, wurde die Verwaltung der Dateien angegangen. Weil die Installationspakete, Patches etc. in der Produktentwicklung zusammengestellt wurden, lagen die Informationen fast seit Beginn als Excel-Tabellen vor. Diese wurden etwa vierteljährlich vorwiegend manuell in CSV-Dateien exportiert und dann in die Datenbank geladen. Der Hauptaufwand bestand darin, Listeneinträge aufzulösen, wenn beispielsweise als Sprache „English, German“ angegeben war.
Mit Hilfe einer Stored Procedure, die in MySQL 5 endlich unterstützt wird, kann die Konvertierung automatisch und performant durchgeführt werden [4]. Dazu wird die Excel-Tabelle in CSV konvertiert und mit dem Import-Befehl von MySQL in eine spezielle Import-Tabelle übernommen. Im zweiten Schritt werden deren Einträge konvertiert und in das Download-Center übernommen. Die Dateien selbst werden in das gesicherte Verzeichnis des Download-Centers kopiert. Zur Laufzeit findet eine Überprüfung statt, ob die referenzierte Datei vorhanden ist, andernfalls wird ein Eintrag ins DevLog von TYPO3 geschrieben.
Da ausschließlich IT-Fachleute an diesem Prozess beteiligt sind, die vor zwei Kommandos in phpMyAdmin nicht zurückschrecken, konnte auf ein komfortableres Importmodul im TYPO3-Backend verzichtet werden.
Open Range!
Wie bereits anfangs erwähnt, bietet visionapp seinen Kunden und Partnern momentan über 3.000 Dateien zum Download an. Im Zuge der „Citrix Ready“-Initiative konnten diese ohne Beeinträchtigungen der Performance mit zusätzlichen durchsuchbaren Metadaten (noch mehr n:m-Relationen) versehen werden. Selbst wenn ein Benutzer alle Dateien anfordert, dauert das keine 30 Sekunden, und der Download erfolgt trotz Streaming per PHP mit voller DSL16.000-Geschwindigkeit.
Allerdings entsteht ein solches System weder über Nacht noch in einem stetigen Entwicklungsprozess, sondern durch sich wandelnde Kundenanforderungen und die dynamische Natur des Web x.0 in mehreren Phasen. Dementsprechend werden in diesem Prozess immer wieder Lösungsansätze erarbeitet, ausprobiert und teilweise dann doch verworfen – so auch im hier dargestellten Fall.
Die Extension hört sich interessant an — aber veröffntlicht wurde sie anscheinend nicht?
Grüße
Stimmt Felix, die Erweiterung ist nicht öffentlich.