So bitte nicht – bad / worse practices – ein Kessel Buntes

Das die Welt nicht grau in grau ist (oder zumindest aktuell sehr zügig endlich der Frühling mit seiner Blüten und Farbenbracht Einzug hält), erfreut das Gemüt. Anders geartet ist da der Datenbank-Entwickler – wie jeder Informatiker ist er “kühl und dunkel” zu lagern und zu halten, damit er optimal arbeitet.  Somit einher geht eine verstärkte Reaktion auf Restlicht (auch das des Monitors), allerdings messerscharf in schwarz/weiß oder zumindest in Graustufen. Spaß beiseite: “Ein Kessel Buntes” ist eine finde ich recht treffende Umschreibung für das was landläufig oftmals als “Datenbank” verkauft und verstanden wird. Leider wieder eine Praxis die auf Dauer nicht tragfähig ist.

Was ist der “Kessel Buntes” und warum ist er keine gute Idee? – Generell bezeichne ich mit diesem Ausdruck nicht richtig getrennte und beschriebene Entitäten. Teilweise trifft das auch nicht richtig spezialisierte Entitäten. Immer wieder trifft man auf diese Art des Datenbank-Designs: Oftmals wird sie aus der Not heraus geboren, oder aus dem Missverständnis, dass eine Datenbank doch nur eine etwas bessere Excel-Tabelle sei. Eine Excel-Tabelle per se ist ja nicht einmal schlecht – sie bringt immerhin etwas Ordnung ins Chaos und ist für viele tagtägliche Anforderungen das flexible Werkzeug, wenn man mal eben eine Analyse machen muss, oder einfach nur eine “Kleinigkeit” visualisieren soll. Eine Tabellenkalkulation ist hierzu sehr flexibel und bietet alle Möglichkeiten die man sich wünschen kann – von Layout bis hin zur Berechnung – nichts ist beschränkt. Genau diese Flexibilität ist es jedoch die bei größeren Projekten schnell vom Vorteil zum Hindernis werden kann. Mit der Flexibilität einer Tabellenkalkulation kann man sich oftmals die doch eher lästige tiefgehende Analyse eines Sachverhaltes für eine Datenbank sparen. Problematisch wird es, wenn Tabellenkalkulationen dann zum Allheilmittel erkoren werden. Ehe man es sich versieht werden da komplexe Matrizen aufgestellt, die dem menschlichen Benutzer die Information schön handlich aufbereiten. Nur die Maschinenlesbarkeit ist dann nicht mehr unbedingt gegeben, und selbst einfach Analysen im Datenbestand arten zur Sisyphus-Arbeit aus, vor allem wenn die Flexibilität voll genutzt wird und jede Matrix ein klein wenig anders aussieht.

Besonders ärgerlich aus Datensicht ist hierbei die Verquickung von Äpfeln und Birnen zu Obstsalat. Ich selbst durfte hierzu ein sehr schönes Beispiel einer gewachsenen Datenbank erleben: In einem Unternehmen gibt es verschiedene Aufträge, mit unterschiedlichen Qualitäten und Eigenschaften. So gibt es Aufträge die intern erzeugt werden und nur innerhalb von Abteilungen verrechnet werden, wenn überhaupt, zudem gibt es Aufträge, welche mit externen Elementen (auch als Kunden bezeichnet) abgewickelt werden. Nun war der Entwickler etwas faul oder es hat sich erst im Laufe der Zeit ergeben: Für die beiden Typen sind unterschiedliche zusätzliche Informationen notwendig. Initialer Weg um Zeit und Arbeit zu sparen: “Es ist ja nicht viel was da dazu kommt, wir fügen einfach Spalten an”. Recht zügig kann man in einer Datenbank der Einsteigerklasse (die sich tatsächlich auch noch als Datenbank bezeichnet) solche Änderungen realisieren. Die Rede ist hier von einem recht bekannten Produkt aus dem Hause “Winzig-Weich”. Problematisch ist bei diesem Produkt schon die Tatsache, dass Datenhaltung und Repräsentation scheinbar nahtlos ineinander übergehen. Für Anfänger ohne große Vorkenntnisse senkt das die Hemmschwelle doch ganz erheblich. Auch das ist ja für sich genommen eine löbliche Sache, nur auch dieses Produkt hat einen Einsatzbereich (der ist zugegebener Maßen recht breit) – wenn man über diesen hinaus wächst (und viele Projekte haben die Tendenz dazu), merkt man irgendwann recht heftig, wo es zwickt und kneift.

Nun haben wir eine aufgebohrte Datenbank-Tabelle – etwas, dass man mit ein klein wenig Aufwand auch in anderen Datenbanksystemen machen kann. Aus Erfahrung weiß ich nur zu gut, dass es immer wieder Fälle gibt, in denen man sich aus gutem Grund dafür entscheidet eine Spalte “Overhead” zu spendieren, die nicht immer gefüllt wird, oder sogar nur in wenigen Fällen einen von NULL unterschiedlichen Wert hat. Man hat zwar dabei ggf. ein leichtes Bauchgrimmen, aber es gibt durchaus Szenarien in denen es weniger auf die Performance im Speicherverbrauch oder die absolute Performance ankommt, es aber mit den zusätzlichen Spalten recht schnell greifbare und brauchbare Ergebnisse gibt.

Das Ganze kann man jetzt noch weiter auf die Spitze treiben, in verschiedenen, nicht gegenseitig-exklusiven Geschmacksrichtungen (oder vielleicht doch besser Geschmacksverirrungen):

Man nehme einen weiteren Auftragstyp dazu, weil das aktuelle Projekt es erfordert: Da man in der Tabellen-Ansicht ja jetzt Felder hat die unbelegt sind und man die spezifischen Daten des neuen Typs ja auch noch speichern muss, fängt man kurzerhand an zu Tricksen und zu sparen: Bestehende Felder werden je nach Auftragstyp umgewidmet. Je nachdem was für einen Auftrag man gerade hat, bekommen die Felder jetzt eine Abhängigkeit, eine Semantik. Das macht die Arbeit bei den Masken recht einfach, auch eine tabellarische Übersicht ist kein Problem  – man muss nur wissen wie die einzelnen Felder jetzt zu interpretieren sind. Besonders spaßig ist dann natürlich die Verwendung falscher Datentypen, weil es halt doch nicht mehr so recht gepasst hat: Man kann auch ein varchar-Feld dazu verwenden um Datumsangaben oder Integerwerte zu speichern. Typecast gemäß Semantik und die Sache ist geritzt…

Die Performance und Wartbarkeit dieses Konstruktes kann sich der geneigte Leser dann mal selbst überlegen – vom Wechsel des Datenbank-Unterbaus hin zu einem professionellen Server mit ggf. sehr scharfer referenzieller Integrität wollen wir lieber einmal gar nicht träumen, diese wird dann oftmals auch einfach “geopfert”.

Zweite besonders zu empfehlende Möglichkeit die Performance noch weiter zu minimieren und dem ganzen ein unbeschreibliches “Geschmäckle” zu verpassen: Die Unterscheidung der Typen ist nicht eindeutig oder klar umrissen, sondern kann womöglich sich zur Laufzeit noch ändern. Viel Spaß schon einmal beim Umsortieren und uminterpretieren der oben missbrauchten/umgewidmenten Felder. Auch Typecast-Mortale genannt (nicht unmöglich und bei heutiger Rechenpower fällt es nicht mal so sehr auf, zumindest für kleinere Datenmengen). Damit die Änderung leicht fällt bzw. weil man sich diesmal um die Felder und die notwendigen Anpassungen des semantischen Codes drücken will (wir erinnern uns: Das ist so sonderlich gut wartbar), macht man es wie in der Realität so häufig auch: Man verwendet “sprechende Schlüssel bzw. sprechende Identifikatoren”. Man kennt diese zur Genüge au vielen Bereichen – so lange der Benutzername beschränkt war auf 8 Zeichen, hat man einfach den ersten Buchstaben des Vornamens plus die 7 ersten des Nachnamens genommen. Wenn es doch mal zu Überscheidungen kommt, gab es eben fortlaufende Endziffern. Nicht schön aber es funktioniert. Ähnliches kann man teilweise bei Dokumenten aus Buchhaltungs-Systemen beobachten: Die ersten Zeichen definieren den Typus des Dokuments, die weiteren sind ggf. noch an das Datum gekoppelt oder gleich einfach fortlaufend. Gängig sind Angaben wie “ANG-xyz” für Angebot Nr. xyz odr der LS-4711 für den Lieferschein mit der Nummer 4711. Weitere Beispiele kann man sich leicht vorstellen.

Die Performance wird allerdings besonders grottig, wenn man diese Typ-Information aus bestimmten Gründen nicht in einer separaten und indizierten Spalte (sehr einfach und dennoch effektiv sind z.B. Enumerations sofern die Datenbank mit dieser “Mini-Foreign-Key-Lösung” umgehen kann) sondern einfach die gesamte Nummer in ein Varchar-Feld packt. Wenn man nun nach unterschiedlichen Typen filtern möchte, muss man doch nur die ersten Zeichen betrachten (vorzugsweise noch unterschiedliche Längen wie etwa: ANG und LS von oben, zusammen mit ANS für Kostenvoranschläge…). Mit dieser Technik bekommt man jede Datenbankengine ins Trudeln. Anti-Performance ist at its best …

