CherryPy, SQLite, Zeichenkodierung

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
encbladexp
User
Beiträge: 61
Registriert: Freitag 7. März 2003, 19:28
Kontaktdaten:

Tag Leute,

nachdem ich es jetzt 2 Stunden mit Error-And-Trial sowie dem guten alten google versucht habe, hiermal ein Problem, welches bestimmt blos eine Kleinigkeit ist :-( , aber ich seh den Wald vor lauter Bäumen irgendwie nicht mehr... :oops:

Problem:
Meine CherryPy Anwendung liefert alle Seiten als UTF-8 aus, das ist auch so gewollt und per Content-Type so eingestellt.

Nun bekommt der Client ein Formular, alles funktioniert wie es soll, aber:
Wenn ein Umlaut, bzw. nicht ASCII-Zeichen in einem Textfeld vorkommt, wird dies bei der Anzeige falsch dargestellt, also z.B. in der Quelltextansicht als dieses ?-Zeichen mit der Box außen rum. Ich vermute er kann das Zeichen irgendwo nicht finden.

Diagnose:
Ich habe die betroffene Seite mal mit wget/curl runtergeladen, und mit vim angesehen -> Filetype ist ISO-8859-1, sollte aber UTF-8 sein. Auch file auf der Konsole bestätigt das, mit ":set fileencoding=utf-8" kann ich die Datei auch nach UTF-8 umwandeln, under Browser zeigt diese dann auch richtig an.

Vermutung:
Meine Datenbankabfrage schiebt die Daten per cursor.execute() direkt in die Datenbank, also so wie es vom Client kommt, natürlich mit Escaping wegen SQL-Injection und co, aber sonst wird nix gemacht.

Bei der Ausgabe wird nicht konvertiert, und so kommt der ISO-8859-1 Bytestring in den Unicode Output der zum Browser geht, und peng haben wir mein Problem.

Aber: Wie Löse ich das Problem? Ich glaube zu wissen woran es liegt, aber ich finde beim besten willen keine Lösung, was ich schon versucht habe:

string.encode("utf-8") -> UnicodeDecodeError (der Klassiker, wenn es um Kodierungen geht)
Content-Type auf ISO-8859-1 -> Betroffener Text ist nun richtig, aber halt dafür der UTF-8 Teil falsch *arg*

Am liebsten wäre es mir wenn ich die Daten direkt als "richtiges" UTF-8 in der Datenbank hätte, dann hätte alles (Templates, Content-Type usw...) UTF-8, und ich muss nur einmal konvertieren, und nicht bei jeder Page-Impression...

mfg Betz Stefan
PS: Hoffentlich konnte mir jetzt dabei jemand folgen....
PPS: Die entsprechenden Code-Teile könnte ich liefern wenn benötigt!
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

stefan_betz hat geschrieben:Nun bekommt der Client ein Formular, alles funktioniert wie es soll, aber:
Wenn ein Umlaut, bzw. nicht ASCII-Zeichen in einem Textfeld vorkommt, wird dies bei der Anzeige falsch dargestellt, also z.B. in der Quelltextansicht als dieses ?-Zeichen mit der Box außen rum. Ich vermute er kann das Zeichen irgendwo nicht finden.
Nein, es gibt so ein Zeichen in deinem Font nicht. Was darauf hinweist, dass da, wenn es einen Font gäbe der das darstellt sowieso nur Quark stehen würde.

Naja, die Lösung ist ganz einfach: dem User Agent sagen er soll alles was er hochlädt UTF-8 kodieren, so dass auf dem Server ein UTF-8 Bytestring ankommt. Den tust du in Unicode decoden (das das bei dir ein Fehler kommt liegt daran dass der Bytestring eben nicht UTF-8 kodiert ist sondern in etwas anderem) und dann in deinem Programm verarbeiten. Wenn du die Sachen in die Datenbank schreibst musst du mal gucken, ob es funktioniert direkt Unicode-Daten dort abzusetzen oder ob du sie erstmal in UTF-8 enkodieren musst.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

Dekodiert CherryPy automatisch eingehende Daten? Wenn nicht musst du das noch selber machen.
TUFKAB – the user formerly known as blackbird
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Hallo Stefan!

1.) Liefere alles als UTF-8 aus
2.) Nimm an, dass du darauf hin auch wieder UTF-8 vom Browser bekommst
3.) Stelle CherryPy so ein, dass es UTF-8 ausliefert, wenn Unicode im Spiel ist.
4.) Stelle CherryPy so ein, dass es UTF-8 automatisch nach Unicode umwandelt, wenn es Daten vom Browser bekommt.

In den Kopf der (X)HTML-Datei:

Code: Alles auswählen

  <meta http-equiv="content-type" content="text/html; charset=utf-8" />
In die INI-Datei:

