UTF-8-Zeichen in Dateinamen

Probleme rund um UTF-8 gibt es immer wieder. Und Erklärungen zu UTF-8-Konfiguration für TYPO3 gibt es inzwischen auch zahlreich. Meistens endet es aber bei der Datenbank und der textlichen Ausgabe. Die Fallstricke im Umgang mit UTF-8-Zeichen im Dateisystem werden kaum beleuchtet.

Ausgangspunkt

Wir haben eine TYPO3-Installation:

  • Datenbank arbeitet mit UTF-8 (Standard-Kollation)
  • DB-Verbindung weiß, dass sie mit UTF-8 arbeiten soll ($TYPO3_CONF_VARS[‚SYS‘][’setDBinit‘])
  • TYPO3-Backend ist angewiesen UTF-8 zu nutzen ($TYPO3_CONF_VARS[‚BE‘][‚forceCharset‘])
  • TYPO3 weiß, dass unser Filesystem UTF-8 versteht ($TYPO3_CONF_VARS[‚SYS‘][‚UTF8filesystem‘])

…und trotzdem finden sich error.log-Einträge, die vermisste Dateien protokollieren:

/usr/bin/gm convert: Unable to open file (uploads/tx_example/berraschung.jpg) [No such file or directory].

Analyse

Wie kann das sein? Warum wird überhaupt eine Datei „berraschung.jpg“ angefordert? In der Datenbank steht doch korrekt „Überraschung.jpg“ drin. Im Dateisystem liegt im Ordner unserer Extension die Datei auch korrekt. Und im PHP-Code wird doch extra vor der Verarbeitung des Bildes nochmals geprüft, ob die Datei existiert (file_exists()).

Verfolgen wir den Dateinamen auf dem Weg aus der Datenbank bis zur Generierung des Bildes:
Um aus dem cObject IMAGE an das Bild zu gelangen, stoßen wir auf imageMagickConvert(). Die Methode t3lib_stdgraphic::imageMagickConvert() ruft t3lib_div::imageMagickCommand() auf, die wiederum t3lib_utility_Command::imageMagickCommand() aufruft, um dann die Rückgabe (Kommando) an t3lib_utility_Command::imageMagickCommand::exec() zu übergeben und ausführen zu lassen.
Auf diesem Weg wird das generierte Kommando auch einmal durch escapeshellarg() geschickt – und hier lauert die Ursache.

Schauen wir uns das mal in rohem PHP genauer an:

$cmd = "'/usr/bin/gm' convert +profile '*' -geometry 170x136! -colorspace RGB -quality 90  '/var/www/example.org/htdocs/uploads/tx_example/Überraschung.jpg'[0] '/var/www/example.org/htdocs/typo3temp/pics/Überraschung.jpg'";
echo escapeshellarg($cmd);

Ausgabe:

''\''/usr/bin/gm'\'' convert +profile '\''*'\'' -geometry 170x136! -colorspace RGB -quality 90 '\''/var/www/example.org/htdocs/uploads/tx_example/berraschung.jpg'\''[0] '\''/var/www/example.org/htdocs/typo3temp/pics/berraschung.jpg'\'''

Ups…Da fehlt plötzlich das „Ü“ 🙁

Lösung

Ein Kommentar in der PHP-Dokumentation verrät die Lösung: unsere Locales passen nicht, wodurch UTF-8-Zeichen beim Escapen verschluckt werden. Mit einer kleinen Änderung am PHP-Beispiel klappt es dann:

setlocale(LC_CTYPE, "de_DE.UTF-8");
$cmd = "'/usr/bin/gm' convert +profile '*' -geometry 170x136! -colorspace RGB -quality 90  '/var/www/example.org/htdocs/uploads/tx_example/Überraschung.jpg'[0] '/var/www/example.org/htdocs/typo3temp/pics/Überraschung.jpg'";
echo escapeshellarg($cmd);