Nun gut, genug gemault und Augen verdreht – woher der Ausdruck “Kessel Buntes” kommt dürfte nun jedem klar sein: Man hat verschiedenste Obst (und ggf. auch Gemüse)-Sorten (im Datenbank-Bereich auch Entitäten genannt) in einer Tabelle zusammengeführt und über die Zeitachse das ganze gut durchgerührt und etwas ziehen lassen … Zeit dafür Lösungen zu präsentieren wie man es besser macht.

Oberstes Gebot bei der Modellierung bzw. dem Abbild der Realität: Entitäten trennen, wie Eiweiß und Eigelb. Beides gehört zwar zur Entität “Ei” aber die Eigenschaften unterscheiden sich schon von der Farbe und dem weiteren Verwendungszweck beim Backen 😉 Daher: Wenn sich zeigt, dass eine weitere, vielleicht auf den ersten Blick sehr ähnliche Entität hinzugenommen werden soll, sehr sehr kritisch prüfen ob man diese unbedingt in das bestehende Schema “pressen” muss. Im ersten Moment mag es zwar mehr Arbeit sein separate Entitäten zu verwalten, aber die Erfahrung zeigt: Jedes Datenbankschema hat auf die mittlere bis lange Frist die Tendenz sich weiter auszudifferenzen und detaillierter zu werden. Also besser gleich von Anfang an verschiedene Tabellen verwenden (ich werde auch noch einen ausführlichen Beitrag zum Thema “one true lookup table – OTLT”  verfassen) – diese im Zweifel per UNION erst einmal wieder zusammen zu führen (was nicht immer vermeidbar ist, oder zumindest für einen Teil der Daten sinnvoll sein kann) ist der bessere Weg.

Im letzten Absatz ist es schon angeklungen, ein Problem das man häufiger hat: “Aber die Dinger aus der Realität sind doch zu 80% ident …” – in der objektorientierten Programmierung ist das ein klarer Fall für die Verwendung von Vererbung ggf. in Kombination mit abstrakten Klassen. Die übergeordnete Klasse stellt die gemeinsame Basis samt Funktionen bereit, und die spezialisierten Klassen kümmern sich um die 20 verblieben Prozent der Details. In einer relationalen Datenbank klappt dieser Ansatz nicht direkt. Hier muss man auf die Kombination von Geschäftslogik und einzelnen Tabellen zurück greifen: In der Geschäftslogik verwendet man den objektorientierten Ansatz wie gerade beschrieben, in der Datenbank führt man Surrogate ein, die es erlauben vom Kleinen auf das Größere zu schließen – dabei muss man ggf. aufpassen, dass keine Doppeldeutigkeiten entstehen (teilweise sind diese jedoch auch wünschenswert, das muss man situativ entscheiden) gibt. Auch bekannt ist das Konzept unter dem Namen “Vererbung für Arme”. So bekommt man zwar auch ein wenig Overhead, aber die Struktur bleibt klar erkennbar und man braucht nicht erst noch eine Tabelle die einem sagt, wie jetzt welcher Wert zu interpretieren ist.

Was auf keinen Fall eine Option sein darf, ist die Integration von Typinformationen in ein anderes Feld – diese Information muss man wo immer möglich in separate Felder auslagern, die man im besten Fall noch mit einer Referenz (Fremdschlüssel) auf eine andere Tabelle mit entsprechenden Meta-Informationen absichert. Sonst passiert es leicht, dass der Benutzer (aus Schusseligkeit oder gar mit Intention) einen neuen Typ einführt der gar nicht definiert ist (z.B. ein Tippfehler der Form “AND” anstelle “ANS”) – welche Semantik dann greift bzw. welch kuriose Fehlinterpretationen und Fehlermeldungen dann auftreten können liegt im Bereich der Spekulation und der Admin-Belustigung. Über die notwendigen Operationen der String-Extraktion denkt man in diesem Fall auch besser nicht nach, geschweige denn daran wie häufig diese Operation angewandt werden muss…

Fazit: Es mag verlockend sein, eine Datenbank möglichst flexibel und “platzsparend” zu gestalten, wie man es auch in einer Tabellenkalkulation machen würde. Aber die gewonnene Sicherheit ist absolut trügerisch und der Performance und Wartbarkeit tut man sich mit einem Kessel Buntes mit absoluter Sicherheit keinen Gefallen. Besser gleich überlegen ob das wirklich notwendig und sinnvoll ist, so klein das Problem aktuell auch sein mag – die Wahrscheinlichkeit, dass man irgendwann einen großen Scherbenhaufen hat ist erheblich vergräßert und dann ist nichts gewonnen, aber viel verloren.

Wenn der Postmann zweimal klingelt – MBox, Thunderbird, Maildir und IMAP

Na da hatte ich mir doch mal wieder eine nette kleine Bastelaufgabe gestellt, als ich einem Kumpel versprochen hatte ihm bei seinen e-mail-Problemen ein wenig zu unterstützen. Ausgangssituation war ein Rechner-Zuwachs bzw. die Nutzung von Smartphone, Laptop und Festrechner. Den e-mail-Account hatten wir schon vor ettlichen Jahren eingerichtet – das war schon so lange her, dass ich mich kaum daran erinnern konnte. Ein deutlicher Hinweis auf das Alter war die Verwendung des Post-Office-Protokolls Version 3 (kurz POP3) – damals noch die Standard-Technik zum Abruf von Mails. Bisher war mein Kumpel mit dem System recht gut gefahren und auch Thunderbird als Mail-Client kommt ja problemlos mit POP3 zurecht.

Was sind die Rahmenbedingungen für POP3 und warum wird es heute nicht mehr verwendet oder besser gesagt nur noch da wo es nicht anders geht? – Sicherlich nicht weil es einfach nicht mehr “in” ist. Vielmehr war zu den frühen Zeiten des Internets (die ich noch erleben durfte) eine unbeschränkte Verbindung ins Netz nicht gegeben (ja es gab eine Zeit vor den Flatrates und DSL – heute kaum mehr vorstellbar) – damals wählte man sich per Modem ins Netz ein – bezahlt wurde nach Minuten-Tarifen. Daher war es wichtig die Leitung möglichst effektiv auszulasten, zumal man in der Regel mit nur einem Anschluss pro Haushalt in der Zeit nicht telefonieren oder Faxe schicken konnte (ISDN war damals das Zauberwort – zwei Kanäle, drei Rufnummern gab es standardmäßig – ich gehörte leider nicht zu den glücklichen Nutzniesern). Nach dem Aufbau der Verbindung holte man seine Mails ab, surfte diverse Seiten an und trennte die Verbindung wieder wenn man sie nicht benötigte. POP3 unterstütze genau diese Funktionalität: Alle Mails aus der Mailbox nacheinander herunterladen auf den eigenen Rechner und dann war erst mal Ruhe. E-mail war ja schon schnell, aber dennoch musste man damals nicht sofort bei jeder e-mail informiert werden (was ich auch heute nur sehr bedingt brauche). Man beantwortete die Mails und sammelte sie, danach baute man die Verbindung für den Versand wieder kurz auf und speißte die Mails ins Internet zur Verteilung ein.

Die Vorteile liegen klar auf der Hand: Die damals wertvolle Bandbreite und Übertragungszeit wurde so möglichst effektiv ausgenutzt. Klar sind aber auch die Nachteile: Verteilte Nutzung von e-mails auf mehreren Rechner war nicht vorgesehen, auch wenn man die Mails in der Mailbox belassen konnte (die dann irgendwann überlief und man keine Mails mehr empfangen konnte – damals waren 5-10MB Mailspeicher schon sehr viel, aber es wurde ja auch nicht jeder Sch… per e-mail weiter verteilt). Schon zu meinen ersten Gehversuchen existierte das konkurierende Protocol Internet Message Access Protocol (IMAP) – das löste das Problem mit der Synchronisation durch eine zentrale Speicher-Instanz. Leider zu dem Preis, dass man in der Regel eine permamente Internet-Verbindung benötigte oder zumindest eine zum e-mail-Server. Gegenüber POP3 war IMAP ein deutlicher Fortschritt – Serverseitige Filterung war ebenso möglich wie verschachtelte Unterordner in der Mailbox (alles was man heute als nahezu selbstverständlich wahrnimmt) – ursprünglich entwickelt für den Mailverkehr innerhalb von Firmen (die schon damals oftmals eine Standleitung hatten). Indirekt populär wurde das Protokoll durch die Entwicklung von Webmail-Services – auch meine erste e-mail-Adresse nutze ich auf diese Art und Weise, da sie unabhängig von weiterer Software war, die auf Schulrechnern ohnehin nicht installiert werden durfte. Als Schnittstelle wurde das Common Gateway Interface genutzt – in aller Regel werkelte dahinter eine Reihe Perl-Skripte.

