ingobar: csv einlesen

Hallo zusammen,

ich habe hier folgende Situation. Eine csv-Datei wird mittels

<form action="readcsv.php?kl_id=1" method="post" enctype="multipart/form-data" name="upload">
<input type="file" value="Importieren" name="csv_file" size="10">
<input type="submit" value="Daten einlesen"></form>

an die Datei readcsv geschickt. Dort möchte ich die Daten gerne in die Datenbank schreiben. Nachdem

$kl_id = mysql_escape_string($_GET['kl_id']);

$filename = $_FILES['csv_file']['tmp_name'];

$handle = fopen ($_FILES['csv_file']['tmp_name'], "r");
$content = fgets($handle);

print_r($content);

Soweit so gut. Ich bekomme die erste Zeile geliefert. Aber wie kann ich jetzt durch das File laufen? Mit JS wüsste ich es ja. Da würde ich mit split die Zeilen in Arrays zerlegen usw. Aber mit php - keine Ahnung. Welche Befehle brauche ich hier?

Ich habe beim googlen auch den Befehl load data... gefunden und habe folgendes versucht:

$kl_id = mysql_escape_string($_GET['kl_id']);

$filename = $_FILES['csv_file']['tmp_name'];

@mysql_query("LOAD DATA INFILE $filename INTO TABLE schuler FIELDS TERMINATED BY ';' (name, vname, gebdatum, gender) set (id = $kl_id)");

Leider ohne Effekt. Keine Fehlermeldung, keine Eintragung.

