ingobar: AJAX: Umlaute abspeichern?

Hallo.

Ich habe Eingabefelder in die der User Namen inklusive Umlaute eintragen kann: Müller. Diese werden per php in einer Datei gespeichert. Wenn ich die Datei dann wieder per php und js öffne sind alle Umlaute futsch.

Ich habe versucht folgendes per js zu machen:

curDescr=document.getElementByID("name_field").value; //Hier steht Müller drin
curDescr=curDescr.replace(/\u00fc/g, "ü");
curDescr=curDescr.replace(/\u00f6/g, "ö");
curDescr=curDescr.replace(/\u00e4/g, "ä");
curDescr=curDescr.replace(/\u00dc/g, "Ü");
curDescr=curDescr.replace(/\u00d6/g, "Ö");
curDescr=curDescr.replace(/\u00c4/g, "Ä");
curDescr=curDescr.replace(/\u00df/g, "ß");
curDescr=curDescr.replace(/ü/g, "ü");
curDescr=curDescr.replace(/ö/g, "ö");
curDescr=curDescr.replace(/ä/g, "ä");
curDescr=curDescr.replace(/Ü/g, "Ü");
curDescr=curDescr.replace(/Ö/g, "Ö");
curDescr=curDescr.replace(/Ä/g, "Ä");
curDescr=curDescr.replace(/ß/g, "ß");

Das scheint aber irgenwie nicht zu funktionieren.

Alle js und php-Dateien sind in iso-latin1 gespeichert. Die von php erzeugte Datei hat das Format Mac OS Roman (ich arbeite auf Apple). Wenn ich Datei dann auf Latin1 konvertiere, dann passen die Umlaute zwar im Texteditor, aber beim importieren bekomme ich nur Fragezeichen.

Was kann ich tun, damit das ganze korrekt läuft? Wie kann ich obige replace-Sequenz so korriegieren, dass sie auch mal die Umlaute findet?

Sollte ich das konvertieren besser mit php machen? Wenn ja wie?

Nützt das umstellen der Codierung im erzeugten File etwas? Wenn ja, wie macht man das mit php? Ich habe keinen entsprechenden Befehl gefunden.

Viele Fragen, ich weiß, aber vielleicht gibt es ja eine simple Lösung.

