[Ajax] Suggest findet keine Umlaute

M

Mr. Snoot

Gast
Hio,

ich spiel derzeit etwas mit Ajax und "(Google) Suggest". Im Großen und Ganzen läuft es auch, ein Problem gibt es aber: bei Eingabe von Umlauten ä, ö, ü, Ä, Ö, Ü oder ß wird kein Treffer zurückgeliefert.

Ich hab schon mit sämtlichen Zeichenkodierungen und PHP-Umwandlungen (htmlspecialchars etc.) rumgespielt, aber es klappt einfach nicht. Hat vielleicht jemand eine Idee, wo es hakt?

Hier mal die Dateien:


Sucheingabe, index.html:
HTML:
<html>

<head>

<style type="text/css"><!--
 a:link{color:#000;}
 a:visited{color:#ff0;}
 a:hover{color: red;}
 a:active{color:#f00;}
--></style>
</head>


<title>Suggest </title>
<script type="text/javascript" src="ajax.js"></script>
<script type="text/javascript" src="suggest.js"></script>

</head>

<body>

<input type="text" size="20" id="eingabe" onkeyup="load()">

<div id="text">Bitte Suchbegriff eingeben!</div>

</body>
</html>
Datenbankabfrage, text.php:
PHP:
<?php

$eingabe=$_POST["eingabe"];

//Bitte die richtigen Zugangsdaten einfuegen:
$conn = @mysql_connect("localhost", "user", "pwd")
      or die("Verbindung zu Datenbank fehlgeschlagen");

//Datenbank auswaehlen:
$rs = @mysql_select_db("db", $conn)
    or die("Auswahl der Datenbank fehlgeschlagen");

$liste="";

if (get_magic_quotes_gpc()) $eingabe = stripslashes($eingabe);
$frage = mysql_query("SELECT * FROM table WHERE wert LIKE '%". mysql_real_escape_string($eingabe) ."%';");

  while ($antwort=mysql_fetch_array($frage)){


  $liste.= '<a href="#">'.$antwort["wert"].'</a><br>';


  }

echo $liste;

?>
XMLHttpRequest, ajax.js:
PHP:
function Ajax() {
  //Eigenschaften deklarieren und initialisieren
  this.url="";
  this.params="";
  this.method="GET";
  this.onSuccess=null;
  this.onError=function (msg) {
    alert(msg)
  }
}

Ajax.prototype.doRequest=function() {
  //Ueberpruefen der Angaben
  if (!this.url) {
    this.onError("Es wurde kein URL angegeben. Der Request wird abgebrochen.");
    return false;
  }

  if (!this.method) {
    this.method="GET";
  } else {
    this.method=this.method.toUpperCase();
  }

  //Zugriff auf Klasse fuer readyStateHandler ermoeglichen
  var _this = this;

  //XMLHttpRequest-Objekt erstellen
  var xmlHttpRequest=getXMLHttpRequest();
  if (!xmlHttpRequest) {
    this.onError("Es konnte kein XMLHttpRequest-Objekt erstellt werden.");
    return false;
  }

  //Fallunterscheidung nach Uebertragungsmethode
  switch (this.method) {
    case "GET": xmlHttpRequest.open(this.method, this.url+"?"+this.params, true);
                xmlHttpRequest.onreadystatechange = readyStateHandler;
                xmlHttpRequest.send(null);
                break;
    case "POST": xmlHttpRequest.open(this.method, this.url, true);
                 xmlHttpRequest.onreadystatechange = readyStateHandler;
                 xmlHttpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
                 xmlHttpRequest.send(this.params);
                 break;
  }

  //Private Methode zur Verarbeitung der erhaltenen Daten
  function readyStateHandler() {
    if (xmlHttpRequest.readyState < 4) {
      return false;
    }
    if (xmlHttpRequest.status == 200 || xmlHttpRequest.status==304) {
      if (_this.onSuccess) {
        _this.onSuccess(xmlHttpRequest.responseText, xmlHttpRequest.responseXML);
      }
    } else {
      if (_this.onError) {
        _this.onError("["+xmlHttpRequest.status+" "+xmlHttpRequest.statusText+"] Es trat ein Fehler bei der Datenbertragung auf.");
      }
    }
  }
}

//Gibt browserunabhaengig ein XMLHttpRequest-Objekt zurueck
function getXMLHttpRequest()
{
  if (window.XMLHttpRequest) {
    //XMLHttpRequest fuer Firefox, Opera, Safari, ...
    return new XMLHttpRequest();
  } else
  if (window.ActiveXObject) {
    try {
      //XMLHTTP (neu) fuer Internet Explorer
      return new ActiveXObject("Msxml2.XMLHTTP");
    } catch(e) {
      try {
        //XMLHTTP (alt) fuer Internet Explorer
        return new ActiveXObject("Microsoft.XMLHTTP");
      } catch (e) {
        return null;
      }
    }
  }
  return false;
}
Ausgabe mit JS, suggest.js:
PHP:
//Instanz der Klasse Ajax erzeugen und mit der Datenuebertragung starten
function load()
{

  var eingabe=document.getElementById("eingabe").value;

  with (new Ajax()){

    url="text.php";
    method="POST";
    params="eingabe="+eingabe;
    onSuccess=successHandler;
    onError=errorHandler;
    doRequest();
  }


//Den Text in die Seite einfuegen
function successHandler(txt,xml){
  document.getElementById("text").innerHTML=txt;

}

//Fehler
function errorHandler(msg){
  document.getElementById("text").innerHTML=msg;
}

}
 
Zuletzt bearbeitet:
Abgesehen von Zeichensatzgeschichten (welche du ja ausschließt) würde ich vorschlagen, den übergebenen Wert in Javascript mit encodeURIComponent(eingabe) zu escapen.

Außerdem würde ich einfach die Prototype-Library von http://ajax.googleapis.com/ajax/libs/prototype/1.6.0.3/prototype.js einbinden anstatt selbst was zu basteln. Die Größe ist nicht so schlimm weil es von Google per gzip übertragen wird (dann noch 30kb), der Traffic nicht bei dir entsteht und zudem viele Seiten das nutzen, so dass es beim User vielleicht eh schon im Browser-Cache liegt.
 
Naja, es läuft ja sonst einwandfrei.

Vielleicht sieht ja jemand, ob irgendwo was mit der codierung nicht stimmt; ist ja sehr gut möglich, dass ich nicht alles bedacht habe.
 
Frage, welchen Browser benutzt du dazu?
Hatte bei einem AJAX Projekt mit dem Eingabefeld für Datenbankabfragen ähnlich seltsame Probleme mit den Umlauten. Das Seltsame war, das es z.B. mit Firefox einwandfrei läuft (Suchen mit Umlauten funktionierten) beim IE gabs immer kein Ergebniss bei Umlauten. Wobei die Seitenkodierung (XML, HTML, UTF-8 oder ISO8859P1 / P15) beim IE kein anderes Ergebnis brachte.
Das Seltsame war hier das es an sich mit allen getesteten Browsern lief, bis eben auf den IE.
 
Also bisher gestet hatte ich die Umlautegeschichte nur im IE - wer denkt denn daran, dass sowas Browser spezifisch laufen könnte :freak: :)

Müsste ich mich morgen mal dahinterklemmen und andere Browser probieren - aber wäre natürlich schöner, wenn es eine generelle Lösung gäbe.
 
Es geht definitiv einwandfrei auch mit dem IE (6), hab sowas erst vor paar Tagen erstellt und das funktioniert browserunabhängig.

Hast du das Escapen denn gemacht wie ich vorgeschlagen habe? Setz auch mal einen Doctype und untersuche dann, was der Browser sendet (im IE mit ieHTTPHeaders-Addon, im Firefox mit dem LiveHTTPHeaders-Addon). Falls du dann siehst, dass der String als UTF-8 übertragen wird, so kannst du evtl. auch mit einem utf8_decode in PHP Abhilfe schaffen.
 
Jo sorry, hatte ich vergessen - die Änderung hat aber leider nichts gebracht.

Mit dem Addon sehe ich bei Eingabe eines 'ü' folgendes:
eingabe=ü

HTTP/1.1 200 OK
Date: Sun, 22 Feb 2009 22:00:55 GMT
Server: Apache/2.2
X-Powered-By: PHP/5.2.6
Content-Length: 0
Content-Type: text/html
Connection: close
(egal was ich als Doctype oder Zeichensatz einstelle)
 
Zuletzt bearbeitet:
Also bei meiner Lösung sieht ein solche Request mit einem "Ü" im Firefox folgendermaßen aus:
POST /ajaxsearch.php?q=%C3%BC HTTP/1.1
Host: xyz.de
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.0.6) Gecko/2009011913 Firefox/3.0.6 (.NET CLR 3.5.30729)
Accept: text/javascript, text/html, application/xml, text/xml, */*
Accept-Language: de-de,de;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
X-Requested-With: XMLHttpRequest
X-Prototype-Version: 1.6.0.3
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Referer: http://xyz.de/ajaxsearch/
Content-Length: 0
Pragma: no-cache
Cache-Control: no-cache
Im IE 6:
POST /ajaxsearch.php?q=%C3%9C HTTP/1.1
Accept: text/javascript, text/html, application/xml, text/xml, */*
Accept-Language: de
x-prototype-version: 1.6.0.3
Referer: http://xyz.de/ajaxsearch/
x-requested-with: XMLHttpRequest
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; .NET CLR 1.1.4322; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)
Host: xyz.de
Content-Length: 0
Connection: Keep-Alive
Cache-Control: no-cache