In den ersten echten Genuss von IMAP kam ich durch das Aufsetzen eines internen Mailservers für Heimzwecke – der holte die Mails per POP3 in festen Intervallen ab und stellte sie dann intern wieder per IMAP zur Verfügung – ich wusste schon zu der Zeit die Vorzüge zu genießen. Selbst ist der Admin 🙂

Der langen Rede kurzer Sinn – Ziel war es nun, das eingerichtete e-mail-Konto von POP3 auf IMAP über zu siedeln. Ich selbst habe diesen Schritt schon häufiger durchgeführt – auch mit Thunderbird. In der Regel ist das kein Problem: Ein zusätzliches Konto per IMAP einrichten, den POP3-Abruf stilllegen, damit er nicht die gerade hochgeschobenen Mails gleich wieder abholt und löscht (den Fehler merkt man recht flott …) und dann kann man mit einer schönen Operation “Drag&Drop” die e-mails aus den lokalen Ordnern auf den Server verschieben. Eine Sache von wenigen Minuten in der Regel.

Doch grau ist bekanntlich alle Theorie – irgendwie wollte das nicht so recht funkionieren – der Transfer zog sich ewig in die Länge und brach dann irgendwann einfach ab. Da es bereits etwas später am Abend war, haben wir es erstmal vertagt.

Ich habe mich dann mal etwas genauer schlau gemacht was da ursächlich sein könnte bzw. wie man das optimieren kann. Kurze Recherhe mit “Prof Dr. Dr.  Google” liefert einen Ansatzpunkt: Thunderbird verwendet für lokal gespeicherte e-mails ein standardisiertes und weithin bekanntes Format zum Speichern von Mails: das gute alte MBox-Format – ein recht einfaches Text-Format in dem alle e-mails in der Reihenfolge des Eingangs hintereinander weg geschrieben werden. Einfache Techniken sind ja in der Regel begrüßenswert, aber in diesem Fall ist die Extraktion nicht wirklich einfach (Regular-Expressions sind sicherlich hiflreich, aber auch die diversen Fragen zum Escaping der From-Lines – näheres siehe im Link). Damit es etwas schneller geht fertigt Thunderbird eine Index-Datei an. Unterordner erhalten bei Thunderbird eigene Dateien.

Eingangs hatte ich anklingen lassen, dass man früher nicht gerade große e-mail-Postfächer hatte – daher war das Mbox-Format auch zielführend. Aber man bedenke etwaige Beschränkungen die jeder PC-Nutzer meiner Generation wohl irgendwann einmal kennen gelernt hat: Beschränkuingen des Dateisystems erlauben nicht, dass eine Datei eine gewisse Größe überschreiten darf – mit FAT32 sind es 4GB, früher unvorstellbar groß – heute noch nicht mal ausreichend für einen Film auf DVD. Nun kann man sich natürlich auch vorstellen wie performant die Arbeit in entsprechend großen Text-Dateien ist, wenn man darin Mails sucht … für große Datenmengen gibt es deutlich besser Aufbewahrungsmethoden, zumal man in der Regel die Mails ja nicht auf Endlos-Papier ausdruckt sondern doch eher Stück für Stück liest. Was Thunderbird so flügellahm machte war die simple Tatsache, dass aufgrund des vielen Inhalts fast 3 GB Mails in einer Datei lagen – in Zeiten von dicken Anhängen und den unvorstellbaren Mengen Speicherplatz aktueller Rechner eigentlich nicht mehr verwunderlich.

Was also tun? Wenn Thunderbird ins Straucheln kommt, dann sinnt man auf Abhilfe mit einfachen Mitteln, zumal ja alles standardisiert ist: Protokolle, Format, da sollte sich doch etwas machen lassen. Mittel der Wahl als Administrator ist für solche “Quick’n’Dirty”-Arbeiten die Programmiersprache Perl. Flexibel, teilweise wirklich sehr kurz und unsauber, aber halt einfach das Schweizer Offiziersmesser wenn es um das stapelweise verhackstücken von Dateien geht. Praktischerweise gibt es mit CPAN ja auch für fast jeden Anwendungszweck passende Module. Recht flott habe ich ein Skript zusammengezimmert, das mir die einzelnen Dateien durchgeht und den Upload per IMAP übernehmen soll. Doch, wa soll das schon wieder – auch dieser Weg scheitert – die Perl Module laden nach und nach die gesamte Datei in der Arbeitsspeicher, bis das Betriebssystem meint “jetzt ist aber gut, und den Prozess abwürgt”.

Nun gut, als Admin fühlt man sich nun doch heraus gefordert – wenns so nicht geht, dann gibts ja immer noch Mittel und Wege. Ich entscheide mich dem Tool das Leben etwas leichter zu machen und die Mail-Datei schon einmal etwas vorzuverdauen. Will heißen wir spalten die große Datei in kleinere Happen auf. Mittel der Wahl für mich in diesem Fall ist das Maildir-Format, das sich als Alternative zum Mbox-Format etabliert hat und das mittlerweile viele Mailserver und auch Clients einsetzen (interessanterweise gibt es auch Ansätze ob Thunderbird das lokal verwenden sollte…) Im Maildirformat ethält jede Mail eine eigene Datei – etwas weniger effizient was den Speicherplatz betrifft, aber der ist ja heute reichlich verfügbar und e-mails sind heute meist derart umfänglich, dass dieser kleine Overhead auch nicht mehr ins Gewicht fällt. Generell ist der Zugriff auf eine einzelne Nachricht nun wesentlich direkter möglich.

Auf zu Versuch Nummer 2 als, diesemal dann mit einem Perl-Modul, das e-mails in Maildir-Verzeichnissen lesen kann. Und wieder ein Griff ins Klo … ich zweifle schon an meinen Fähigkeiten, als ich dann doch diverse Reports im Netz finde, dass die Iteration über Mailboxes mit dem Perl-Modul wohl einen Bug hat und den allokierten Speicher nicht mehr rechtzeitig frei gibt. Ein klassisches Memory-Leak also.

Weiter verfolgen muss ich das nun aber nicht mehr, mein Kumpel hat in der Zwischenzeit eine wesentlich bessere Variante gefunden, als Brute-Force alles auf den Server zu transferieren: Einfach vorher das Postfach mal grundlegend entrümpeln und wirklich nur die erhaltenswerten Mails auf den Server verschieben. Das ist natürlich auch eine Lösung, auch wenn sie für mich technisch natürlich nicht an den Charme eines Skriptes heran kommt. Aber was immer hilft soll mir in diesem Fall ja recht sein.

Was haben wir also gelernt: POP3 ist nur noch in Ausnahmefällen eine sinvolle Alternative, vor allem weil heute ja kein echter Mangel an Bandbreite und Dauererreichbarkeit mehr besteht. Selbst für den Offline-Fall bringt heute jeder IMAP-Client notwendige Mechanismen zum Caching der Mails mit. Zweitens: Auch das MBox-Format ist inzwischen mit Vorsicht zu genießen, ich selbst verwende es ja schon seit den Anfängen des eigenen Mailservers nicht mehr (auch weil qmail es damals nicht aktiv unterstützte sondern die Grundlage für Maildir legte). Aber das allerwichtigste ist wohl: “Schmeiß auch mal weg, trenne dich von Dingen die du eh nicht mehr brauchst” – das regelmäßige Bereinigen eines Postfachs macht zwar auch Mühe, aber man kann es ja auch wieder automatisieren: Wer hat jemals e-mails angeschaut, die älter als drei Jahre waren? Wirklich wichtige Informationen speichert man ohnehin als Datei ab oder druckt sie dokumentenecht auf Papier aus. Die ganzen restlichen Alltagsmails kann man nach einer gewissen Zeit gefahrlos löschen. Es lebe der Frühjahrsputz. So und jetzt greife ich dann auch mal zum digitalen Schrubber – das könnte etwas länger dauern – derzeit habe ich rund 5 GB an e-mails herum liegen … da hilft wohl doch eher der Hochdruckreiniger denn ein Schrubber …

 

 

Typo3 und ImageMagick – was zu beachten ist

Für einen guten Zweck arbeite ich auch als Hosting-Anbieter für die Interessensgemeinschaft Herzogenried. Die Verbindung zum Quatiermanagement entstand schon vor einigen Jahren, damals ging es primär darum überhaupt eine Präsenz im Netz aufzubauen. Der verantwortliche Mitarbeiter war mir schon von daher sympathisch, dass er vieles bis ins Detail verstehen wollte und auch im Netz selbstständig agieren wollte. Er hat sich mit enormen Eifer und einiger Unterstützung damals die Grundlagen von HTML selbst beigebracht.

Zwischenzeitlich ist der Bedarf gewachsen, es wurde umgestellt auf Joomla! als Content-Management-System (CMS) – für mich auch keine große Sache, jedoch habe ich mich nicht in der Tiefe mit dem System auseinander setzen können wie ich es gerne gewollt hätte. Aber die Mannschaft hat es auch so recht gut hinbekommen – einige Kleinigkeiten habe ich noch unterstützend beitragen können.

