Umstellung von Webprojekten auf UTF-8

Im letzten Artikel habe ich die Grundlagen zusammengefasst, mit denen ich mich beschäftigen musste um mein aktuelles Projekt voran zu bringen. Das Problem war ursprünglich die nicht einheitliche Handhabung diverser Zeichenketten, was bei Benutzer-Inhalten und Sonderzeichen zum berühmten Mojibake führen konnte (aber eben nicht zwingend muss). Nun denn, gehen wir ans Eingemacht und stellen das Projekt auf UTF-8 um, damit habe ich hoffentlich dann einen wichtigen Schritt in Richtung Zukunftsfähigkeit getan. Außerdem bietet sich UTF-8 wegen seiner Kompatibilität zu ASCII an – Programmcode wird dadurch nicht angetastet und PHP ist dankenswerter Weise sehr einfach gestrickt war Text-Ausgaben mittels „echo“ oder ähnlichen Befehlen betrifft: Was hintendran als Argument kommt wird genauso wiedergegeben wie es reingekommen ist – Byte für Byte. Damit hat man wenig Probleme, auch wenn eine Seite eben mal doch Sonderzeichen enthält (wie es im Deutschen leider häufiger der Fall ist). Dieser Post kann als grundlegendes Howto verwendet werden, es gilt jedoch immer: „Keine Garantie“ und „your milage may vary“

Erster Schritt – Anpassen der Entwicklungsumgebung

Damit man in Zukunft mit der Entwicklungsumgebung weiterhin einfach arbeiten kann, ohne sich jedesmal Gedanken über irgendwelche Sonderzeichen machen zu müssen – wenn man mal eben drei Zeilen Kommentar schreibt, sollte man sich auf dessen Inhalt konzentrieren können. Je nachdem was man verwendet gibt es da verschiedene Stellen die eingestellt werden müssen. Ich verwende Eclipse, dort kann man das Encoding einmal generell (unter Window -> Preferences -> General -> Workspace:  Text-File-Encoding) einstellen.  Zudem sollte man für die verschiedenen Einträge unter „Content Types“ sicherstellen, dass per default dort auch UTF-8 genommen wird. Unter Linux habe ich festgestellt, dass es meistens schon vorab eingestellt ist, denn die meisten aktuellen Linux-Distris sind vom System aus schon löblicherweise auf UTF-8 als Standard umgestellt. Ein Blick in die Äste Web -> CSS Files und Web -> HTML-Files schadet auch nicht. Im Ast XML sollte es per Default auch schon passen, aber Nachgucken schadet auch hier nicht.

Nun muss man noch die Projekt-Einstellungen anpassen (wenn man bestehende Projekte hat) – wenn man den Fehler gemacht hatte und ein neues Projekt angefangen hat ohne sich vorher über die Verwendung von Zeichensätzen Gedanken zu machen (sowas sollte auf jeder Checkliste für Projekte stehen, aber wer achtet da schon drauf wenn es mal eben um eine kleines Projekt geht …. das dann später wächst …). Wenn man die Umstellung gemacht hat, kann man einmal Buchstabensuppe sehen, indem man eine Datei öffnet die Sonderzeichen enthält … die sehen nun etwas komisch aus. Alle händisch ersetzen ist nur was für Hartgesottene oder sehr sehr kleine Projekte.

Zweiter Schritt – Datein umwandeln / umcodieren

Es gibt ein praktisches Tool zum Umwandeln <code>iconv</code> das Werkzeug gibt es auch für Windows, aber so richtig mächtig und scharf wird das erst in Kombination mit ein wenig Scripting (bei mir in Bash)


#!/bin/bash

for file in $(find . -type f -name ‚*.php‘)
do
iconv -f iso88591 -t utf8 -o $file.utf8 $file
if [ $? -eq 0 ]
then
#echo „$file erfolgreich“
mv $file.utf8 $file
else
echo $file geht nicht $?
fi
done