Mein HTML sieht im Wesentlichen so aus:
PHP:
<html>
<head>
<title>Ajax Test</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
...
...
<input type="text" name="searchtext" id="searchTextField" value="" size="30" onkeyup="showResult(this.value)">
Alternativ zur Angabe des content-types an dieser Stelle wäre es auch wichtig, dass dein Apache das als UTF-8 ausliefert. Man kann zumindest den Header auch mit PHP erzwingen mittels 'header("Content-Type: text/html; charset=UTF-8")'. Außerdem sollte man den PHP-Sourcecode auch als UTF-8 abspeichern (geht z.B. mit UltraEdit) sonst sind im Quellcode vorhandene Umlaute falsch.

Außerdem nutze ich die genannte Prototype-Lib und rufe folgendermaßen auf in JS:
PHP:
function showResult(str){
  var newString = encodeURIComponent(str);
  new Ajax.Request('ajaxsearch.php?q='+newString, {
    method:'post',
    onSuccess: function(transport){
      alert(transport.responseText);
    }
  }
}
 
Zuletzt bearbeitet:
Pack mal am Anfang deiner text.php:
PHP:
header('Content-Type: text/html; charset=iso-8859-1');

So funktioniert das bei mir. Einige Leute schreiben, dass das auch geht, indem du von php die Funktion utf8_decode() benutzt, also in deinem Fall in der text.php:

PHP:
$liste.= '<a href="#">'.utf8_decode($antwort["wert"]).'</a><br>';

Das habe ich aber nicht probiert, da erste Variante das Problem bei mir löst.
 
Nachtrag (@Mr. Snoot): "eingabe=ü" zeugt eigtl. davon, dass es eben gerade nicht im Request escaped wird (siehe meine Requests im Vergleich). Ich hatte das schon in meinem ersten Post geschrieben aber offensichtlich hast dus nicht gelesen. Denn ü ist tatsächlich schon UTF-8 aber eben nicht korrekt escaped so wie mans in HTTP-Requests nunmal machen muss.
Die Sache mit dem utf8_decode() (was ich im Übrigen auch schon vorgeschlagen habe) ist auch eher ein Workaround für falsche HTTP-Requests und funktioniert zudem nicht immer.
 
@ DerEineDa: klappt leider beides nicht

@ BerniG: eingabe=ü bekomme ich doch zurück, bevor irgendwas durchs JS läuft, das ist also die direkte Eingabe im Browser, oder nicht? Ich drücke ja nicht auf Absenden oder so.


edit: ne billige Variante wäre natürlich
PHP:
$eingabe = str_replace("ü", "&uuml;", $eingabe);
und ich ersetze die Umlaute in der DB entsprechend ;)
 