Nunmehr stand wieder ein Neuanfang auf dem Programm – von Zeit zu Zeit sollte jede Homepage mal einem Review und ggf. auch einer Modernisierung unterzogen werden. Wie sich zeigte war Joomla! nicht mehr die absolute Präferenz, zumal sich nun auch Personen mit deutlich besseren Kenntnissen in Sachen Layout und Gestaltung gefunden hatten. Die neue Homepage soll unter Typo3 entstehen. Mir ist das System letztlich egal – jeder soll das System verwenden mit dem er am Besten arbeiten kann. Nicht jedes Werkzeug ist automatisch für jeden Zweck geeignet nur weil viele es für diesen einsetzen.

Für mich als Systemadmin ändert sich durch den Wechsel des CMS eigentlich nichts – die Anforderungen sind recht human: Apache als Webserver (es gingen wohl auch einige andere), MySQL bzw. MariaDB als Datenbank und PHP als Skriptsprache die das ganze zusammen hält. Soweit nichts außergewöhnliches.

Schon interessanter werden da diverse nette Features die Typo3 so mitbringt, wie etwa das automatische Skalieren von Bildern oder auch die Erzeugung von PDFs. Alles Funktionen die gut ankommen wenn man sie richtig einsetzt. Für die ganze Bildbearbeitung kommt ein mir nicht unbekanntes Tool zum Einsatz ImageMagick – diese in C geschriebene Toolbox ist das Schweizer Taschenmesser was automatisierte Bildbearbeitung betrifft – die Bedienung der Tools auf der Kommandozeile scheint anfänglich etwas kryptisch, aber gerade für Stapelaufgaben ist sie hervorragend geeignet. Die Libary dazu habe ich schon länger auf meinem Server installiert – für meine Webprojekte verwende ich direkt die PHP-Schnittstelle, die auf den Namen Imagick hört. Diese ermöglicht unter anderem die Berechnung von Thumbnails on demand, und ist dabei dank C-Implementierung um ein vielfaches schneller als die GDLib, die sonst in PHP für die Bearbeitung von Bildern verwendet wird. Ich selbst habe Imagick schon für die von mir betreute Website der THW-Jugend in Mannheim verwendet – irgendwann war es mir einfach lästig geworden jedes Mal für eine Bildergalerie die Thumbnails von Hand zu berechnen – mit ein klein wenig Datenbank-Background habe ich das dann aus der Welt geschafft. Klingt zwar im ersten Moment etwas schräg ausgerechnet Bilder als Binary large Object in eine Datenbank zu packen, aber die Optionen sind einfach zu schön. Mal ganz davon abgesehen, dass man sich nicht mehr um irgendwelche Dateirechte in shared hosting Umgebungen Gedanken machen muss – auch etwas wie Schlagworte oder Gruppierungen sind in einer relationalen Datenbank einfach wesentlich leichter möglich, als wenn alles im Dateisystem liegt.

Typo3 geht einen etwas anderen, universelleren Weg und ruft das Tool “convert” aus dem Imagick-Paket auf – das macht es mächtiger aber in meinen Augen auch umständlicher zu bedienen. Jedenfalls ist die Installation auch kein Hexenwerk. Paketverwaltung auf – installieren, ja, Installation fertig. Soweit mal die Vorbereitung.

Die Rückmeldung lässt nicht lange auf sich warten: ImageMagick funktioniert generell, aber wir haben ein Problem mit der Version … der Kunde wünscht in diesem Fall eine ältere Version – was mir als Betreiber natürlich etwas widerstrebt, gibt es doch zahlreiche Bugfixes auf die ich selbst angewiesen bin und diverse kleinere Lücken im Code, die geschlossen wurden.

Nach etlichem Hin und Her ist das Problem zumindest einmal eingegrenzt: Wann immer man mit Typo3 versucht eine Adobe Illustrator-Datei in ein JPEG zu überführen, knirscht es bezüglich der verwendeten Transparenz. Der Hintergrund wird nicht weiß sondern schwarz dargestellt, was gerade beim Weiterverwenden in PDFs nicht gut aussieht.

In diversen Foren ist das Problem auch beschrieben und es gibt diverse Abhilfe Vorschläge – unter anderem ein Downgrade, was für mich ja wie geschrieben eigentlich nicht in Frage kommt. Also geht die Suche nach der Ursache weiter – ich bin ja sogar Willens mich ggf. mit dem Code von Image Magick auseinander zu setzen – Bildbearbeitungsalgorithmen habe ich zwar mal gelernt, aber so schwer kann es in dem Fall ja nicht werden.

Über mehrere Zwischenstufen kristallisiert sich für mich langsam die Struktur von ImageMagick heraus – mit Nichten ist das eine allwissende Bibliothek mit angeschlossenem Werkzeugkasten, wie ich lange Zeit gedacht hatte. Vielmehr lagert ImageMagick diverse Aufgaben an dezidierte Programme aus – was ja auch sinnvoll ist, man braucht das Rad ja nicht zweimal zu erfinden und nirgendwo ist die Wiederverwendung von Programmen und Code so einfach wie in Software und gerade im OpenSource-Bereich.

Ich lerne Adobe Illustrator Dateien sind nur verkappte PDFs mit einigen Erweiterungen – zum Lesen eignet sich das vielseitige Ghostscript, das ursprünglich mal als PostScript-Interpreter gestartet ist. Man muss wissen, dass PDF anfänglich auch nur eine etwas aufgebohrte Version von PostScript war. PostScript war lange Zeit die Sprache um Drucker sauber und effizient anzusteuern – ein guter Netzwerkdrucker versteht sich zur Freude von Linux-Anwendern und Mac-Nutzern auch heute noch auf PostScript. Die Logik zur Aufbereitung von Dokumenten und Druckvorbereitung lag damals schon im Drucker. Erst mit GDI und PCL gab es die ersten “Thin”-Printer – also Drucker ohne große Eigenintelligenz die vom Rechner “ferngesteuert” wurden. PDF war der Schritt vom Papier in die digitale Welt – also eine Art unabhängiges Dokumentenformat, das sich aber auch auf Referenzen verstand.

Halten wir also fest Typo3 ruft ImageMagick bzw. dessen Tool convert mit einigen Parametern auf, das wiederum übergibt die Sache zumindest teilweise an Ghostscript. Was genau wohin übergeben wird, steht in der

delegates.xml

– wo genau die sich findet hängt ein wenig von der Distribution ab – unter Ubuntu findet man sie unter

/etc/ImageMagick/delegates.xml

.

Einer der Tipps aus den Foren lautet den vollständigen Pfad für ghostscript gs  anzugeben, das betrifft aber im Wesentlichen die Windows-Welt – schaden kann es ja mal nichts, aber leider bleibt mir der Erfolg versagt. Das Problem besteht weiterhin – die Hintergründe werden schwarz anstelle transparent (also weiß) dem auf Papier (es sei denn man druckt gerne auf schwarz, wobei dann die meisten Drucker mit ihren Farben an die Grenzen des Möglichen kommen – weiß als Tinte oder Toner habe ich noch bei den wenigsten Druckern gesehen).

Nächster Schritt in der Fehlersuche: Handarbeit: Also einmal ein Bild von Hand auf der Kommandozeile mit convert umwandeln – die Befehlszeile dazu lautet anhand von Typo3:

convert' +profile '*' -geometry 170x170! -colorspace RGB -quality 70  'typo3logotype.ai'[0] 'install_read_ai.jpg'

Was mir auffällt: Das Ausgabe-Format ist JPEG – wie ich weiß und mich auch nochmals informiere unterstützt JPEG keine Transparenz (dafür gibt es andere praktische Formate wie PNG oder früher auf GIF) – indem ich mir ein PNG ausgeben lasse, kann ich das Problem wieder ein Stück herunter brechen: Das Einlesen funktioniert wohl sauber, denn das ausgegebene Bild enthält korrekt weiterhin die Transparenz – ergo muss irgendwas bei der Umwandlung in JPEG schiefgehen.

Die Lösung des Problems ist recht simpel:

-background white -flatten

in die Angabe eingebaut und schon kommt das passende Ergebnis bei heraus – es geht unter anderem natürlich auch mit anderen Farben als Hintergrund.

Nun ist eine Lösung an sich ja schon mal was tolles, aber ich will ja wissen warum es früher mal so funktioniert hat und jetzt nicht mehr. Wie schon vermutet hat sich in der neuen Version von ImageMagick etwas bei JPEG schreiben verändert. Die Funktion zum “plattklopfen” bzw. dem Zusammenführen von Ebenen aus einen konstruierten Bild wird jetzt nicht mehr implizit aufgerufen. Bei vorherigen Versionen war dies der Fall wenn Transparenz vorlag und ein Hintergrund gegeben wurde. So eine simple und auch gut nachvollziehbare Änderung (jede Funktion sollte das machen was drauf steht, das richtig, aber auch bitte nicht noch mehr), hat mich hier eine ganze Weile auf Trab gehalten.

