Bastian: Umlaut-Probleme bei Excel-Export von MySQL-Tabelle

Hallo ihr

Ich habe eine Adressen-Tabelle in MySQL. Der Benutzer kann im Browser die Adressen anzeigen lassen und auf Wunsch einen Excel-Export vornehmen.

In PHP habe ich dazu folgenden Header definiert:

header("Content-type: application/octet-stream");
    header("Content-Disposition: attachment; filename=Adressen.xls");
    header("Pragma: no-cache");
    header("Expires: 0");

Der Export klappt eigentlich gut, allerdings werden die Umlaute falsch dargestellt.
Gibt es eine Möglichkeit in PHP oder in phpMyAdmin dies zu korrigieren?

Lieber Gruss
Bastian

  1. Hallo Bastian,

    ich hatte ein ähnliches Problem: Beim MYSQL-Importieren mit PHPMYADMIN wurden die Umlaute nicht richtig dargestellt. Nachdem ich das Format "binary" beim Import eingestellt habe wurden auch die Umlaute richtig übernommen. Umgekehrt müsste es auch möglich sein das Format in PHPMYADMIN einzustellen.

    Grüße von Guma

  2. echo $begrüßung;

    Der Export klappt eigentlich gut, allerdings werden die Umlaute falsch dargestellt.

    Es gibt viele Möglichkeiten, etwas falsch darzustellen. Und es gibt viele Möglichkeiten, Zeichen zu kodieren.

    Finde zunächst heraus, welche Kodierung vorliegt und welche erwartet wird. Um den ersten Teil zu beantworten kann ein Browser helfen. Öffne die Datei und stelle im Menü Ansicht verschiedene Zeichenkodierungen ein (ISO-8859-1 und UTF-8 sind dabei am sinnvollsten). Wenn die Umlaute richtig dargestellt werden, ist es diese Kodierung. Allerdings wird das bei Binärdateien, wie .xls eine sein wird, nicht besonders von Erfolg gekrönt sein.

    Du schreibst auch nicht, wie du diese Datei erzeugst, wie dieser "Excel-Export" abläuft.

    Gibt es eine Möglichkeit in PHP oder in phpMyAdmin dies zu korrigieren?

    Dazu muss zuerst die Ursache herausgefunden werden.

    echo "$verabschiedung $name";

    1. Finde zunächst heraus, welche Kodierung vorliegt und welche erwartet wird. Um den ersten Teil zu beantworten kann ein Browser helfen. Öffne die Datei und stelle im Menü Ansicht verschiedene Zeichenkodierungen ein (ISO-8859-1 und UTF-8 sind dabei am sinnvollsten). Wenn die Umlaute richtig dargestellt werden, ist es diese Kodierung. Allerdings wird das bei Binärdateien, wie .xls eine sein wird, nicht besonders von Erfolg gekrönt sein.

      Okay, ich hole mal etwas weiter aus. Auf der Website wird die MySQL-Tabelle mit PHP ausgegeben:

      <?php
       $sql = "SELECT name, vorname, adresse, plz, ort FROM adressen";
       $erg = mysql_query($sql);
      ?>
      <table>
      <?php
       echo "<tr>";
       echo "<td><h3>Name, Vorname</h3></td>";
       echo "<td><h3>Adresse</h3></td>";
       echo "<td><h3>PLZ</h3></td>";
       echo "<td><h3>Ort</h3></td>";
       echo "</tr>";

      while ($zeile = mysql_fetch_assoc($erg)) {

      echo "<tr>";
        echo "<td>" . $zeile["name"] . " " . $zeile["vorname"] . "</td>";
        echo "<td>" . $zeile["adresse"] . "</td>";
        echo "<td>" . $zeile["plz"] . "</td>";
        echo "<td>" . $zeile["ort"] . "</td>";
        echo "</tr>";

      }
      ?>
      </table>
      <a href="adressen_export.php?sql=<?php echo $sql ?>">Adressen als Excel-Tabelle herunterladen</a>

      ====================================================

      Die Datei adressen_export.php erzeugt den Export:

      <?php
       include "../scripts/datenbank.php";

      $sql = stripslashes($_GET["sql"]);
       $erg = mysql_query($sql);

      $felder = mysql_num_fields($erg);

      for ($i = 0; $i < $felder; $i++) {

      $header .= ucfirst(mysql_field_name($erg, $i)) . "\t";

      while ($zeile = mysql_fetch_row($erg)) {

      $linie = '';

      foreach($zeile as $wert) {

      if ((!isset($wert)) OR ($wert == "")) {

      $wert = "\t";

      } else {

      $wert = str_replace('"', '""', $wert);
            $wert = '"' . $wert . '"' . "\t";
           }

      $linie .= $wert;
          }

      $data .= trim($linie) . "\n";
         }

      $data = str_replace("\r", "", $data);

      }

      header("Content-type: application/octet-stream");
        header("Content-Disposition: attachment; filename=Adressen.xls");
        header("Pragma: no-cache");
        header("Expires: 0");
        echo "$header\n$data";
      ?>

      ====================================================

      Wenn ich den Link anklicke, startet der Download der Excel-Datei. Die Spaltennamen und alle Inhalte werden korrekt übernommen, ausser die Umlaute. Die sehen in Excel dann so aus:
      ä wird zum Promillezeichen
      ö wird zu ^
      ü wird zu einem Cedille.

      1. echo $begrüßung;

        Finde zunächst heraus, welche Kodierung vorliegt und welche erwartet wird. Um den ersten Teil zu beantworten kann ein Browser helfen. Öffne die Datei und stelle im Menü Ansicht verschiedene Zeichenkodierungen ein (ISO-8859-1 und UTF-8 sind dabei am sinnvollsten). Wenn die Umlaute richtig dargestellt werden, ist es diese Kodierung. Allerdings wird das bei Binärdateien, wie .xls eine sein wird, nicht besonders von Erfolg gekrönt sein.

        Okay, ich hole mal etwas weiter aus. Auf der Website wird die MySQL-Tabelle mit PHP ausgegeben:

        Deinem Code entnehme ich, dass ein CSV-Format erstellt wird. Da das sowas wie Text ist, kannst du diese Datei im Browser öffnen und die Zeichenkodierungen durchprobieren. Somit dürftest du die Kodierung haben, die erstellt wird. Die Frage ist nur, warum wird das so erstellt und wie kann man das gleich "richtig" machen. Unter welcher Version läuft dein MySQL-Server? Ist es eine Version 4.1 oder höher könnte ein "SET NAMES latin1" als erster Befehl an die Datenbank nach dem Verbindungsaufbau dafür sorgen, dass die Ergebnisse ISO-8859-1-kodiert zurückkommen. Das wäre eine Kodierung, die Excel verstehen müsste.
        Wenn das nicht funktioniert oder die Server-Version kleiner als 4.1 ist, sehe ich nur eine Umkodierung im abfragenden Script von der oben ermittelten Kodierung nach ISO-8859-1. Dazu sind die Erweiterungen iconv und recode vorgesehen.

        Wenn ich den Link anklicke, startet der Download der Excel-Datei. Die Spaltennamen und alle Inhalte werden korrekt übernommen, ausser die Umlaute. Die sehen in Excel dann so aus:
        ä wird zum Promillezeichen
        ö wird zu ^
        ü wird zu einem Cedille.

        Hier muss ich passen, ich kenne keine Zeichenkodierungen, bei denen sowas rauskäme.

        Noch ein paar andere Anmerkungen:

        $sql = "SELECT name, vorname, adresse, plz, ort FROM adressen";
        $erg = mysql_query($sql);
        while ($zeile = mysql_fetch_assoc($erg)) {

        Wenn mysql_*-Funktionen nicht erfolgreich waren geben sie false zurück statt der Ressourcenkennung, die die nachfolgende mysql_*-Funktion gern hätte. Das ergibt dann bei der nachfolgenden Funktion eine Fehlermeldung. Man sollte diese Rückgabewerte auswerten und nicht einfach so durchreichen. Ebenso sollte man probieren, was das eigene Script macht, wenn dein Fehler auftritt. Diese kann man simulieren, indem man probehalber mal

        • fehlerhafte Login-Daten verwendt (mysql_connect)
        • einen falschen Datenbanknamen angibt (mysql_select_db)
        • einen Fehler ins SQL-Statement einbaut (mysql_query)

        <a href="adressen_export.php?sql=<?php echo $sql ?>">Adressen als Excel-Tabelle herunterladen</a>
        $sql = stripslashes($_GET["sql"]);
        $erg = mysql_query($sql);

        Das SQL-Statement auf diese Weise zu übergeben ist sehr bedenklich. Kann doch nun jeder ganz beliebige eigene Statements an die Datenbank senden, die zumindest all das machen können, was mit den Rechten des verwendeten MySQL-Benutzers möglich ist.

        stripslashes) ist nur nötig, wenn Magic Quotes eingeschaltet sind. Das beste wäre, ganz auf dieses Feature zu verzichten und die Behandlung der Sonderzeichen gemäß dem Ausgabemedium selbst mit einer passenden Funktion vorzunehmen (MySQL: mysql_real_escape_string(), HTML: htmpspecialchars(), usw.). Ist es nicht möglich, die Magic Quotes zu deaktivieren, sollte man stripslashes() in Abhängigkeit von get_magic_quotes_gpc() ausführen.

        foreach($zeile as $wert) {
             if ((!isset($wert)) OR ($wert == "")) {

        isset($wert) wird an dieser Stelle immer true zurückgeben, da $wert ja vom foreach-Statement angelegt wird. Ausnahme wäre wenn ein NULL-Wert von der DB zurückkommt, dann ergäbe isset(null) false. Wenn du !isset($wert) wegen dieses NULL-Werts eingebaut hast, wäre die Absicht dahinter deutlicher zu sehen, wenn du dafür die Funktion is_null() nimmst.

        echo "$verabschiedung $name";