Archive for July, 2010

Mysqldump und die Fehlermeldung “Unknown command ‘\0′”

Sofern man versucht, einen von mysqldump erzeugten Datenbankdump in einen (anderen) MySQL-Server zu importieren, kann man unter Umständen auf folgende Fehlermeldung stoßen:

Unknown command '\0'

Die wahrscheinlichste Ursache sind Datenfelder vom Typ BLOB, welche mysqldump beim Speichern im Textformat nicht richtig kodiert hat.

Der einfachste Weg zur Umgehung dieses Problems besteht darin, bereits beim Exportieren der Datenbank die Option –hex-blob zu setzen:

mysqldump -ubenutzername -p --hex-blob datenbankname > datenbankname.sql

Damit erzeugt mysqldump für jeden BLOB eine hexadezimale Repräsentation, wie es beispielsweise auch bei phpMyAdmin seit geraumer Zeit Standard ist.

Den PHP-Fehler “Exception thrown without a stack frame in Unknown on line 0″ beheben

Wenn man viel mit (objektorientiertem) PHP arbeitet, stößt ab und an auf die wenig aussagekräftige Fehlermeldung “Exception thrown without a stack frame in Unknown on line 0“.

Dieser Fehler ist wenig hilfreich, insbesondere bricht die Programmausführung ab und man hat keine Möglichkeit zu erkennen, wo die Ursache der Meldung liegt. Ich habe diese Meldung häufig erhalten und nie versucht zu begreifen, was sie eigentlich bedeutet. Stattdessen habe ich solang am Code gepatcht, bis das Programm wieder lief. Für alle, die ähnliche Probleme haben, findet sich hier eine Übersicht der Ursachen dieser Meldung.

Solange PHP “normal” läuft, erzeugt es für jede geworfene Exception einen Stacktrace, bei nicht abgefangenen Exceptions wird dieser Stacktrace im Log ausgegeben. Es gibt jedoch bestimmte Zustände, in denen PHP noch nicht respektive nicht mehr vollständig läuft, in diesen Fällen ist es scheinbar nicht möglich, einen Stacktrace zu erzeugen. Die folgende (nicht vollständige) Liste enthält alle  Ursachen, die mir bisher untergekommen sind:

  • Eine Exception im benutzerdefinierten Exception-Handler werfen: Wen man in PHP mittels set_exception_handler() eine Funktion registriert, die ihrerseits eine weitere Exception wirft, kann PHP mit dieser nichts anfangen und gibt exakt die oben genannte Fehlermeldung aus.
    Somit ist es ratsam, im Exception-Handler sämtlichen Code in einen try-catch-Block zu verfrachten und etwaig auftauchende Exceptions beispielsweise mittels error_log() in den Log zu schreiben.
  • Im Konstruktor oder Destruktor Exceptions werfen: Eine Exception im Konstruktor sorgt dafür, dass das Objekt nicht vernünftig erzeugt wird, es wird somit in einem undefinierten Zustand hinterlassen. Im Destruktor hingegen kann es sein, dass das Objekt (oder andere, referenzierte Objekte) bereits nicht mehr existieren. Auch hier ist es ratsam, alle Funktionsaufrufe, die potentiell eine Exception werfen können, mit einem try-catch-Block zu umschliessen.
  • Exceptions im Autoloader: Es scheint nur teilweise der Fall zu sein, dass eine im mittels spl_autoload_register() registrierten Autoloader geworfene Exception ebenfalls diese Fehlermeldung erzeugt.

Diese Liste ist sicher noch nicht vollständig, sofern mir neue Ursachen unterkommen füge ich sie entsprechend ein.

Mittels CSS DIV-Elemente mit 100% Höhe erzeugen

Um in HTML ein DIV-Element zu erzeugen, welches tatsächlich die gesamte Höhe des Fensters ausfüllt, reicht es nicht, diesem per CSS die Höhe 100% zuzuweisen.

Zusätzlich müssen nämlich noch sämtliche Elternknoten die Höhe 100% annehmen, dazu gehören insbesondere die Element HTML und Body.

Der folgende CSS-Code zeigt, wie es richtig geht:

html{
  height: 100%;
}

body{
  height: 100%;
}

div#fullHeight{
  height: 100%;
}

Natürlich muss das DIV-Element in diesem Fall direkt unterhalb des BODY-Elements eingefügt werden, andernfalls ist auch für alle zwischenliegenden Knoten die Höhenangabe obligatorisch.

Ein Subversion-Repositories mittels svnsync spiegeln

Für einige Einsatzzwecke ist es erforderlich, ein komplettes Subversion-Repository zu spiegeln. Ein gutes Beispiel hierfür ist Trac, welches zumindest nach meinem Kenntnisstand derzeit nur auf lokale Repositories zugreifen kann.

Anstatt nun den gesamten Verzeichnisinhalt etwa per rsync synchon zu halten bietet es sich an, direkt auf Ebene des Subversion-Protokolls zu spiegeln. Dazu dient das Programm svnsync, welches in den Subversion-Pakete der meisten Distributionen enthalten sein sollte.