Was machen wir und warum mache ich da so? Ersteinmal suche ich alle betroffenen Dateien heraus, da ich mit PHP arbeite sind das alle Dateien die auf <code>.php</code> enden. Jede dieser Dateien lasse ich durch Iconv laufen und als neue Datei abspeichern. Man sollte nicht auf die Idee kommen <code>iconv -f iso88591 -t utf8 -o $file $file</code> zu verwenden. Das klappt nur bei kleinen Dateien. Wenn das nicht der Fall ist, hat man evtl. unvollständige Dateien und wundert sich was passiert ist, denn <code>iconv</code> gibt in diesem Fall keine Fehlerme. Mit dem Speichern in eine separate Datei bleibt das Original erst einmal unberührt und man kann sich ggf. auf die Fehlersuche machen, denn: Wenn beim Konvertieren selbst etwas schiefgeht gibt es einen exit-Code > 0. Wo es geklappt hat, überschreibe ich das Original. Ansonsten ein kleines <code>echo</code> das mir die fehlerhaften Dateien angibt damit man dort nachsuchen kann, meistens hat man schon irgendwo mal etwas als UTF8 gespeichert oder die Zeichensätze verbeult, das findet sich aber meist recht schnell. Bei mir waren es von 500 Dateien zwei Stück die etwas Handarbeit erforderten. Das gleiche Schema kann man auf alle reinen Textdateien anwenden, wenn man es braucht, z.B. reine HTML-Dateien (Endung htm oder html) oder auch JavaScript-Code. Wichtig ist noch dass man seinem Webserver ggf. beibringt, per default auch in UTF-8 auszuliefern. Dazu sucht man in den Konfigurationsdateien die folgende Zeile:

AddDefaultCharset UTF-8

Nach einem Neustart des Daemons wird das dann als default verwendet. Warum aber nur im default-Fall? Klar es gibt noch ne Möglichkeit das einzustellen und zwar in den ganzen HTML-Headern. Dort gibt es das META-Tag mit dem man Vorgaben machen kann auch für den Fall, dass man auf dem Server keinen Zugriff auf die Einstellungen des Apache oder wie auch immer sonst gearteten Webserver-Prozess hat.

&lt;meta equiv="content-type" content="text/html; charset=utf8"&gt;

Damit sollte jeder aktuelle und die allermeisten der älteren Browser in der Lage sein zu erkennen: Jetzt kommt was in UTF8.

Wenn man nur eine statische Website hat, ist man jetzt schon fertig – nur wer hat das schon heute noch?

Datenbankumstellung (MariaDB/MySQL)

Die Website an sich sollte nach der Umstellung weiterhin funktionieren, denn der eingebettete PHP-Code ist besteht nur aus Zeichen des ASCII-Repertoires und ist somit nicht verändert. Über das was zwischen Klammern steht oder einfach „unverdaut“ ausgegeben wird, macht PHP sich praktischerweise keine Gedanken sondern gibt es einfach aus, egal wie viel Bytes das sind und ob das nun ein besonderes Zeichen ist oder nicht.

Unlustig sind die Dinge die jetzt noch dynamisch aus der Datenbank nachgeladen werden. Wenn man es bisher (wie häufig bei Standardinstallationen) versäumt hatte auf UTF8 umzustellen, dann muss das jetzt auch noch erfolgen. Ich halte nichts davon die Daten bei jeder Ausgabe in UTF8-Strings zu konvertieren – das ist viel zu viel Aufwand wenn das Projekt eine gewisse Größe erreicht hat. Im übrigen haben viele Leute noch per default den Zeichensatz auf „latin1-swedish“ stehen, ein Hinweis woher MySQL denn ursprünglich mal kam. Im 0815-Tagesgeschäft fällt das aber in Europa meist niemandem auf.

Praktischerweise gibt es die Funktion
ALTER TABLE xyz CONVERT TO CHARACTER SET charset_name [COLLATE collation_name]

Damit kann man jeweils eine ganze Tabelle umstellen und eine Collation vorgeben, wir erinnern uns: Collations regeln die Sortierreihenfolge je nach dem wie es gehandhabt werden soll.

Das klingt nicht schlecht und klappt im Allgemeinen auch ganz hervorragend, wenn da nicht einige Fallstricke wären.

