Zum abertausendsten mal: zeichenkopierung
heinetz
- webserver
Hallo Forum,
ich muss mal wieder einem Problem Herr werden, dass mit
unterschiedlichen Zeichenkodierungen zu tun hat.
Folgende Situation:
-------------------
auf meiner lokalen Entwicklungsumgebung (OS X 10.5) habe ich ein
relative aktuelles Xampp installiert. Der Liveserver ist ein
Linux-Server mit PHP Version 5.1.6 also auch nichts ganz
altes. Auf beiden Systemen läuft ein und die selbe Website (Der
Code ist m.E. absolut identisch. Ich habe die Files vom Live-
server vor 2 Tagen per FTP heruntergeladen) und ich beobachte ein
sehr seltsames Verhalten, dass ich nicht wirklich deuten kann:
Auf der Seite gibt es eine Suche. Die Suche besteht aus einem Formular mit einem einfachen Textinput-Feld. Dieses Formular
wird auf jeder Unterseite eingebunden und beim Abschicken
an die Suchseite geschickt, die mit den empfangenen Daten eine Volltextsuche durchführt und das Ergebnis darstellt.
Unabhängig von der Suchseite unterscheidet sich das Verhalten
schon an dieser Stelle:
Gebe ich auf meiner Entwicklungsumgebung in das Suchfeld den
String "Übung" ein und schicke das Formular dann ab, lautet
der Request: ?Suchbegriff=Übung
Mache ich das selbe auf dem Liveserver lautet der Request:
?Suchbegriff=%DCbung
Einen Unterschied kann ich erkennen, wenn ich mir mit FF
die Sieteninformationen der Seite ausgeben lassen, wo ich
den Suchbegriff eingebe:
Der Liveserver sagt, die Kodierung sei ISO-8859-1, mein
Server hingegen sagt etwas von UTF-8.
Ich vermute, dass das irgendwie eine Konfiguration des Servers
ist (defualt_charset wird unter phpinfo() allerdings in beiden
Fällen mit no value angezeigt).
Da das Script allerdings auf beiden Servern funktionieren muss,
frage ich mich, wie ermittel ich die Kodierung der Seite, von
der aus das Formular abgeschickt wurde, bzw. wie ermittel ich
das auf der Seite selbst, um daraus einen Paramter zu machen,
den ich im Form mitschicke.
Ich bin mir bewusst, dass da langfristig grössere Aufräumarbeiten
vorgenommen werden müssen, um die Kodierung auf der ganzen Seite
sauber zu vereinheitlichen. Allerdings brauche ich jetzt erst
einmal eine kurzfristige Lösung.
Warum sagt der eine Server, die Kodierung sei ISO-8859-1,
wähend der andere sagt, sie sei UTF-8?
danke für TIpps und
beste gruesse,
heinetz
Hallo
Warum sagt der eine Server, die Kodierung sei ISO-8859-1,
wähend der andere sagt, sie sei UTF-8?
Weil das auf dem jeweiligen Server tatsächlich so ist?
Wenn beide PHP-Installationen mit den mb-Funktionen arbeiten, kannst du die Zeichenkodierung *für die Ver- bzw. Abarbeitung der Skripte* mit mb_internal_encoding festlegen. Wenn *beide Server* die dabei generierten Dokumente auch mit *einer* Zeichenkodierung ausliefern (im Zweifelsfall per PHP mit header erzwingbar) und die Datenbankroutinen auf beiden Seiten ebenfalls *diese eine Kodierung* verwenden, sollte sich an dieser Stelle Gleichstand zwischen beiden Installationen herstellen lassen.
Tschö, Auge
danke für die Antworten!
aber ich wollte ja die Zeichenkodierung ja nicht festlegen, sondern wissen, ob ich das, was Firefox scheinbar weiss,
irgendwie mit PHP herausfinden kann.
Wenn das nicht geht und ich die Fälle nicht unterscheiden
kann, um per Script unterschiedlich darauf zu reagieren,
wird es wohl auf ein php:header() hinauslaufen ...
gruesse,
heinetz
Hi!
aber ich wollte ja die Zeichenkodierung ja nicht festlegen, sondern wissen, ob ich das, was Firefox scheinbar weiss, irgendwie mit PHP herausfinden kann.
Es ist notwendig, die verwendete Zeichenkodierung festzulegen. Beim Sprechen kannst du auch nicht erst durch Zuhören herausfinden, in welcher Sprache die Wörter sind, die deinen Mund verlassen. Wenn du dir keine Gedanken um die Kodierung machst und/oder sie nicht definiert bekanntgibst, kommt irgend ein Default-Wert raus, oder der Browser rät, und das passt dann zufällig oder eben auch nicht. Um beim Beispiel mit der Sprache zu bleiben: Es ist auch nicht zweifelsfrei und in jedem Fall möglich, die Kodierung anhand eines Textes zu erkennen.
Wenn das nicht geht und ich die Fälle nicht unterscheiden kann, um per Script unterschiedlich darauf zu reagieren, wird es wohl auf ein php:header() hinauslaufen ...
Gib aber nicht einfach irgendwas an, sondern das was du verwendet hast. Und wenn du das nicht weißt, dann wird es Zeit, dass du herausfindest, wie man allen beteiligten Systemen beibringt, in einer definierten Kodierung zu arbeiten. Das fängt beim Editor an, geht über PHP, DBMS, weiterer Datenquellen und -senken und Webserver bis zum Browser.
Bei Fragen frag das Archiv, bei Verständnisproblemen uns™.
Lo!
hi,
Gib aber nicht einfach irgendwas an, sondern das was du verwendet hast. Und wenn du das nicht weißt, dann wird es Zeit, dass du herausfindest, wie man allen beteiligten Systemen beibringt, in einer definierten Kodierung zu arbeiten. Das fängt beim Editor an, geht über PHP, DBMS, weiterer Datenquellen und -senken und Webserver bis zum Browser.
und da ist es schon, das Verständnisproblem. Mir ist vollkommen
klar, dass das System so, wie es ist, von verschiedenen Stellen
zusammengemurkst wurde, weil sich keiner um Zeichensätze
gekümmert hat, als es entstanden ist. Wenn ich heute neue Syteme
aufsetze, achte ich einfach darauf, dass alles einheitlich utf-8
ist und habe kein Problem. Jetzt habe ich aber ein System, dass
1. mal auf einer MySQL 4.0 entstanden ist
2. In dem eine fremdes Modul läuft, auf dass ich keinen
Einfluss nehmen kann.
3. In dem mein Kunde ca. 700 Unterseiten angelegt hat, die
als Datensätze vorhenden sind.
Der Aufwand, alles zu vereinheitlichen, ist gerechtfertigt,
was mir vollkommen klar ist, will aber bezahlt werden, was
ich dem Kunden klar machen muss. Das versuche ich gerade,
muss aber bis dahin mit dem Misstand leben und irgendwas
basteln, was ich nicht verstehe, damit ein 'ä' auch aussieht,
wie ein 'ä' ...
Abgesehen davon halte ich es für wichtig, zu verstehen, wie
das alles zusammenwirkt und bewerte damit z.B. so eine Info,
wie:
header('Content-Type: text/html; charset=...');
überschreibt in der Regel alles, was irgendwo konfiguriert ist. In absteigender Reihenfolge folgen: PHPs default_charset und Charset-Konfiguration vom Apachen (siehe Direktiven-Übersicht, nach charset suchen und alle anschauen, die nicht nach was sehr speziellem aussehen).
... für mich als hilfreicher, als den Aufruf zu einer sauberen
Programmierung, weil ich mir des Misstands bewusst bin.
Ich hab tatsächlich einige Schwierigkeiten, den Damen in
der Marketingabteilung klar zu machen, warum die Vereinheit-
lichung der verwendeten Zeichnsäzze sinnvoll ist.
beste gruesse,
heinetz
Hi!
Jetzt habe ich aber ein System, dass
- mal auf einer MySQL 4.0 entstanden ist
- In dem eine fremdes Modul läuft, auf dass ich keinen Einfluss nehmen kann.
- In dem mein Kunde ca. 700 Unterseiten angelegt hat, die als Datensätze vorhenden sind.
Dann muss man höchstwahrscheinlich davon ausgehen, dass da das hierzulande übliche Windows-1252 Verwendung fand, unter MySQL als Latin1 bezeichnet. Offizieller wäre ISO-8859-1. Die Unterschiede siehst du in der Wikipedia (ISO-8859-1) und betreffen vorwiegend das €-Zeichen und typografische Anführungszeichen. Die Browser sind auch so friedlich, bei angegebenem ISO-8859-1 und tatsächlich verwendetem Windows-1252 beispielsweise das als 0x80 kodierte € als solches anzuzeigen.
Wenn du noch wenig Überblick über die Problematik hast, solltest du erst einmal Zeichencodierung für Anfänger lesen.
Bei Punkt 2 deiner obigen Auflistung wäre interessant, was das Modul macht. Ist es nur Datendurchreicher oder betreibt es Stringverarbeitung (Zeichen zählen, Strings vergleichen oder umgestalten). Kommuniziert es mit anderen Systemem? Macht es dazu explizit Angaben zur Kodierung. Siehe auch nachfolgender Abschnitt. Wenn es recht alt ist, wird es von ISO-8859-1/Windows-1252/Latin1 ausgehen. Wenn es moderner und die Zeichenkodierungsproblematik berücksichtigend entwickelt wurde, hat es eine Konfigurationsmöglichkeit oder definiert irgendwo in der Dokumentation, was es verwendet. Dazwischen gibt es selbstverständlich noch weitere Möglichkeiten.
Als Übergangslösung, bevor du dich an UTF-8 wagst, kannst du ja erst einmal dafür sorgen, dass überall ISO-8859-1/Windows-1252/Latin1 vereinbart wird / eingestellt ist. Dazu und um kennenzulernen, wo überall was eingestellt werden kann, solltest du dir eine Übersicht malen, welche Systeme über welche Wege miteinander reden. Dazu muss man mitunter Sende- und Empfangsrichtung getrennt betrachten. Mindestens dabei sein sollten Browser, PHP/Webserver, das DBMS und nicht zu vergessen der Quellcode-Editor. Dabei solltest du herausfinden, wie die jeweiligen Systeme so eingestellt werden, dass sie intern richtig arbeiten können, wenn sie nicht nur Durchreicher sind. Weiterhin ist die Kommunikation untereinander wichtig. Wie teile System A dem System B mit, welche Kodierung zu verwenden sei, mit der Zusatzfrage wo genau es konfiguriert wird, damit diese Information den Weg von A nach B findet.
Alle Hilfsmittel inklusive Archivsuche und hier gestellten Nachfragen sind erlaubt, wir sind ja hier nicht bei einer Prüfung. :-)
Zum Beispiel hat Gunnar Bittersmann noch weitere Übersetzungen im Angebot, was die Komponenten Webserver und Browser betrifft. Mit dem Stichwort "SET NAMES" lassen sich im hiesigen Archiv viele Beiträge zu MySQL und PHP finden.
Lo!
hello,
mir ist heute sehr viel sehr sehr klar geworden!
danke,
heinetz
hi,
Als Übergangslösung, bevor du dich an UTF-8 wagst, kannst du ja erst einmal dafür sorgen, dass überall ISO-8859-1/Windows-1252/Latin1 vereinbart wird / eingestellt ist.
seit mir klar ist, dass mein externes Modul durchgängig
ISO-8859-1 benutzt (ich kann mit Sicherheit sagen, was
darin alles verwendet wird. Ich habe nur an sehr vielen
Stellen in dem Code u.A. in XML-Files die Angabe von
ISO-8859-1 gefunden) und seit dem mir klar ist, dass es
vielmehr um eine einheitliche Benutzung des selben als
um die Benutzung eines bestimmten geht, verfolge ich Deinen
Vorschlag. Auf den ersten Blick sieht es so aus, als würde
alles korrekt dargestellt, was ja erstmal ganz schön ist ...
Allerdings verstehe ich nicht ganz, warum es einfacher sein
soll, dafür zu sorgen, dass überall ISO-8859-1 verienbart/
eingestellt ist. Dass es wahrscheinlich fehlerunanfälliger
ist, sehe ich ein, weil das wohl bei den meisten Einstellungen
der Default ist. Leider weiss ich aber nun auch nicht mehr,
wo welche Einstellung oder Vereinbarung welche andere u.U.
falsche überschreibt.
Was ich für mich als sinnvoll erachten würde, wäre eine Art
Rangliste. Was überschreibt was bzw. wer ist stärker. Ein
Paar Dinge sind, glaube ich, mir klar:
für jede Datei, die in irgendeiner Form zur Anzeige kommt
und die Sonderzeichen enthält, muss beim Abspeichern die
Zeichenkodierung festgelegt werden.
das wohl schwächste Gleid in der Kette habe ich festgelegt:
<meta content="text/html; charset=iso-8859-1"
PHP Core
--------
default_charset no value
Apache Environment
------------------
HTTP_ACCEPT_CHARSET ISO-8859-1,utf-8;q=0.7,*;q=0.7
HTTP Headers Information
------------------------
HTTP Request Headers
Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7
HTTP Response Headers
Content-Type text/html; charset=ISO-8859-1
PHP Variables
-------------
_SERVER["HTTP_ACCEPT_CHARSET"] ISO-8859-1,utf-8;q=0.7,*;q=0.7
Die vom Server gesendete Information lässt sich mit
php:header() überschreiben.
Für den Datenbankserver habe ich einen verwedendeten
Zeichensatz unter phpmyadmin gefunden:
MySQL-Zeichensatz: UTF-8 Unicode (utf8)
für die Kommunikation zwischen Web- und Datenbankserver
wird auch irgendwo ein Zeichensatz festgelegt.
Auch der lässt sich explizit durch "SET NAMES" überschreiben.
Ich denke, für mein Verständis muss das Ziel nun erstmal sein,
überall dort explizit den zu verwendenden Zeichensatz festzulegen,
wo er festgelegt werden muss, mit keiner Einstellung eine andere
zu überschreiben und am Ende gezielt den Default festlegen/
überprüfen, um eine weitere Sicherheit einzubauen.
beste gruesse,
heinetz
Hi!
Allerdings verstehe ich nicht ganz, warum es einfacher sein
soll, dafür zu sorgen, dass überall ISO-8859-1 verienbart/
eingestellt ist. Dass es wahrscheinlich fehlerunanfälliger
ist, sehe ich ein, weil das wohl bei den meisten Einstellungen
der Default ist.
Die Empfehlung zu ISO-8859-1 traf ich, weil das bei dir der vermutlich aktuelle Stand ist und mit dem wenigsten Aufwand deine aktuellen Probleme zu beseitigen sind (unter der Voraussetzung, dass du keine Zeichen außerhalb von ISO-8859-1/Windows-1252 verwenden möchtest). Für neue Projekte empfehle ich UTF-8. Auch wenn man denkt, dessen Möglichkeiten derzeit noch nicht ausnutzen zu wollen, es schadet nicht/kaum, darauf vorbereitet zu sein.
Was ich für mich als sinnvoll erachten würde, wäre eine Art
Rangliste. Was überschreibt was bzw. wer ist stärker. Ein
Paar Dinge sind, glaube ich, mir klar:
- für jede Datei, die in irgendeiner Form zur Anzeige kommt
und die Sonderzeichen enthält, muss beim Abspeichern die
Zeichenkodierung festgelegt werden.
Ob eine Datei Sonderzeichen enthält, ist für das Prinzip unwichtig. Sie muss immer in einer bestimmten Kodierung gespeichert werden, und sei es ASCII.
- das wohl schwächste Gleid in der Kette habe ich festgelegt:
<meta content="text/html; charset=iso-8859-1"
Ja, aber auch das hat seinen Verwendungszweck. Bei lokal gespeicherten Dateien steht zum Öffnen kein Webserver bereit, der eine Kodierungsangabe machen könnte, so dass der Browser diese Angabe nehmen kann. (Im Prinzip ist das ein Paradoxon, denn man muss erst einmal den Inhalt richtig interpretieren können, um diese Angabe korrekt lesen zu können. Hier geht man praktischerweise davon aus, dass es reicht, den Text als ASCII zu interpretieren. Alle Kodierungsnamen lassen sich bisher mit ASCII darstellen.)
- Der Server sendet im Header die Zeichenkodierung mit.
Aus Sicht des Browsers sind das die beiden interessanten Angaben, das Meta-Element und der (stärkere) HTTP-Header.
Dass der die Dateien vor dem Ausliefern auf ihren Zeichnsatz
überprüft kann ich mir nicht vorstellen.
In seiner Grundstellung macht er das nicht, aber es gibt Module, die die Kodierung zumindest anhand eines Dateinamenszusatzes oder durch Suchen des Meta-Elements bestimmen können.
Ich interpretiere das, was ich darüber gefunden habe so:
Mit den Direktiven AddCharset und AddDefaultCharset werden
die Zeichenkodierungen festgelegt, mit denen die entsprechenden
Dateiendungen ausgeliefert werden. Diese Information wird
dem Browser im Header mitgesendet.
Überschreiben lässt sich dieser Wert durch CGI- oder als Modul eingebunden Programme.
Legt man die Direktiven nicht fest, bleibt dem Browser nur zu Raten.
Ja, und das ist immer Mist, wenn man ein definiertes Ergebnis bevorzugt.
Unter phpinfo() habe ich folgende Informationen bzgl. Zeichensatz gefunden:
PHP Core
default_charset no value
Dieser Wert überschreibt Apaches Add(Default)Charset-Konfiguration (natürlich nur wenn PHP im Spiel ist), und er wird von den Programmierern meist zugunsten eines header()-Aufrufs ignoriert.
(Ich sortiere die Zitate übrigens mal etwas um, weil manche Dinge anders zusammengehören als du sie aufzähltest.)
- Die vom Server gesendete Information lässt sich mit
php:header() überschreiben.
Ja, im Allgemeinen. Wobei man auch den Apachen das letzte Wort haben lassen kann, wenn ich mich recht erinnere. Das hatten wir vor kurzem hier im Forum mal diskutiert, aber ich habe mir das Ergebnis nicht genau gemerkt, weil es aus meiner Sicht in der Praxis zu selten vorkommt, als dass es sich lohnt, die Details abrufbereit zu haben. Es ging wohl mit mod_headers.
HTTP Headers Information
HTTP Response Headers
Content-Type text/html; charset=ISO-8859-1
Ich weiß nicht genau, wo diese Angabe steht, vermutlich im Apache-Block. Ich hab grad keinen hier und kann dazu nichts konkretes sagen. So sähe jedenfalls eine HTTP-Header-Zeile aus wie sie der Browser bekommt (wenn man sich noch einen Doppelpunkt hinter Content-Type denkt).
Apache Environment
HTTP_ACCEPT_CHARSET ISO-8859-1,utf-8;q=0.7,*;q=0.7
HTTP Headers Information
HTTP Request Headers
Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7PHP Variables
_SERVER["HTTP_ACCEPT_CHARSET"] ISO-8859-1,utf-8;q=0.7,*;q=0.7
Alle drei Angaben sind das selbe, werden vom Browser gesendet und in der Regel von den Programmierern ignoriert. Die Browser kommen auch gut damit zurecht, wenn man sich nicht nach ihren Wünschen richtet, sondern stattdessen für die Response einfach eine Kodierung selbst festlegt.
- Für den Datenbankserver habe ich einen verwedendeten
Zeichensatz unter phpmyadmin gefunden:MySQL-Zeichensatz: UTF-8 Unicode (utf8)
Was der PMA da auf seiner Startseite erzählt, hat keine Auswirkungen auf andere Anwendungen. Ich verweise da mal auf </archiv/2010/1/t194524/#m1301030> und hoffe, dass das erst einmal als Erklärung reicht. Wenn nicht, weißte ja, nachfragen hilft. :-)
- für die Kommunikation zwischen Web- und Datenbankserver
wird auch irgendwo ein Zeichensatz festgelegt.- Auch der lässt sich explizit durch "SET NAMES" überschreiben.
mysql(i)_set_charset() wäre die bevorzugte Variante, aber für ISO-8859-alle (und UTF-8) ergibt es zu einem SET-NAMES-Statement keinen Unterschied. (SET CHARACTER SET taucht gelegentlich als Gefährte von SET NAMES auf, aber das will man üblicherweise nicht haben, wenn man sich des Unterschieds nicht bewusst ist.)
Ich denke, für mein Verständis muss das Ziel nun erstmal sein,
überall dort explizit den zu verwendenden Zeichensatz festzulegen,
wo er festgelegt werden muss, mit keiner Einstellung eine andere
zu überschreiben und am Ende gezielt den Default festlegen/
überprüfen, um eine weitere Sicherheit einzubauen.
Die meisten Optionen gibt es bei der Konfiguration des Apachen und im Zusammenspiel mit PHP. Wenn man sich da auf PHPs header() (plus Meta-Element im HTML) beschränkt, ist man üblicherweise gut bedient und kommt unabhängig von Add(Default)Charset zum Ziel.
Lo!
Hi!
Einen Unterschied kann ich erkennen, wenn ich mir mit FF die Sieteninformationen der Seite ausgeben lassen, wo ich den Suchbegriff eingebe:
Der Liveserver sagt, die Kodierung sei ISO-8859-1, mein Server hingegen sagt etwas von UTF-8.
Das kann auch vom Firefox geraten sein. Gewissheit bekommst du, wenn di dir die livehttpheaders-Extension installierst. Dann siehst du bei den Response-Headern unter Content-Type die charset-Angabe (oder auch keine) Diese hat Vorrang vor dem gleichnamigen Meta-Element.
Ich vermute, dass das irgendwie eine Konfiguration des Servers ist (defualt_charset wird unter phpinfo() allerdings in beiden Fällen mit no value angezeigt).
In dem Fall gilt das, was der Server sendet.
wie ermittel ich die Kodierung der Seite, von der aus das Formular abgeschickt wurde, bzw. wie ermittel ich das auf der Seite selbst, um daraus einen Paramter zu machen, den ich im Form mitschicke.
Die Kodierung der Seite legst du fest, achtest darauf, dass die Daten in dieser Kodierung gehalten sind und konfigurierst das an den entsprechenden Stellen. Im Form gibt es accept-charset, das kann man aber vergessen, weil es nicht unbedingt funktioniert.
Ich bin mir bewusst, dass da langfristig grössere Aufräumarbeiten vorgenommen werden müssen, um die Kodierung auf der ganzen Seite sauber zu vereinheitlichen. Allerdings brauche ich jetzt erst einmal eine kurzfristige Lösung.
header('Content-Type: text/html; charset=...');
überschreibt in der Regel alles, was irgendwo konfiguriert ist. In absteigender Reihenfolge folgen: PHPs default_charset und Charset-Konfiguration vom Apachen (siehe Direktiven-Übersicht, nach charset suchen und alle anschauen, die nicht nach was sehr speziellem aussehen).
Warum sagt der eine Server, die Kodierung sei ISO-8859-1, wähend der andere sagt, sie sei UTF-8?
Das wird an unterschiedliche Konfigurationen liegen.
Lo!
Moin!
Der Liveserver ist ein Linux-Server mit PHP Version 5.1.6 also auch nichts ganz altes.
Doch. Die Version ist schon ziemlich sehr alt. Sie ist vom 24. August 2006, immerhin die letzte aus dem 5.1-Zweig, aber dennoch schon als uralt zu betrachten. Hier wäre mal ein Update angebracht.
Selbst das älteste Debian-Linux "Etch" hat schon 5.2.0 (Security-Support läuft dieses Wochenende aus), Debian "Lenny" hat 5.2.6. Und Debian steht nun nicht gerade im Ruf, die topaktuellsten Versionen anzubieten, sondern eine extrem stabile Plattform.
Außerdem bietet PHP ab Version 5.2 diverse Features an, die manche Software heutzutage unverzichtbar benötigt.
Aktuell ist übrigens Version 5.3.1.
- Sven Rautenberg