Code: Alles auswählen

[/]
tools.encode.on = True
tools.encode.encoding = "utf-8"
tools.decode.on = True
Und jetzt musst du nur noch darauf achten, dass von CherryPy Unicode oder (wenn schon Bytestring, dann) UTF-8 ausgeliefert wird.

In die SQLite-Datenbank immer nur Unicode oder UTF-8-Bytestrings speichern. Unicode wird automatisch nach UTF-8 umgewandelt, da das das vordefinierte Textencoding von SQLite ist. Und wenn du Text aus der SQLite-Datenbank ausliest, dann bekommst du Unicode zurück.

Siehe: http://www.python-forum.de/topic-6654.html

Halte mich am Laufenden, ob es funktioniert hat.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
encbladexp
User
Beiträge: 61
Registriert: Freitag 7. März 2003, 19:28
Kontaktdaten:

gerold hat geschrieben:1.) Liefere alles als UTF-8 aus
Wird schon gemacht.
gerold hat geschrieben:2.) Nimm an, dass du darauf hin auch wieder UTF-8 vom Browser bekommst
Schön wärs :-)
gerold hat geschrieben:In den Kopf der (X)HTML-Datei:
Sollte eigentlich nicht nötig sein, da CherryPy ja schon den korrekten Header ausliefert, ich habs testweise aber dennoch mit rein, man weis ja nie.
gerald hat geschrieben:In die INI-Datei:
Kommt ein UnicodeDecodeError beim Ausliefern der Logon-Page...

Einfache Lösung wäre natürlich wenn man den Browser "zwingen" könnte UTF-8 auszuliefern, aber nur wie?

Aber was mir noch auffällt, beim UnicodeDecodeError kommt immer das der ascii Codec XYZ nicht kann, wo stellt man nochmal das Default Encoding ein? Das könnte auch das Problem der 3 INI-Zeilen von dir lösen...

mfg Betz Stefan
PS: Die Python Datei, wo aktuell auch noch die Templates drin sind hat auch coding: utf-8...[/code]
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Hallo Stefan!

Wenn du intern nicht mit Unicode, sondern mit UTF-8 arbeitest, dann darfst du ``tools.decode.on = True`` nicht einschalten.

Das sieht dann so aus:
- cpexample.ini: http://paste.pocoo.org/show/17540/
- cpexample.py: http://paste.pocoo.org/show/17541/

Wenn du intern *mit Unicode* arbeitest, dann musst du ``tools.decode.on = True`` aktivieren. Damit wird das was du vom Browser zurück bekommst automatisch nach Unicode umgewandelt.

Achte darauf, dass der Vorlagentext im Beispiel jetzt Unicode ist. Das sieht dann so aus:
- cpexample.ini: http://paste.pocoo.org/show/17542/
- cpexample.py: http://paste.pocoo.org/show/17543/

Und falls du Cheetah als Vorlagensprache verwendest, musst du entweder ``#encoding utf-8`` oder ``#unicode utf-8`` setzen. Je nachdem ob du Unicode oder Bytecode von der Vorlage zurück bekommen möchtest.
Und so sieht das Beispiel aus, wenn du intern mit Unicode arbeitest:
- cpexample.ini: http://paste.pocoo.org/show/17542/
- cpexample.py: http://paste.pocoo.org/show/17544/
- cpexample.tmpl: http://paste.pocoo.org/show/17545/

Achte darauf, dass in der Cheetah-Vorlage ganz oben ``#unicode utf-8`` steht. Diese Anweisung kümmert sich darum, dass die Vorlage automatisch von utf-8 nach Unicode umgewandelt wird. Das ist noch ziemlich neu (seit Version 2.0rc8)

Halte mich bitte wieder am Laufenden.

mfg
Gerold
:-)

PS: Beim Testen dieser Beispiele hinter dem Apachen (mit mod_fastcgi) hat mir der Apache kurz einen Streich gespielt. Ich hatte unvorsichtigerweise in der ``apache2.conf`` die Einstellung ``AddDefaultCharset On`` gesetzt. Das bewirkt dass der Apache alles als "iso-8859-1" ausliefert. Nach dem Auskommentieren dieser Einstellung lief alles wie erwartet. :D
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
encbladexp
User
Beiträge: 61
Registriert: Freitag 7. März 2003, 19:28
Kontaktdaten:

Problem ist jetzt gelöst, und zwar hatten meine ganzen Internen String kein u vor dem String, waren also normale Bytestrings. Dadurch konnte das mit dem tools.encode & co ja nicht gehen, deswegen kam auch der Fehler.

Mit deinen 3 Zeilen in der .ini, und dem u vor den Strings in meinen Sourcen geht es jetzt einwandfrei.

Danke nochmal für die Hilfe

mfg Betz Stefan :lol:
Antworten