Ausgabe:

''\''/usr/bin/gm'\'' convert +profile '\''*'\'' -geometry 170x136! -colorspace RGB -quality 90 '\''/var/www/example.org/htdocs/uploads/tx_example/Überraschung.jpg'\''[0] '\''/var/www/example.org/htdocs/typo3temp/pics/Überraschung.jpg'\'''

Ok, und wie bekommen wir es nun noch hin, dass das in den Tiefen von TYPO3 funktioniert? Wie so oft findet sich die Lösung in der TSref: config.locale_all

PHP: setlocale(„LC_ALL“, [value]);
value-examples: deutsch, de_DE, danish, portuguese, spanish, french, norwegian, italian. See www.php.net for other value.
Also on linux, look at /usr/share/locale/

Ein Blick in den Ordner verrät uns, dass es neben de_DE auch ein de_DE.UTF-8 gibt (auf anderen Systemen auch de_DE@UTF-8 odgl.). Somit ist die Lösung, im TS-Setup:

config.locale_all = de_DE.UTF-8

Das könnte dich auch interessieren …

5 Antworten

  1. Wolfgang Löer sagt:

    Danke für die flotte Antwort – so schnell hatte ich nicht damit gerechnet 🙂

    Tatsächlich habe ich noch im Installtool unter „All Configuration“ die Einstellung [SYS][systemLocale] gefunden. Wenn ich dort die korrekte Locale eintrage, funktionierts! (Keine Ahnung, warum es die Einstellung somit quasi zweimal gibt …)

    Bzgl. neuer FAL-Fehlerquellen hast du übrigens Recht:
    z.B. bekommt man leider aktuell Probleme, wenn man im fileadmin einen Ordner umbenennt, verschiebt, oder löscht, nachdem er von FAL referenziert wurde (auch wenn er inzwischen leer ist) – neue Bilder lassen sich dann nämlich nicht mehr in Inhaltselementen referenzieren. Ohne diesen Bug hätten wir die Ordner einfach umbenannt …

  2. Julian sagt:

    Ohne dass ich mit einer 6x-Version nachgeforscht habe: vielleicht ergaben sich Änderungen (bzw. weitere mögliche Fehlerquellen) durch die Einführung von FAL.
    Probier evtl. mal ein Standalone-PHP um ein bestimmtes Bild zu generieren. Wenn Du Dich damit herangetastet hast, weißt Du zumindest, welche Parameter/Einstellungen TYPO3 nutzen müsste.

  3. Wolfgang Löer sagt:

    Ich kann nur zustimmen – wirklich anschaulich und gut geschrieben.
    Deinen PHP-Test kann ich auch genau nachvollziehen.

    Leider hatte ich die config.locale_all allerdings schon lange entsprechend eingestellt (und auch jetzt extra nochmal die vorliegenden Locales überprüft), Imagemagick lässt sich trotzdem bei Bildern mit Umlauten im Pfad nicht zur Zusammenarbeit überreden. (andere lassen sich normal skalieren)

    Hast du zufällig noch eine Idee, wie ich die Funktion der locale_all überprüfen kann, oder die Einstellung an anderer Stelle vornehmen kann (System ist Typo3 6.0.6)?

  4. Christian Geiselmann sagt:

    Wow! Vielen Dank für diese ausführliche Schritt-für-Schritt-Erklärung, die den Dingen gründlich auf den Grund geht! Solche Hilfestellung würde man gerne öfters finden…

    • Julian sagt:

      Freut mich. Ich stimme Dir zu. Auch ich würde gerne häufiger etwas mehr über Hintergründe finden. Das ist auch der Grund, weshalb ich versuche nach meinen Recherchen die Erkenntnisse zusammengefasst bereitzustellen. Wäre ja irgendwie schade, wenn jeder sich aufs Neue in das reinarbeiten müsste, wo sich andere schon durchgearbeitet haben.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert