Alexander44564: Binärcodeausgabe funktioniert nicht bei Sonderzeichen

Nachdem ich hier heute schon eine Frage gestellt habe und mir geraten wurde, das ganze anders anzugehen, habe ich alles neu überarbeitet. Jetzt bin ich auf neue Probleme gestoßen. Hier mein Quelltext, ich habe ihn auskommentiert.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  
<html xmlns="http://www.w3.org/1999/xhtml">  
<head>  
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  
<title>Text-Encode</title>  
</head>  
  
<body>  
  
<?php  
//Header://  
error_reporting(E_ALL);  
  
//Ein einzelnes Zeichen wird eingegeben:  
 $string = htmlentities($_GET['textfeld'], ENT_QUOTES);		//kodiert Umlaute und Sonderzeichen in mehrere gültige Zeichen  
 echo $string."<br />\n";									//zeigt die codierten Zeichen (mehrere)  
 echo html_entity_decode($string, ENT_QUOTES)."<br />\n";	//zeigt das Originalzeichen (eines)  
 for ($i = 0; $i < strlen($string); $i++) {					//gibt immer ein Zeichen (der codierten Zeichen) nach dem anderen aus  
  $x = ord ( $string );										//gibt den ASCII Wert des Zeichens aus  
  echo $x."<br />\n";  
  
  if ($x < 64) {							//wegen der htmlentities gibt es nur mehr Zeichen mit einem Wert < 128  
	  $z = sprintf ( '%b', $x );							//gibt den ASCII Wert als Binärcode aus  
	  echo '00'.$z."<br />\n";								//fügt vorne zwei Nullen an, um den Binärcode auf 8-bit zu bringen  
  } else {  
	  $z = sprintf ( '%b', $x );  
	  echo '0'.$z."<br />\n";								//fügt eine Null an, um den Binärcode auf 8-bit zu bringen  
  }  
  echo chr($x);											//zeigt das als Binärcode ausgegebene Zeichen normal an  
 }  
  
?>  
  
</body>  
</html>

Da die Ausgabe von Umlauten als Binärcode mit sprintf nicht funktioniert hat (es sind immer über 8-stellige Zahlen herausgekommen), habe ich mir gedacht, den eingegeben Text vorher zu codieren. In dem Beispiel ist jetzt angenommen, dass der User ein Zeichen angibt. Wenn das ein Umlaut ist, wird es zu einer Zeichenfolge umgewandelt, die einzeln durch die for Schleife läuft. Für jedes dieser Zeichen soll ein 8-stelliger Binärcode ausgegeben werden. Die Ausgabe sieht aber so aus (für ü):

ü  
38  
00100110  
&38  
00100110  
&38  
00100110  
&38  
00100110  
&38  
00100110  
&38  
00100110  
&38  
...

Wo ist da mein Fehler? Arbeite jetzt schon seit Stunden daran...

  1. hi,

    Da die Ausgabe von Umlauten als Binärcode mit sprintf nicht funktioniert hat (es sind immer über 8-stellige Zahlen herausgekommen), habe ich mir gedacht, den eingegeben Text vorher zu codieren.

    Was möchtest Du denn von einem eingegebenen Zeichen ermitteln/anzeigen? Den Codepoint oder das URI-Encoding? Letzteres ist ein Vector an Integer-Werten und sieht für das 'ä' beispielsweise so aus:

    UriEncode: %C3%A4
    Vector: C3.A4
    Codepoint: E4

    Hotti

    1. Naja eigentlich will ich nur Umlaute in Zeichen umwandeln, die in ASCII vorkommen und die ich später wieder zurückumwandeln kann. Ich weiß nicht genau was dafür die beste Lösung ist...

      1. Aber ich denke auch dass es da noch andere Probleme gibt, weil die Ausgabe passt überhaupt nicht zu dem was ich möchte.

      2. Naja eigentlich will ich nur Umlaute in Zeichen umwandeln, die in ASCII vorkommen und die ich später wieder zurückumwandeln kann.

        Genau das passiert ja bei der Übertragung per HTTP. Da Umlaute nicht ASCII sind, werden die in Integer-Werte umgewandelt. Egal, ob das ein POST oder ein GET ist, bei einem GET jedoch kannst Du das in der URI sehen:

        Nimm ein Formular (z.B. google), gib da einen Umlaut ein, drücke Enter und beobachte den URI der in der Adresszeile angezeigt wird.

        Jetzt kommts darauf an, welche Codierung im Browser vor dem Submit eingestellt war, hattest Du ISO-8859-1 eingestellt, siehst Du nach dem Submit ein 'ä' als %E4 (dezimal 228 in der ISO-8859-1-Codepage).

        Schickst Du ein russisches ф, kommt das als %26%231092%3B

        Hast Du jedoch UTF-8 eingestellt (Default bei google), kommt das 'ä' als %C3%A4 (dezimal 195.164) in die URL.

        ein russisches ф kommt nach einem Submit mit einem UTF-8 codierten Formular als %D1%84 in den URI.

        All das macht der serverseitige Parser wieder rückgängig und der Server bekommt das richtige Zeichen.

        Ich weiß nicht genau was dafür die beste Lösung ist...

        Tja, wofür denn?

        Hotti

        --
        Wenn der Kommentar nicht zum Code passt, kann auch der Code falsch sein.
        1. Das Problem, dass ich am Anfang hatte, war ja dass ord($string) zwar die ASCII Werte ausgibt, auch bei Sonderzeichen und Umlauten (halt Zahlen über 128), aber wenn ich diese Zahlen dann mit sprintf('%b',$string) in einen binärcode umwandeln wollte, hat das nie richtig funktioniert (bei Zahlen über 128). Deshalb habe ich mir ja erst überlegt, die Texte, die aus dem Formular kommen zu verändern. Und nach deinem Posting bin ich ganz verwirrt.

          Wie mache ich das jetzt am besten?
          Ich will einfach einen String in einen Binärcode umwandeln, egal welche Umlaute/Sonderzeichen der enthält.

          1. moin ;-)

            Ich will einfach einen String in einen Binärcode umwandeln, egal welche Umlaute/Sonderzeichen der enthält.

            Und damit komme ich wieder auf meine erste Frage: Möchtest Du den Codepoint? Der ist eindeutig:

            Das 'ä' hat CP 0xE4
            Das 'ф' hat CP 0x444

            In ISO jedoch haben das 'ф' und das 'ä' den gleichen Integer-wert, nämlich 228 (dezimal), wobei der für das 'ä' auch der Codepoint ist (228 = 14*16 + 4 = E4).

            Hotti

            1. Naja wenn es eindeutiger ist dann die erste Variante.
              Außer die ist viel aufwändiger, dann reicht auch ein Codebereich ohne Russische Sonderzeichen =)

              Aber am wichtigsten ist mir dass das mal läuft... dass ich den String in einen Binärcode ausgeben kann...

              1. moin,

                Aber am wichtigsten ist mir dass das mal läuft... dass ich den String in einen Binärcode ausgeben kann...

                Zum Testen? Also Du möchtest nur was Ausgeben, um es anschaulich zu machen?

                Also sowas http://rolfrost.de/cgi-bin/findchar.cgi

                Da kann ich Dir sagen, wie ich das mit Perl mache. Für PHP musst Du Dir das mal selbst erarbeiten. Sichtworte: Codepoint hexadezimal character

                Den Codepoint als hexadezimale Zahl kannst Du dann mit printf() auch als Dualcode binär darstellen.

                Wichtig: Das Formular muss mit einem UTF-8-Header gesendet werden, prüfe also die Header, wenn Du sowas baust.

                Hotti

  2. Hallo,

    Nachdem ich hier heute schon eine Frage gestellt habe und mir geraten wurde, das ganze anders anzugehen, habe ich ...

    ... nun ein Doppelposting abgesetzt, in dem ich dasselbe Problem nochmal vortrage. - Warum? War dein erster Thread von heute nachmittag plötzlich nicht mehr gut?

    Jetzt bin ich auf neue Probleme gestoßen.

    Dafür haben wir immer noch dasselbe: Wir wissen nicht, wozu du solche Klimmzüge machst, und wir wissen nicht, welche Probleme du dabei hast, weil du außer "geht nicht" oder ähnlichen Formulierungen nichts sagst.

    Hier mein Quelltext, ich habe ihn auskommentiert.

    Nein. Unter "auskommentieren" versteht man, einen Abschnitt des Quelltexts als Kommentar zu setzen, um ihn wirkungslos zu machen, ohne ihn gleich zu löschen.

    //Ein einzelnes Zeichen wird eingegeben:
    $string = htmlentities($_GET['textfeld'], ENT_QUOTES); //kodiert Umlaute und Sonderzeichen in mehrere gültige Zeichen

    Und damit wird dein eingegebenes "ü" schon mal zu "&uuml;", ...

    echo $string."<br />\n"; //zeigt die codierten Zeichen (mehrere)

    ... wovon du dich an dieser Stelle durch einen Blick in den Quellcode &uuml;berzeugen kannst. Du hast also bereits hier deine Forderung erfüllt, dass der String nur noch aus ASCII-Zeichen bestehen soll. Alles weitere ist eigentlich Unsinn.

    for ($i = 0; $i < strlen($string); $i++) { //gibt immer ein Zeichen (der codierten Zeichen) nach dem anderen aus

    Der Kommentar ist falsch: Zwar lässt du eine Schleife so oft durchlaufen, wie der String Zeichen hat, aber ...

    $x = ord ( $string ); //gibt den ASCII Wert des Zeichens aus

    ... du betrachtest in jedem der 6 Durchläufe nur das erste Zeichen des Strings.

    echo $x."<br />\n";

    Die Ausgabe "38" hat mich an der Stelle erst verunsichert, weil es sehr unüblich ist, Zeichencodes in dezimal anzugeben. Ich hatte deine Ausgabe daher erst als 0x38 interpretiert (das wäre die Ziffer 8) und konnte mir keinen Reim drauf machen. In Wirklichkeit ist es ja 0x26, also das &-Zeichen. Völlig korrekt.

    if ($x < 64) { //wegen der htmlentities gibt es nur mehr Zeichen mit einem Wert < 128
      $z = sprintf ( '%b', $x ); //gibt den ASCII Wert als Binärcode aus
      echo '00'.$z."<br />\n"; //fügt vorne zwei Nullen an, um den Binärcode auf 8-bit zu bringen
      } else {
      $z = sprintf ( '%b', $x );
      echo '0'.$z."<br />\n"; //fügt eine Null an, um den Binärcode auf 8-bit zu bringen
      }

    Warum diese komplizierten Fallunterscheidungen? Gib doch einfach im Formatstring an, dass du die Ausgabe 8stellig mit führenden Nullen haben willst:

    $z = sprintf('%08b', $x);

    echo chr($x); //zeigt das als Binärcode ausgegebene Zeichen normal an

    Das kennst du doch schon. Warum hier nochmal?

    Da die Ausgabe von Umlauten als Binärcode mit sprintf nicht funktioniert hat (es sind immer über 8-stellige Zahlen herausgekommen), ...

    Hä? Dann hattest du noch andere grobe Fehler drin, die dein gezeigter Code nicht mehr erkennen lässt.

    Wenn das ein Umlaut ist, wird es zu einer Zeichenfolge umgewandelt, die einzeln durch die for Schleife läuft. Für jedes dieser Zeichen soll ein 8-stelliger Binärcode ausgegeben werden.

    Das geht nicht. Der Vorrat an darstellbaren Zeichen umfasst viele tausend, mit 8bit sind aber nur 256 Zeichen darstellbar. Das erfordert, dass manche Zeichen durch mehr als ein Byte (8bit) repräsentiert werden - entweder, indem man sie mit htmlentities() in Entity-Referenzen oder NCRs umwandelt, oder indem man sie direkt in UTF-8 codiert.

    So long,
     Martin

    --
    Husten kann böse Folgen haben.
    Besonders im Kleiderschrank.
    1. hi,

      $x = ord ( $string ); //gibt den ASCII Wert des Zeichens aus

      ... du betrachtest in jedem der 6 Durchläufe nur das erste Zeichen des Strings.

      Genau das macht ord(). Es nimmt aus einem String stets nur das erste Zeichen. Wenn ein 'ä' am Server ankommt, egal ob mit GET oder POST, ist das jedoch eine Liste von Integer-Werten [siehe 1]. Jetzt kommts drauf an, wie das Formular codiert ist, bzw. war in dem Moment wo ein Submit erfolgte. War es utf-8, kommt ein 'ä als Liste C3.A4 am Server an. ord() nimmt daraus den ersten Wert, das ist C3 und ord() zeigt Dir eine 195 (dezimal).

      War das Fom in ISO-8859-1, ist die Liste kürzer, ein 'ä' kommt da als E4 an, was bei ISO-8859-1 dem Dezimalwert von 228 entspricht [siehe 2].

      Dies nur mal so als Ergänzung, es ist also durchaus wichtig, zu wissen, wie die Datenquelle, hier der UserAgent, bspw. ein Formular codiert ist. Beachtenswert ist evnt. auch der Umstand, dass ein Besucher die Codierung eines Formulars im Browser vor dem Submit anders einstellen könnte [siehe 3].

      [1] Um aus einer solchen Liste (Vector) die Einzelwerte zu kriegen, dazu gibt es Bit-Operatoren. In Perl gibt es die Funktion unpack().

      [2] Da es mehrere ISO-Tabellen gibt, sind diese Integer-Werte unterschiedlich.

      [3] Er kann das nicht, bzw. was Besucher im Browser einstellt, ist für ein XHR-Objekt unerheblich. D.h., bei einem AJAX Request ist die Vector-Codierung immer gleich und entspricht der Codierung eines UTF-8-Formulars.

      In der Hoffnung, dass nun alle Klarheiten beseitigt sind,
      Horst Haselhuhn

      --
      Ich bin zwar ein altes Schiff, aber ich boote noch ;-)
      1. Hallo,

        $x = ord ( $string ); //gibt den ASCII Wert des Zeichens aus
        ... du betrachtest in jedem der 6 Durchläufe nur das erste Zeichen des Strings.
        Jetzt kommts drauf an, wie das Formular codiert ist, bzw. war in dem Moment wo ein Submit erfolgte. War es utf-8, kommt ein 'ä als Liste C3.A4 am Server an. ord() nimmt daraus den ersten Wert, das ist C3 und ord() zeigt Dir eine 195 (dezimal).

        ja, die Ausführungen sind richtig und verständlich (finde ich), aber Alexander verstümmelt seine Eingabedaten ja gleich zu Anfang mit htmlentities(). Und dann hat er für ein "ä" eben nicht mehr C3,A4 oder E4, sondern 26,61,75,6D,6C,3B (entspricht "&auml;").
        Vorausgesetzt, das "ä" kommt in einer 1-Byte-Codierung wie etwa ISO-8859-x an. Falls es UTF-8-codiert ankommt, würde es durch htmlentities() zu "&Atilde;&curren;" gewandelt, also 26,41,74,69,6C,64,65,3B,26,63,75,72,72,65,6E,3B.

        Und das ist es, was ich nicht verstehe: Er macht sich einen Riesenaufwand, um den String so umzucodieren, dass er nur noch ASCII-Zeichen enthält, dabei ist diese Forderung hier an dieser Stelle bereits erfüllt (unter Umständen mit einer Verfälschung der Information: ä -> ä).

        [1] Um aus einer solchen Liste (Vector) die Einzelwerte zu kriegen, dazu gibt es Bit-Operatoren. In Perl gibt es die Funktion unpack().

        Da reicht schon der Zugriff auf die einzelnen Zeichen im String.

        So long,
         Martin

        --
        F: Was sagt die kleine Kerze zur großen Kerze?
        A: Ich gehe heute nacht aus!
        1. h1,

          [1] Um aus einer solchen Liste (Vector) die Einzelwerte zu kriegen, dazu gibt es Bit-Operatoren. In Perl gibt es die Funktion unpack().

          Da reicht schon der Zugriff auf die einzelnen Zeichen im String.

          Freilich, das ist ja alles schon fix und fertig, aber ich denke, unser Patient will es ganz genau wissen. Eigentlich ist das ja Alles reines IO-Zeugs, worauf auch das HTTP aufsetzt. Und leider ist es so, dass gerade SELFHTML hierzu die meiste Verwirrung stiftet, z.B. wo steht, dass beim URI-Encoding der Hexadezimalwert des Zeichens genommen wird. Dieser Sonderfall gilt NUR für eine nach ISO-8859-1 codierte Übertragung und auch NUR für Zeichen aus dieser Code-Tabelle!!!

          Aber lassn mal machen, wir lernen ja selber noch dazu dabei ;-)

          Horst Leberwurst