Frank: Stringvergleich mit Umlauten und Sonderzeichen

Hallo zusammen!

Ich würde gerne mit PHP den alten und neuen Inhalt eines Textfeldes vergleichen. Das ganze funktioniert auch solange, bis das Textfeld entweder Umlaute oder Zeichen wie " oder HTML-Code enthält.

Wie kann ich denn diese Sonderfälle abfangen und erreichen, dass folgender Vergleich dazu führt, dass beide Strings identisch sind:

ü"<tr> = ü"<tr>

Danke schonmal!

Gruß,
Frank

  1. Hallo,

    Ich würde gerne mit PHP den alten und neuen Inhalt eines Textfeldes vergleichen. Das ganze funktioniert auch solange, bis das Textfeld entweder Umlaute oder Zeichen wie " oder HTML-Code enthält.

    Wie ist denn der "alte" Inhalt des Textfeldes gespeichert?
    Überträgst du den noch zusätzlich in einem Hidden Field oder
    fragst du ihn erst beim Vergleich ab?

    Ich tipp darauf, dass du eine der beiden Variablen in htmlentities() packen solltest.

    Grüße, Matze

    1. Hello,

      Ich würde gerne mit PHP den alten und neuen Inhalt eines Textfeldes vergleichen. Das ganze funktioniert auch solange, bis das Textfeld entweder Umlaute oder Zeichen wie " oder HTML-Code enthält.

      Ich tippe mal wieder auf ein UTF-8-Problem.

      Mit welchem Editor bearbeitest Du Deine Scripte? In welcher Codierung speichert der ab?
      Unter welchem Zeichnsatz lässt Du Deinen Browser arbeiten? ISO-8859-1 oder utf-8 oder noch 'was anderes? Dazu solltest Du wissen, welches default-Character-Set beim Server eingestellt ist.

      Wenn Du im Editor noch in "Ansi" (also iso8859-1) speicherst, der Browser aber utf-8 liefert, dann sind natürlich die 1-Byte-Codes des Editors und die Multibyte-Codes des Browsers nicht mehr gleich.

      Testen, was der Browser liefert, mit http://web-sniffer.net oder einem anderen Tool, z.B. einer Firefox-Extension für die Anzeige der HTTP-Header

      oder anzeigen lassen als Hex-Codierter String. Der wird nicht nochmal "verkurbelt" bei der Anzeige, weil alle Zeichen aus dem ersten Block (0-127) stammen.

      Außerdem könnte es helfen, das Script dann auch vollständig zu überarbeiten und die Multibyte-Funktionen zu verwenden anstelle der Einbyte-Stringfunktionen
      http://de3.php.net/manual/de/ref.mbstring.php

      Viel Spaß[tm] beim Überarbeiten der Scripte...

      Harzliche Grüße vom Berg
      http://bergpost.annerschbarrich.de

      Tom

      --
      Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
      Nur selber lernen macht schlau
      Ein Jammer ist auch, dass die Dummen so selbstsicher und die Klugen voller Zweifel sind. Das sollte uns häufiger zweifeln lassen :-)

    2. Der ursprüngliche String wird aus einer Datenbank ausgelesen. Das Feld ist vom Typ varchar mit Codierung latin_general_ci.

      Ich brauche einen Stringvergleich, der in jedem Browser funktioniert, nicht nur in meinem.
      htmlentities hatte ich auch schon versucht, hat aber nicht funktioniert.

      1. echo $begrüßung;

        Ich brauche einen Stringvergleich, der in jedem Browser funktioniert, nicht nur in meinem.

        PHP läuft auf dem Server, also sollte der Browser irrelevant sein. Was aber nicht irrelevant ist, ist die Kodierung in der deine Zeichenketten vorliegen.

        Der ursprüngliche String wird aus einer Datenbank ausgelesen. Das Feld ist vom Typ varchar mit Codierung latin_general_ci.

        Das ist nur eine Seite der Medaille. Damit liegst du im Grunde genommen nur fest, welche Zeichen in dem Feld gespeichert werden können. Welche Kodierung verwendest du auf der Verbindung zwischen MySQL und dem Client (hier dein PHP)? MySQL liefert dir den String in der Kodierung der Verbindung aus, wozu es gegebenenfalls den Feldwert umkodiert.

        Und dann musst du auch noch wissen, in welcher Kodierung du die Daten aus dem Browser bekommst. Der sendet sie im Allgemeinen in der Kodierung zurück, in der die Seite gehalten ist.

        echo "$verabschiedung $name";

        1. Ich hab das Problem jetzt dadurch umgangen, dass ich den Wert aus der Datenbank in einem anderen Feld zwischenspeichere - dann klappt der Stringvergleich komischerweise!?!
          Sehr seltsam - beim Auslesen aus der Datenbank und Speichern in einer Variable und dem anschließenden Vergleich der Variable mit dem Textfeld, bekomme ich als Ergebnis Ungleichheit. Vergleiche ich hingegen zwei Textfelder miteinander, sind beide Werte gleich!?!?!

          Naja, Hauptsache es geht jetzt! Danke für die Tipps!

          1. echo $begrüßung;

            Sehr seltsam - beim Auslesen aus der Datenbank und Speichern in einer Variable und dem anschließenden Vergleich der Variable mit dem Textfeld, bekomme ich als Ergebnis Ungleichheit. Vergleiche ich hingegen zwei Textfelder miteinander, sind beide Werte gleich!?!?!

            Dann lass dir doch mal anzeigen, was du da genau miteinander vergleichst, denn das Ganze liest sich so, als ob du ein grundlegendes Problem hast, das du nun einfach nur durch eine zufällige Methode umgehst.

            Ich hab das Problem jetzt dadurch umgangen, dass ich den Wert aus der Datenbank in einem anderen Feld zwischenspeichere - dann klappt der Stringvergleich komischerweise!?!

            Das kann dir bei nächster Gelegenheit wieder böse auf die Füße fallen. Du (nachdem du vergessen hast, dass da mal was war - "Kommentar? wozu dass denn?") oder jemand anderes denkt sich, dass diese Stelle doch eigentlich überflüssig ist, streicht sie raus und merkt nicht, dass unter bestimmten Umständen nun Fehler auftreten ...

            Als erstes für detaillierte Kontrollausgaben eignet sich var_dump(). Da siehst du unter anderem auch eine Längenangabe des Strings mit der Anzahl der Bytes (Bytes! nicht Zeichen! denn PHP geht vom Prinzip "ein Zeichen gleich ein Byte" aus). Als nächstes wären die Bytewerte interessant, denn daraus kann man gewisse Rückschlüsse auf die Kodierung ziehen.

            // chunk_split() sorgt für eine aufgelockerte Darstellung
              echo chunk_split(bin2hex($delinquent), 2, ' ');

            Und nun sucht man sich die Kodierung, in der das abweichende Zeichen diese angezeigten Bytewerte hat. Hierzulande ist es mit hoher Wahrscheinlichkeit ISO-8859-1/Latin1, Windows-1252 oder UTF-8. Damit kann man beispielsweise schlussfolgern: Kodierung X kommt, Kodierung Y will ich aber eigentlich haben. - Wo ist die Ursache? (Vermutlich, wie so oft, ein vergessenes SET NAMES nach dem Aufbau der Datenbankverbindung.)

            echo "$verabschiedung $name";

            1. Hello,

              [...] Vermutlich, wie so oft, ein vergessenes SET NAMES nach dem Aufbau der Datenbankverbindung.

              könntest Du darauf bitte noch etwes näher eingehen?

              Auch die automatsiche Umwandlung von Codierungen an der Datenbank erscheint mir noch sehr nebulös. Einen als utf-8 gespeicherten String kann ich doch nicht (nicht immer) als ISO 8859-1 wiedergeben.

              Wie ist das also gemeint, dass die Datenbank in der Codierung der Verbindung sendet?

              Harzliche Grüße vom Berg
              http://bergpost.annerschbarrich.de

              Tom

              --
              Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
              Nur selber lernen macht schlau
              Ein Jammer ist auch, dass die Dummen so selbstsicher und die Klugen voller Zweifel sind. Das sollte uns häufiger zweifeln lassen :-)

              1. echo $begrüßung;

                [...] Vermutlich, wie so oft, ein vergessenes SET NAMES nach dem Aufbau der Datenbankverbindung.
                könntest Du darauf bitte noch etwes näher eingehen?

                Bin ich doch schon so oft. Steht alles im Archiv. :-)

                Wenn du als Client dem MySQL-Server nicht mitteilst, welche Kodierung ihr miteinander sprechen wollt, dann nimmt er (s)einen Default-Wert. Genauer gesagt sind es allein für die Verbindung 3 Konfigurationswerte, die man mit SET NAMES einstellt. Reicht es, wenn ich dich da zunächst mal ins MySQL-Handbuch schicke, Kapitel Connection Character Sets and Collations? (Den Rest des Kapitels Character Set Support zu lesen, ist übrigens auch nicht verkehrt.)

                SET NAMES ist eigentlich auch nur ein Notbehelf, aber einer, der mit den hierzulande üblichen Kodierungen funktioniert. Denn SET NAMES bewirkt zwar, dass der MySQL-Server nun von der angegebenen Kodierung ausgeht, aber diese Einstellung geht nicht wirklich in die Metadaten der aktuellen Client-Verbindung ein. Ein mysql_real_escape_string(), das diese Client-Verbindungskodierung berücksichtigt, bleibt weiterhin auf dem Wert stehen, der zum Verbindungsaufbau (per Defaultwert) eingestellt war. Der korrekte Weg wäre mysqli_set_charset(). Zu dieser Funktion gibt es jedoch kein Pendant unter den "Nicht-i-mysql-Funktionen". (Wieder ein Grund, wenn auch ein ganz kleiner, auf die MySQL Improved Extension umzusteigen.) Siehe dazu MySQL-API-Beschreibung zu mysql_real_escape_string().

                Warum kann dennoch SET NAMES und PHPs mysql_(real_)escape_string() verwendet werden? Die von beiden Funktionen berücksichtigten Zeichen sind in allen Kodierungen der ISO-8859-Reihe und in UTF-8 mit eineindeutigen Bytewerten versehen. Die Zeichen liegen alle im reinen/7-Bit ASCII-Bereich, sind also für alle ISO-8859-X gleich, und alle Nicht-ASCII-Zeichen haben in UTF-8 Byte-Werte jenseits von ASCII. Unter den asiatischen Kodierungen gibt es jedoch mindestens eine, bei der auch unter den mehrbyte-kodierten Zeichen Bytewerte kleiner als 0x80 vorkommen. Doch die verwendet hierzulande ja k(aum )einer.

                Ich hab das mal vor geraumer Zeit mit einem nicht dokumentierten Versuch probiert und konnte das beschriebene Verhalten nachvollziehen.

                Auch die automatische Umwandlung von Codierungen an der Datenbank erscheint mir noch sehr nebulös. Einen als utf-8 gespeicherten String kann ich doch nicht (nicht immer) als ISO 8859-1 wiedergeben.

                Das ist richtig. Dessen muss man sich immer bewusst sein, dass man Werte einer Kodierung nur dann verlustfrei in eine andere Kodierung umkodieren kann, wenn die Werte mit der Zielkodierung darstellbar sind. MySQL kann da auch nicht zaubern, und das fragliche Zeichen wird in dem Fall zu einem Fragezeichen.

                Wie ist das also gemeint, dass die Datenbank in der Codierung der Verbindung sendet?

                Wenn du mit MySQL in der Kodierung X sprichst, die Felder (oder auch nur eins, oder auch jedes einzelne anders) aber auf Kodierung Y eingestellt sind, was soll MySQL dann machen? Es bleibt ihm nicht viel anderes übrig als eine Umkodierung vorzunehmen, will es nicht zu jedem Einzeldatum die Kodierung mit abspeichern.

                Zum Thema Umkodierungen habe ich mal eine Versuchsreihe dokumentiert: </archiv/2007/7/t157019/#m1021663>

                echo "$verabschiedung $name";