Zuletzt bearbeitet:
eingabe=ü bekommst du doch mit LiveHTTPHeaders bzw. IEHttpHeaders wenn du auf der Seite ein ü eingibst, oder (hast du zumindest geschrieben!)? Und dieser HTTP-Request wird ja von Javascript abgesetzt, sonst könntest du ja gar kein Suggest machen.
 
In meinem Beispiel mit dem Header nutze ich natürlich "charset=iso-8859-1" in der Annahme, dass die Daten in der Codierung in der Datenbank liegen. Das kann aber durchaus auch ein anderes Format sein, also checke mal die Konfiguration deiner Datenbank.
 
@ BerniG: trotzdem hilft encodeURIComponent(eingabe) nicht :(

@ Der EineDa: also bei der DB selbst steht MySQL-Zeichensatz: UTF-8 Unicode (utf8), bei der entsprechenden Tabelle hab ich verschiedene Kollationen probiert (was müsste ich da einstellen, oder wo müsste ich es sonst ändern?).


Was ich mir noch dachte: wenn ich die Umlaute wie oben geschrieben per str_replace ersetzen kann, dann müssen die Umlaute hier doch auch so wie sie sind vorliegen, und nicht kodiert ala ü; sonst könnt ich's ja nicht ersetzen, oder?
 
Zuletzt bearbeitet:
Mr. Snoot schrieb:
@ BerniG: trotzdem hilft encodeURIComponent(eingabe) nicht :(
Stimmt denn dann der Request mit dem überein was bei mir rauskommt? Nimm doch vielleicht mal meinen Code in Verbindung mit besagter Prototype-Lib her...
Hast du das auf einem öffentlichen Webspace, so dass mans mal testen kann?
 
Also wenn ich bei dir
Code:
params="eingabe="+encodeURIComponent(eingabe);
in die suggest.js reinschreibe, dann sieht das korrekt aus:
POST /test/text.php HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.0.6) Gecko/2009011913 Firefox/3.0.6 (.NET CLR 3.5.30729)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: de-de,de;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Referer: http://localhost/test/
Content-Length: 15
Pragma: no-cache
Cache-Control: no-cache
eingabe=%C3%BC
Was hast du denn gemacht???

Wobei ich es über die URL übergeben würde. Also
Code:
url="text.php?search="+encodeURIComponent(eingabe);
und den Param weg. Als nächstes würde ich einfach mal in deinem PHP-Script die Eingabe zurückgeben so dass du siehst, ob PHP es richtig in UTF-8 macht.
 
Genau da (dein erster Vorschlag) hab ich's hingepackt! Vermutlich hab ich irgendwas verplant :freak: ;)


Also direkt bei der Eingabe bekomme ich:
eingabe=...denn%20zum%20k%C3%BCssen%20sind%20sie%20da
Ab dem 'ü' erhalte ich aber keine Vorschläge mehr.

Wenn ich es dann abschicke, bekomme ich das:
POST http: //movie.halbleiter.org/results.php HTTP/1.1
Accept: image/gif, image/jpeg, image/pjpeg, application/x-ms-application, application/vnd.ms-xpsdocument, application/xaml+xml, application/x-ms-xbap, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/x-shockwave-flash, application/x-silverlight, */*
Referer: http://movie.halbleiter.org/
Accept-Language: de
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; WOW64; Trident/4.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.0.04506; Media Center PC 5.0; OfficeLiveConnector.1.3; OfficeLivePatch.0.0)
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
Host: movie.halbleiter.org
Content-Length: 55
Proxy-Connection: Keep-Alive
Pragma: no-cache
Cookie: __utma=28204965.1579043052.1234088505.1234459936.1235234226.15; __utmz=28204965.1234106543.3.2.utmcsr=computerbase.de|utmccn=(referral)|utmcmd=referral|utmcct=/forum/profile.php

poll=...denn+zum+K%C3%BCssen+sind+sie+da
 
Zuletzt bearbeitet:
Das ist aber eigtl. derselbe Request dann. Der einzige Unterschied den ich sehe:
Beim Ajax-Request wird der content-type eigtl. korrekt übergeben:
Code:
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Beim "normalen" Request dagegen wird das Encoding weggelassen:
Code:
Content-Type: application/x-www-form-urlencoded
Allerdings ist das egal (Ersteres ist soundso eher richtig). Da man sieht, dass bei einem Klick auf absenden das ü tatsächlich korrekt wieder zurückgeliefert wird, wird der Fehler nicht an der Kommunikation sondern eher an deiner Datenbank oder deinem PHP-Skript liegen. Probier doch mal in deinem PHP-Skript eine statische Abfrage mit einem Umlaut. Wenn die nicht funktioniert, so stimmt was in deiner MySQL-Datenbank nicht. Problematisch bei MySQL ist, dass man den Zeichensatz an X Stellen getrennt setzen kann (für die Verbindung, Session, Tabelle, Feld). Vielleicht hilft eines der drei:
PHP:
mysql_set_charset('utf8',$dblink);
PHP:
mysql_query("SET NAMES 'utf8'");
PHP:
mysql_query('set character set utf8;');
vor dem Absetzen der Query?
 
Zuletzt bearbeitet:
So, geschafft (fast) :D Vielen Dank schon mal.

Die drei Befehle tun es alle, allerdings scheint es so, als werden bei Eingabe eines ü jetzt auch alle u gefunden (bei ö alle o bzw. bei ä alle a). Lässt sich das noch korrigieren?

Außerdem muss ich (set ... utf8) jetzt auch beim Schreiben in die DB machen, damit bei Umlauten eine Übereinstimmung zwischen DB und Eingabe gefunden wird. Kann ich das durch eine Einstellung jetzt generell ändern?
 
Zurück
Oben