Jo: PHP Curl memory Fehler

Hallo ich hole mittels Curl in PHP teilweise recht große Daten von unterschiedlichen Server:

//Daten mittels Curl zurückgeben
function get_data($url){
  $ch = curl_init();
  $timeout = 5;
  curl_setopt($ch,CURLOPT_URL,$url);
  if($GLOBALS["wms_proxy"]){
	curl_setopt($ch, CURLOPT_PROXY, $GLOBALS["wms_proxy_host"]);
	curl_setopt($ch, CURLOPT_PROXYPORT, $GLOBALS["wms_proxy_port"]);	  
  }
  curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
  curl_setopt($ch,CURLOPT_CONNECTTIMEOUT,$timeout);
  $data = curl_exec($ch);
  curl_close($ch);
  return $data;
}

Wenn die Daten zu groß werden kommt es manchmal zu folgender Fehlermeldung (auf die Zeile $data = curl_exec($ch); ):

Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 133961509 bytes) in

Das Memory Limit in der PHP.ini will ich nicht ändern, wie kann ich das abfangen und den Fehler sauber behandeln?

Danke Jochen

  1. Hallo Jo,

    Wenn die Daten zu groß werden kommt es manchmal zu folgender Fehlermeldung (auf die Zeile $data = curl_exec($ch); ):

    Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 133961509 bytes) in

    Das Memory Limit in der PHP.ini will ich nicht ändern, wie kann ich das abfangen und den Fehler sauber behandeln?

    Die kurze Antwort: gar nicht.

    Die lange Antwort: PHP stellt keine konventionellen Mittel zur Verfügung, um fatal errors abzufangen, weil sie nicht möchten, dass die abgefangen werden. Das einzige, was du tun kannst, ist einen Shutdown-Handler zu registrieren und dort zu prüfen, ob ein Fehler vorliegt:

    register_shutdown_function("my_shutdown_handler");
    
    function my_shutdown_handler() {
      $error = error_get_last();
    
      if($error !== NULL) {
        // tu was
      }
    }
    

    LG,
    CK

  2. Tach!

    Wenn die Daten zu groß werden kommt es manchmal zu folgender Fehlermeldung [...]

    Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 133961509 bytes) in

    Das Memory Limit in der PHP.ini will ich nicht ändern, wie kann ich das abfangen und den Fehler sauber behandeln?

    Nicht abfangen, vermeiden lautet die Devise. Es gibt die Option CURLOPT_FILE und auch CURLOPT_WRITEFUNCTION.

    dedlfix.

    1. Nicht abfangen, vermeiden lautet die Devise. Es gibt die Option CURLOPT_FILE und auch CURLOPT_WRITEFUNCTION.

      O.K., danke für den Tipp, ich hab nun folgendes ausprobiert:

      //Daten mittels Curl zurückgeben
      function get_data($url){
        $ch = curl_init();
        curl_setopt($ch,CURLOPT_URL,$url);
        if($GLOBALS["wms_proxy"]){
      	curl_setopt($ch, CURLOPT_PROXY, $GLOBALS["wms_proxy_host"]);
      	curl_setopt($ch, CURLOPT_PROXYPORT, $GLOBALS["wms_proxy_port"]);	  
        }
        curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
        curl_setopt($ch,CURLOPT_CONNECTTIMEOUT,5);
        curl_setopt($ch, CURLOPT_WRITEFUNCTION, 'curl_write_function');
        $data = curl_exec($ch);
        curl_close($ch);
        return $data;
      }
      
      //Curl write Funktion zum Abfangen von zu großen Datenanfragen
      $curl_data_string = "";
      function curl_write_function($handle, $data) {
      	global $curl_data_string;
      	$curl_data_string .= $data;
      	if (strlen($curl_data_string) > 100000) {
      		return 0;
      	}else {
      		return strlen($data);
      	}
      }
      

      Verstehe ich das richtig, die Anfrage wird gestoppt, wenn die Länge des z.B. angefragten XML-Dokumentes mehr als 100000 Zeichen hat und gibt dann nix zurück? Wenn die Bedingung erfüllt wird bekomme immer eine 1 zurück. Das klappt auch, muss ich also diese Bedingung abfragen und bei 1 den Curl Request erneut ohne CURLOPT_WRITEFUNCTION absetzen?

      ??? Jo

      1. Tach!

        Nicht abfangen, vermeiden lautet die Devise. Es gibt die Option CURLOPT_FILE und auch CURLOPT_WRITEFUNCTION.

        curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);

        Beim RETURNTRANSFER war doch das Problem, dass die Datei vollständig in den Speicher geladen wurde und der dann platzte. Das gilt es doch grade zu vermeiden. Und deswegen meinte ich, du sollst das gleich in eien Datei schreiben lassen.

        function curl_write_function($handle, $data) {
        	global $curl_data_string;
        	$curl_data_string .= $data;
        	if (strlen($curl_data_string) > 100000) {
        		return 0;
        	}else {
        		return strlen($data);
        	}
        }
        

        Damit jedenfalls hast du nichts gewonnen. Diese Funktion legt nun global einen String mit dem Inhalt an. Der wird ständig stückchenweise länger und muss dazu gegebenenfalls umkopiert werden. Es kann sein, dass du nun bei kleineren Dateien schon auf das Speicherlimit stößt.

        Verstehe ich das richtig, die Anfrage wird gestoppt, wenn die Länge des z.B. angefragten XML-Dokumentes mehr als 100000 Zeichen hat und gibt dann nix zurück? Wenn die Bedingung erfüllt wird bekomme immer eine 1 zurück.

        Vermutlich. Probier es aus. Aber, hmm? Wenn dir das Dokument zu groß ist, dann lässt du es einfach bleiben, es zu verarbeiten?

        Das klappt auch, muss ich also diese Bedingung abfragen und bei 1 den Curl Request erneut ohne CURLOPT_WRITEFUNCTION absetzen?

        Was ist mit dem Inhalt von $curl_data_string?

        Was ist denn dein eigentliches Ziel? Müssen die Daten unbedingt vollständig im Speicher sein?

        XML sagst du. Willst du das dann noch auswerten? Das belegt dann unter Umständen noch mehr Speicher, wenn du daraus einen DOM-Baum erstellst. Wenn dir nun keine Methode einfällt, das Teil häppchenweise zu verarbeiten, wirst du um ein höheres Speicherlimit nicht umhin kommen.

        dedlfix.

        1. Moin!

          XML sagst du. Willst du das dann noch auswerten? Das belegt dann unter Umständen noch mehr Speicher, wenn du daraus einen DOM-Baum erstellst. Wenn dir nun keine Methode einfällt, das Teil häppchenweise zu verarbeiten, wirst du um ein höheres Speicherlimit nicht umhin kommen.

          Womit wir dann auch wieder bei einem der Nachteile von XML wären: Lässt sich nicht (wirklich) zeilenweise, also speicherschonend verarbeiten. Stellt sich die Frage ob man das Grundübel beseitigen kann in dem man z.B. CSV benutzt. (Dazu müsste man mehr über die Datenstruktur wissen.)

          Jörg Reinholz

          1. Tach!

            Womit wir dann auch wieder bei einem der Nachteile von XML wären: Lässt sich nicht (wirklich) zeilenweise, also speicherschonend verarbeiten.

            Das geht schon, nur nicht mit DOM-Methoden.

            dedlfix.

            1. Moin!

              Tach!

              Womit wir dann auch wieder bei einem der Nachteile von XML wären: Lässt sich nicht (wirklich) zeilenweise, also speicherschonend verarbeiten.

              Das geht schon, nur nicht mit DOM-Methoden.

              dedlfix.

              Also ... griffiges dazu habe ich dort nicht gefunden, nur dass scheinbar (lib)expat (soll streamorientiert arbeiten können, was ja passen würde) benutzt wird. Auch in den Beispielen wird das XML komplett eingelesen, darunter dann Bockstürze wie:

              $data = implode("", file($file));
              

              (Nicht zu Hause nachmachen, Kinder!)

              Jörg Reinholz

              1. Tach!

                Also ... griffiges dazu habe ich dort nicht gefunden, nur dass scheinbar (lib)expat (soll streamorientiert arbeiten können, was ja passen würde) benutzt wird. Auch in den Beispielen wird das XML komplett eingelesen, darunter dann Bockstürze wie:

                xml_parse_into_struct() ist ja auch wieder ein „alles auf einmal“. Das stückweise Verarbeiten geht mit dem Setzen von Handlern und dem Füttern von xml_parse().

                dedlfix.

                1. Moin!

                  Das stückweise Verarbeiten geht mit dem Setzen von Handlern und dem Füttern von xml_parse().

                  Zeigen!

                  Jörg Reinholz

                  1. Tach!

                    Das stückweise Verarbeiten geht mit dem Setzen von Handlern und dem Füttern von xml_parse().

                    Zeigen!

                    Lesen! Erster Nutzerkommentar bei xml_parse()

                    dedlfix.

                    1. Moin!

                      Lesen! Erster Nutzerkommentar bei xml_parse()

                      Hatte es gerade selbst herausgefunden:

                      <?php
                      class Books {
                        protected $parser;
                        protected $elementStack = array();
                        protected $authors = array();
                      
                        public function __construct() {
                          $this->parser = xml_parser_create();
                      
                          xml_set_object($this->parser, $this);
                      
                          xml_set_element_handler(
                            $this->parser,
                            'startElement',
                            'endElement'
                          );
                      
                          xml_set_character_data_handler(
                            $this->parser,
                            'characterData'
                          );
                      
                          xml_set_default_handler(
                            $this->parser,
                            'characterData'
                          );
                        }
                      
                        public function __destruct() {
                          xml_parser_free($this->parser);
                        }
                      
                        /*
                        public function readCatalog($catalog) {
                          xml_parse(
                            $this->parser,
                            file_get_contents($catalog),
                            TRUE
                          );
                        }
                        */
                      
                        public function readCatalog($catalog) {
                          $handle = fopen($catalog, "r");
                          if ($handle) {
                              while ( ($buffer = fgets($handle)) !== false ) {
                                  xml_parse(
                                      $this->parser,
                                      $buffer,
                                      FALSE
                                  );
                              }
                              xml_parse( $this->parser,'',TRUE);
                          }
                        }
                      
                      
                        protected function  startElement($parser, $element, $attributes) {
                          array_push($this->elementStack, $element);
                      
                          if ($element == 'BOOK') {
                            $this->authors = array();
                          }
                        }
                      
                        protected function endElement($parser, $element) {
                          array_pop($this->elementStack);
                        }
                      
                        protected function characterData($parser, $cdata) {
                          $level   = sizeof($this->elementStack) - 1;
                          $element = $this->elementStack[$level];
                      
                          switch($element) {
                              case 'AUTHOR': {
                                $this->authors[] = $cdata;
                              }
                              break;
                      
                              case 'TITLE': {
                                print 'Autoren: ' . implode(', ', $this->authors) . "\n";
                                print 'Titel: ' . $cdata . "\n";
                              }
                              break;
                      
                              case 'ISBN': {
                                print 'ISBN: ' . $cdata . "\n\n";
                              }
                              break;
                          }
                        }
                      }
                      
                      $books = new Books;
                      $books->readCatalog('books.xml');
                      ?>
                      

                      books.xml:

                      <BOOKS>
                          <BOOK>
                              <AUTHOR>Sebastian Bergmann</AUTHOR>
                              <TITLE>Professionelle Softwareentwicklung mit PHP 5</TITLE>
                              <ISBN>ISBN: 3-89864-229-1</ISBN>
                          </BOOK>
                          <BOOK>
                              <AUTHOR>Hakan Kücükyilmaz, Thomas M. Haas, Alexander Merz</AUTHOR>
                              <TITLE>PHP 5</TITLE>
                              <ISBN>3-89864-236-4</ISBN>
                          </BOOK>
                      </BOOKS>
                      

                      Jörg Reinholz

                      1. Hallo Jörg,

                            while ( ($buffer = fgets($handle)) !== false ) {
                        

                        Arbeite nicht Zeilenweise, sondern mit Chunks. Ein XML-Dokument vollständig in einer Zeile ist mindestens well-formed (die DTD muss auf einer eigenen Zeile stehen) und keine Seltenheit bei maschinell erstellten Dokumenten. In dem Fall würdest du wieder das ganze Dokument in einem Rutsch lesen.

                        LG,
                        CK

                        1. Moin!

                          Arbeite nicht Zeilenweise, sondern mit Chunks. Ein XML-Dokument vollständig in einer Zeile ist mindestens well-formed (die DTD muss auf einer eigenen Zeile stehen) und keine Seltenheit bei maschinell erstellten Dokumenten. In dem Fall würdest du wieder das ganze Dokument in einem Rutsch lesen.

                          Das ist mir eben so klar wie Dir. Aber für das "10-Minuten-Beispiel" wollte ich mir nicht das Hirn und die Tastatur zermartern, wie ich in PHP schnell aus einem einzeiligen XML ein mehrzeiliges erhalte ohne das gesamte Dokument zu lesen. Vermutlich würde ich das auch extern mit sed lösen.

                          Jörg Reinholz

                          1. Hallo Jörg,

                            Vermutlich würde ich das auch extern mit sed lösen.

                            Wozu?

                            LG,
                            CK

          2. Moin!

            Ja-Nee, war klar. Jetzt werden natürlich die Glaubenskriege über [+][-] ausgefochten. Sachlich ist die Aussage nämlich nicht zu widerlegen. Freilich kann man eine Datei auch byteweise auslesen und einen Parser füttern. Ich befürchte nur, dann gibt es Probleme mit der zulässigen Laufzeit, die - genau wie der zulässige Speicher - auch nicht erhöht werden soll.

            Da stellt sich wieder die Frage, warum nicht? Ist es etwa ein Vorgang, den Benutzer einer Webseite auslösen? Wenn das nämlich nicht der Fall ist, dann stellt sich die Frage, warum (zum Teufel) der Vorgang in PHP abgearbeitet werden soll.

            Jörg Reinholz

            1. Hallo Jörg,

              Ja-Nee, war klar. Jetzt werden natürlich die Glaubenskriege über [+][-] ausgefochten.

              Deine Aversion gegen negative Bewertungen ist mir schonmal aufgefallen. Warum nimmst du dir das zu so sehr Herzen? Die Gründe für ein +/- sind vielfältig und privat (von Aversion über Ton des Postings hin zu sachlichen Gründen), du solltest die Entscheidung des Einzelnen hinnehmen.

              Sachlich ist die Aussage nämlich nicht zu widerlegen.

              Falsch. SAX-Parser arbeiten schon seit Ewigkeiten in Chunks. Deshalb hat man sie ja erfunden: weil damit eben nicht das ganze Dokument im Speicher gehalten werden muss. Dafür ist die API komplizierter.

              LG,
              CK

              1. Moin!

                Hallo Jörg,

                Ja-Nee, war klar. Jetzt werden natürlich die Glaubenskriege über [+][-] ausgefochten.

                Sachlich ist die Aussage nämlich nicht zu widerlegen.

                Falsch. SAX-Parser arbeiten schon seit Ewigkeiten in Chunks.

                Mag sein. Aber wie realisiere ich das in PHP? Ich finde nur Beispiele, bei denen die Daten zunächst komplett gelesen werden - womit wir ja wieder beim Ausgangsproblem landen. Also sowas wie das hier:

                http://professionelle-softwareentwicklung-mit-php5.de/programming-php.xml.sax.html

                 public function readCatalog($catalog) {
                    xml_parse(
                      $this->parser,
                      file_get_contents($catalog), # hier käme es zur Verletzung der Speicherbegrenzungs-Regel
                      TRUE
                    );
                  }
                

                Deshalb hat man sie ja erfunden: weil damit eben nicht das ganze Dokument im Speicher gehalten werden muss. Dafür ist die API komplizierter.

                Wie gefragt: Wie übergebe ich einen Stream, Chunks, Zeilen - aber nicht das gesamte XML-Dokument?

                Jörg Reinholz

                1. Hallo Jörg,

                  Sachlich ist die Aussage nämlich nicht zu widerlegen.

                  Falsch. SAX-Parser arbeiten schon seit Ewigkeiten in Chunks.

                  Mag sein. Aber wie realisiere ich das in PHP? Ich finde nur Beispiele, bei denen die Daten zunächst komplett gelesen werden - womit wir ja wieder beim Ausgangsproblem landen. Also sowas wie das hier:

                  Pseudo-Code (also, schon PHP, aber so wird es nicht funktionieren; es zeigt nur das Schema):

                  $parser = xml_parser_create();
                  xml_set_element_handler($parser, 'myStartHandler', 'myEndHandler');
                  xml_set_character_data_handler($parser, 'myCharHandler'); 
                  
                  $fd = fopen('file', 'r');
                  
                  while(($data = fread($fp, 512))) {
                    if(!xml_parse($parser, $data, feof($fd))) { 
                      echo "Error in document";
                    }
                  }
                  

                  Das würde ein Dokument in 512-Byte-Blöcken lesen und parsen. Die Handler musst du dir selber bauen.

                  LG,
                  CK

                  Edit: Huch, der Parse-Prototyp war da falsch, den hatte ich mir nur dahin kopiert um ihn nicht im Kopf haben zu müssen

                  1. Moin!

                    Das würde ein Dokument in 512-Byte-Blöcken lesen und parsen. Die Handler musst du dir selber bauen.

                    Da sollte man dem Jo noch auf den Weg geben, dass, da er ja eine recht große Datenmenge hat, 512-Byte-Blöcke "nicht in jedem Fall ideal" sind. Da könnten schon die Festplatten die Daten recht langsam liefern. Ich habe jedenfalls bei mir festgestellt, dass dd je nach Platte(!) mit einer Blocksize von 2048 oder 8196 die beste Performance liefert - die auch wieder zusammenbricht, wenn ich bs auf 16384 setze.

                    Jörg Reinholz

          3. Moin!

            XML sagst du. Willst du das dann noch auswerten? Das belegt dann unter Umständen noch mehr Speicher, wenn du daraus einen DOM-Baum erstellst. Wenn dir nun keine Methode einfällt, das Teil häppchenweise zu verarbeiten, wirst du um ein höheres Speicherlimit nicht umhin kommen.

            Womit wir dann auch wieder bei einem der Nachteile von XML wären: Lässt sich nicht (wirklich) zeilenweise, also speicherschonend verarbeiten. Stellt sich die Frage ob man das Grundübel beseitigen kann in dem man z.B. CSV benutzt. (Dazu müsste man mehr über die Datenstruktur wissen.)

            Niemand will CSV nutzen! CSV ist das Synonym für "irgendein Dateiformat, feld- bzw. tabellenbasiert, mit irgendwelchen Trennzeichen, irgendwelchen Stringbegrenzern und irgendwelchen Escape-Zeichen".

            So einen Mist, wie man ihn in CSV-Dateien findet, findet man nicht mal in /dev/urandom.

            Also in ziviler Sprache ausgedrückt: Das sogenannte CSV-Dateiformat ist extrem unterspezifiziert und sorgt durch die Vielfalt an möglichen Formaten und die Unmöglichkeit der Kennzeichnung des konkret verwendeten Formats in einem Metadatenkanal für häufige Inkompatibilitätsprobleme.

            Grüße Sven

            1. Hallo,

              Also in ziviler Sprache ausgedrückt: Das sogenannte CSV-Dateiformat ist extrem unterspezifiziert und sorgt durch die Vielfalt an möglichen Formaten und die Unmöglichkeit der Kennzeichnung des konkret verwendeten Formats in einem Metadatenkanal für häufige Inkompatibilitätsprobleme.

              also genau wie TIFF im Bereich der Grafikformate. Und trotzdem gibt es eine Menge Leute, die es für das Beste seit geschnitten Brot halten. Warum sollte das für CSV nicht gelten? ;-)

              So long,
               Martin

              1. Moin!

                Hallo,

                Also in ziviler Sprache ausgedrückt: Das sogenannte CSV-Dateiformat ist extrem unterspezifiziert und sorgt durch die Vielfalt an möglichen Formaten und die Unmöglichkeit der Kennzeichnung des konkret verwendeten Formats in einem Metadatenkanal für häufige Inkompatibilitätsprobleme.

                also genau wie TIFF im Bereich der Grafikformate. Und trotzdem gibt es eine Menge Leute, die es für das Beste seit geschnitten Brot halten. Warum sollte das für CSV nicht gelten? ;-)

                Immerhin ist TIFF "tagged". Man weiß also, wie man die Daten zu interpretieren hat, es ist "nur" sehr komplex. Bei CSV gilt dies nicht - da weiß man nichts.

                Außerdem ist TIFF ungeeignet, große Bilder zu speichern. Die internen Pointer sind nur 32 Bit breit, bei 4 GB ist also Schluss - abgesehen von der Problematik, aufgrund von Rückwärtspointern eventuell das gesamte Bild im Speicher halten zu müssen.

                Grüße Sven

                1. Hi,

                  also genau wie TIFF im Bereich der Grafikformate. Und trotzdem gibt es eine Menge Leute, die es für das Beste seit geschnitten Brot halten. Warum sollte das für CSV nicht gelten? ;-)

                  Immerhin ist TIFF "tagged". Man weiß also, wie man die Daten zu interpretieren hat, es ist "nur" sehr komplex.

                  ja, und es bedeutet letztendlich doch, dass das Format Glückssache ist. Selbst wenn ein Programm behauptet, mit TIFF umgehen zu können, heißt das noch nicht unbedingt, dass es auch mit einem ganz betimmten TIFF-Bild umgehen kann. Denn die meisten Programme unterstützen nur einen Teil der TIFF-Spezifikation. Glückssache, wenn es gerade der Teil ist, den das vorliegende TIFF-Bild auch verwendet.

                  Bei CSV gilt dies nicht - da weiß man nichts.

                  Richtig, aber wie Robert alias frankx schon erwähnt, gibt es typische Werte, die in schätzungsweise 90% der Fälle passen. Mit LF oder CR/LF als Datensatztrenner, Komma oder Tab als Feldtrenner (seltener auch ein Semikolon) und Anführungszeichen als Stringbegrenzer bin ich bisher immer gut gefahren. Egal ob ich selbst CSV-Dateien erzeugt habe oder welche aus anderen Quellen bekommen habe. Nur sehr selten musste ich eine gewisse Heuristik anwenden.

                  Außerdem ist TIFF ungeeignet, große Bilder zu speichern. Die internen Pointer sind nur 32 Bit breit, bei 4 GB ist also Schluss

                  Hast du schon mal ein Bild gesehen, das tatsächlich in den GB-Bereich kommt? Die größten Bilddateien, die ich je in den Fingern hatte, lagen im zweistelligen MB-Bereich.

                  So long,
                   Martin

            2. Ahoi Sven

              Also in ziviler Sprache ausgedrückt: Das sogenannte CSV-Dateiformat ist extrem unterspezifiziert und sorgt durch die Vielfalt an möglichen Formaten und die Unmöglichkeit der Kennzeichnung des konkret verwendeten Formats in einem Metadatenkanal für häufige Inkompatibilitätsprobleme.

              Da hast für die berufliche Praxis sicher recht, ich fand das Format immer ganz cool,

              es braucht
              ein Zeichen als Umgebungszeichen (eigentlich das Anführungszeichen)
              ein Zeichen als Spaltentrenner (eigentlich das Komma)
              ein Zeichen als Zeilentrenner (eigentlich die Absatzmarke)

              tauchen Spaltentrenner oder Zeilentrenner in der Zelle auf, wird ein Umgebungszeichen drum rumgemacht. Soll das Umgebungszeichen auftauchen, wir es verdoppelt. Feine Sache, wie ich finde. Eigentlich.
              http://tools.ietf.org/html/rfc4180, http://de.wikipedia.org/wiki/CSV_%28Dateiformat%29, http://php.net/manual/de/function.fgetcsv.php.

              Dank und Gruß,

              bob from berlin

              1. Hallo,

                tauchen Spaltentrenner oder Zeilentrenner in der Zelle auf, wird ein Umgebungszeichen drum rumgemacht.

                ist das so?

                Soll das Umgebungszeichen auftauchen, wir es verdoppelt.

                ist das so?

                Feine Sache, wie ich finde. Eigentlich.

                und uneigentlich?
                Da wo Absprachen stattfanden und klar ist, mit welcher software gearbeitet wird, sprich alle Unwägbarkeiten abgewogen wurden, spricht nix gegen den Einsatz von csv.

                Gruß
                Kalk

                1. Ahoi Tabellenkalk

                  Hallo,

                  tauchen Spaltentrenner oder Zeilentrenner in der Zelle auf, wird ein Umgebungszeichen drum rumgemacht.

                  ist das so?

                  Soll das Umgebungszeichen auftauchen, wir es verdoppelt.

                  ist das so?

                  Feine Sache, wie ich finde. Eigentlich.

                  und uneigentlich?
                  Da wo Absprachen stattfanden und klar ist, mit welcher software gearbeitet wird, sprich alle Unwägbarkeiten abgewogen wurden, spricht nix gegen den Einsatz von csv.

                  Ich hatte ja den RFC dazu verlinkt. Ich weiß ehrlich gesagt nicht, ob es so ist, ich finde aber, dass das ein "cooles" Format ist: Wähle drei x-beliebige Zeichen (Umgebungsvar, Spaltentrenner, Zeilentrenner) und escape allein die Umgebungsvar, indem Du sie zum Escapen verdoppelst. Wieso PHP da noch ein Escape-Zeichen bei fgetcsv() braucht, weiß ich nicht.

                  Rein praktisch nutze ich es allein, um aus Excel "rauszukommen" (mit VBA eine CSV erstellen). Die wiederum lässt sich dann mit PHP einlesen.

                  Klar auch, dass wenn jeder macht wie er will (Excel bzw. MS zB. indem per VBA erzeugtes CSV anderer Delimiter hat als per Menü), dann "funzt" es natürlich nicht. Die zu Grunde liegende Logik (ich wiederhole mich), dünkt mir aber "extrem" praktikabel. Is ja nicht so kompliziert, und "man" könnte sich ja mal schlicht auf die drei (oder vier \n\r) Ascii Zeichen einigen, die da in Frage kommen.

                  Dank und Gruß,

                  bob from berlin

                  1. Liebe Mitdenker, liebe Wissende, liebe Neugierige,

                    Ich hatte ja den RFC dazu verlinkt. Ich weiß ehrlich gesagt nicht, ob es so ist, ich finde aber, dass das ein "cooles" Format ist: Wähle drei x-beliebige Zeichen (Umgebungsvar, Spaltentrenner, Zeilentrenner) und escape allein die Umgebungsvar, indem Du sie zum Escapen verdoppelst.

                    Wieso PHP da noch ein Escape-Zeichen bei fgetcsv() braucht, weiß ich nicht.

                    Um auch unsaubere Formate lesen zu können, in denen mit Escape-Character anstelle von Verdoppelung gearbeitet wurde oder Kommata, Semikola usw. im Text vorkommen, ohne dass dieser in Anführungszeichen (oder wie festgelegt) eingeschlossen ist.

                    Es ist ein ganz hilfreicher Versuch, sich einen eigenen Parser zu ersparen für verknotete Texte.

                    Spirituelle Grüße
                    Euer Robert
                    robert.r@online.de

                    --
                    Möge der wahre Forumsgeist ewig leben!
                  2. Hi,

                    [...] ich finde aber, dass das ein "cooles" Format ist: Wähle drei x-beliebige Zeichen (Umgebungsvar, Spaltentrenner, Zeilentrenner) und escape allein die Umgebungsvar, indem Du sie zum Escapen verdoppelst.

                    ja, ich mag CSV grundsätzlich auch gern, zumal es gegenüber vielen "besseren", aber proprietären Formaten noch einen Vorteil hat: Es lässt sich mit einem gewöhnlichen Texteditor öffnen und als Klartext lesen. Das ist bei XML-basierten Formaten schon etwas umständlicher.

                    Rein praktisch nutze ich es allein, um aus Excel "rauszukommen" (mit VBA eine CSV erstellen).

                    Ich gehe gern genau den umgekehrten Weg: Ich erzeuge z.B. Messprotokolle als CSV, um sie dann mit Excel oder LO Calc zu importieren und z.B. Diagramme daraus zu machen.

                    Klar auch, dass wenn jeder macht wie er will (Excel bzw. MS zB. indem per VBA erzeugtes CSV anderer Delimiter hat als per Menü), dann "funzt" es natürlich nicht. Die zu Grunde liegende Logik (ich wiederhole mich), dünkt mir aber "extrem" praktikabel. Is ja nicht so kompliziert, und "man" könnte sich ja mal schlicht auf die drei (oder vier \n\r) Ascii Zeichen einigen, die da in Frage kommen.

                    Zumal die angesprochenen Programme (Excel und LO Calc) beim CSV-Import ja alle Parameter im Dialog abfragen, sogar mit Vorschau anhand der echten Daten (also nicht nur Beispieldaten).

                    So long,
                     Martin

                    1. Liebe Mitdenker, liebe Wissende, liebe Neugierige,

                      [...] ich finde aber, dass das ein "cooles" Format ist: Wähle drei x-beliebige Zeichen (Umgebungsvar, Spaltentrenner, Zeilentrenner) und escape allein die Umgebungsvar, indem Du sie zum Escapen verdoppelst.

                      ja, ich mag CSV grundsätzlich auch gern, zumal es gegenüber vielen "besseren", aber proprietären Formaten noch einen Vorteil hat: Es lässt sich mit einem gewöhnlichen Texteditor öffnen und als Klartext lesen. Das ist bei XML-basierten Formaten schon etwas umständlicher.

                      Rein praktisch nutze ich es allein, um aus Excel "rauszukommen" (mit VBA eine CSV erstellen).

                      Ich gehe gern genau den umgekehrten Weg: Ich erzeuge z.B. Messprotokolle als CSV, um sie dann mit Excel oder LO Calc zu importieren und z.B. Diagramme daraus zu machen.

                      Klar auch, dass wenn jeder macht wie er will (Excel bzw. MS zB. indem per VBA erzeugtes CSV anderer Delimiter hat als per Menü), dann "funzt" es natürlich nicht. Die zu Grunde liegende Logik (ich wiederhole mich), dünkt mir aber "extrem" praktikabel. Is ja nicht so kompliziert, und "man" könnte sich ja mal schlicht auf die drei (oder vier \n\r) Ascii Zeichen einigen, die da in Frage kommen.

                      Zumal die angesprochenen Programme (Excel und LO Calc) beim CSV-Import ja alle Parameter im Dialog abfragen, sogar mit Vorschau anhand der echten Daten (also nicht nur Beispieldaten).

                      Und Excel versteht in der ersten Zeile das Name=Value Pärchen sep=x (x für den Seperator). \r\n für das Zeilenende wird vorausgesetzt. Mehr aber scheinbar nicht.

                      Viele Programme (z. B. die Export-Toold der Fritzbox) mutzen das.

                      PHPs Funktion fgetcsv() berücksichtigt das nicht, man könnte es ihr aber beibringen, dass (mehrere) Settings als Name=Value Pärchen in einzelnen Zeilen vorangehen und die Daten erst dann beginnen, wenn keine Settings mehr kommen. Dabei sollte dann eine Reihenfolge eingehalten werden (linefeed, sep, enclosure, ...). Mal sehen, wann das "auto-flag) in der Funktion auftaucht *gg*

                      Spirituelle Grüße
                      Euer Robert
                      robert.r@online.de

                      --
                      Möge der wahre Forumsgeist ewig leben!
              2. Hallo

                Das Format ist zwar einfach, aber eben doch auch kompliziert.

                es braucht
                ein Zeichen als Umgebungszeichen (eigentlich das Anführungszeichen)

                Die werden aber sehr gerne weggelassen.

                ein Zeichen als Spaltentrenner (eigentlich das Komma)

                Gerne wird auch das Semikolon, die Pipe oder der Tab genommen.

                ein Zeichen als Zeilentrenner (eigentlich die Absatzmarke)

                Joah, Zeilenumbruch, das ist noch das Harmloseste.

                Das sind die Probleme, die ich im Format sehe. Wenn ich CSV-Dateien für mich benutze, ist das egal. Ich lege ein Format fest und halte mich daran. Als Austauschformat ist CSV wegen der obigen Aufzählung aber nur sehr bedingt geeignet. Die Importfunktion z.B. in Excel oder Calc mit der Abfrage des Feldtrenners, des Einschlusses von Texten in welche Anführungszeichen etc. spricht da meiner Meinung nach Bände.

                Tschö, Auge

                --
                Verschiedene Glocken läuteten in der Stadt, und jede von ihnen vertrat eine ganz persönliche Meinung darüber, wann es Mitternacht war. Terry Pratchett, “Wachen! Wachen!
                1. Hallo Auge,

                  und jetzt leg noch die Encoding-Problematik oben drauf ;-)

                  LG,
                  CK

                  1. Hallo

                    und jetzt leg noch die Encoding-Problematik oben drauf ;-)

                    Die ist mir soeben beim testen auch entgegengesprungen. Ich musste ja auch unbedingt das Wort „Köln“ in meinen zwei Datensätzen haben. :-)

                    Die Encoding-Abfrage als solche habe ich übrigens in meinem vorherigen Posting unter „etc.“ subsumiert.

                    Tschö, Auge

                    --
                    Verschiedene Glocken läuteten in der Stadt, und jede von ihnen vertrat eine ganz persönliche Meinung darüber, wann es Mitternacht war. Terry Pratchett, “Wachen! Wachen!