uli: PHP Problem - fgetcsv

hallo,

habe gerade eine webseite auf einen neuen server gezogen. auf dem alten lief/läuft alles problemlos, beim neuen habe ich probleme mit fgetcsv.

und zwar öffne mit fopen und fgetcsv eine datei, trennzeichen ist §. wenn die zeile wie folgt lautet:

wert1§wert2§wert3

ist alles in ordnung. ist aber ein wert leer, zb:

wert1§§wert3

bekomme ich beim auslesen mit $zeile[1] den dritten wert statt den zweiten, welcher leer und nicht ausgeprägt ist. das bringt dann natürlich alles durcheinander..

auf dem alten server ist ist php version 4.4.9 drauf, auf dem neuen 5.2.6, beides linux.
lokal auf meinem laptop (vista) habe ich php 5.2.4 drauf, da läuft alles problemlos. falls das noch wichtig ist.

hat jemand eine idee woran das liegen könnte?

danke im voraus

gruss, uli

  1. Hallo,

    Auf php.net (Link) ist nicht festgelegt, wie ein leeres Element interpretiert wird. Hast du eine phpinfo() verfügbar von deinem neuen Server?
    Achja: zwischen 5.2.4 und 5.2.6 hat sich mehr getan als die Versionsnummern vermuten lassen, gerade in diesem Bereich. Kann auch sein, dass das PHP auf dem Server anders kompiliert worden ist, habe aber auch nichts dergleichen gefunden. Ich würde eine Klasse machen, die eine CSV-Datei kapselt und man per Array darauf zugreifen kann. Dann kann man bei solchen Problem ganz schnell alles ändern. Ist aber wahrscheinlich schwer, das nachträglich zu machen :(

    mfg, Flo

    --
    Developers are dying. Computers are getting trash. CEO's become forgetten. The only remaining things are ideas, lies and crises. So if you want to be immortal, first think, than stop it and go to microsoft and become later a manager at Lehman Brothers...
    sh:) fo:| ch:? rl:( br:^ n4:| ie:{ mo:| va:} de:> zu:} fl:{ ss:) ls:< js:|
    *Zu dem de:> Ich benutze wegen IE im moment noch tabellen, weil dieser display:table noch nicht versteht. Ich werde aber, wenn IE 6 & IE 7 < 10% mein neues CSS-Layout einspielen...
    1. hi flo,

      danke für deine fixe antwort. die ganze phpinfo kann ich hier leider nicht posten, einen link würde ich nur ungern posten, da auf dem server noch einige sachen offen sind, bevor das ganze wirklich life geht.

      welchen abschnitt brauchst du denn, dann poste ich den hier.

      danke und gruss, uli

      1. Hallo,

        Am besten PHP Core wo was mit CSV drin ist oder eine Extension, die etwas mit CSV-Dateien zu tun hat. Wenn du da nichts findest, kannst du wahrscheinlich nichts tun. Eine Idee hätte ich noch: Das ist ja nich schwer, fgetcsv selber zu machen (Kombination aus fgets und explode) und du kannst ja selber was in der Richtung proggen und dann mit einem Editor deiner Wahl beim kompletten Projekt fgetcsv durch myFgetCsv ersetzen. Dürfte nicht schwer zu realisieren sein.

        mfg, Flo

        --
        Developers are dying. Computers are getting trash. CEO's become forgetten. The only remaining things are ideas, lies and crises. So if you want to be immortal, first think, than stop it and go to microsoft and become later a manager at Lehman Brothers...
        sh:) fo:| ch:? rl:( br:^ n4:| ie:{ mo:| va:} de:> zu:} fl:{ ss:) ls:< js:|
        *Zu dem de:> Ich benutze wegen IE im moment noch tabellen, weil dieser display:table noch nicht versteht. Ich werde aber, wenn IE 6 & IE 7 < 10% mein neues CSS-Layout einspielen...
        1. ja, das mit dem selber basteln sollte kein problem sein, nur wollte ich mir das gerne ersparen. ;)

          hier der auszug: PHP Core

          Directive Local Value Master Value
          allow_call_time_pass_reference On On
          allow_url_fopen On On
          allow_url_include Off Off
          always_populate_raw_post_data Off Off
          arg_separator.input & &
          arg_separator.output & &
          asp_tags Off Off
          auto_append_file no value no value
          auto_globals_jit On On
          auto_prepend_file no value no value
          browscap no value no value
          default_charset no value no value
          default_mimetype text/html text/html
          define_syslog_variables Off Off
          disable_classes no value no value
          disable_functions no value no value
          display_errors On On
          display_startup_errors Off Off
          doc_root no value no value
          docref_ext no value no value
          docref_root no value no value
          enable_dl On On
          error_append_string no value no value
          error_log no value no value
          error_prepend_string no value no value
          error_reporting 6135 6135
          expose_php On On
          extension_dir ./ ./
          file_uploads On On
          highlight.bg #FFFFFF #FFFFFF
          highlight.comment #FF8000 #FF8000
          highlight.default #0000BB #0000BB
          highlight.html #000000 #000000
          highlight.keyword #007700 #007700
          highlight.string #DD0000 #DD0000
          html_errors On On
          ignore_repeated_errors Off Off
          ignore_repeated_source Off Off
          ignore_user_abort Off Off
          implicit_flush Off Off
          include_path .:/usr/local/lib/php .:/usr/local/lib/php
          log_errors Off Off
          log_errors_max_len 1024 1024
          magic_quotes_gpc On On
          magic_quotes_runtime Off Off
          magic_quotes_sybase Off Off
          mail.force_extra_parameters no value no value
          max_execution_time 30 30
          max_input_nesting_level 64 64
          max_input_time 60 60
          memory_limit 128M 128M
          open_basedir no value no value
          output_buffering no value no value
          output_handler no value no value
          post_max_size 8M 8M
          precision 12 12
          realpath_cache_size 16K 16K
          realpath_cache_ttl 120 120
          register_argc_argv On On
          register_globals On On
          register_long_arrays On On
          report_memleaks On On
          report_zend_debug On On
          safe_mode Off Off
          safe_mode_exec_dir no value no value
          safe_mode_gid Off Off
          safe_mode_include_dir no value no value
          sendmail_from no value no value
          sendmail_path /usr/sbin/sendmail -t -i /usr/sbin/sendmail -t -i
          serialize_precision 100 100
          short_open_tag On On
          SMTP localhost localhost
          smtp_port 25 25
          sql.safe_mode Off Off
          track_errors Off Off
          unserialize_callback_func no value no value
          upload_max_filesize 2M 2M
          upload_tmp_dir no value no value
          user_dir no value no value
          variables_order EGPCS EGPCS
          xmlrpc_error_number 0 0
          xmlrpc_errors Off Off
          y2k_compliance On On
          zend.ze1_compatibility_mode Off Off

          1. Hi,

            ja, das mit dem selber basteln sollte kein problem sein, nur wollte ich mir das gerne ersparen. ;)

            Die Nutzerkommentare zur Funktion im Manual bieten einige fertige Vorschlaege.

            MfG ChrisB

            --
            „This is the author's opinion, not necessarily that of Starbucks.“
          2. Hallo,

            magic_quotes_gpc On On
            register_globals On On
            short_open_tag On On

            wenn du Zugriff auf die Serverkonfiguration hast, würde ich dir dringend empfehlen, die genannten drei Parameter auf "off" zu setzen. Hat zwar mit deinem aktuellen Problem nichts zu tun, kann dir bei zukünftigen Projekten aber eine Menge Nerven und Ärger ersparen.

            So long,
             Martin

            --
            Das Gehirn ist schon eine tolle Sache: Es fängt ganz von allein an zu arbeiten, wenn man morgens aufsteht, und hört erst damit auf, wenn man in der Schule ankommt.
              (alte Schülererkenntnis)
  2. Guten Tag,

    auf dem alten server ist ist php version 4.4.9 drauf, auf dem neuen 5.2.6,
    beides linux.
    lokal auf meinem laptop (vista) habe ich php 5.2.4 drauf, da läuft alles
    problemlos. falls das noch wichtig ist.

    Ich testete eben mal und kann bestätigen, dass sich das Verhalten von fgetcsv() zwischen PHP 4.4.8 und 5.2.6 geändert hat.

    In PHP4(.3.0|.4.8) werden leere Element als ein String mit 0 Zeichen Länge zurückgeliefert, in PHP5 fehlt das Element einfach.

    Gruß
    Christoph Jeschke

    --
    Zend Certified Engineer
    1. Hallo Christoph,

      auf dem alten server ist ist php version 4.4.9 drauf, auf dem neuen 5.2.6,
      beides linux.
      lokal auf meinem laptop (vista) habe ich php 5.2.4 drauf, da läuft alles
      problemlos. falls das noch wichtig ist.

      Ich testete eben mal und kann bestätigen, dass sich das Verhalten von fgetcsv() zwischen PHP 4.4.8 und 5.2.6 geändert hat.

      In PHP4(.3.0|.4.8) werden leere Element als ein String mit 0 Zeichen Länge zurückgeliefert, in PHP5 fehlt das Element einfach.

      danke für den Test. Ich bin verblüfft. Im Changelog habe ich dazu nichts gefunden und auch die Bugliste zu fgetcsv() weiß nichts davon. Für mich wäre dieses Verhalten ein Bug, denn leere Einträge sind in CSV-Dateien normal und eine Funktion, die mit CSV-Dateien umgehen können will, muss mit leeren Einträgen korrekt umgehen können. Weglassen ist kein korrekter Umgang.

      Freundliche Grüße

      Vinzenz

      1. Guten Tag,

        danke für den Test. Ich bin verblüfft. Im Changelog habe ich dazu nichts
        gefunden und auch die Bugliste zu fgetcsv() weiß nichts davon. Für mich
        wäre dieses Verhalten ein Bug, denn leere Einträge sind in CSV-Dateien #
        normal und eine Funktion, die mit CSV-Dateien umgehen können will, muss mit
        leeren Einträgen korrekt umgehen können. Weglassen ist kein korrekter
        Umgang.

        Streng genommen müssen Felder auch Zeichen enthalten (so sagt es RFC4180). Andererseits verstößt das Verhalten gegen RFC793.

        Gruß
        Christoph Jeschke

        --
        Zend Certified Engineer
        1. Hallo Christoph,

          danke für den Test. Ich bin verblüfft. Im Changelog habe ich dazu nichts
          gefunden und auch die Bugliste zu fgetcsv() weiß nichts davon.

          erst mal vielen Dank für das Eintragen in die Bugliste. Das hätte ich mir sonst für heute vorgenommen :-)

          wäre dieses Verhalten ein Bug, denn leere Einträge sind in CSV-Dateien #
          normal und eine Funktion, die mit CSV-Dateien umgehen können will, muss mit
          leeren Einträgen korrekt umgehen können. Weglassen ist kein korrekter
          Umgang.

          Streng genommen müssen Felder auch Zeichen enthalten (so sagt es RFC4180). Andererseits verstößt das Verhalten gegen RFC793.

          Nein, RFC4180 erlaubt leere Einträge, schauen wir es uns an:

          <zitat quelle = RFC4180, Abschnitt 2>
             file = [header CRLF] record *(CRLF record) [CRLF]
             header = name *(COMMA name)
             record = field *(COMMA field)
             name = field
             field = (escaped / non-escaped)
             escaped = DQUOTE *(TEXTDATA / COMMA / CR / LF / 2DQUOTE) DQUOTE
             non-escaped = *TEXTDATA
          <zitat>

          mit RFC2234, in der die Augmented Backus-Naur-Form spezifiziert wird:

          <zitat quelle = RFC2234, Abschnitt 3.6>
             Default values are 0 and infinity so that *<element> allows any
             number, including zero; 1*<element> requires at  least  one;
          </zitat>

          Da nun entweder *TEXTDATA oder DQUOTE *(TEXTDATA / ...) DQUOTE gilt, folgt, dass leere Einträge erlaubt sind, was sinnvoll und notwendig ist.

          Freundliche Grüße

          Vinzenz

          1. Guten Tag,

            Da nun entweder *TEXTDATA oder DQUOTE *(TEXTDATA / ...) DQUOTE gilt, folgt, dass leere Einträge erlaubt sind, was sinnvoll und notwendig ist.

            Danke für die Korrektur.

            Gruß
            Christoph Jeschke

            --
            Zend Certified Engineer
      2. Guten Tag,

        danke für den Test. Ich bin verblüfft. Im Changelog habe ich dazu nichts
        gefunden und auch die Bugliste zu fgetcsv() weiß nichts davon.

        Jetzt schon.

        Gruß
        Christoph Jeschke

        --
        Zend Certified Engineer
        1. Hallo Christoph,

          danke für den Test. Ich bin verblüfft. Im Changelog habe ich dazu nichts
          gefunden und auch die Bugliste zu fgetcsv() weiß nichts davon.

          Jetzt schon.

          ich kann den Bug nicht reproduzieren. Ich kann nur nachvollziehen, dass es mit dem Paragraphenzeichen als Trennzeichen Probleme gibt. Bei mir sieht es so aus, dass das Paragraphenzeichen überhaupt nicht gefunden wird.

          Skript sowie CSV-Datei sind UTF-8-codiert. Auch mit einer Kopie aus Deiner Bugmeldung erhalte ich das gleiche Resultat - genauso mit einer vom gleichen Skript geschriebenen CSV-Datei.

          Mit typischen Trennzeichen wie dem Komma oder dem Semikolon erhalte ich das erwartete Resultat mit leeren Feldern.

          Getestet mit:
          PHP 5.2.6 unter Windows (Zip-Archiv von php.net)
          PHP 5.2.6-5 unter Debian Lenny

          Freundliche Grüße

          Vinzenz

    2. Hello,

      Ich testete eben mal und kann bestätigen, dass sich das Verhalten von fgetcsv() zwischen PHP 4.4.8 und 5.2.6 geändert hat.

      In PHP4(.3.0|.4.8) werden leere Element als ein String mit 0 Zeichen Länge zurückgeliefert, in PHP5 fehlt das Element einfach.

      Ich habe das eben in ellenlanger Sitzung (das verflixte Semikolon hinter der while-Schleife *duck*) auch nochmal ausprobiert.

      Hier das Ergebnis:

      Das Script:

      <?php    ### fgetcsv01.php ###

      Im welche Typen werden unterschiedliche Elemente umgesetzt?

      #------------------------------------------------
      function show(&$_data)
      {
              echo "<pre\r\n>";
      #        echo htmlspecialchars(print_r(func_get_args(),1));
              var_dump($_data);
              echo "</pre\r\n>";
      }
      #------------------------------------------------
      $filename = "csv01.txt";

      define('MAX_LINE_LENGTH', 4096);
      define('FIELD_SEPARATOR', ';');
      define('FIELD_ENCLOSURE', '"');

      echo "<h2>PHP-Version: ".phpversion()."</h2>\r\n";

      ini_set('auto_detect_line_endings','true');

      $fh = fopen($filename,  'rb');

      $_rec = array();
      $_list = array();

      if ($fh)
      {
          echo "<pre\r\n>";
          while (!feof($fh))
          {
              $buffer = fgets($fh, MAX_LINE_LENGTH);
              echo htmlspecialchars($buffer);
          }
          echo "</pre\r\n>";

      rewind($fh);

      while (( $_rec = fgetcsv($fh, MAX_LINE_LENGTH, FIELD_SEPARATOR, FIELD_ENCLOSURE)) !== false )
      #    while (( $_rec = fgetcsv($fh)) !== false )
          {
              show($_rec);
              $_list[] = $_rec;
          }

      fclose($fh);
          show($_list);
      }
      ?>

      PHP-Version: 5.2.5 im XAMPP

      1;"Erste Zeile";0;"Text"
      2;"Zeite Zeile";0.11;"mehr Text"
      3;"Dritte Zeile";;"kein Eintrag vorhanden"

      5;"nach der Leerzeile";22;"letzter Eintrag"

      array(4) {
        [0]=>
        string(1) "1"
        [1]=>
        string(11) "Erste Zeile"
        [2]=>
        string(1) "0"
        [3]=>
        string(4) "Text"
      }

      array(4) {
        [0]=>
        string(1) "2"
        [1]=>
        string(11) "Zeite Zeile"
        [2]=>
        string(4) "0.11"
        [3]=>
        string(9) "mehr Text"
      }

      array(4) {
        [0]=>
        string(1) "3"
        [1]=>
        string(12) "Dritte Zeile"
        [2]=>
        string(0) ""
        [3]=>
        string(22) "kein Eintrag vorhanden"
      }

      array(1) {
        [0]=>
        string(0) ""
      }

      array(4) {
        [0]=>
        string(1) "5"
        [1]=>
        string(18) "nach der Leerzeile"
        [2]=>
        string(2) "22"
        [3]=>
        string(15) "letzter Eintrag"
      }

      Könnte es sein, dass in der nächsten PHP-Version versucht wurde, die Typenumsetzung einzubauen?
      Wenn Enclosures angegeben werden, werden nicht eingeschlossene Felder als Numeric, eingeschlossene  Felder als String und nicht eingeschlossene leere Felder als NULL dargestellt. Das hat es meiner Erinnerung nach schon mal bei einer älteren PHP-Version gegeben.

      Leider kollidierte das mit dem Array-Verhalten. Ein Array-Element, dem man NULL zuwies, verschwand einfach aus der Liste.

      Liebe Grüße aus Syburg bei Dortmund

      Tom vom Berg

      --
      Nur selber lernen macht schlau
      http://bergpost.annerschbarrich.de