Wenn man den Aufruf in der Typo3-Konfiguration anpasst, dann klappt auch die Umwandlung ohne Probleme. Nur schade, dass diese so simple Lösung (die noch dazu auch mit älteren Versionen von ImageMagick richtige Ergebnisse liefert) den Weg noch nicht in die aktuelle Fassung von Typo3 gefunden hat. Wollen wir hoffen, das dies bald der Fall ist.

Quick’n’Dirty in MySQL und anderen Datenbanken

Heute habe ich mich mal wieder einer Altlast der Datenbankentwicklung hingegeben, da sich einige Veränderungen ergeben hatten. Ich hatte schon mehrfach, die Hoffnung diese Tabellen der Datenbank endlich einmal längere Zeit in Ruhe lassen zu können um mich neuen Funktionen zu widmen – aber Pustekuchen wars.

Also wieder das Design auf den Prüfstand und schauen wie man es an die neuen Anforderungen anpassen kann. Ich weiß, dass ich vor etwa einem halben Jahr noch mit einem Freund und ausgesprochenen Experten in Sachen Datenbankdesign mich über einige Dinge ausgetauscht habe. An einigen Stellen hatte ich mich für geschickt gehalten bzw. wollte an dem Design nicht mehr übermäßig rütteln. Es hat ja auch alles soweit funktioniert und gerade die Schlüsseldefinitionen folgten auch einer gewissen Logik. Ich hatte mich für einen kombinierten Schlüssel entschieden – ein referenziertes Objekt kann zu einem Zeitpunkt (auf die Sekunde genau) nur an einer Stelle sein – für den Anwendungsfall eine absolut zutreffende Annahme. Zudem hatte ich den Schlüssel dann auch noch über mehrere Tabellen als Fremdschlüssel “durchgeschleift” – vom damaligen Standpunkt aus war das eine mögliche Lösung die mir eigentlich auch gut gefiel – löste sie doch elegant auch diverse Bezugsprobleme, bzw. ich konnte einen Trigger verwenden um die notwendige Abhängigkeit einer Tabelle von einer anderen automatisch aufzulösen. Es gab also die Basis-Tabelle, eine erweiterte Tabelle und eine Tabelle die in vergleichsweise wenigen Fälle sich auf die erweiterte Tabelle stützte – ein klassisches Prozessgefälle – aus vielen kleinen Datensätzen werden am Ende nur wenige bis zur Blüte oder gar Reife gebracht.

Nun, die Anforderungen haben sich verschoben und die  mittlere/erweiterte Tabelle musste angepasst werden. Wie sich gezeigt hatte brauchten wir für eine spezielle Auswertung nicht nur eine Referenz auf die Basis-Tabelle sondern mindestens zwei, nach eingehender Analyse bin ich auf vier gekommen. Dies liegt in der Tatsache begründet, dass die erweiterte Tabelle eigentlich ein Zusammentreffen mehrer Datensätze aus der Basis-Tabelle abbildet. Das ist mir aber erst im Laufe der weiteren Entwicklung klar geworden – ich denke ich habe das auch beim letzten Mal eher “on the fly”,”mal eben schnell”, “quick’n’dirty” entwickelt ohne die wahren Beziehungen zu erkennen. Was will man machen – so manches wird einem eben erst im Laufe der Zeit klar.

Erste Konsequenz – der ursprünglich ach so geschickte natürliche Schlüssel über zwei Spalten war nun nicht mehr tragbar – viel zu umständlich: für vier mögliche Referenzen wären es acht Spalten gewesen – Übersichtlichkeit gegen null, zumal die Aussagekraft der jeweiligen Schlüsselpaare zum Gesamtbild nur vergleichsweise wenig beiträgt.- und selbst wenn man es braucht – gejoint ist es dank Indizierung und Foreign Keys doch recht fix. Daher bekommt die Basis-Tabelle neben den natürlichen Spalten ein Surrogat – einen eindeutigen numerischen Primärschlüssel. Wie leicht der einem die Arbeit im weiteren macht ist mir bei der Anpassung des Programmcodes dann aufgefallen.

Wie mit der erweiterten, nunmehr ja eher aggregierenden Tabelle weiter verfahren – außer den vier Spalten für die Referenz – ein natürlicher Primärschlüssel über vier Felder schien mir doch recht gewagt, zumal diese Referenzen sich auch mal im Nachinein noch verändern können. Also auch hier die “künstliche” Variante mit einem Surrogat.Das entschlackt auch die letzte Tabelle in der Reihe – deren Referenz musste ja auch wieder irgendwie hergestellt werden – nachdem der ursprünglich “durchgereichte” Schlüssel ja nicht mehr da war musste da eh etwas neues her – auch hier erweist sich die Lösung per Surrogat doch recht tauglich.

Lehrwerte dieser Aktion:

Erstens – natürliche Schlüssel haben einen gewissen Charme – auch wenn sie zur Not aus zwei Spalten bestehen – moderne Datenbank-Systeme stecken das recht gut weg, auch was die Performance betrifft.

Zweitens – eine sorgfältige Analyse und Diskussion eines Entwurfs und die Bedeutung eines Objekts im Gesamtzusammenhang ist durch nichts zu ersetzen – leider zeigt sich hier mal wieder, dass es in meinem Fall keinerlei Prozessdefinition gab und somit natürlich auch die Artefakte nur sehr lückenhaft beschrieben waren. Ein Pflichtenheft wurde aus Kostengründen auch nicht erstellt – stattdessen gab es eine Alt-Datenbank an der man sich orientieren sollte – in bestimmten Dingen war das Design eine Anleitung “wie man es tunlichst nicht machen sollte” (bei Gelegenheit werde ich dazu mal noch ein paar Zeilen schreiben). Auf einem solchen weichen Untergrund ein solides Fundament und hinterher ein Gebäude zu errichten ist nahezu unmöglich – irgendwo sackt es am Ende doch unangenehm weg.

Drittens – Surrogate sind im ersten Moment oftmals hinderlich und an einigen Stellen “verstellen” sie teilweise den Blick aufs Wesentliche – man muss sich ggf. die weiterführenden Informationen aus anderen Tabellen erst mal zusammen suchen. Aber sie haben auch eine Menge Vorteile in Sachen Eindeutigkeit und Handhabbarkeit – wenn es einen eindeutigen Wert gibt, erleichtert dass das Auffinden eines Datensatzes und das Instanzieren eines Objekts daraus ganz erheblich.

Mal sehen welche alten Entscheidungen ich demnächst wieder ausgraben muss und mich über meine eigene Schusseligkeit wundern/ärgern darf. In diesem Sinne: Augen auf beim Datenbank-Design.

MySQL und der Null-Pointer

Da denkt man mal wieder an nichts Böses und prompt holt einen das 2. Gebot der C-Programmierung ein – obwohl man nicht in C programmiert, sondern eigentlich nur in einer Datenbank unterwegs ist.

Die 10 Gebote finden sich hier:

http://www.geekhideout.com/c-ten-commandments.shtml

Und die Aussage “Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.”  ist mir dabei mal wieder wie Schuppen von den Augen gefallen.

Was war passiert? Ich habe eine Datenbank-Tabelle, die mir angibt welche Subunternehmen an einer Arbeit mit beteiligt werden: Pro Arbeit kann es mehrere Subunternehmer geben, und jeder Subunternehmer kann an beliebig vielen Arbeiten mitwirken. Soweit so gut, ein klassischer Fall einer n:m Beziehung (wie man das im ER-Modell bezeichnen würde, UML ist da etwas genauer und würde in diesem Fall von einer 0..n:0..m Beziehung sprechen). Nun habe ich feststellen müssen: Selbst wenn das offiziell nur ein Subunternehmen ist, dann kann das immer noch recht groß ausfallen – die reine Angabe einer Firma als Referenz reicht also nicht unbedingt aus. Soweit ja kein Problem: Es gibt ja auch noch eine Tabelle aller am Projekt beteiligten Mitarbeiter – und ggf. ist einer davon als Ansprechpartner definiert. Leider nur ggf. und nicht zwingend – bei kleineren Firmen gibt es eine solche Zuweisung leider nicht.

Nun ja, was macht der geneigte Datenbank-Programmierer, genau, er macht das was er mal gelernt hat: Wenn es keine Referenz gibt, dann tragen wir den speziellen Wert “NULL” ein. Selbst die referentielle Integrität kommt damit nicht aus dem Tritt – vielmehr ist es ein ganz klares Zeichen: Hier muss gar nicht erst nach einem passenden Partner in der anderen Tabelle gesucht werden – es gibt ihn schlichtweg nicht. Alles nicht richtig spannend und für mich bis dato kalter Kaffee.

Spannend wurde es im Zusammenhang mit der Modifikation der Datensätze: Um zu verhindern das Doppelte Einträge vorhanden sind, habe ich einen Unique-Key über die drei Spalten “Arbeit”,”Firma”,”Ansprechpartner” angelegt. Zudem enthält die Tabelle noch ein paar zusätzliche Information, die aber nichts zu Sache tun. Was liegt also näher als mit einem “Insert ignore”, “Upsert” bzw. dem praktischen MySQL-Konstrukt “Insert into …. on duplicate key update ….”  zu arbeiten? Das ist im Prinzip wie geschaffen für den beschriebenen Fall: Gibt es schon einen entsprechenden Eintrag in den  Schlüsselspalten, dann muss man nur noch die Satellitendaten entsprechend dem Bedarf aktualisieren (das lässt z.B. gut Luft für eine Überwachung durch wen und wann die letzte Änderung durchgeführt wurde).