Danke dafür.

  1. echo $begrüßung;

    Beim Fehlersuchen ist es wichtig, genau zu beobachten. Wenn du andere bei der Fehlersuche um Rat fragst, ist es ebenfalls wichtig, genau zu beschreiben. Zwei Beispiele:

    [...] sind alle Umlaute futsch.

    Anstelle eines Zeichens, für das es in einer bestimmten Kodierung keine Codes gibt, kann ein Ersatzzeichen verwendet worden sein. Dieser Vorgang ist irreversibel, solange man nicht aus dem Kontext erkennen kann, was das für ein Zeichen hätte sein sollen. Es kann aber auch einfach nur eine andere dir unbekannte Kodierung sein, und du betrachtest dir den Text mit der falschen Dekodierung. Meist kann ein geübtes Auge feststellen, welche Kodierung vorliegt, und kann dann genauere Rückschlüsse auf das vorliegende Problem ziehen.

    [...] aber beim importieren [...]

    Hier habe ich nicht einfach nur zu wenig zitiert. Es gelang mir nicht, aus dem restlichen Kontext zu erkennen, von wo nach wo du hier etwas importierst. Im Titel erwähnst du AJAX, im restlichen Text tauchen aber nur die allgemeinen Orte "php" und "js" auf. Der eigentliche Datenfluss erschließt sich mir nicht genau. Deshalb kann ich nur allgemein antworten, in der Hoffnung, dass du das Prinzip verstehst und darauf dann ein fehlerfreies System erstellen kannst.

    Es gibt mittlerweile diverse Zeichenkodierungssysteme. Es ist technisch unmöglich, aus einem vorliegenden Text exakt die verwendete Kodierung zu ermitteln. Deshalb muss der Absender dem Empfänger die verwendete Kodierung mitteilen, wenn letzterer nicht raten oder seine eigene Default-Einstellung verwenden soll, was zu beliebigen Ungenauigkeiten führen kann. Im Webumfeld wird die Kodierung in der charset-Angabe des HTTP-Headers namens Content-Type angeführt. Ersatzweise gibt es in HTML das gleichnamige http-equiv-Meta-Element. An einigen Stellen ist jedoch eine Kodierung unveränderlich festgelegt. Das betrifft den XMLHttpRequest. Dort wird generell UTF-8 als Kodierung verwendet. Das musst du als Empfänger (z.B. in PHP) berücksichtigen. Wenn du nur auf die deutschen Umlaute Wert legst, und dir andere Zeichen außerhalb von ISO-8859-1 bzw. Latin1 verlustig gehen können, kannst du die empfangenen Werte mit utf8_decode() nach ISO-8859-1 umkodieren. Wenn du einen Request beantwortest, kannst du die Werte mit utf8_encode() behandeln. Oder du informierst den Empfänger im erwähnten HTTP-Header über die verwendete Kodierung.

    Wenn dir aber auch die anderen Zeichen wichtig sind (z.B. auch das €-Zeichen) solltest du dir überlegen, ob du nicht generell auf UTF-8 umstellst. Es kann dir auch passieren, dass jemand deutsche „Anführungszeichen“ oder ein … (Auslassungszeichen) verwendet, weil er den Text in Word vorschreibt, und das so frei ist, diese Zeichen autokorrigierend aus "..." zu erstellen. Diese Zeichen sind nicht in ISO-8859-1 enthalten und gehen beim utf8_decode() verloren (werden durch ein Fragezeichen ersetzt). Probleme dieser Art kannst du vermeiden, wenn du die Universal-Kodierung UTF-8 verwendest. Das musst du dann aber durchgängig auf der gesamten Verarbeitungslinie berücksichtigen, sonst hast du ja wieder umkodierungsbedingte Verluste.

    echo "$verabschiedung $name";

    1. Ersteinmal Danke für die ausfürhliche Antwort. Ich versuche jetzt noch einmal genau zu beschreiben was passiert.

      Der User hat Eingabefelder (html-Datei mit <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1"> und als Latin1 im Texteditor gespeichert.) Durch Klick auf Specichern passiert folgendes:

      1. Es wird die folgende Funktion aufgerufen:

      var saveDB_ajax_anfrage = null;

      function writeDB() {
       //var dbName = prompt("Unter welchem Namen soll die Datenbank gespeichert werden?");
       var dbName = "test";
       if (dbName) {
        saveDB_ajax_anfrage = null;
        saveDB_ajax_anfrage = erzeugeDB_Anfrage();

      var url = "./php/writedb.php?";
        var data2send = "filename="+dbName;
        data2send += "&data="+escape(changeDataForExport());
        if (saveDB_ajax_anfrage!=null) {
         saveDB_ajax_anfrage.open("POST", url, true);
         saveDB_ajax_anfrage.onreadystatechange = zeigeBestaetigung_save_writeDB;
         saveDB_ajax_anfrage.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
         saveDB_ajax_anfrage.send(data2send);
        } else {
         alert("Es konnte keine Verbindung zum Server aufgebaut werden.");
        }
       }
      }

      2. In der ersten Funktion steht die Zeile data2send += "&data="+escape(changeDataForExport());

      3. In der Zeile changeDataForExport() wird u.a. versucht die Umlaute zu erzeugen und anderen Daten in der mir gewünschten Art und Weise zusammenzustellen.

      4. Das Ganze wird an folgende php-Datei geschickt:

      function write_curData($filename,$data) {
       $today = date("Ymd_His");
              $filename = $filename.$today;
       }
       $dirName = "savedDBs";
       $file = "../".$dirName."/".$filename.".txt";

      if (!$handle = fopen($file, "w")) {
        echo "Kann die Datei $file nicht öffnen";
        exit;
       }
       if (!fwrite($handle, $data)) {
        echo "Kann in die Datei $file nicht schreiben";
        exit;
       }

      fclose($handle);

      echo ("Erfolgreich geschrieben.");
      }
      write_curData($_POST['filename'],$_POST['data']);

      5. Wenn der User die erzeugte Datei nun wieder laden will, kommt der Aufruf in dieser js-Datei an:
      var readDB_ajax_anfrage = null;

      function readDB(filename) {
       readDB_ajax_anfrage = null;
       readDB_ajax_anfrage = erzeugeDB_Anfrage();
       var url = "./php/readdb.php?";
       var data2send = "filename="+filename;
       if (readDB_ajax_anfrage!=null) {
        readDB_ajax_anfrage.open("POST", url, true);
        readDB_ajax_anfrage.onreadystatechange = zeigeBestaetigung_readDB;
        readDB_ajax_anfrage.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
        readDB_ajax_anfrage.send(data2send);
       } else {
        alert("Es konnte keine Verbindung zum Server aufgebaut werden.");
       }
      }

      function zeigeBestaetigung_readDB(){
       if (readDB_ajax_anfrage.readyState == 4) {
          if (readDB_ajax_anfrage.status == 200) {
           var antwort = readDB_ajax_anfrage.responseText;
         var xmlAntwort = readDB_ajax_anfrage.responseXML;
         var splittedAntwort = antwort.split("\n");
          } else {
           var antwort = readDB_ajax_anfrage.responseText;
         alert("Fehler! Anfragestatus ist " + readDB_ajax_anfrage.status);
           }
         }
      }

      6. Die Datei readdb.php macht folgendes:

      <?php
      error_reporting(E_ALL);
      //print_r ($_POST);

      function read_DBdata($filename) {
       $resStr = "";
       $lines = file ($filename);
       foreach ($lines as $line_num => $line) {
        if ($line!="") {
         $resStr .=  $line;
        }
       }
       echo $resStr;
      }

      read_DBdata($_POST['filename']);
      ?>

      7. Die empfangen Daten werden dann wieder dargestellt.

      Hilft der ganze Code noch beim Helfen?

      1. Hallo,

        1. In der ersten Funktion steht die Zeile data2send += "&data="+escape(changeDataForExport());

        Mit 'escape' bist du auf dem richtigen Weg. Den ganzen URL-encoding-Kram, den Browser und Webserver von sich aus machen, musst Du mit Ajax zu Fuss erledigen. escape() und unescape() sind JavaScript-Funktionen. Du brauchst auch die passenden Funktionen zu in PHP.

        In Perl liefert das Modul 'URI::Escape' die entsprechenden Methoden. Zu PHP bitte selbst nachlesen, da gibt es das bestimmt auch.

        Viele Grüße,
        Horst Haselhuhn

        1. echo $begrüßung;

          Mit 'escape' bist du auf dem richtigen Weg. Den ganzen URL-encoding-Kram, den Browser und Webserver von sich aus machen, musst Du mit Ajax zu Fuss erledigen. escape() und unescape() sind JavaScript-Funktionen. Du brauchst auch die passenden Funktionen zu in PHP.

          Nein, braucht man nicht. PHP ist so freundlich, in $_GET und $_POST bereits die transportsicherungsbefreiten Daten zur Verfügung zu stellen. Beim Zurücksenden in Richtung Client benötigt man ebenfalls kein URL-Encoding, da die Daten ja wie ganz normale Dokumente transportiert werden.

          echo "$verabschiedung $name";

          1. Mit 'escape' bist du auf dem richtigen Weg. Den ganzen URL-encoding-Kram, den Browser und Webserver von sich aus machen, musst Du mit Ajax zu Fuss erledigen. escape() und unescape() sind JavaScript-Funktionen. Du brauchst auch die passenden Funktionen zu in PHP.

            Nein, braucht man nicht. PHP ist so freundlich, in $_GET und $_POST bereits die transportsicherungsbefreiten Daten zur Verfügung zu stellen. Beim Zurücksenden in Richtung Client benötigt man ebenfalls kein URL-Encoding, da die Daten ja wie ganz normale Dokumente transportiert werden.

            In Perl auch nicht. Das CGI Modul übernimmt wie in allen anderen CGI Anwendungen auch, die Dekodierung und umgekehrt ist es wie in PHP.

            Struppi.

      2. echo $begrüßung;

        var data2send = "filename="+dbName;
          data2send += "&data="+escape(changeDataForExport());
           saveDB_ajax_anfrage.send(data2send);

        Du wendest zwar escape() auf deine zu exportierenden Daten an, aber nicht auf dbName. Wenn da also Zeichen jenseits von ASCII drinstehen werden die von send() UTF-8-kodiert. So sieht es die Implementation der Browser und der W3C-Standardisierungsvorschlag vor. Mit escape() bringst du Nicht-ASCII-Daten (und einige Steuerzeichen) in eine ASCII-kompatible Kodierung. Da sich escape() nur um ISO-8859-1 kümmert, bekommst du schon beim €-Zeichen unbrauchbare Ergebnisse.

        escape('ä-€') ergibt im Firefox %E4-%u20AC. Beim Dekodieren liest man aus dem %E4 ein ISO-8859-1-ä. Nun kommt ein UTF-8-€ dahergelaufen, und was nun? Soll der bisherige 'ä-'-String nach UTF-8 umkodiert werden, damit das € drin aufgenommen werden kann? Das hätte zur Folge, dass die nachfolgenden Prozesse mit der UTF-8-Kodierung umzugehen wissen müssen. Du siehst, das gibt ein großes Kuddelmuddel.

        Wende auf der Javascript-Seite die Funktion encodeURI() auf das an, das du hinter filename und data hängen willst. Das ergibt eine UTF-8- plus URL-Kodierung. Die URL-Kodierung entfernt PHP selbständig. Übrig bleibt ein UTF-8-kodierter String. Wenn du den unter PHP mit utf8_decode() unter Verlust aller Nicht-ISO-8859-1-Zeichen zu ISO-8859-1 machen willst, kannst du das da vor der Weiterverarbeitung tun.

        Auf dem Rückweg zum Client gib einen Content-Type-Header mit passender charset-Angabe an. Wenn das mit ISO-8859-1 nicht funktionieren sollte, weil einige Browser das vielleicht ignorieren (mir fehlt da die konkrete Erfahrung), dann sollten auf alle Fälle eine charset-Angabe von UTF-8 plus utf8_encode() auf die Werte zum Erfolg führen.

        Hilft der ganze Code noch beim Helfen?

        Code hilft immer dann, wenn man als Außenstehender damit das Problem nachvollziehen kann, und er nicht zu viel für das Problem Irrelevantes enthält. Am besten ist es, wenn du das Problem in einer neuen Datei und mit dem geringstmöglichen Code nachzuvollziehen versucht. Manchmal stellt sich als Nebeneffekt bei solch einer Aufbereitung und Problemisolierung heraus, dass die Ursache gar nicht an der vermuteten Stelle liegt. Und das hilft ja auch bei der Ursachenforschung.

        echo "$verabschiedung $name";