Im Folgenden wird davon ausgegangen, dass das entfernte Repository unter der Adresse http://example.com/svn verfügbar ist und ein Zugriff mit dem Benutzernamen svnsync möglich ist. Das Zielrepository soll in diesem Fall l0kal unter dem Pfad /srv/svnMirror vorliegen. Da Subversion die Protokolle transparent handhabt sollten auch beliebige Kombinationen mit http(s), ssh und file möglich sein.

Zunächst muss das lokale Repository mit leerem Inhalt angelegt werden:

svnadmin create /srv/svnMirror

Anschließend hat man die Wahl: Sofern aus das gespiegelte Repository keine weiteren Benutzer als der svnsync-Benutzer zugreifen, kann man gefahrlos die folgenden beiden Kommandos ausführen:

echo "#!/bin/bash" > /srv/svnMirror/hooks/pre-revprop-change
chmod u+x /srv/svnMirror/hooks/pre-revprop-change

Allerdings haben in diesem Fall alle Benutzer einen Vollzugriff auf das Verzeichnis, können insbesondere auch Revisionen löschen. Sofern also weitere Benutzer Zugriff auf die Kopie erhalten soll, empfiehlt es sich, die folgenden Zeilen in die Datei /srv/svnMirror/hooks/pre-revprop-change einzutragen und diese anschließend ausführbar zu machen:

#!/bin/sh
USER="$3"
if [ "$USER" = "svnsync" ]; then exit 0; fi
echo "Only the svnsync user can change revprops" >&2
exit 1

Mit dieser Kombination erhält nur der Benutzer svnsync den Vollzugriff.

Wie auch immer man sich entschieden hat, anschließend erfolgt eine initiale Synchronisation, hier muss man unter anderem das Passwort für den Zugriff eingeben:

svnsync init --username=svnsync /srv/svnMirror

Anschließend stößt man den Synchronisationsvorgang mit folgendem Befehl an:

svnsync /srv/svnMirror

Die erste Synchronisation kann, je nach Alter und Größe des entfernten Repositories, einige Zeit in Anspruch nehmen, da jede einzelne Revision sukzessive kopiert werden.

Auch für jede weitere Kopiervorgang benutzt man nun das obige Kommando, es empfiehlt sich in den meisten Fällen, dies in einen Cronjob einzutragen.

Den Fehler “no database selected” im Typo3 Installtool beheben

Die Typo3 version 4.3.3 scheint einen Fehler im Installtool aufzuweisen. Bei der Erstinstallation im 1-2-3-Mode werden auf der ersten Seite zunächst die Datenbankparameter abgefragt. Nach einem Klick auf Submit wird man auf eine Fehlerseite weitergeleitet, die nur folgende Meldung enthält:

no database selected

Außerdem werden in der localconf.php keinerlei Datenbankparameter hinterlegt und es gibt keine Möglichkeit, mit der Installation fortzufahren.

Ein einfacher Workaround hierzu ist es, die Datenbankparameter direkt in der Konfigurationsdatei einzufügen. Dazu öffnet man einfach die Datei typo3conf/localconf.php mit einem Texteditor und passt die folgenden Zeilen an die eigenen Gegebenheiten an:

$typo_db_username = 'user';
$typo_db_password = 'password';
$typo_db_host = 'localhost';
$typo_db = 'dbname';

Anschließend kann man die Fehlerseite im Installtool neu laden und die Installation mit dem Importieren des Datenbankdumps fortfahren.

Tipp: Falls man das Installtool schon weggeklickt hat oder nicht mehr im 1-2-3-Mode ist nutzt man den folgenden Link:

http://serveradresse/typo3/install/index.php?mode=123&step=2

Backticks in MySQL

Ich habe mich immer gefragt, warum bestimmte Programme wie phpMyAdmin in von ihnen generierten SQL-Queries immer Backticks verwenden, während andere System diese nie nutzen.

Der Grund dafür ist eigentlich sehr simpel und soll in einem kurzen Beispiel erläutert werden. Angenommen, innerhalb einer Datenbank soll folgende Tabelle erzeugt werden:

Table-1

Das ist in MySQL ein durchaus gültiger Tabellenname. Um nun den Inhalt dieser Tabelle aufzulisten würde man beispielsweise den folgenden Query nutzen:

SELECT * FROM Table-1;

Weit gefehlt, anstatt den Inhalt der Tabelle zu Gesicht zu bekommen erhält man eine Fehlermeldung wie “You have an error in your SQL syntax”. Wenn man sich den Query genauer ansieht wird man feststellen, dass dieser nicht eindeutig ist. Der Parser kann also nicht mit Sicherheit sagen, ob man die Tabelle Table-1 referenzieren möchte oder von einem Feld mit dem Namen Table die Eins subtrahieren möchte.