Der erste ist ja noch gut gemeint seitens der Engine-Designer: Möglicherweise zu kleine Felder werden in das nächstgrößere Format überführt, wenn der Ausgangszeichensatz einer mit nur einem Byte pro Character ist, der Zielzeichensatz aber mehrere hat oder zumindest haben kann. So werden Textfelder mit bis zu 256 Zeichen zu Mediumtext umgewandelt. Das ist von der Auswirkung her eigentlich zu verschmerzen, aber in meinem Fall habe ich das hinteher wieder manuell korrigiert. richtig problematisch wird das wenn man über die entsprechenden Spalten Indizes angelegt hat, denn Textspalten lassen sich nicht indizieren.

Womit wir beim nächsten Fallstrick wären: An einigen Stellen funktioniert das mit der Umstellung nicht wie geplant, Ursache sind die Foreign-Keys. Ich habe an einigen Stellen „sprechende“ Schlüssel anstelle von numerischen verwendet. Gerade dann wenn man in den referenzierten Tabellen wirklich nur Sateliten-Informationen stehen, wie etwa ein Icon und eine ausführliche textuelle Beschreibung zu einem bestimmten Zustand. Einige werden jetzt die Hände über dem Kopf zusammen schlagen, aber ich habe bisher keine negativen Auswirkungen auf die Performance feststellen können, eher positive Effekte bei der Fehlersuche. Wenn man schon anhand des Eintrags in der Tabelle selbst weiß was Sache ist, kann man sich einen zusätzlichen Join sparen. Das hat ja auch seine Vorteile.

Was also tun? Im Netz findet man praktische Anweisungen, die gesamte DB einmal per  mysqldump in eine Textdatei zu konvertieren, dort dann mit iconv das Gleiche zu veranstalten wie mit den Code-Files, danach noch die Tabellen-Definitionen automatisiert anpassen und den Dump wieder in die Datenbank kippen. Das funktioniert, ist aber bei größeren Datenmengen unhandlich.

Stattdessen habe ich mir die Information-Schema-Tabellen zu Nutze gemacht: dort stehen die Meta-Informationen zu den Tabellen in Tabellen, die man wie gewohnt mit SQL-Befehlen lesen kann – schreiben leider nicht, aber immerhin etwas. Dort sucht man sich nun die betroffenen Spalten und Tabellen heraus (Varchars und Texte), zudem schaut man auf die Foreign-Keys und merkt sich diese. Dann schmeißt man die Foreign Keys weg, führt die Veränderungen an den Tabellen durch (das geht ja dann). Wenn das durchgelaufen ist, kann man noch die vergrößerten Spalten wieder auf die Original-Größe zurück setzen (also Mediumtext => Text usw). Zu guter Letzt schaltet man die Foreign-Keys die man sich gemerkt hat wieder scharf. Fertig ist die Laube. Ganz so einfach ist es im Detail nicht, denn man muss stets vollständige Spaltendefinitionen verwenden, einfach nur den Typ ändern geht so leider nicht, auch wenn das eine praktische Sache wäre.

Jetzt hat man das gesamte Projekt umgestellt – zumindest was die Datenbasis und was die HTML-Seiten und den eingebetteten JS-Code betrifft. Das ist in aller Regel alles was man braucht.

Was noch an Problemen auftreten kann, beschreibe ich in einem weiteren Artikel. Stichwort sind hier externe Libraries und Frameworks.

Mojibake – Buchstabensuppe

Na da hatte ich mir doch eine lange währende Aufgabe ausgesucht, die ich in der aktuellen Pflegephase meines Softwareprojekts endlich einmal angehen wollte. Aktuell läuft das Produkt soweit zufriedenstellend, nur an einigen kleiner Ecken knackt und knirscht es immer mal wieder. Unter anderem das leidige Thema „Sonderzeichen und deren Darstellung“ – da nicht absolut zwingend für die Funktionsfähigkeit habe ich das längere Zeit nicht großartig beachtet.

