DerWaldgeist: Umlaute in String beim auslesen eines pop3 Postfaches

Hallo,

ich versuche momentan einen kleinen Email-Client zu erstellen. Nun bin ich dabei die Funktion zu erstellen, welche die Nachrichten vom pop3 Server ausliest. Dabei ergibt sich das für mich leider bisher unlösbare Problem der Umlaute in den abgerufenen Emails -- diese werden immer als unbekannte Zeichen dargestellt (im Firefox ein �), wie ich es auch anfange. Meine Versuche sind unten im Skript ersichtlich (wo die vielen //????// stehen) ... ich bin für jede Hilfe dankbar.

Das Skript, dass ich verwende, sieht etwa so aus:

  
<?  
  
// Funktionen zum Auslesen eines bestimmten MIME-Types  
  
function get_mime_type(&$structure)  
{  
    $primary_mime_type = array("TEXT", "MULTIPART", "MESSAGE", "APPLICATION", "AUDIO", "IMAGE", "VIDEO", "OTHER");  
    if ($structure->subtype) {  
        return $primary_mime_type[(int) $structure->type] . '/' . $structure->subtype;  
    }  
    return "TEXT/PLAIN";  
}  
  
function get_part($stream, $msg_number, $mime_type, $structure = false, $part_number = false)  
{  
$prefix = "";  
    if (!$structure) {  
        $structure = imap_fetchstructure($stream, $msg_number);  
    }  
    if ($structure) {  
        if ($mime_type == get_mime_type($structure)) {  
            if (!$part_number) {  
                $part_number = "1";  
            }  
            $text = imap_fetchbody($stream, $msg_number, $part_number);  
            if ($structure->encoding == 3) {  
                return imap_base64($text);  
            } else if ($structure->encoding == 4) {  
                return imap_qprint($text);  
            } else {  
                return $text;  
            }  
        }  
        if($structure->type == 1) /* multipart */  
        {  
            while (list($index, $sub_structure) = each($structure->parts)) {  
                if ($part_number) {  
                    $prefix = $part_number . '.';  
                }  
                $data = get_part($stream, $msg_number, $mime_type, $sub_structure, $prefix . ($index + 1));  
                if ($data) {  
                    return $data;  
                }  
            }  
        }  
    }  
    return false;  
}  
  
  
  
  
// hier Script mit den Benutzerdaten des POP3-Servers konfigurieren  
$hostname = "pop3.web.de";  
$username = "irgendwer@irgendwo.de";  
$kennwort = "sososososo";  
  
$mailbox = imap_open("{".$hostname."}", $username, $kennwort);  
// $mailbox = imap_open ("{".$hostname.":110/pop3}INBOX", $username, $kennwort); // für GMX und andere bekannte Freemailer  
  
  
$mails = imap_fetch_overview($mailbox,"1:*", FT_UID); // Holt eine Übersicht aller Emails  
$nachricht_tell = "";  
  
$size=count($mails); // Anzahl der Nachrichten  
$cmsg = 0;           // Zur Ausgabe einer fortlaufenden Nummer  
  
for ($i=$size-1; $i>=0; $i--) { // für alle vorhandenen Mails durchlaufen  
  
    $cmsg++;  
    $value = $mails[$i];  
  
    $mail = get_part($mailbox, $value->msgno, "TEXT/PLAIN"); // aus der Nachricht den Plaintext holen  
   $mail2 = get_part($mailbox, $value->msgno, "TEXT/HTML"); // aus der Nachricht den Htmltext holen  
  
if ($mail2 != ''){  
	  
  $msgBody = $mail2;  
	  // $msgBody=ereg_replace("ü","&uuml;",$mail2);  
  
}else{  
	  
  $msgBody=ereg_replace("\n","<br>",$mail);  
  $msgBody=preg_replace("/([^\w\/])(www\.[a-z0-9\-]+\.[a-z0-9\-]+)/i","$1http://$2", $msgBody);  
  $msgBody=preg_replace("/([\w]+:\/\/[\w-?&;#~=\.\/\@]+[\w\/])/i","<A TARGET=\"_blank\" HREF=\"$1\">$1</A>", $msgBody);  
  $msgBody=preg_replace("/([\w-?&;#~=\.\/]+\@(\[?)[a-zA-Z0-9\-\.]+\.([a-zA-Z]{2,3}|[0-9]{1,3})(\]?))/i","<A HREF=\"mailto:$1\">$1</A>",$msgBody);  
  // ???????????????????????????????????????????????????????????????????????????????????? //  
  // $msgBody=preg_replace("/[^a-z0-9 äöü]/usi", "",$msgBody);  // funktioniert nicht  
  // $msgBody=ereg_replace("ü","&uuml;",$msgBody); //  funktioniert nicht  
  // utf8_encode($msgBody);  //  funktioniert nicht  
	  
/** das hier geht aber so wie es soll ??  
$str = 'ERZ$EÜDLÖFÄEWHGUOIE$gfbo8w34';  
$str = preg_replace("/[^a-z0-9 äöü]/usi", "", $str);  
echo $str;  
**/  
  
    };  
  
echo $msgBody;  
  
}  
  
imap_close($mailbox); // Verbindung zum POP3-Server beenden  
  
  
  
  
?>  

Danke schonmal,
Alex

  1. Hi

    diese ? character sind meist fehlformatierungen ... ich weiß nicht wo du deine Ausgaben machst aber für mich klingt es als wäre deine "ausgabe" site in ISO und die Mail daten in UTF so das es zu display schwierigkeiten kommt ... teste mal http://de.php.net/manual/en/function.utf8-decode.php um das ganze als UTF8 auszugeben und dann im html

    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  
    
    

    Greets
    --------------

    IT & PR - Fenebris.com
    janfeddersen _at_ dunkelnetz _dot_ de
    Kredite, Umschuldung, Finanzen

    1. Hi

      diese ? character sind meist fehlformatierungen ... ich weiß nicht wo du deine Ausgaben machst aber für mich klingt es als wäre deine "ausgabe" site in ISO und die Mail daten in UTF so das es zu display schwierigkeiten kommt ... teste mal http://de.php.net/manual/en/function.utf8-decode.php um das ganze als UTF8 auszugeben und dann im html

      <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

      
      >   
      > Greets  
      > --------------  
      >   
      > IT & PR - Fenebris.com  
      > janfeddersen \_at\_ dunkelnetz \_dot\_ de  
      > [Kredite, Umschuldung, Finanzen](http://fenebris.com)  
        
        
      Sorry mein Fehler ..... entweder UTF in iso convertieren mit utf8\_decode oder setzen der UTF formatierung damits im firefox richtig angezeigt wird  
      ~~~html
      <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  
      
      

      sonst kannst du auch mit
      ORD dir anschauen wes das für ein ASCII wert ist und damit rausfinden was das für ne zeichentabelle ist  ....

      Gruß

      1. Mit ORD komme ich leider auch nicht weiter, weil das Zeichen offenbar gar kein ü mehr ist wenn es ausgelesen wird -- ü müsste in ascii  195 sein, wenn ich aber nach 195 suche findet das Skript gar nichts, obwohl jede Menge ü in der Email vorhanden wären...

          
        // echo ord('ü'); // ergibt 195  
        function clean_string_input($msgBody)  
        {  
        $interim = strip_tags($msgBody);  
          
            if(get_magic_quotes_gpc())  
            {  
                $interim=stripslashes($msgBody);  
            }  
          
            // now check for pure ASCII input  
            // special characters that might appear here:  
            //   195: ü  
          
            $result = '';  
            for ($i=0; $i<strlen($interim); $i++)  
            {  
                $char = $interim{$i};  
                $asciivalue = ord($char);  
                if ($asciivalue == 195)  
                {  
                    $result .= '&uuml;';  
                };  
          
          
            }  
          
            return $result;  
        }  
        
        

        ... Hoffe es hat irgendjemand noch irgendwelche Ideen -- irgendwie muss es an dem Abrufen als Email (pop3) liegen - offenbar ist das kein normaler string ?? ... ??

        1. echo $begrüßung;

          ... Hoffe es hat irgendjemand noch irgendwelche Ideen -- irgendwie muss es an dem Abrufen als Email (pop3) liegen - offenbar ist das kein normaler string ?? ... ??

          Die einfachste und wichtigste: Wenn du nicht weißt, wie etwas aussieht, schau es dir an. Mach eine Kontrollausgabe. Am besten in Hex (bin2hex() oder auch urlencode()). Wie sieht dein ü darin aus?

          In einer Email gibt es gelegentlich einen Content-Type-Header mit einer charset-Angabe. Das sollte die Kodierung sein, die der Absender für den Mailinhalt (oder den Teil bei Multipart-Mails) verwendet hat. (Für Headerzeilen (z.B. Subjekt) gibt es eine eigene Syntax.)

          echo "$verabschiedung $name";

          1. Vielen Dank,
            jetzt kriege ich wenigstens mal irgend einen Wert zurück -- allerdings weiß ich ehrlich gesagt nicht genau, wie ich meine hexadez. erkannten Zeichen jetzt konvertiere.
            Wandelt man den gesamten String mit bin2hex(); um und sucht hernach nach besagten hexadez.-Werten um diese z.B. durch ein &uuml; zu ersetzen ?
            Und, wenn ja, wie mache ich dass ??  hab bissle rumgebastelt, aber ich kriege dass irgendwie nicht hin ...

            echo bin2hex($msgBody);  ergibt fc0d3c62723e

            Den Header habe ich mit imap_headers(); ausgelesen. Das ergibt in Falle meiner Testmail " chars ". Ich weiß nur auch hier nicht recht was ich dmit anfangen soll ...

            Danke für die Hilfe,
            Alex

            1. .. habe es so versucht:

              $hex = bin2hex($msgBody);  
              // echo $hex;  
              	  
              // fc0d3c62723e hexadez. für ü  
                
              if (preg_match("/\bfc0d3c62723e\b/i", $hex)) {  
                // echo "Es wurde eine Übereinstimmung gefunden.";  
                 $nachr = preg_replace("/\bfc0d3c62723e\b/i", "&uuml;" , $hex);  
              } else {  
                 // echo "Es wurde keine Übereinstimmung gefunden.";  
              }  
              echo "<br><br>".$nachr;
              

              Damit bekomme ich für $nachr ein ü -- aber jetzt habe ich einen hexadezimalstring mit einem ü mitten drin. Habe das Gefühl, das ist leider ziemlicher Blödsinn ... ?

              1. ... ok vergesst das oben mal. War in der Tat Blödsinn ...
                Ich habe nicht bemerkt dass in meinem $hex = bin2hex($msgBody); string auch Leerstellen drin waren ... Mein ü ist also nicht fc0d3c62723e sondern nur fc.

                Der Normale Hexadezimalwert für ü ist aber c3bc. Man muss also nur im hexadezimalen string das fc durch ein c3bc ersetzen ...

                Ich stand da wohl etwas auf dem Schlauch (na ja, leider gibts' hier ja keine Löschfunktion für eigene Postings - dann würde ich meine letzen beiden Einträge löschen um der Verwirrung etwas entgegenzuwirken ...)

                Hier also meine momentane Lösung:

                  
                function hex2bin($h)  // ist ein Bsp. aus dem Manual  
                  {  
                  if (!is_string($h)) return null;  
                  $r='';  
                  for ($a=0; $a<strlen($h); $a+=2) { $r.=chr(hexdec($h{$a}.$h{($a+1)})); }  
                  return $r;  
                  }  
                	  
                	$hex = bin2hex($msgBody);  // umwandeln in hexadez.  
                	/**  
                	echo "<br>ue: ".bin2hex('ü')."<br>";  
                	echo "<br>bin: ".hex2bin("fc")."<br>";  
                        echo $hex;  
                	**/  
                	  
                //  fc hexadez. für ü  
                //  soll c3bc werden  
                  
                if (eregi("fc", $hex)) {  
                  // echo "Es wurde eine Übereinstimmung gefunden.";  
                   $nachr = eregi_replace("fc", "c3bc" , $hex);  
                   $kon_nachr = hex2bin($nachr);  
                };  
                  
                echo "<br><br>".$kon_nachr;
                

                :-) Alex

                1. Hallo,

                  ... ok vergesst das oben mal. War in der Tat Blödsinn ...

                  ja. ;-)

                  Ich habe nicht bemerkt dass in meinem $hex = bin2hex($msgBody); string auch Leerstellen drin waren

                  Nein, da waren keine. Nur ein Zeilenumbruch.

                  Der Normale Hexadezimalwert für ü ist aber c3bc.

                  In UTF-8, ja.

                  Man muss also nur im hexadezimalen string das fc durch ein c3bc ersetzen ...

                  Nein.

                  Hier also meine momentane Lösung:

                  Autschn.

                  Ciao,
                   Martin

                  --
                  Man gewöhnt sich an allem, sogar am Dativ.
                2. leider habe ich das oben etwas spät gelesen. In der Tat:

                  Content-Type: text/plain; charset=ISO-8859-15;

                  utf8_encode($msgBody); funktioniert leider dennoch nicht (das hatte ich ganz zu Beginn schonmal versucht)...

                  1. Hi,

                    Content-Type: text/plain; charset=ISO-8859-15;
                    utf8_encode($msgBody); funktioniert leider dennoch nicht (das hatte ich ganz zu Beginn schonmal versucht)...

                    hast du das tatsächlich so angewendet, wie es der obige Codeschnipsel andeutet? Also die Funktion aufgerufen und dann das Ergebnis weggeworfen? Oder benutzt du tatsächlich das Funktionsergebnis?

                    So long,
                     Martin

                    --
                    Ungeschehene Ereignisse können einen katastrophalen Mangel an Folgen nach sich ziehen.
                      (Unbekannter Politiker)
                    1. hast du das tatsächlich so angewendet, wie es der obige Codeschnipsel andeutet? Also die Funktion aufgerufen und dann das Ergebnis weggeworfen? Oder benutzt du tatsächlich das Funktionsergebnis?

                      »»

                      Mein Gott -- Danke -- manchmal fragt man sich ... da hätte ich mir wohl ein paar Stunden sparen können ... das kommt davon wenn man PHP im "bastel-Modus" lernen möchte ...

                      Danke jedenfalls für die Geduld,
                      Alex

                      1. Moin!

                        »» hast du das tatsächlich so angewendet, wie es der obige Codeschnipsel andeutet? Also die Funktion aufgerufen und dann das Ergebnis weggeworfen? Oder benutzt du tatsächlich das Funktionsergebnis?
                        »»

                        Mein Gott -- Danke -- manchmal fragt man sich ... da hätte ich mir wohl ein paar Stunden sparen können ... das kommt davon wenn man PHP im "bastel-Modus" lernen möchte ...

                        Es ist empfehlenswert, zum Umcodieren eine vernünftige Funktion zu verwenden, der man Eingabe- und Ausgabecodierung einfach übergibt, und die dann macht.

                        iconv() ist dafür ein sehr guter Ansatz. Die Eingabecodierung entnimmst du aus den Headerangaben der Mail, und Ausgabecodierung ist immer UTF-8, weil deine Website damit am Besten klarkommt, wenn grundsätzlich beliebige Codierungen in den Mails verwendet werden könnten und deshalb sämtliche Unicode-Zeichen verwendet werden könnten.

                        - Sven Rautenberg

            2. Hallo,

              Wandelt man den gesamten String mit bin2hex(); um und sucht hernach nach besagten hexadez.-Werten um diese z.B. durch ein &uuml; zu ersetzen ?

              nein, sicher nicht. Du hast vermutlich ein simples Codierungsproblem, mehr nicht.

              echo bin2hex($msgBody);  ergibt fc0d3c62723e

              Okay. Angenommen, das sei ISO-8859-1, entspricht das dem Klartext-String "ü\r<br>".
              Anscheinend kommt dein Text aus der Mailnachricht also in ISO-8859-x an (das hättest du schon längst anhand der Mail-Header überprüfen können), du gibst ihn aber auf einer UTF-8-codierten Seite aus, ohne ihn umzuschlüsseln.
              In UTF-8 ist ein einzeln auftretendes 0xFC nämlich ungültig, daher das Fragezeichen:
              Nach dem Codierungsschema in Wikipedia ist 0xFC das erste Byte einer Sequenz, die aus 6 Bytes besteht (und *ein* Zeichen repräsentiert). Die folgenden fünf Bytes müssen aber alle im Bereich 0x80..0xFF liegen, andernfalls ist die gesamte Sequenz ungültig. Ergo wird das 0xFC mit den nachfolgenden fünf Bytes ignoriert und stattdessen ein Fragezeichen ausgegeben.

              Den Header habe ich mit imap_headers(); ausgelesen. Das ergibt in Falle meiner Testmail " chars ".

              Das ist auch ein ungünstiger Ansatz. Benutze stattdessen imap_fetchheader(). Diese Funktion gibt dir den gesamten Headerbereich einer Mailnachricht als String zurück. Darin findest du dann alle Angaben über die Anatomie deiner empfangenen Nachricht.

              Falls du dann feststellst, dass die Codierung tatsächlich ISO-8859-x ist (was ich vermute), kannst du den Text vor der Ausgabe mit utf8_encode() passend umcodieren.

              So long,
               Martin

              --
              Die letzten Worte des Systemadministrators:
              Nur gut, dass ich ein intaktes Backup habe.
            3. echo $begrüßung;

              jetzt kriege ich wenigstens mal irgend einen Wert zurück -- allerdings weiß ich ehrlich gesagt nicht genau, wie ich meine hexadez. erkannten Zeichen jetzt konvertiere.
              Wandelt man den gesamten String mit bin2hex(); um und sucht hernach nach besagten hexadez.-Werten um diese z.B. durch ein &uuml; zu ersetzen ?

              Das bin2hex() war nur zu Analyse gedacht. Diese Analyse bildet nun die Grundlage für ein weiteres gezieltes Vorgehen. Ohne zu ermitteln, was da konkret vorliegt, ist das Ganze nicht viel mehr als ein Stochern im Nebel. Das bin2hex() soll dabei Hexwerte anzeigen, die im Allgemeinen durch das Ausgabemedium (Browser) nicht weiter fehlinterpretiert werden können, weil sie alls im ASCII-Bereich liegen. Wenn du den String einfach so ausgibst, dann sind da Nicht-ASCII-Zeichen dabei, die wegen falscher Interpretation ein unbrauchbares Anzeigeergebnis liefern.

              Nachdem du nun konkret weißt, welche Bytewerte du vorliegen hast, kannst du sie mit den üblichen Kodiertabellen vergleichen und die Kodierung mehr oder weniger genau herausfinden. Die Zielkodierung kennst du auch, fehlt nur noch eine Konvertierung. Einfacher ist natürlich, die Kodierungsangabe der Quelle auszuwerten. (Die kann auch falsch angegeben sein, aber das ist dann ein anderes Problem.)

              Die konkrete Kodierung anhand der Bytewerte herauszusuchen, kann aber nur im Zuge einer Fehlersuche ein Weg sein. Denn der Mail-Sender kann eine beliebige Kodierung für seine Mail verwenden.

              Den Header habe ich mit imap_headers(); ausgelesen. Das ergibt in Falle meiner Testmail " chars ". Ich weiß nur auch hier nicht recht was ich dmit anfangen soll ...

              Da fehlt was. Ein " chars " allein ist nicht so richtig sinnvoll. Du solltest eine Header-Zeile à la

              Content-Type: text/plain; charset=iso-8859-1

              bekommen. Davon musst du - in diesem Beispiel - den Teil iso-8859-1 extrahieren. Da kann auch was ganz anderes stehen, je nachdem, was der Absender verwendet hat. Diese Angabe musst du nun als Quellkodierung für deinen Umkodiervorgang nehmen.

              echo "$verabschiedung $name";

    2. Hi,

      danke für die schnelle Antwort, leider war dass wohl nicht der Fehler:

      "ich weiß nicht wo du deine Ausgaben machst"

      -> Die Ausgabe mache ich momentan testhalber direkt über das Skript
      echo $msgBody;

      utf8_decode($msgBody); habe ich eingefügt

      Der HTML Header meines Skriptes sieht etwa so aus:

        
      <!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" />  
      <meta http-equiv="cache-control" content="no-cache" />  
      <!-- weitere meta Angaben wie title usw. -->  
      </head>  
      <body>  
      <?php hier liegt mein Skript ?>  
      </body>  
      </html>  
      
      

      Leider sind immer noch alle ü,ö und ä als ? dargestellt.

      ??

      Alex