Doch was ist das: Beim Testen der Funktion tauchen nach dem Speichern der Modifikation plötzlich Einträge doppelt und dreifach auf – also gerade nicht das was man erwartet hätte.

Erster Schritt in der Fehlersuche: Irgendwas im Code wurmig? – Nein, da stimmt alles und es gibt auch keine enstsprechenden Extra-Inserts – die Statements sehen so aus wie man sich das gewünscht hat. Nächster Schritt: Statements “manuell” ausführen und … aha! – man kann Einträge bei denen der Ansprechpartner auf “NULL” steht beliebig oft einfügen ohne dass die Schlüsselmechanismen ansprechen…. erster Verdacht: MySQL-Bug! – aber weit gefehlt: “It’s not a bug, it’s a feature” zumindest in den Augen der MySQL-Entwickler … aber Abhilfe gibt es auch: einfach einen “primary” anstelle eines “unique” keys nehmen…. gesagt getan: Aber dann hagelts erst richtig: Denn in einem “Primary”-Key dürfen keine “NULL”-Werte auftauchen – was macht MySQL intern: Man behilft sich, und verändert sie Spalte – sie darf jetzt nicht “NULL” enthalten und der Default-Wert ist “0” – und das trotz eines Fremdschlüssels? – Und genau da beißt sich die Schlange dann in den Hintern … denn die bestehenden Daten sind komischerweise “valide” – keine Schlüsselverletzung. Aber Einfügen geht nicht mehr: Will man “NULL” einfügen sperrt sich die Tabellendefinition, will man “0” verwenden, gibt es von Seiten der referentiellen Integrität auf die Finger … So ein Mist!

Lösungen gibt es bisher dafür keine 😐 zumindest nicht auf Datenbank-Ebene. Ich habe jetzt einen Hack-Around gemacht: Man lösche alle Einträge zur Arbeit und lege sie danach alle wieder an und schon kann man mit dem Unique-Key leben, man hat praktisch die Prüfung etwas weiter nach oben verlagert (wo sie in meinen Augen nicht hingehört).

Aber wie schon da Commandement von oben sagt: Null-Pointer sind ganz böse Dinge – und wenn man nicht aufpasst findet man sich in der Hölle wieder 😉

 

PHP, Imagick und Windows

Für heute hatte ich mir ein weiteres komplexeres Thema unserer Datenbank auf Arbeit vorgenommen:
An vielen Stellen benötigen wir externe Dateien – sei es um Handbücher schnell und einfach greifbar zu haben, Bilder von einem Schaden oder auch nur zur allgemein zu einem Bauteil ablegen zu können.
Eine Option wäre die Ablage als Datei im Dateisystem des Webservers – das funktioniert, aber es ist schwierig Meta-Informationen wie den Titel abzulegen. Für Bilder ist es oftmals hilfreich eine Ansicht zu haben, die nicht gleich das vollständige Bild sondern nur eine Vorschau zeigt – sei es als originäres Thumbnail oder auch nur in einer Größe die nicht gleich den Bildschirm sprengt, sondern sich in die Seite nach Bedarf einpasst.
Und was auch ganz praktisch wäre – wenn schon etwas gelöscht wird, sollten vielleicht auch die Leichen in Form von nicht mehr benötigten Dateien verschwinden.

Für die THW-Website, welche ich eine zeitlang betreut habe, hatte ich sowas schon einmal realisiert, allerdings war das technisch nicht so ganz ausgereift und ich wollte es wenn dann gleich auch noch technisch sauber bekommen – wenn man schonmal dabei ist. Eine Anpassung war ohnehin notwendig, denn es geht jetzt nicht mehr nur um Bilder sondern um Dateien und Dokumente in jeglicher Form: Also auch PDFs, Excel-Tabellen, und diverse andere Dinge die da so anfallen können.

Aber das Basis-Wissen war ja glücklicherweise schon da. Nach ein wenig Bastelei und Anpassungen an der Datenbank-Struktur war der Code dann auch soweit lauffähig. Mit dem kleinen Problem, dass ich bisher auf meinem Entwicklungsrechner kein Imagick installiert hatte.
Was zum …. ist Imagick? – Imagick ist eine recht umfangreiche und mächtige Bibliothek zur Bildbearbeitung, die auch recht zügig arbeitet. Unter anderem kann sie Bild-Dateien in der Auflösung reduzieren und bietet praktische Möglichkeiten um Bilder zu bearbeiten (Stichwort: Wasserzeichen, Copyright-Vermerke etc.).

Von meiner Linux-Umgebung bin ich ja schon etwas verwöhnt – “apt-get install xyz” hilft in den meisten Fällen und wenn nicht hat man die notwendigen Erweiterungen dank PECL und PEAR auch recht schnell nachinstalliert. Unter Windows gestaltet sich das nicht ganz so einfach – vor allem die Fehlersuche ist mühsam und besteht aus jeder Menge Trial-Error.

Auf Anhieb tut mal gar nichts – auch nicht nach der Installation der aktuellen Imagick-Version. Ständig bekomme ich beim Serverstart die Meldung “Modul kann nicht gefunden werden” – sehr aussagekräftig. Wenn man dann mal ein wenig sucht, findet man, im Englischen heißt die Fehlermeldung “could not find procedure” – das gibt immerhin schonmal einen besseren Anhaltspunkt wo der Fehler sein könnte – es mangelt wohl nicht an der DLL-Datei sondern an der von dort referenzierten Library in Imagick.

Was dann noch erwschwerend hinzu kommt: Es gibt mehrere Versionen und Compilate der DLL für Windows:
thread-safe, non-thread-safe und einmal mit Visual C 6 und Visual C9 kompiliert (entsprechend den Versionen von Visualstudio) kompatibel sind die natürlich nicht :-O

Es hat mich ziemlich viel Nerven gekostet, aber hier habe ich jetzt eine Lösung die mit folgender Kombination funktioniert:
– WAMP-Server 2.1
– Apache 2.2.17
– PHP 5.3.5
– ImageMagick 6.6.9-7

Hier die Anleitung:

1.) ImageMagick installieren und zwar genau diese Version hier:
http://www.imagemagick.org/download/binaries/ImageMagick-6.6.9-7-Q16-windows-dll.exe
Das ist die dynamisch gelinkte Version mit 16 Bit Qualität pro Subpixel und inklusive der notwendigen DLLs
2.) Eine Umgebungsvariable anlegen die auf das Installationsverzeichnis verweist: MAGICK_HOME=c:\Programme\Imagick-xyz\
3.) Neustart machen (warum Windows das braucht – keine Ahnung aber erst dann rafft es die Kiste, dass es da überhaupt Libraries für gibt – und die Fehlermeldungen werden klarer)
4.) WAMP 2.1 ist mit VC6 kompiliert, also brauchen wir eine entsprechende Version der Extension DLL für PHP – sonst gibt es Fehlermeldungen der Art:
PHP-Build-Version = “Zahlenkombination”
Module-Build Version = “Zahlenkombination”
Those values need to match
Die passende Version für unseren Fall findet sich hier:
[url]http://www.sk89q.com/downloads/imagick/2.3.0/API20090626-TS-VC6/php_imagick.dll[/url]
5.) Datei herunterladen und im WAMP-Verzeichnis\PHP\5.3.5\ext\ ablegen
6.) PHP.ini anpassen und die Extension in die Liste eintragen
7.) Server neu starten – es sollte diesmal keine Fehlermeldung geben
8.) Geschafft und man kann sich den eigentlichen Problemen zuwenden!

Ergo: Es ist verdammt aufwändig Erweiterungen für PHP unter Windows einzubauen – die verschiedenen Versionen machen es einem ebensowenig leicht wie die teils wenig hilfreichen Fehlermeldungen und die Tatsache das so Dinge wie der Neustart in keiner Dokumentation auftauchen.

Dank an all die verschiedenen Seiten und Leute die sich ebenfalls schon mit dem Problem beschäftigt haben und Tipps zur Lösung geben haben:

[list]
[*][url]http://www.blogix.net/2011/04/03/imagemagick-xampp-windows-installieren/[/url]
[*][url]http://www.sk89q.com/2010/03/vc6-windows-binaries-for-imagick-2-3-0/[/url]
[*][url]http://www.knowledge-transfers.com/it/installing-imagemagick-on-windows-setup-imagick-on-php/[/url]
[*][url]http://valokuva.org/?page_id=50&cpage=7#comments[/url]
[/list]

Schade, dass es so aufwändig ist eine derart praktsiche Bibliothek unter Windows einzusetzen – wie gesagt unter Linux ist sie hervorragend gepflegt.

Posted in Web |

Wozu es Standards im Netz gibt