Kann mir mal jemand mit einem Tipp/Befehl weiterhelfen. Am Einfachsten wäre wohl der zweite Fall, oder?

  1. hi,

    Aber wie kann ich jetzt durch das File laufen?

    Mit einer Schleife?

    Da würde ich mit split die Zeilen in Arrays zerlegen usw. Aber mit php - keine Ahnung. Welche Befehle brauche ich hier?

    fgetcsv.

    gruß,
    wahsaga

    --
    /voodoo.css:
    #GeorgeWBush { position:absolute; bottom:-6ft; }
  2. Hello,

    $handle = fopen ($_FILES['csv_file']['tmp_name'], "r");

    #> $content = fgets($handle);

    $_record = array();

    while (!eof($handle))
    {
      $_record[] = fget_csv($handle);
    }

    print_r($_records);

    Mit fgets() bekommt man immer nur maximal eine Zeile.
    Wenn es sich um eine echte CSV-Datei handelt, ist fget_csv() besser, weil auch die Sonderfälle

    - Linefeed ist im Datenfeld vorhanden
      - Delimiter ist im Feld enthalten
      - Seperator ist im Feld enthalten

    abgehandelt werden.

    Seperator = Trennzeichen zwischen den Feldern, meistens Semikolon
    Delimiter = Begrenzer des Datenfeldes, meistens Doppelhäkchen

    PHP verwendet die Begriffe hier leider anders, als es für das SDF (Standard Data Format) bis zu PHP üblich war.

    Harzliche Grüße vom Berg
    http://www.annerschbarrich.de

    Tom

    --
    Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
    Nur selber lernen macht schlau

    1. Vielen Dank für die ausführliche Antwort Tom. Leider bekomme ich aber eine Fehlermedung. Mein Code

      $filename = $_FILES['csv_file']['tmp_name'];
      $handle = fopen ($_FILES['csv_file']['tmp_name'], "r");

      $content = fgets($handle);

      $_record = array();

      while (!eof($handle))
      {
        $_record[] = fget_csv($handle);
      }

      print_r($_records);

      Die Fehlermeldung:

      Fatal error: Call to undefined function eof() in /Users/username/Sites/php/readcsv.php on line 20

      Zeile 20 ist die mit dem while. Kannst du nochmal helfen?

      1. Hello,

        Vielen Dank für die ausführliche Antwort Tom. Leider bekomme ich aber eine Fehlermedung. Mein Code

        $filename = $_FILES['csv_file']['tmp_name'];

        #> $handle = fopen ($_FILES['csv_file']['tmp_name'], "r");

        $handle = fopen ($filename);

        #> $content = fgets($handle);

        $_record = array();

        while (!feof($handle))

        {
          $_record[] = fget_csv($handle);
        }

        print_r($_record);

        Es gibt http://www.php.net/ extra zum Nachschlagen...
        Wenn Du 'eof' eingegeben hättest, dann wäre eine Hilfsseite gekommen
        http://www.php.net/manual-lookup.php?pattern=eof,
        die Dir gezeigt hätte, dass ich mal wieder nicht zwischen Pascal und C (PHP) unterschieden habe :-)

        Harzliche Grüße vom Berg
        http://www.annerschbarrich.de

        Tom

        --
        Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
        Nur selber lernen macht schlau

        1. Hello,

          Hello,

          Vielen Dank für die ausführliche Antwort Tom. Leider bekomme ich aber eine Fehlermedung. Mein Code

          $filename = $_FILES['csv_file']['tmp_name'];
          #> $handle = fopen ($_FILES['csv_file']['tmp_name'], "r");

          $handle = fopen ($filename,'r');

          #> $content = fgets($handle);

          $_record = array();

          while (!feof($handle))

          {
            $_record[] = fget_csv($handle);
          }

          print_r($_record);

          Harzliche Grüße vom Berg
          http://www.annerschbarrich.de

          Tom

          --
          Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
          Nur selber lernen macht schlau

          1. $_record[] = fget_csv($handle);

            Diese Zeile habe ich mit php.net ;) noch zu

            $_record[] = fgetcsv($handle,100,";");

            abgeändert. Danke schon mal dafür.

            Kannst du mir jetzt noch verraten was ich mit falsch dargestellten Umlauten machen soll?

            Zum Beispiel habe ich ein ˆ statt ö oder ein ÷ statt Ö. Vom Hersteller der Datei habe ich auf Nachfrage nach dem Zeichensatz in der DB folgende Infos bekommen:

            german(de-utf8)
            MySQL-Zeichensatz:  UTF-8 Unicode (utf8)
            Zeichensatz / Kollation der MySQL-Verbindung utf8_general_ci

            bei den Namen latin1_german2_ci

            Und das Problem tritt natürlich in den Namen auf. Stelle ich meine DB jetzt auch auf utf-8 ein oder latin1? Sehe ich die Sonderzeichen nur, weil ich einfach nur print_r mache und damit keinen Zeichensatz in der angezeigten "HTML"-Seite habe?

            Es wäre schön, wenn du mir nochmals helfen könntest.

            1. Hello,

              Kannst du mir jetzt noch verraten was ich mit falsch dargestellten Umlauten machen soll?

              Zum Beispiel habe ich ein ˆ statt ö oder ein ÷ statt Ö. Vom Hersteller der Datei habe ich auf Nachfrage nach dem Zeichensatz in der DB folgende Infos bekommen:

              german(de-utf8)
              MySQL-Zeichensatz:  UTF-8 Unicode (utf8)
              Zeichensatz / Kollation der MySQL-Verbindung utf8_general_ci

              Da müsstest Du als allererstes eine entsprechende Umwandlung der Zeichensätze vornehmen.
              Allerdings würden dabei eventuell Informationen verloren gehen.

              Oder aber, du speicherst die Daten codiert ab und verwendest für die anschließende Darstellung wieder das passende Werkzeug. Die Soder- und Trennzeichen sollten dann im ersten Layer des utf-8-Codes liegen (0 bis 127), sodass sie ohnehin nicht von einer Umwandlung betroffen wären.

              Harzliche Grüße vom Berg
              http://www.annerschbarrich.de

              Tom

              --
              Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
              Nur selber lernen macht schlau

              1. Da müsstest Du als allererstes eine entsprechende Umwandlung der Zeichensätze vornehmen.

                Wie macht man sowas?

                Oder aber, du speicherst die Daten codiert ab und verwendest für die anschließende Darstellung wieder das passende Werkzeug. Die Soder- und Trennzeichen sollten dann im ersten Layer des utf-8-Codes liegen (0 bis 127), sodass sie ohnehin nicht von einer Umwandlung betroffen wären.

                Wie hast du das gemeint, Tom? Sorry, wenn ich das nachfrage. Es ist mein erstes php-Projekt und mir fehlen einfach Kenntnisse über mögliche Funktionen.

            2. echo $begrüßung;

              Zum Beispiel habe ich ein ˆ statt ö oder ein ÷ statt Ö.

              Das sieht nach MacRoman aus.
              Byte  MR  ISO-8859-1
              xD6   ÷      Ö
              xF6   ˆ      ö

              Vom Hersteller der Datei habe ich auf Nachfrage nach dem Zeichensatz in der DB folgende Infos bekommen:

              german(de-utf8)
              MySQL-Zeichensatz:  UTF-8 Unicode (utf8)
              Zeichensatz / Kollation der MySQL-Verbindung utf8_general_ci

              Das ist die Ausgabe der Titelseite von phpMyAdmin. Die erste Zeile ist phpMyAdmins eingestellte Sprache und Kodierung in Richtung Browser, die dritte Zeile ist phpMyAdmins Einstellung für die Kommunikation zur DB. Daraus kann man keinerlei Schlussfolgerungen für eigene Verbindungen zur DB ziehen.
              (Woher phpMyAdmin die Information für die zweite Zeile nimmt, ist mir derzeit noch unklar. Das Umstellen meines Servers auf latin1 ließ ihn nicht davon abbringen, dort weiterhin utf8 anzuzeigen.)

              Für deine Script gelten entweder die Server-Default-Werte character_set_client, character_set_connection und character_set_results (nachzulesen im phpMyAdmin auf der Seite "MySQL-System-Variablen anzeigen" in der (so vorhanden) mit "(Globaler Wert)" gekennzeichneten Zeile) oder der individuell ausgehandelte Wert. Stichwort: SET NAMES ...

              bei den Namen latin1_german2_ci

              Dieser Wert gibt an, welchen Zeichenvorrat Werte in diesem Feld haben. Weicht die Kodierung der Felder von der der Verbindung ab, übersetzt MySQL zwischen beiden hin und her. (Technisch bedingt kann es dabei auch zu Datenverlust kommen.)

              Und das Problem tritt natürlich in den Namen auf. Stelle ich meine DB jetzt auch auf utf-8 ein oder latin1?

              Das kommt darauf an, welchen Zeichenvorrat du berücksichtigen willst. Die in Westeuropa üblichen Zeichen: latin1. Alle möglichen: utf8. Wenn du dich für utf8 entscheidest, solltest du das auf ganzer Linie fahren, sonst gibt es Datenverlust beim Umwandeln.

              Sehe ich die Sonderzeichen nur, weil ich einfach nur print_r mache und damit keinen Zeichensatz in der angezeigten "HTML"-Seite habe?

              Die verwendete Zeichenkodierung sollte im HTTP-Header Content-Type angegeben werden. Ersatzweise im gleichnamigen http-equiv-Meta-Element im HTML-Header. Wenn der Browser keine Kodierungsangabe findet muss er raten oder seine Default-Einstellung verwenden. Der Browser muss immer eine Zeichenkodierung verwenden, sonst könnte er nur Byte-Werte anzeigen.

              Im Zweifelsfall solltest du dir die Byte-Werte der Zeichen *) ansehen und mit Zeichentabellen (liegen genügend in der Wikipedia rum) vergleichen.

              *) möglichst nah an der Quelle, sonst können schon wieder beteiligte Systeme daran etwas uminterpretiert/umkodiert haben.

              echo "$verabschiedung $name";

              1. Hallo,

                ich habe jetzt folgendes gemacht:

                Beim schreiben der Daten

                $db = @mysql_connect(MYSQL_HOST, MYSQL_USER, MYSQL_PASS) or die(mysql_error());
                 @mysql_select_db(MYSQL_DATABASE,$db) or die(mysql_error());
                 mysql_query("SET NAMES 'utf8'");
                 mysql_query("SET CHARACTER SET 'utf8'");

                In der php-Datei, die ein Ergebnis zeigt:

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

                Beide Dateien sind als utf-8 gespeichert im Editor gespeichert worden. Dennoch habe ich hier ein Kˆnig statt eines König.

                Noch irgendeine Idee?

                Gefunden hatte ich das übrigens in

                http://forum.de.selfhtml.org/archiv/2007/1/t143210/#m930175

                1. echo $begrüßung;

                  ich habe jetzt folgendes gemacht:
                  mysql_query("SET NAMES 'utf8'");
                  mysql_query("SET CHARACTER SET 'utf8'");

                  Eine von beiden Zeilen ist überflüssig, beide machen aber nicht das gleiche. Siehe Connection Character Sets and Collations

                  Beide Dateien sind als utf-8 gespeichert im Editor gespeichert worden. Dennoch habe ich hier ein Kˆnig statt eines König.
                  Noch irgendeine Idee?

                  Ich nehme an, du hast schon beim Einlesen in den Editor nicht darauf geachtet, die Datei mit der richtigen Zeichenkodierung zu lesen.

                  echo "$verabschiedung $name";

                  1. Eine von beiden Zeilen ist überflüssig,

                    Welche ist denn überflüssig?

                    beide machen aber nicht das gleiche. Siehe Connection Character Sets and Collations

                    Deswegen habe ich ja auch beides auf utf-8 gesetzt.

                    Beide Dateien sind als utf-8 gespeichert im Editor gespeichert worden. Dennoch habe ich hier ein Kˆnig statt eines König.
                    Noch irgendeine Idee?

                    Ich nehme an, du hast schon beim Einlesen in den Editor nicht darauf geachtet, die Datei mit der richtigen Zeichenkodierung zu lesen.

                    Da hast du mich wohl missverstanden. Die php-Datei ist als utf-8 gepspeichert. Denn Inhalt der Datei hole ich mir bei der Anzeige im Browser jedesmal neu aus der Datenbank.

                    Sonst keine Idee mehr?

                    1. echo $begrüßung;

                      Eine von beiden Zeilen ist überflüssig,
                      Welche ist denn überflüssig?

                      Bei beiden gleich ist

                      SET character_set_client = x;
                        SET character_set_results = x;

                      Der Unterschied ist die Einstellung von character_set_connection. SET NAMES setzt ihn auf den angegebenen Wert, SET CHARACTER SET setzt ihn auf die Einstellung der Datenbank. Wenn du konsequent auf nur eine Kodierung setzt, ist es egal, welche von beiden Zeilen du verwendest.

                      beide machen aber nicht das gleiche. Siehe Connection Character Sets and Collations
                      Deswegen habe ich ja auch beides auf utf-8 gesetzt.

                      Egal, wie herum du die beiden Anweisungen schreibst, die letzte überschreibt immer die erste, und macht die erste damit überflüssig.

                      Beide Dateien sind als utf-8 gespeichert im Editor gespeichert worden. Dennoch habe ich hier ein Kˆnig statt eines König.
                      Ich nehme an, du hast schon beim Einlesen in den Editor nicht darauf geachtet, die Datei mit der richtigen Zeichenkodierung zu lesen.
                      Da hast du mich wohl missverstanden. Die php-Datei ist als utf-8 gepspeichert. Denn Inhalt der Datei hole ich mir bei der Anzeige im Browser jedesmal neu aus der Datenbank.

                      Möglicherweise habe ich dich missverstanden. Wenn schon falsche Daten aus der DB kommen und auch der phpMyAdmin nicht die gewünschten Zeichen anzeigt, dann ist halt schon in der Datenbank irgendwas verkehrtes drin.

                      echo "$verabschiedung $name";

    2. echo $begrüßung;

      Seperator = Trennzeichen zwischen den Feldern, meistens Semikolon
      Delimiter = Begrenzer des Datenfeldes, meistens Doppelhäkchen
      PHP verwendet die Begriffe hier leider anders, als es für das SDF (Standard Data Format) bis zu PHP üblich war.

      Das Handbuch spricht (neuerdings?) von Delimiter (was LEO auch als Feldtrenner übersetzt) und Enclosure (z.B. mit Einfassung übersetzbar). Insofern sollte es schon eindeutig sein, was fgetcsv() mit den Parametern meint.

      echo "$verabschiedung $name";

      1. Hello,

        Das Handbuch spricht (neuerdings?) von Delimiter (was LEO auch als Feldtrenner übersetzt) und Enclosure (z.B. mit Einfassung übersetzbar). Insofern sollte es schon eindeutig sein, was fgetcsv() mit den Parametern meint.

        Das war mWn schon immer die Nomenklatur in PHP.
        Aber sowohl LEO als auch PHP sind neuer, als die bisherige Datentechnik.
        Diverse Firmen hatten sich (annodazumal) auf das SDF geeinigt.
        Das wurde dann auch bei Open Access, dBase, den Borland-Produkten, ... Standard in nder PC-Welt.
        Erst Gates hat dann "CSV" daraus gemacht und später wurden die gewählten Fachbegriffen umgedeutet...

        Wenn Daten-Konsistenz unser Besteben ist, dann sollte uns der Wandel der Begriffe nicht aus dem Augenmerk entgleiten.

        Harzliche Grüße vom Berg
        http://www.annerschbarrich.de

        Tom

        --
        Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
        Nur selber lernen macht schlau