Um dem Parser genau zu erläutern, was gemeint ist, nutzt man einfach die Backticks, die den von ihnen eingeschlossenen Inhalt als Feld-, Tabellen- oder Datenbanknamen ausweisen:

SELECT * FROM `Table-1`;

Natürlich gilt gleiches auch für andere Feld- oder Datenbanknamen. Ein weiteres (beliebtes) Beispiel ist eine Tabelle, die ein Feld max oder min enthält. Hier ist sich MySQL nicht darüber im Klaren, ob die Funktionen MAX() respektive MIN() oder das entsprechende Feld gemeint ist.

Ein Hinweis für tippfaule Leute: Es ist durchaus möglich, die Backticks nur bei benötigten Teilen des Queries zu nutzen.

Typo3: Falsches Auslesen der PHP-Einstellung für safe_mode

Die derzeit aktuelle Typo3-Version 4.4.0 enthält einen Bug, durch welche Typo unter Umständen suggeriert, PHP würde im Safe Mode laufen obwohl es dies gar nicht tut.

Das Problem liegt im Abfragen der PHP-Einstellung, die in etwa wie folgt aussieht:

if(ini_get('safe_mode')){
  //Safe Mode ist aktiviert
}

Solange in der PHP- und Apache-Konfiguration eine 0 oder eine 1 für deaktivierten respektive aktivierten Safe Mode stehen, bereitet diese Abfragetechnik kein Problem. Allerdings ist es auch erlaubt, die Wörter “off ” oder “on” zu nutzen. Eine Einstellung wie diese

safe_mode=off

führt jedoch unweigerlich dazu, dass Typo3 fälschlicherweise einen aktiven Safe Mode erkennt, obwohl dieser deaktiviert ist.

Das Problem ist bereits in einem Bugreport vorhanden und sollte mit einer der nächsten Versionen gefixt werden.

Typo3 komplett für UTF-8 konfigurieren

In Typo3 gibt es verschiedene Konfigurationsparameter, um eine durchgängige Nutzung von UTF-8 als Zeichensatz zu erzwingen. Und häufig kommt es vor, dass nur einige der Parameter umgesetzt werden, während andere nicht berücksichtigt wurden. Dies kann unter Umständen zu einer inkonsistenten Installation führen.

Dieser Beitrag listet die wichtigsten Parameter gesammelt auf. Vorher noch ein wichtiger Hinweis: Diese Einstellungen sollten gesetzt werden, bevor Inhalte für die Seite angelegt werden. Anderweitig kann die Kodierung der Texte in der Datenbank von den Systemeinstellungen abweichen, dies würde nach erneutem Editieren zur Zerstörung aller nicht-ASCII-Zeichen führen.

Einstellungen in der localconf.php

Die folgenden Werte müssen in der localconf.php gesetzt werden, diese findet sich im Typo3-Root unter typo3conf/localconf.php. Die Werte können entweder direkt von Hand in der Datei gesetzt werden oder, bequemer, über das Typo3 Installtool.

forceCharset

Der Wert dieses Feldes wird von Typo3 intern für zum Setzen verschiedener Zeichensätze genutzt. Er muss auf utf-8 gestellt werden.

multiplyDBfieldSie

Da UTF-8 für jedes Zeichen nur ein Feld benötigt, muss diese Einstellung auf 1 gesetzt werden. Dies entspricht einem Feld pro Zeichen.

setDBinit

Die in diesem Feld vorhandenen Befehle werden direkt nach dem Aufbau jeder Datenbankverbindung an den DB-Server gesendet und sollen für die Nutzung der korrekte Zeichenkodierung in der Datenbankverbindung sorgen.
In der Regel sollten die folgenden beiden Befehle ausreichen:

SET NAMES utf8;
SET CHARACTER SET utf8;

UTF8filesystem

Sofern das verwendete Dateisystem UTF-8-Zeichen unterstützt, werden bspw. für den Upload auch Dateinamen mit Umlauten unterstützt. Dies sollte insbesondere bei Unix-System auf true gesetzt werden.

Gesammelte Einstellungen der localconf.php

Alternativ zum Setzen der Einstellungen über das Install-Tool kann auch der folgende Abschnitt direkt in die localconf.php kopiert werden:

$TYPO3_CONF_VARS['SYS']['UTF8filesystem'] = '1';
$TYPO3_CONF_VARS['BE']['forceCharset'] = 'utf-8';
$TYPO3_CONF_VARS['SYS']['setDBinit'] = 'SET NAMES utf8;'.chr(10).'SET CHARACTER SET utf8;';
$TYPO3_CONF_VARS['SYS']['multiplyDBfieldSize']=1;

Einstellungen in TypoScript

Zusätzlich sollten noch ein paar Einstellungen im Template der Seite gemacht werden. Der folgende Codeausschnitt sollte möglichst im Root-Template der Seite gesetzt werden:

config{
  additionalHeaders = Content-Type:text/html; charset=utf-8
  metaCharset = utf-8
}
Return top