Derzeit arbeite in beruflich an einem Web-Projekt. Da es um Datenhandling geht, kommt man um Formulare eigentlich nicht herum. Nun hat man aber immer wieder das Problem doch einige Tabellen in JavaScript füllen zu müssen. Dank mittlerweile halbwegs standardisiertem und akzeptiertem Document Object Model (DOM) auch nicht mehr übermäßig komplex, wenn auch sicherlich keine Aufgabe für Anfänger.

Prinzipiell gibt es zwei Ansätze die man verfolgen kann – entweder man baut sich mittels Skript Befehlen die gewünschten Objekte jeweils from Scratch zusammen und fügt sie dann in das Dokument ein, oder man verwendet eine Art Vorlage, die man sich dann jeweils an den Bedarf anpasst.
Für einfache Dinge eignet sich die Methode “from Scratch” sicherlich ganz gut, wenn es dann an formatierte Tabellenzellen mit Formularen und möglicherweise langen Auswahllisten geht, ist man mit der Vorlage doch einfacher dran – zumal man Auswahllisten ja schon vorab aus der Datenbank generieren kann. Es ginge auch mit AJAX zu realisieren, aber warum so kompliziert wenn es in den allermeisten Fällen auch einfach geht.

Das schöne an dem mittlerweile einheitlichen DOM ist: Man hat sehr schnell Erfolge in den meisten Browsern. Ich verwende standardmäßig Opera und Firefox, denn diese bringen schon seit geraumer Zeit hilfreiche Werkzeuge fürs Debugging von Skripten und auch für Stylesheets mit. Wer sich schonmal genauer mit den Auswirkungen diverser Formatierungsangaben in verschiedenen Browsern auseinander gesetzt hat, weiß den Komfort zu schätzen, den diese Werkzeuge mit sich bringen.

Die große Ernüchterung macht sich dann meist breit, wenn man anfängt zu testen. Dann treten die diversen lästigen Details zu Tage und die ein oder andere Ungereimtheit auch mal wieder. Ärgerlicherweise ist es dann oft ein singulärer Browser, der eine Extrawurst braucht und für den man wieder mal jede Menge Arbeitszeit opfern muss, weil er nunmal in vielen Firmen immer noch der Standard ist … ja die Rede ist vom Internet-Explorer. Auch wenn er in den letzten Versionen endlich mal wichtige Schritte in die richtige Richtung gemacht hat – ein wirklich attraktives Werkzeug ist er für mich immer noch nicht. Das mag einfach mit den Erfahrungen zusammen hängen, als ich meine ersten Schritte im Netz gemacht habe – da war der Internet-Explorer eine eher schlechte Option – der Netscape Navigator war das Tool der Wahl für die Profis. Nachdem Netscape pleite war und Firefox noch nicht in Reichweite, gab es wenig Wahl und der IE setzte sich leider immer mehr durch (obwohl eigentlich das schlechtere Produkt – wie leider so üblich) – ich habe damals durch die c’t Opera kennen und schätzen gelernt.

Aber zurück zum Thema: Das mit dem Einfügen der Tabellenzeilen funktioniert in allen Browsern außer dem Internet-Explorer 🙁 Allerdings kann ich auch keine Fehlemeldung entdecken, dass in dem Skript etwas falsch laufen würde. Googlen bringt erste Hinweise ans Licht: Der Internet-Explorer braucht zwingend ein

<tbody><tr><td></td></tr></tbody>

Konstrukt in der Tabelle. Das Tag selbst habe ich schon mehrfach gesehen und die Funktion ist auch klar zu erkennen – es deklariert den Datenteil einer Tabelle, zusätzlich gibt es noch

<thead>Tabellenkopfzeilen</thead>

und

<tfoot>Tabellenfußzeilen</tfoot>

Nun gut, erst mal fühle ich mich ertappt: Mal wieder nicht an den Standard gehalten und etwas genommen was du schon ewig so machst – ggf. mal in den Standard schauen hilft … zu oft habe ich schon unschöne Seiteneffekte erlebt, weil ich etwas im Kopf hatte was so aber nicht mehr Stand der Technik war oder einfach nie gestimmt hat (einmal falsch abgeguckt und nicht nachgedacht – passiert jedem mal und irgendwann fällt es einem dann doch auf …).

Da ich Standards ja für sinnvoll halte und auch gerne einhalten will, gerade was (X)-HTML betrifft, ist der nächste Schritt klar: Ab mit der Seite in den Validator vom W3C – was wenn nicht dieses Tool wird mir sagen ob mein HTML stimmt oder Lücken / Fehler hat. Und Tatsache: Es gibt haufenweise Fehler, zumindest im ersten Anlauf … die üblichen Verdächtigen, die jeder im Web kennt: Da mal wieder vergessen ein inhaltsleeres Tag wie etwa

<br />

oder

<input />

oder auch

<img />

als ein solches zu kennzeichnen. Dann noch das übliche Gemeckere über die vergessen Alt-Tags für grafische Elemente, die man als international verwendbare Icons für bestimmte Links verwendet hat … alles kein Drama und die meisten Fehler sind mehrfach da, schließlich werden die Tabellen aus der Datenbank gespeist und die hat meist halt mal mehr als einen Datensatz …
Nachdem der Validator dann sagt “alles ok” wundert man sich doch – man hat an der Tabelle noch nichts geändert, sie ist in klassischer Weise definiert:

<table><tr><td></td></tr></table>

und das scheint auch seine Richtigkeit zu haben.

Nun will es aber genau wissen und ich schlage im Standard selbst nach – in der Document Type Definition für XHTML nach. Und siehe da: Die Verwendung von

<tbody></tbody>

ist tatsächlich optional. Na wenigstens hab ich mir nichts direkt vorzuwerfen. Um die zusätzliche Kennzeichnung und eine neuerliche Anpassung des Codes komme ich zwar nicht rum, aber immerhin habe ich jetzt Gewissheit wo der Fehler liegt.

Irgendwie ärgert mich das doch glatt mal wieder ziemlich, dass man es in Redmond mal wieder versteht sämtliche Standards einfach so zu verdrehen wie es einem gerade beliebt. Ansonsten ist der IE sich doch sonst zu nichts zu Schade und rendert jeden noch so verkorksten Code immer noch recht ansehnlich, wo andere bereits die Flügel strecken, weil es vom Standard her einfach nicht mehr geht. Warum gerade hier bei solchen Kleinkram den Entwicklern wieder das Leben schwer gemacht wird, weiß ich nicht. So schwer kann es doch nunmal nicht sein einen Standard zu lesen. Sicherlich weißen viele Standards im Webbereich einiges an Interpretationsspielraum auf – mit SIP hatte ich die Erfahrung ja auch schon. Aber hier gibt es keinen solchen Auslegungsspielraum – nicht im Geringsten! Also bitte liebe Entwickler lernt lesen und behebt diesen Fehler endlich, so schwer kann das doch wirklich nicht sein. Die anderen Hersteller bekommen es doch auch hin…

Als Rat bleibt mir nur noch zu sagen: Wann immer möglich, nehmt alternative Browser – man muss nicht immer das erstbeste nehmen was man bekommt – zumal es die Alternativen ebenfalls zum Nulltarif gibt. Vom Funktionsumfang her stecken sie meiner Erfahrung nach den IE noch immer in die Tasche

Posted in Web |

MS Office + Joomla => Murks im IE

Heute hatte ich mal wieder einen etwas komischen Fehler: Ein Website verwendet Joomla als Content-Management System (CMS) – soweit so gut, und es funktioniert auch soweit wie es soll.
Nur bei einigen neu erstellten Inhalten gibt es Probleme, abhängig davon, welcher Browser eingesetzt wird – verwendet man Opera, Firefox oder irgendeinen anderen Browser außer dem Internet-Explorer, so werden die Inhalte anstandlos angezeigt. Nur mit dem Internet-Explorer klemmt es.

Erster Verdacht: Irgendwo im Code von Joomla ist eine uralte Technik namens Browserweiche enthalten, die mit dem IE irgendwas veranstaltet, was man früher tun musste, aber mittlerweile nicht mehr notwendig ist (dieses Stück Software hält sich ja tatsächlich mittlerweile doch an einige Standards im Bezug auf HTML und CSS). Ein Verlgeich der ausglieferten Quellcodes zeigt: Da ist alles in Ordnung und auch die Tatsache, dass früher alles ja funktioniert hat mit dem IE bekräftigt den Verdacht: Es muss am Quelltext der HTML-Datei selbst liegen, und wahrscheinlich am Inhalt, denn es sind nur spezifische Seiten betroffen…

Also rein mit dem Ding in den Editor und mal gestöbert … und da fällt denn doch etwas auf: an bestimmten Stellen im Quelltext werden Inhalte als Kommentare gekennzeichnet. Soweit nicht schlimm – solche Hilfen verwendet jeder vernünftige Webdesigner um sich besser zu orientieren zu können. Mache ich als Programmierer ja auch. Aber was ich da lesen musste sah so rein gar nicht menschlichem Kommentar aus, vielmehr hatte irgendwas besondere Syntax eingeführt

<!--- 
[if gte os9] ...
usw....
--->