Nun gut, was ist das eigentliche Problem und woher kommt es? Die Ursachen liegen in der Historie des PCs ver- oder besser begraben: Da Speicher und Datenverarbeitung teuer war, hat man so sparsam wie möglich gearbeitet. Man stellte dabei fest: Inklusive aller wichtigen Zeichen der englischen Sprache und allem was man als Steuerzeichen (Zeilenumbruch, Tabulator, etc.) benötigt, bekommt man in 7 Bit unter. Das ist schon mal etwas krumm, denn gängig ist bei allem was Rechner betrifft doch eigentlich etwas eine Potenz von 2. Die ersten Rechner die ich verwendet habe (mit einem Intel 8088 als Unterbau) konnten nur 8 Bit parallel verarbeiten – immer mehr als die 7. Schon wenig später gab es 16Bit als Standard und mit der großen Verbreitung des PCs in die Büros war der Standard 32 Bit erreicht. Heute findet der sich bereits größtenteils in Ablösung durch 64Bit-Systeme. Was war der Sinn des 8. Bits? Man konnte es je nach Gusto verwenden: Entweder bohrte man damit den Zeichenvorrat auf, oder man konnte es zur Fehlererkennung und Korrektur einsetzen. Insgesamt muss man sagen: Alles mit Hand und Fuß.

Nur leider waren Rechner damals noch nicht gängigerweise vernetzt und die Standard-Definitoren etwas kurzsichtig – erst einmal wurde nur an die eigene Heimat gedacht, dass es möglicherweise andere Sprachen gibt, die nicht Englisch sind und einige Zeichen mehr mitbringen – wer konnte das schon ahnen? So kam was kommen musste: Einschränkungen bei diversen Dingen wie dem Betriebssystem: Umlaute oder Sonderzeichen in Dateinamen waren einfach nicht vorgesehen oder führten zu unvorhergesehenen Ergebnissen. Für das Verfassen und Verarbeiten von Texten war das natürlich keine Option, wer in Deutschland einen Text schreiben wollte, der sollte das auch tun können. Daher erweiterte man den Zeichensatz auf das 8 Bit und schon hatte man jede Menge Möglichkeiten auch Sonderzeichen abzuspeichern. Wichtig war nur, das jeder die gleiche Zuordnung traf und nicht einer ein ü für ein ö verwendete was die binäre Darstellung betraf. Soweit so gut oder auch schlecht.

Nun gehen leider bei verschiedenen Betrachtungen immer wieder einige Dinge durcheinander, auch ich habe hier am Anfag so meine liebe Mühe gehabt alles richtig zu verorten, daher hier einmal die Kurzfassung, zu allem was notwendig ist bzw. was sich auf die Darstellung und Handhabung von Texten am Rechner auswirken kann.

Binärer-Code

Eine Abfolge von 0en und 1en die irgendetwas darstellen – was ist für den Rechner erstmal unerheblich, dafür bedarf es einer Zuordnungs oder Code-Tabelle oder eines Algorithmus, der den Binärcode in etwas umsetzt, das dem Benutzer eher vertraut ist (leider sind wir Menschen nicht sonderlich gut binär veranlagt).

Code-Tabelle/Zuordnung/Algorithmus

Je nachdem was für eine Datentyp abgebildet werden soll, gibt es verschiedene Methoden dies zu tun. Am einfachsten sind ganze, positive Zahlen. Diese lassen sich aus der Abfolge von 0en und 1en entsprechend „errechnen“ – man muss nur noch wissen wo man anfangen muss (little endian vs. big endian). Für positive und negative Ganzzahlen hat sich das Zweierkomplement bewährt, für Fixkomma und Gleitkomma gibt es entsprechende Standards. Alles ein Thema für sich, denn wir wollen ja Texte bzw. Strings beleuchten. Hier hat sich eine Übersetzungstabelle als Mittel der Wahl erwiesen – sie ordnet jeder möglichen Abfolge von 0en und 1en eine menschenlesbare Bedeutung zu. So wird z.B aus der binären Folge 0110 1101  = 0x6D = O155 = „m“. Die Zuordnung an und für sich ist reine Willkür – man hat sich mal auf gewisse Standards geeinigt bzw. diese festgelegt, damit eben auf allen Rechner ein „m“ ein „m“ ist und nicht aus der „e-mail“ durch Willkür eine „e-nail“ wird. Der Urvater aller Standards dazu heißt ASCII (America Standard Code for Information Interchange) – wie der Name schon sagt ein nationales Standardformat. Auch bekannt ist diese Tabelle als Character-Set.

