Enrico: Unterschiedliche Stringlängen PHP/JavaScript nach Definition?

Hallo,

gut, ich bin noch nicht geblockt und kann ein weiteres Problem publik machen :-)

Ich definiere - zu Testzwecken - in einer PHP-Datei einen String mit dem Inhalt, beispielsweise "Öde und unsinnig!", um die korrekte Übertragung im UTF-8-Format zu prüfen. In einer anderen Datei hole ich mir diesen String über Ajax, weil ich damit weiter arbeiten will.

base64_encode funktioniert auf Seite des Client und des Servers einwandfrei, getrennt betrachtet, aber nicht mehr nach der Übertragung, egal in welcher Richtung.

Ich habe mir dann mal die Stringlängen ausgeben lassen und habe festgestellt, dass der in PHP definierte String $Original = "Öde und unsinnig!" nicht 17 Zeichen lang, sondern länger ist, der in einer anderen Datei über Ajax geholte String aber die richtige Länge hat.

Codierung ist jeweils UFT-8.

Woran liegt es/kann es liegen?
Wie kann ich vermeiden, dass ein definierter String länger ist, als er eigentlich sein dürfte?

Gruß,
Enrico

  1. Woran liegt es/kann es liegen?
    Wie kann ich vermeiden, dass ein definierter String länger ist, als er eigentlich sein dürfte?

    Kann es sein, dass du strlen() verwendest?
    Bei einem multi-byte-kodierten Zeichen muss man AFAIK mb_strlen() verwenden.

    MfG
    bubble

    --
    If "god" had intended us to drink beer, he would have given us stomachs. - David Daye
    1. Hallo bubble,

      Kann es sein, dass du strlen() verwendest?

      Ja, ganz genau.

      Bei einem multi-byte-kodierten Zeichen muss man AFAIK mb_strlen() verwenden

      Wir haben hier also einen strlen-Befehl, der sich beim Zählen verzählt... ^^

      Probiere ich gleich aus, sobald ich daheim bin.

      Danke Dir.

      Gruß,
      Enrico

      1. Hallo,

        Kann es sein, dass du strlen() verwendest?
        Bei einem multi-byte-kodierten Zeichen muss man AFAIK mb_strlen() verwenden
        Wir haben hier also einen strlen-Befehl, der sich beim Zählen verzählt... ^^

        nein, wir haben eine Funktion, die die Länge in Bytes zählt, nicht in Zeichen.
        In Javascript dagegen gibt die length-Eigenschaft eines Strings dessen Länge immer in Zeichen an,

        Ciao,
         Martin

        --
        Zwei Stammtischbrüder:
        Hier steht, dass laut Statistik über 60 Prozent aller Ehefrauen fremdgehen.
        Was soll ich mit dieser Information? Ich brauche Namen, Fotos, Telefonnummern ... !
        Selfcode: fo:) ch:{ rl:| br:< n4:( ie:| mo:| va:) de:] zu:) fl:{ ss:) ls:µ js:(
        1. @@Der Martin:

          nuqneH

          In Javascript dagegen gibt die length-Eigenschaft eines Strings dessen Länge immer in Zeichen an,

          Nein.

          Qapla'

          --
          „Talente finden Lösungen, Genies entdecken Probleme.“ (Hans Krailsheimer)
  2. gut, ich bin noch nicht geblockt und kann ein weiteres Problem publik machen :-)

    Hier wurde noch nie jemand geblockt. Das war auch nicht nötig, die meisten sind vor lauter Hohn und Spott von alleine geflohen.

    Ich habe mir dann mal die Stringlängen ausgeben lassen und habe festgestellt, dass der in PHP definierte String $Original = "Öde und unsinnig!" nicht 17 Zeichen lang, sondern länger ist, der in einer anderen Datei über Ajax geholte String aber die richtige Länge hat.

    Codierung ist jeweils UFT-8.

    Woran liegt es/kann es liegen?

    PHP verarbeitet keine Zeichen, sondern Bytes. Javascript hingegen verarbeitet Zeichen, keine Bytes.

    Zeichen werden vom Computer nicht als Zeichen gespeichert, sondern als Zahlen, die ihrerseits auf Schriftzeichen in einer Tabelle verweisen. US-ASCII, die ISO-8859-Familie und auch Unicode sind solche Tabellen. US-ASCII umfasst 128 Werte, die 8859-Familie umfasst mehrere Tabellen à 256 Zeichen, Unicode wiederum definiert eine Tabelle mit Hundertausenden Schriftzeichen.

    Ein Byte kann 256 verschiedene Werte aufnehmen. Da sich die Menschheit aber mehr als 256 Schriftzeichen ausgedacht hat, muss entweder der Zeichensatz beschränkt werden (US-ASCII, 8859-Familie) oder die größeren Werte müssen bei Bedarf irgendwie auf Bytes (oder andere Wortlängen) runtergebrochen werden.

    Bedarf für Letzteres ist dort, wo zum Beispiel Programmiersprachen mit Konzepten aus der Steinzeit der Meinung sind, ein Zeichen entspräche immer einem Byte. In solchen Fällen kommt dann eine Kodierungen wie utf-8 zum Einsatz. utf-8 kann auch sehr große Werte so in ein oder mehrere Bytes verpacken, dass kein greises Programm sich daran verschluckt.

    Dummerweise ist es natürlich so, dass ein derart tatteriges Programm sich bei solcherart kodierten Zeichenketten verzählt. Das ist dann Pech, aber ich bin mir sicher, PHP hat auch dafür irgendeine Ich-klopp'-dich-bis-es-passt-Funktion parat.

    1. @@Doktor Knallcharge:

      nuqneH

      PHP verarbeitet keine Zeichen, sondern Bytes. Javascript hingegen verarbeitet Zeichen, keine Bytes.

      Njein. JavaScript verarbeitet keine Zeichen, sondern Zwei-Bytes. Das heißt, JavaScript versagt (noch) bei Zeichen jenseits der BMP ab Codepoint U+10000.

      Das Unicode-Zeichen 𝄞 U+1D11E MUSICAL SYMBOL G CLEF bspw. wird als Folge der Surrogates U+D834 U+DD1E repräsentiert:

      var clef="\uD834\uDD1E";  
      console.log(clef.length); // 2
      

      Das ändert sich erst mit ECMAScript 6:

      var clef="\u{1D11E}";  
      console.log(clef.length); // 1
      

      Qapla'

      --
      „Talente finden Lösungen, Genies entdecken Probleme.“ (Hans Krailsheimer)
      1. Hallo Gunnar,

        Njein. JavaScript verarbeitet keine Zeichen, sondern Zwei-Bytes. Das heißt, JavaScript versagt (noch) bei Zeichen jenseits der BMP ab Codepoint U+10000.

        D.h. es gibt keine Implementierung in JavaScript, die 100% kompatible zu base64_encde/base64_decode in PHP ist?

        Gruß,
        Enrico

        1. Njein. JavaScript verarbeitet keine Zeichen, sondern Zwei-Bytes. Das heißt, JavaScript versagt (noch) bei Zeichen jenseits der BMP ab Codepoint U+10000.

          D.h. es gibt keine Implementierung in JavaScript, die 100% kompatibel zu base64_encde/base64_decode in PHP ist?

          Mit base64 kodierst du Bytes in Text, das ist noch wieder eine andere Baustelle.

          Selbstverständlich lässt sich base64 in Javascript einwandfrei zurückverwandeln. Dann bekommst du allerdings auch genau die Bytes, die du mit PHP reingesteckt hast - im Falle einer Zeichenkette eine Reihe Bytes, die utf-8-kodierte Zeichen darstellen. Anders ausgedrückt: Wenn du eine Zeichenkette mit PHP erst utf-8- und dann base64-kodierst, musst du _beide_ Kodierungen in Javascript auch wieder rückgängig machen. Das gilt auch, wenn du utf-8 in PHP, wie es meist geschieht, unwissentlich verwendest, einfach weil der Texteditor, mit dem du deine PHP-Skripte schreibst, bereits utf-8-kodiert speichert.

          Grundsätzlich wäre es einfacher, wenn du bestehende Mechanismen zur Übermittlung von Textdaten verwendest. Im Falle von HTTP (du schriebst von AJAX) ist das die Content-Type-Zeile mit korrekter charset-Angabe. Ist die falsch oder "verschleierst" du die von PHP gesendeten Textdaten mit base64, kann der Browser sie logischerweise nicht korrekt in eine Javascript-Zeichenkette umwandeln. Dort solltest du ansetzen.

        2. Hi,

          Njein. JavaScript verarbeitet keine Zeichen, sondern Zwei-Bytes. Das heißt, JavaScript versagt (noch) bei Zeichen jenseits der BMP ab Codepoint U+10000.
          D.h. es gibt keine Implementierung in JavaScript, die 100% kompatible zu base64_encde/base64_decode in PHP ist?

          das Problem ist nicht base64, sondern deine Erzeugung desselben. Ich weiß nicht, wie du dabei vorgehst; aber um einen base64-String zu erzeugen, musst du das "Rohmaterial" byteweise durchgehen. AFAIK kann Javascript einen String aber nicht byteweise indizieren, sondern immer zeichenweise. Also wirst du z.B. charCodeAt() verwenden müssen, und wenn der Code an der aktuellen Zeichenposition größer als 0xFF ist, ihn nach der UTF-8-Codierungsregel in zwei, drei oder vier Bytes umformen.
          Im umgekehrten Fall könnte dir fromCharCode() weiterhelfen.

          Ein bisschen Rechnen und Bit-Schieberei bleibt dir aber vermutlich nicht erspart.

          So long,
           Martin

          --
          Time's an illusion. Lunchtime doubly so.
            (Douglas Adams, "The Hitchhiker's Guide To The Galaxy")
          Selfcode: fo:) ch:{ rl:| br:< n4:( ie:| mo:| va:) de:] zu:) fl:{ ss:) ls:µ js:(
          1. Hallo Martin,

            Also wirst du z.B. charCodeAt() verwenden müssen, und wenn der Code an der aktuellen
            Zeichenposition größer als 0xFF ist, ihn nach der UTF-8-Codierungsregel in zwei, drei oder
            vier Bytes umformen.
            Im umgekehrten Fall könnte dir fromCharCode() weiterhelfen.

            Optimal, das führt mich auf die richtige Fährte :-)

            Danke! :-)

            Gruß,
            Enrico

      2. Längerer Artikel zum Nachlesen:

        http://mathiasbynens.be/notes/javascript-unicode

        BMP bezeichnet hier übrigens das Basic Multilingual Plane – für die, die unter dem Namen nur das Bildformat kennen.

        Mathias

  3. Hallo,

    nach etlichen Fehlversuchen konnte ich mein Problem lösen und die Lösung ist sehr einfach:

    Vor der Übertragung den zu übertragenden String mittels rawurlencode bearbeiten und dann in einen Hex-String umwandeln.

    Nach der Übertragung den umgekehrten Werg gehen.

    Dies funktioniert sowohl von JavaScript nach PHP als auch umgekehrt.

    Gruß,
    Enrico