Danach folgten diverse xml deklarationen zur Formatierung, alles Dinge die man so aber nun wirklich nicht braucht und die in der Website (immerhin hat sie ja selbst Formatvorlagen) nichts zu suchen haben. Im Netz fand ich dann auch relativ schnell die Erleuchtung zum Thema: [url]http://www.nochfragen.de/joomla-15/7-texte-aus-ms-word-in-joomla-kopieren.html[/url]
Aber wer denkt denn auch an solchen Murks? Bzw. noch schlimmer: Wer hat sich denn diesen Kram überhaupt einfallen lassen? Ich kann bei weitem keinen Sinn darin erkennen, außer indirekt bekannt zu geben, das jemand den Text irgendwann mal in Word bearbeitet hat (was über die Text-Qualität bekanntlich eh nichts aussagt). Dass es dann auch gerade noch mit dem Produkt aus dem eigenen Haus nicht funktioniert ist dann echt nur noch peinlich für den Hersteller Microsoft. Wenn ich schon so Extras einbaue, dann sollten sie auch zuverlässig funktionieren, so dass es keiner merkt. Aber so ist es doch eine wunderbare Werbung nicht den Internet-Explorer zu verwenden, eben weil er nicht richtig funktioniert… es sieht fast so aus, als würden die Entwickler von Office und Internet-Explorer sich leidenschaftlich gegenseitig Steine in den Weg legen. Mir ist das eh eigentlich gleich, schließlich gibt es so viel schönere Alternativen als den unseeligen Standard-Browser aus Redmond.

Posted in Web |

SPAM SPAM SPAM – und wie man dagegen vorgeht …

Wer in der letzten Zeit meinen Blog und die Kommentare verfolgt hat, wird verärgert festgestellt haben, dass sich unerfreulich viel SPAM in den Kommentaren fand – für Designer-Klamotten und sonstigen Schwachsinn den kein normaler Mensch braucht und der mit Sicherheit nicht zu der Klientel passt, die diesen Blog aboniert hat oder liest. Anfänglich habe ich es noch als “passiert leider auch mir” hingenommen und habe manuell gelöscht …

Nun dachte ich eigentlich, dass ich mit der eingebauten Sicherheitsfunktion von MyBloggie hier recht gut gegen solchen Schwachsinn gewappnet zu sein. Immerhin muss jeder ja ein kleines Captcha lösen. Wie es mir erschien war das aber wohl mittlerweile in die Jahre gekommen und dementsprechend geknackt. Zugegeben – es war wirklich einfach, keine großartig verschwurbelten Zahlen oder Zeichenfolgen, einfach nur eine kleine Grafik, die es abzutippen galt.

Nun gut, was macht der geneigte und genervte Admin? – Erster Blick: Gibts ein Update, dass ich übersehen habe und möglicherweise schon tut was ich brauche. Leider Fehlanzeige – irgendwie scheint das MyBloggie-Projekt nicht mehr groß gepflegt zu werden, was ich etwas schade finde. Aber es ist ja OpenSource und in PHP geschrieben, von daher: werfen wir doch mal einen Blick in den Code, vielleicht lässt sich da ja etwas machen.

Beim Code hat es mich dann erst mal etwas Mühen gekostet, ihn auf meinem Testsever überhaupt zum Laufen zu bewegen, denn man verwendete noch ganz altmodisch die kurzen Einleitungstags für PHP

<? PHPCode kommmt hier dazwischen ?>

anstelle der mittlerweile üblichen und “sichereren” langen Ausführung:

<?php  PHPCode kommmt hier dazwischen ?>

Gut, das war dann also mal zum Warmwerden, und ein paar Regex-Schubsereien sind auch immer mal wieder ganz gutes Gehirn-Jogging.

Richtig ärgerlich wurde es dann beim eigentlich Code für das Captcha – ich habe es mir angeschaut und mir war klar: Wenn ich es will, kann ich mir mit wenig Aufwand einen Bot basteln, der mir die notwendigen Berechnungen quasi synchron gegen rechnet. Das hat man davon, wenn die Zeit als Grundlage für die Zeichenfolge herhalten muss. Der nächste Fehler: Der erzeugte Code wird zwar pseudo-verschlüsselt, landet aber direkt im HTML-Formular und wird beim Abesenden mitgeschickt 😯 – noch einfacher geht es ja kaum. Da der Quellcode frei verfügbar ist, kann jeder sich anschauen wie es gemacht wird und kann sogar noch vor dem Absenden prüfen ob die Zeichenfolge die er ausgerechnet hat auch passt – mit heutiger Rechenleistung kann man das natürlich auch für eine etwas größere Zeitspanne sehr zügig machen bis man einen Treffer landet. Ich weiß nicht ob die Angreifer das so gemacht haben, aber wenn ich es machen müsste, würde ich es so versuchen. Auch musste ich feststellen: Die Bilder für die einzelnen Zeichen der Zeichenfolge sind hardcodiert hinterlegt, ändern sich also nicht bei jedem Aufruf. Sonst hätte man ja auch einfach mal die Bilder entsprechend austauschen können oder für jeden Buchstaben zumindest mal einen ganzen Satz mit verschiedenen Verzerrungen und Verkippungen nehmen können.

Also nix mit mal eben was einbauen, damit der Unfug aufhört. Nun stellt sich der geneigte Administrator natürlich die Frage: Selbst was entwickeln oder gibt es möglicherweise fertige Lösungen die man verwenden kann und die nur drauf warten eingebaut zu werden oder sich zumindest einfach adaptieren lassen.
Natürlich gibt es sowas – leider nicht als Plug and Play-Lösung oder Modul für MyBloggie. Ich habe mich für das Recaptcha-Projekt entschieden, es ist recht einfach einzubinden und gut dokumentiert. Auch wenn da partiell Google mit drinsteckt. Die Auslagerung hat auch andere Vorteile: Dort beschäftigen sich Profis mit dem Thema und es gibt immer wieder Verbesserungen, die man automatisch eingebaut bekommt, ohne nochmals den Code dafür anfassen zu müssen. Also definitiv besser als jede Lösung die ich mir zeitraubend aus den Fingern gesaugt hätte.

Der Einbau in MyBloggie ist denn auch kein Hexenwerk – der Code ist halbwegs vernünftig dokumentiert und so findet man relativ schnell die Stelle an der es um das Captcha geht – den alten Code stilllegen (nicht löschen) und dann die von reCaptcha gestellte Bibliothek einbinden und die notwendigen Funktionsaufrufe gemäß der ausführlichen Anleitung aus dem Beispiel tätigen, fertig ist der Lack.

Ich werde das jetzt die nächsten Tage mal testen und sehen wie gut es funktioniert – ich hoffe mal, es ist jetzt erst mal Ruhe mit Blog-Spam. Und einen schönen Gruß an die Leute die es nötig haben sich solche Bots einfallen zu lassen: Könnt ihr eure Kreativität nicht sinnvoller einsetzen – viele Projekte im Web warten nur darauf angegangen zu werden – es ist ja nichts dagegen einzuwenden Sicherheitslücken zu suchen und auch zu finden – nur sollte man dann auch den Mut haben eine Lösung öffentlich zu machen, wie man diese Dinger abstellt. Die Webgemeinde wird es danken.

Posted in Web |

Lästig – Zusatzsoftware: Toolbars

So hilfreich manche Erweiterung der diversen Browser ja sein mag, man sollte es immer mit Maß und Ziel betreiben. Einige Plugins sind sicherlich nützliche Helfer für den jeweiligen Benutzer, aber wenn man nur noch Toolbars hat, und dadurch Anzeigfläche für den Browser verloren geht, dann wird es lästig. Von Geschwindigkeitsproblemen und möglichen Sicherheitslücken mal ganz zu schweigen.

Besonders lästig ist die Praxis, dass in letzter Zeit immer mehr Software noch zusätzliche Toolbars von irgendwelchen Suchmaschinenanbietern mit installieren will – meist sogar vorausgewählt. Da wird dem Kunden dann ein kostenloser Zusatznutzen versprochen. Ich weiß ja nicht was die Anbieter der Software treibt, aber ich empfinde es einfach nur noch als nervig. Lasst den Krempel der nicht direkt zu betreffenden Software gehört doch bitte einfach weg – wenn ich eine Toolbar brauche, dann installiere ich mir die als mündiger Benutzer schon selbst. Wenn ich eine Software installiere, dann will ich genau diese Software und keine andere installieren – was hat bitte eine Suchmaschine mit einem CD-Brennprogramm zu tun oder mit einer Grafiksoftware (für die man auch noch Geld bezahlt hat)? Helfen wird mir die Toolbar sicherlich im laufenden Betrieb wenig …

Zeit, dass Software wieder nach dem alten Unix-Motto geschrieben wird: “Do one thing and do it right” – mach genau eine Sache und mach sie richtig. Für alles andere gibt es mehr als genügend Programmier und Skriptsprachen, die sind dafür gedacht den Arbeitsfluss zu automatisieren, wenn mehrere Programme miteinander zusammenarbeiten.

Posted in Web |