Windows-Codepages und Nornumg

Für verschiedene Regionen wurden verschiedene Verwendungen des verbliebenen 8. Bits (siehe oben) standardisiert – leider teilweise recht unterschiedlich, zum Teil nur an wenigen Stellen. Ziel war es, die in der jeweiligen Region verwendeten Sprachen möglichst gut abzubilden. Leider gab es da erst sehr spät eine Einigung auf einheitliche Standards, so dass zeitweise unterschiedliche Hersteller unterschiedliche Zuordnungen trafen. Ganz genauso wie wenn man Dateien ohne Angabe des verwendeten Zeichensatzes weitergab konnte es also passieren, dass der Zielrechner die Bit-Folge unterschiedlich interpretierte, weil bestimmte Bitfolgen eben etwas unterschiedliches bedeuteten. Dankenswerterweise hat man dabei die sichtbaren Zeichen (leider nicht so bei den Steuerzeichen) aus dem Urvater ASCII gleich belassen (das hatte sich ja bewährt, und für den internationalen Textaustausch reichte dieser kleinste gemeinsame Nenner auch aus). Gängig sind in der westlichen Welt die Standards der ISO 8859 in den Varianten 1-16, unter Windows die Codepage 1250 und unter DOS die Codepage 850.

Unicode

Mit der steigenden Internationalisierung und der immer stärker zunehmenden Vernetzung von Computern ist das mit den Nachschlagetabellen so eine Sache – man muss immer wieder etwas anderes berücksichtigen: Das Betriebsystem und die Region bzw. die Regionaleinstellungen des Anwenders – nur damit Text auch so ankommt wie er einegeben wurde. An einigen Stellen hat man sich beholfen oder die Probleme durch menschliche Intuition überbrückt – durch die Redundanz in der menschlichen Sprache kann man viele Worte ja auch lesen wenn Buchstaben vertauscht wurden oder nicht lesbar sind. Jeder Mensch der Lesen lernt kann das mehr oder weniger: Wenn aus einen Königreich dann plötzlich ein K$nigreich wird, dann wird der geneigte Leser das immer noch erkennen, auch wenn so ein Text etws mühsamer zu lesen ist. Ohnehin: wenn es international wird, dann ist die Sprache der Wahl in aller Regel doch Englisch und somit problemfrei. Aber wäre es nicht toll, wenn jemand eine Lösung hätte, damit ich auch chinesische Texte richtig angezeigt bekomme? Oder auch mal einen arabischen Text im Original anschauen? Das klingt weit hergeholt, aber diese Anwendungsfälle gibt es häufiger als man denkt. Die ursprüngliche Idee mit 32Bit und somit 4 Bytes pro codiertem Zeichen zu arbeiten (UTF-32) ist zwar einfach zu realisieren, aber ein wenig „over the top“ ist das schon: Wer überträgt schon gerne 3 komplett genullte Bytes wenn die Info doch nur in einem steht? Außerdem ist der Standard nicht abwärtskompatibel, er bricht mit den alten Vorgaben von ASCII, was bei älterer Software oder inkompatibler Software Ärger machen kann. Daher gibt es verschiedene Methoden mit variabler Anzahl von Zeichen, sozusagen das Beste aus beiden Welten: UTF-16 oder UTF-8 sind hierbei die bekanntesten Möglichkeiten.

Schriftarten und Glyphen

