Excel CSV Export und das Non-Breaking Space

Lukas Schnieper [php, Business]

Ein Kunde meldete uns Probleme beim Import seiner Artikeldaten aus dem ERP in den Online Shop. Plötzlich seien alle Preise bei 0 CHF. Das schlägt natürlich auf die Marge. Bei der Suche nach der Lösung fühle ich mich wie ein Forensiker.

Am Shop sowie an der eingesetzten PHP Version hat sich nichts geändert. Die Datei wird aus dem ERP Opacc im Excel Format exportiert und dann mit Excel ins CSV Format konvertiert. Auf Nachfrage erfahre ich, dass zwar die Microsoft Office Version mit 2013 noch die selbe ist, das ganze aber neu unter Windows 8 statt Windows 7 geschieht.

Die Logische Schlussfolgerung: Irgendwas an der CSV Datei ist anders als zuvor.

Mit LibreOffice zeigt sich mir folgendes Bild. Oben der Windows 7 Export, unten der mit Windows 8. Die Zahl im Feld sieht identisch aus.

Noch steht über meinem Kopf ein grosses Fragezeichen.

Das in Office unsichtbare Leerzeichen

Der nächste Schritt ist der Debugger. Hier wieder der Vergleich. Zuerst die CSV Datei aus Windows 7, unten die aus Windows 8. Bei genauerem hinsehen entdecke ich einen Unterschied: Da hat sich offenbar ein Leerzeichen eingeschlichen.

php-trim räumt auf

Ein Leerzeichen ist eigentlich kein Problem. Jede Spalte wird durch die trim Funktion von PHP durchgeschleust. Diese schneidet die überflüssigen Zeichen vorne und hinten ab. Neben dem Leerezeichen auch Tabs, Zeilenumbrüche und den 0-Character.

Dennoch ist beim Debuggen etwas weiter unten der Preis eine glatte 0.

Die einzige logische Erklärung: Das Leerzeichen ist gar kein Leerzeichen sondern sieht nur so aus.

array_walk($info, array('ImportController', 'trim'));
private static function trim($data) {
    return trim($data);
}
function trim ($str, $charlist = " \t\n\r\0\x0B") {}

Suche mit dem Hex-Editor

Ein Hex Editor kann mir hier genauere Informationen liefern. Dieser interpretiert die Datei nicht danach, was darin sein könnte und wie man das in etwas darzustellen hätte, sondern zeigt unverbülmt ein Binärzeichen nach dem anderen in der Datei an.

Rechts sieht man die alte Datei. Die 28.85 steht ganz alleine Datei. Links die neue Datei. Vor der Zahl hat sich sich Hex A0 eingeschlichen. Im Unterschied zum gängigen Leerzeichen Hex 20 ist das Hex A0 das Non-Breaking Space. Dieses wird eingesetzt, wenn sich trotz Leerzeichen der Text zwischen zwei Wörtern nicht umbrechen darf.

Die Lösung

Was macht dieses Zeichen plötzlich da? Keine Ahnung. Aber jetzt wo ich es kenne, ist nun auch Logisch weshalb es von Trim nicht automatisch entfernt wird. Die Lösung: Hex A0 im Zeichensatz von trim ergänzen.

Hier muss man beachten: Die Importdatei ist im ISO-8859-1 Format, weil dies von Excel automatisch so erstellt wird. Wir arbeiten aber mit UTF-8. Das Non-Breaking Space in UTF-8 wird Hex C2 A0 encodiert wird. Mit \x kann man in Strings Zeichen encodieren. Also hängen wir das C2A0 einfach hinten an.

Und so klappts nun auch wieder mit dem Import.

return trim($data, " \t\n\r\0\x0B\xC2\xA0");

zurück