Software-Entwicklung mit WordPress
80% der Zeit machen wir Webapps bzw Software-Projekte mit WordPress, und keine Homepages o.ä.
Die meiste Arbeitszeit stecken wir also in das Erstellen von Kundenprojekten, wo WordPress als Framework dient. Also statt Softwareentwicklung mit Laravel, Symfony oder CakePHP verwenden wir WordPress als Basis für Software-Entwicklung
Das als Einleitung, warum ich hier über das Einlesen von CSV-Dateien in PHP schreibe.
Das Dilemma: CSV Funktionen in PHP fehlerhaft?
PHP bietet viele Funktionen um CSV-Dateien einzulesen.
- https://www.php.net/manual/de/function.fgetcsv.php
- https://www.php.net/manual/de/function.str-getcsv.php
- https://www.php.net/manual/de/function.fputcsv.php
Manchmal stößt man auf Probleme, wo es nur eine Erklärung geben kann:
Da ist ein BUG! In PHP! Ich hab einen PHP-Bug gefunden, yeah!
Tipp: Nein. Meistens sitzt der Bug an der Tastatur vor dem Bildschirm.
Oder der „Bug“ liegt in externen Eingaben. Hey, es sind immer die externen Eingaben die Probleme machen!
Das Problem: Unlesbare Zeichen!
Ok, sorry! Viel herumgejodele, ohne zum Thema zu kommen. Darum geht es:
Wird die Datei in PHP eingelesen, dann verarbeitet PHP solche wirren Zeichen.
Öffnet man die selbe Datei am Computer, sieht man davon nichts.
Das ist nämlich der Inhalt der Ausgangsdatei:
Die Datei kann man hier gerne downloaden, um sich selbst ein Bild zu machen:
Ein weiteres Beispiel: Wenn man die Datei mit LibreOffice öffnet, dann hat man die Probleme nicht:
Auch wenn die Datei im normalen Texteditor geöffnet wird, gibt es da keine Probleme:
Aber warum verarbeitet PHP die Datei nicht richtig und liest keine passenden CSV-Werte aus?
Was PHP aus der Datei macht:
Die PHP-CSV-Funktionen arbeiten fast korrekt, Fehler fallen auf den ersten Blick gar nicht auf!
So schlecht schaut das Ergebnis auf den ersten Blick nicht aus.
Der erste Gedanke:
AH! Der Separator wird nicht richtig escapet!
Blöde Datei – warum werden die Felder mit normalem Komma (also „,“) getrennt, wenn doch der Betrag auch eine Kommastelle enthält?
Aber die PHP-Funktionen können damit umgehen, es gibt einen passenden Parameter, nämlich Enclosure:
Damit teil man PHP mit, wie mit „problematische Strings“ umgegangen werden soll.
Damit zb Geldbeträge als eine zusammengehörende Zeichenkette gesehen werden, eine Kommastelle also kein neues CSV-Feld anzeigt.
Die Ausgangsdatei (=CSV) macht das eh passend. Der Betrag ist in Hochkommas verpackt; es sollte also egal sein, dass der Separator (also das Komma) in der Zeichenkette enthalten ist.
PHP sollte diese Zeichenkette nicht trennen, tut das aber:
Wie kann das sein?? Ein Herumspielen mit anderen Separatoren, anderen Enclosure- oder Escape-Parameter half nicht!
Verzweiflung?
Nein, Herausforderung!
Beim Programmieren verrennt man sich gerne, also ist es ratsam, einige Schritte zurück zu gehen.
Ok, also eine Zeile aus der besorgniserregenden Datei rauskopieren und hartkodiert in eine Funktion stecken.
Das ist die besagte Zeile in einem Texteditor:
Diese Zeile wird jetzt der PHP-Funktion übergeben:
Das ist somit 1:1 der String, wie er auch in der Originaldatei enthalten ist!
Was ist das ernüchternde Ergebnis? Das:
Kopiere ich den String aus der Textdatei und füge den in die Funktion ein, funktioniert alles.
Tadellos.
WIE KANN DAS SEIN????
Nun, wie debuggt man modern? Genau, print_r() und var_dump() sind die bevorzugten Tools :p
Ok, wie kann das sein?
Die Zeichenketten schauen identisch aus!
Aber der hartkodierte String, den ich händisch eingegeben habe, hat nur 90 Zeichen.
Die exakt gleiche Zeile aus der Datei, aber mit PHP ausgelesen, hat 181 Zeichen!
Wir kommen der Sache näher, es ist aber unverständlich.
Wo kommen die zusätzlichen Zeichen her?
Wir kommen der Sache näher!
Xdebug to the rescue! Xdebug hilft, indem man mehr Debug-Infos bekommt.
Auf dem Server war XDebug nicht aktiviert, daher war die Debug-Ausgabe eher mager. Aber XDebug ist auf unseren Server schnell aktiviert, und dann gibt’s mehr Kontext.
Durch Xdebug sieht man nämlich das:
Eindeutig! Da muss es ein Problem mit der Zeichenkodierung geben!
Das lässt sich auch nachstellen, wenn man den Inhalt der Textdatei rauskopiert und in eine neue Datei reinkopiert. Das Original ist fast doppelt so groß, wie die Kopie:
Das Original hat 11,4 kb, die Datei mit dem gleichen VISUELLEN Inhalt hat 5,7 kB:
Finale: Zeichenkodierung als Fehlerquelle!?
Höchstwahrscheinlich liegt es daran, aber so genau kann ich das nicht sagen!
Mehrere Funktionen und Helferleins wurden versucht. Nichts brachte diese wirren Zeichen weg.
Daher auch ein kleiner Aufruf:
Wer dieses Problem kennt und lösen kann, möge sich bitte bei mir/uns melden! Danke!
Als Referenz für euch, das habe ich zusätzlich probiert:
Sogar auf Binär-Ebene hab ich herumgespielt:
Aber das ist nicht mein Metier:
Wie wurde das Problem nun gelöst?
Developer sind Tüftler, so einfach geben wir uns nicht geschlagen! Eine Lösung musste her!
Eine schöne, saubere Lösung habe ich so (noch) nicht gefunden. Aber natürlich gibt es einen Weg, nämlich den:
Jap, richtig! Ich stelle mir Arrays mit allen Zeichen zusammen, die ich erlaube.
In einer Schleife gehe ich dann den String durch und lasse nur über, was in den Arrays erlaubt ist:
Wichtig Anmerkungen
- Das Array mit den erlaubten Zeichen nie mit in_array() durchsuchen, sondern mit isset() oder array_key_exists(). Quelle: https://stackoverflow.com/questions/700227/whats-quicker-and-better-to-determine-if-an-array-key-exists-in-php
- Auf die Multibyte-Funktionen achten! Daher mb_str_split() verwenden, sonst werden zb die Umlaute Ä, Ü, Ö nicht korrekt berücksichtigt!
- Eine Foreach-Schleife ist hier viel transparenter und auffälliger. Damit auch leichter lesbar. Klar, könnte man den Code cleverer und mit fancy Code lösen, aber darunter würde die Lesbarkeit leiden. Unser Motto:
Nachstellen des Problems – betrifft das auch andere?
Zeichenkodierung ist nicht einfach, daher kamen Zweifel auf, ob es nicht an meinen Fähigkeiten liegt.
Schön an WordPress ist ja das Ökosystem. Für jeden Anwendungsfall gibt es irgend ein Werkzeug (=Plugin).
Werkzeuge, die sich 100.000 mal verkaufen und daher auch dementsprechend gewartet werden.
Werkzeuge, die in der freien Wildbahn mit allen nur denkmöglichen Dateien arbeiten müssen. Dementsprechend viele Edgecases (=Sonderfälle) werden die als Supportanfrage reinbekommen haben.
Ok, weniger abstrakt: Ich denke da zb an das WP All Import Plugin, das so ziemlich der Platzhirsch im WordPress-Universum sein dürfte.
Haben die das gleiche Problem?
Ja, haben die!
Zum Schluss: Woher kommt die CSV-Datei?
Schön wäre es, wenn der fehlerhafte Export behoben werden könnte!
Das ist auch ein Ziel dieses Beitrages. Es ist kein „mit dem Finger auf jemanden Zeigen“, sondern auch ein Bugreport.
Also liebe Leute von der Sparkasse/Ersten Bank, bitte schaut auch den CSV-Exporter im George Onlinebanking an!