Wir haben uns nun langsam von der Bits & Bytes-Ebene nach oben gearbeitet hin zum abstrakten Begriff eines „characters“. Es gibt aber noch eine Ebene obendran – die Schriftarten oder auch Glyphen. Das ist im Prinzip eine weitere Tabelle die festlegt wie ein abstraktes Zeichen auf dem Ausgabemedium dargestellt werden soll. Jeder der sich einmal durch den Schriftenkatalog einer gängigen Office-Sammlung gewühlt hat, weiß das ein A ein A bleibt, auch wenn es etwas unterschiedlich geformt ist. Das beste Beispiel ist noch immer die eigene Handschrift im Vergleich zu einem beliebigen, gedruckten Werk. So lange eine gewisse Basis-Form erhalten bleibt, erkennt jeder Leser darin auch weiterhin ein A. Es gibt natürlich auch wieder Spezielle Schriftarten die als Darstellungvon Buchstaben Symbole haben, die nichts mit dem eigentlichen Zeichen zu tun haben – das bekannteste dürfte die Schriftarte Wingding oder auch Webdings sein. Besonders unpraktisch fällt mir diese immer wieder in e-mails aus Outlook auf, wenn man diese als Text ließt. Dort wird der Smily 🙂 automatisch in ein J umgewandelt und mit der Schriftart Wingdings formatiert – sieht zwar im ersten Moment richtig aus, aber mancher hat sich schon gewundert wo das „J“ denn nun herkommt. Ich merke es mir immer so: Ein Glyph macht aus einer Bit-Folge mittels einer Tabelle eine ganz bestimmte Grafik. Das ist zwar etwas vereinfacht, denn Schriftarten machen manchmal noch mehr, aber um den Überblick zu behalten reicht es allemal.

Collations

Was nochwas? Haben wir nicht alles endlich abgehandelt? Leider noch nicht ganz: Es gibt nämlich noch etwas was man mit Zeichenketten gerne macht: Aufreihen und Sortieren. Kling trivial, und es gibt doch Sortieralgorithmen wie Sand am Meer. Könnte man meinen, leider ist dem nicht ganz so (und das ist mit ein Grund weshalb man Sortieralgorithmen am besten an Zahlen erklärt …), denn auch wenn es im ersten Moment verlockend sein mag zu sagen: Man sortiert einfach nach der Größe der entsprechenden Ganzzahl der Bitfolge, das bringt leider nicht das gewünschte Ergebnis, denn schon bei ASCII haben wir ja große und kleine Buchstaben, ordnet man nun nach der errechneten Wertigkeit, so würde das folgende Sortierreihenfolge ergeben A,B,C…..,X,YZ,a,b,c – für die alphabetische Auflistung eines Materialkatalogs nicht das gewünschte Ergebnis – auch im Telefonbuch sucht man die Leute mit „von“ im Vornamen ja nicht unter „v“ sondern unter „V“ und dort irgendwo nach „Voldemort“…. und nun wirds ganz interessant: Wo ordne ich denn die Sonderzeichen wie Ä,Ö,Ü ein … sind das separate Zeichen am Ende? Oder soll ich sie behandeln wie „Ae“,“Oe“ und „Ue“? Das ganze nun noch auf die internationale Ebene gehoben und es wird ganz spannend: Je nach Land gibt es gleiche Zeichen, aber die werden unterschiedlich einsortiert, aber der Rechner soll es dennoch richtig machen. Das kann nur bedingt funktionieren, alles weitere regelt man über die Collation, die kann man zur Not auch bei der Sortierung mit angeben, und dem Sortierprogramm somit die Regeln vorgeben.

So jetzt habe ich einmal die Grundlagen zusammengefasst, die Auswirkungen und Mittel die man braucht um das alles umzusetzen behandle ich in einem separaten Artikel.

 

 

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

&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;

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

&lt;thead&gt;Tabellenkopfzeilen&lt;/thead&gt;

und

&lt;tfoot&gt;Tabellenfußzeilen&lt;/tfoot&gt;

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

&lt;br /&gt;

oder

&lt;input /&gt;

oder auch

&lt;img /&gt;

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:

&lt;table&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;

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

&lt;tbody&gt;&lt;/tbody&gt;

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

&lt;!--- 
[if gte os9] ...
usw....
---&gt;

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 |