Linuchs: HTML-Dokument **UND** CSV-Datei senden

Moin,

per Filter zeige ich die gewünschten Adressen an und stelle den CSV-string dieser Adressen zur Verfügung. Auf dem Server wird keine Datei erzeugt, sondern der String mit echo ausgegeben. Der Empfänger kann ihn wahlweise in sein Kalkulationsprogramm importieren oder als Datei speichern.

Kann ich HTML und CSV in einem Programmlauf ausgeben oder „behaken” sich die header-Angaben? Bisher mache ich es entweder - oder.

Problem: Die vorherige Liste mit ggf. einem anderen Filter bleibt auf dem Display stehen, weil ja kein HTML ausgegeben wird.

  if ( $arr_in['csv_datei'] ) {
    header('content-type: text/csv; charset=utf-8');
    header('Content-Disposition: attachment; filename="adressen_' .date("Ymd-His", time()) .'.csv"');
    echo $csv_string;
  } else {
    header('content-type: text/html; charset=utf-8');
    ...
  }

Gruß, Linuchs

  1. Hallo Linuchs,

    Kann ich HTML und CSV in einem Programmlauf ausgeben oder „behaken” sich die header-Angaben? Bisher mache ich es entweder - oder.

    Nur, wenn du die Dateien in einem Archiv-Format zusammenfasst. Also z.B. tar oder zip.

    Freundliche Grüße,
    Christian Kruse

    1. Hi,

      Kann ich HTML und CSV in einem Programmlauf ausgeben oder „behaken” sich die header-Angaben? Bisher mache ich es entweder - oder.

      Nur, wenn du die Dateien in einem Archiv-Format zusammenfasst. Also z.B. tar oder zip.

      oder z.B. indem Du im HTML eine Textarea anlegst und das CSV dort als Inhalt reinkippst - der User muß es sich dann halt rauskopieren.

      cu,
      Andreas a/k/a MudGuard

      1. Hallo MudGuard,

        oder z.B. indem Du im HTML eine Textarea anlegst und das CSV dort als Inhalt reinkippst - der User muß es sich dann halt rauskopieren.

        Hehe, kreativer Hack – coole Idee.

        Freundliche Grüße,
        Christian Kruse

        1. @@Christian Kruse

          oder z.B. indem Du im HTML eine Textarea anlegst und das CSV dort als Inhalt reinkippst - der User muß es sich dann halt rauskopieren.

          Hehe, kreativer Hack – coole Idee.

          Ist sie das? Was nicht dazu bestimmt ist gelesen zu werden, sollte auf einer Webseite auch nicht angezeigt werden.

          Mein erster Gedanke war, die Daten in ein <script type="text/csv">-Element[1] zu packen und einen Button vorzusehen, mit dem der Nutzer auf Knopfdruck die Daten in die Zwischenablage kopieren kann. Dann ist man allerdings auf JavaScript angewiesen – ohne Fallback; nicht so dolle.

          Da ist die Idee mit der Textarea als Grundfunktionalität doch gar nicht so dumm. Als progressive enhancement wird die Textarea per JavaScript ausgeblendet und stattdessen o.g. Button angezeigt.

          LLAP 🖖

          --
          „Man kann sich halt nicht sicher sein“, sagt der Mann auf der Straße, „dass in einer Gruppe Flüchtlinge nicht auch Arschlöcher sind.“
          „Stimmt wohl“, sagt das Känguru, „aber immerhin kann man sich sicher sein, dass in einer Gruppe Rassisten nur Arschlöcher sind.“

          —Marc-Uwe Kling

          1. Berichtigt. Vorher stand da fälschlicherweise <style …>. ↩︎

      2. Hallo Andreas,

        genau das war der erste Ansatz. Das HTML-Dokument enthält diesen CSV-String, der dann per JS zu <table> wird.

        Der Benutzer kann nach [Strg][U] den betr. HTML-Code zwar in die Zwischenablage kopieren, aber jede CSV-Zeile belegt bei [Strg][V] im Kalkulationsprogramm nur eine Zelle, ein Split nach ; findet nicht statt, also unbrauchbar.

        Wie kommt die Zwischenablage korrekt ins Kalkulationsprogramm?

        Gruß, Linuchs

        1. Hallo,

          Der Benutzer kann nach [Strg][U] den betr. HTML-Code zwar in die Zwischenablage kopieren, aber jede CSV-Zeile belegt bei [Strg][V] im Kalkulationsprogramm nur eine Zelle, ein Split nach ; findet nicht statt, also unbrauchbar.

          das ist von den Einstellungen und Fähigkeiten des verwendeten Programms abhängig. In Excel ist es immer wieder ein Drama, CSV-Dateien zu importieren, weil genau das passiert: Excel erkennt die Feld-Trennzeichen (z.B. Semikolon) nicht wie gewünscht und klatscht alles in die erste Spalte. Es kommt auch auf das eingestellte Dezimaltrennzeichen an: Verwendet man den Punkt als Dezimaltrennzeichen und das Komma als Feldtrennzeichen, klappt der CSV-Import meist besser.
          Sonst muss man den Weg über den Import-Assistenten gehen, dem man das alles von Hand erklären kann.

          LO Calc ist nach meiner Erfahrung ein bisschen weniger zickig; eine Garantie für "alles ist gut" gibt es da aber auch nicht.

          So long,
           Martin

          --
          Sei n die Anzahl der bekannten Fehler in einer Software, dann gilt stets: n = n+1
          1. Hallo Martin,

            Excel erkennt die Feld-Trennzeichen (z.B. Semikolon) nicht wie gewünscht und klatscht alles in die erste Spalte.

            Das ist scheinbar eine weithin unbekannte Funktion von Excel.

            Daten-Tab, "Text in Spalten" Button. Macht genau das, was beim Import aus Textdateien auch angeboten wird. Zeilenumbrüche in Anführungszeichen-begrenzten Strings sind natürlich immer noch ein Drama.

            Rolf

            --
            sumpsi - posui - clusi
        2. Hallo,

          genau das war der erste Ansatz. Das HTML-Dokument enthält diesen CSV-String, der dann per JS zu <table> wird.

          warum denn ein <table>? Warum kein output oder pre?

          Gruß
          Jürgen

          1. Hallo Jürgen,

            warum denn ein <table>? Warum kein output oder pre?

            <table> kann man spaltenweise sortieren. Ein pre kann in einer Zeile nicht umbrechen und erzeugt einen horizontalen scroll.

            Gruß, Linuchs

            1. Hallo,

              <table> kann man spaltenweise sortieren.

              dann kopier es in ein „geeignetes Element“.

              Ein pre kann in einer Zeile nicht umbrechen und erzeugt einen horizontalen scroll.

              Sind denn deine Zeilen so lang? Aber das Kopieren geht auch mit strg a strg v, also ohne Markieren mit der Maus.

              Gruß
              Jürgen

              1. Hallo Jürgen,

                ich schätze immer deinen Rat, aber nach [Strg][U] (dieser Ast) bekommst du ALLES.

                1. Hallo,

                  ich schätze immer deinen Rat, aber nach [Strg][U] (dieser Ast) bekommst du ALLES.

                  mit strg u bekomme ich den Quelltext.

                  Aber bei strg a hast du Recht. Nur bei input und bei textarea wählt strg a den Inhalt des Elements.

                  Gruß
                  Jürgen

        3. Hallo Linuchs,

          genau das war der erste Ansatz. Das HTML-Dokument enthält diesen CSV-String, der dann per JS zu <table> wird.

          Das heißt du erstellst mit JS eine HTML-Tabelle, deren Zellen du aus dem CSV-String befüllst?

          Bis demnächst
          Matthias

          --
          Du kannst das Projekt SELFHTML unterstützen,
          indem du bei Amazon-Einkäufen Amazon smile (Was ist das?) nutzt.
          1. Hallo Matthias,

            genau das war der erste Ansatz. Das HTML-Dokument enthält diesen CSV-String, der dann per JS zu <table> wird.

            Das heißt du erstellst mit JS eine HTML-Tabelle, deren Zellen du aus dem CSV-String befüllst?

            so habe ich ihn bisher verstanden. Das ist auf der einen Seite effizient, weil für die Tabelle nur die Nutzdaten übertragen werden, und nicht der Quellcode für das ganze Tabellengerüst; andererseits geht es zu Lasten der Client-CPU.

            Wenn man von einem ausgewachsenen Desktop- oder Notebook-PC als Client ausgeht, mag das in Ordnung sein, weil dessen CPU beim berühmten Otto Normalverbraucher sowieso selten mehr als 5..10% ausgelastet ist. Bei mobilen Clients sieht es schon anders aus, weil CPU-Power eher knapp ist und auch noch kräftig "Akku" kostet.

            So long,
             Martin

            --
            "Sehen Sie, das ist gelebte Emanzipation: Wenn ich Ihnen die Tür aufhalte!", sagte neulich eine Kollegin zu mir, die zufällig vor mir zur Tür hinausging,
            1. @@Der Martin

              Bei mobilen Clients sieht es schon anders aus, weil CPU-Power eher knapp ist und auch noch kräftig "Akku" kostet.

              Wie Frances Berriman im gestrigen Türchen des Adventskalenders 24 Ways sagte:

              “Keep processing off the client - do anything you can server-side. Consider a server-side render […] to keep client-side JavaScript to the minimum. This way you’re spending your CPU, not the user’s.”

              LLAP 🖖

              --
              „Man kann sich halt nicht sicher sein“, sagt der Mann auf der Straße, „dass in einer Gruppe Flüchtlinge nicht auch Arschlöcher sind.“
              „Stimmt wohl“, sagt das Känguru, „aber immerhin kann man sich sicher sein, dass in einer Gruppe Rassisten nur Arschlöcher sind.“

              —Marc-Uwe Kling
              1. Tach!

                Bei mobilen Clients sieht es schon anders aus, weil CPU-Power eher knapp ist und auch noch kräftig "Akku" kostet.

                Wie Frances Berriman im gestrigen Türchen des Adventskalenders 24 Ways sagte:

                “Keep processing off the client - do anything you can server-side. Consider a server-side render […] to keep client-side JavaScript to the minimum. This way you’re spending your CPU, not the user’s.”

                Bei dieser pauschalen Betrachtung fehlt der Aufwand für die Datenübertragung. Es nützt ja nichts, wenn ich des Clients CPU zu sparen versuche, aber im Zweifelsfall mehr CPU-Last für das Prozessieren der Datenübertragung zuzüglich Datenvolumen und Energie für die Funkverbindung verbrauche. Bei Optimierungen zur Performance muss man messen, sonst kann man keine qualifizierte Aussage zu eventuellen Verbesserungen treffen.

                dedlfix.

  2. Problem: Die vorherige Liste mit ggf. einem anderen Filter bleibt auf dem Display stehen, weil ja kein HTML ausgegeben wird.

    Dann biete doch einfach einen Link zum CSV-Download des aktuellen Filterstatus an.

    1. Dann biete doch einfach einen Link zum CSV-Download des aktuellen Filterstatus an.

      Mache ich ja:

      CSV Datei

      Der Schönheitsfehler ist, dass die vorangegangene Anzeige mit z.B. Merkmal 3 stehen bleibt.

      Ich wollte zumindest den Kopf der Seite anzeigen, aber entweder anzeigen (auch das Löschen der Anzeige ist eine Anzeige) oder CSV ausgeben.

      1. Dann biete doch einfach einen Link zum CSV-Download des aktuellen Filterstatus an.

        Mache ich ja:

        CSV Datei

        Das ist kein Link, sondern eine Checkbox innerhalb des Filterforms.

        Der Schönheitsfehler ist, dass die vorangegangene Anzeige mit z.B. Merkmal 3 stehen bleibt.

        Checkbox aus dem Filterform rausnehmen. Stattdessen ein neuer Button „Aktuelle Anzeige als CSV herunterladen“. Problem gelöst.

        1. Checkbox aus dem Filterform rausnehmen. Stattdessen ein neuer Button „Aktuelle Anzeige als CSV herunterladen“. Problem gelöst.

          Danke.

          So habe ich es gemacht. Der Link-Button wird mit den Parametern der Liste versehen und gibt die Adressen als CSV aus, die auf dem Display zu sehen sind. Die bleiben da stehen, aber das ist jetzt in Ordnung.

          Linuchs

          1. Checkbox aus dem Filterform rausnehmen. Stattdessen ein neuer Button „Aktuelle Anzeige als CSV herunterladen“. Problem gelöst.

            Danke.

            So habe ich es gemacht. Der Link-Button wird mit den Parametern der Liste versehen

            Genau das ist die Verwendung von Schlüsselparametern womit man die serverseitigen Aktionen steuert.

            MFG

  3. Hallo,

    du könntest die Daten per PHP in eine Javascriptvariable schreiben, und diese dann im Browser per Javascript abspeichern. Stichwort: filesaver.

    Gruß
    Jürgen

  4. Kann ich HTML und CSV in einem Programmlauf ausgeben oder „behaken” sich die header-Angaben?

    Die Antwort auf diese Frage gibt Dir die Antwort nach der Frage der Benutzerfreundlichkeit: Der Besucher bekommt genau das was er, dem Angebot entsprechend, anfordert.

    Und was den Programmablauf betrifft, arbeite mit Schlüsselparametern. Bspw. wird HTML geliefert wenn der Parameter html=1 gesetzt ist. Andernseits wird CSV geliefert wenn der Parameter csv=1 gesetzt ist.

    Hier ist ein Beispiel wie das mit Grafiken geht.

    MFG

    1. @@pl

      Und was den Programmablauf betrifft, arbeite mit Schlüsselparametern. Bspw. wird HTML geliefert wenn der Parameter html=1 gesetzt ist. Andernseits wird CSV geliefert wenn der Parameter csv=1 gesetzt ist.

      Warum 2 verschiedene Parameter? Es geht doch um ein Ding (die Daten), die in 2 (oder mehr) verschiedenen Formaten ausgeliefert werden sollen. Also ?format=html bzw. ?format=csv.

      (Nebst Betrachtung, was bei keiner Angabe der Default ist.)

      LLAP 🖖

      --
      „Man kann sich halt nicht sicher sein“, sagt der Mann auf der Straße, „dass in einer Gruppe Flüchtlinge nicht auch Arschlöcher sind.“
      „Stimmt wohl“, sagt das Känguru, „aber immerhin kann man sich sicher sein, dass in einer Gruppe Rassisten nur Arschlöcher sind.“

      —Marc-Uwe Kling
      1. @@pl

        Und was den Programmablauf betrifft, arbeite mit Schlüsselparametern. Bspw. wird HTML geliefert wenn der Parameter html=1 gesetzt ist. Andernseits wird CSV geliefert wenn der Parameter csv=1 gesetzt ist.

        Warum 2 verschiedene Parameter?

        Das vereinfacht die Kontrollstruktur.

        Es geht doch um ein Ding (die Daten), die in 2 (oder mehr) verschiedenen Formaten ausgeliefert werden sollen. Also ?format=html bzw. ?format=csv.

        Das ist schon richtig, aber bevor man den Wert haben will muss man auf diese Art und Weise erstmal fragen ob der Parameter überhaupt gesetzt ist.

        Mit richtigen Schlüsselparametern hingegen wird nur geprüft ob die gesetzt sind, das sieht dann z.B. so aus:

          if( $this->param('html') ){}     # HTML ausgeben
          else if( $this->param('csv') ){} # CSV ausgeben
          else if( $this->param('pdf') ){} # PDFausgeben usw.
          else{} # unbekannter Parameter
        

        und das macht die Sache schön übersichtlich. MFG

        1. Tach!

            if( $this->param('html') ){}     # HTML ausgeben
            else if( $this->param('csv') ){} # CSV ausgeben
            else if( $this->param('pdf') ){} # PDFausgeben usw.
            else{} # unbekannter Parameter
          

          Für jeden weiteren Wert ein erneuter Funktionsaufruf. switch existiert und kommt mit einem Funktionsaufruf aus (im Falle von format=xxx), ist auch nicht unübersichtlich und zeigt zudem deutlicher, dass ein einzelner Parameter auf verschiedene Inhalte geprüft wird, und es sich nicht um möglicherweise mehrere unabhängige Bedingungen handelt. Das weiß man bei den if-else-Verkettungen erst nachdem man alle analysiert hat.

          dedlfix.

          1. Tach!

              if( $this->param('html') ){}     # HTML ausgeben
              else if( $this->param('csv') ){} # CSV ausgeben
              else if( $this->param('pdf') ){} # PDFausgeben usw.
              else{} # unbekannter Parameter
            

            Für jeden weiteren Wert ein erneuter Funktionsaufruf. switch existiert und kommt mit einem Funktionsaufruf aus (im Falle von format=xxx), ist auch nicht unübersichtlich und zeigt zudem deutlicher, dass ein einzelner Parameter auf verschiedene Inhalte geprüft wird, und es sich nicht um möglicherweise mehrere unabhängige Bedingungen handelt. Das weiß man bei den if-else-Verkettungen erst nachdem man alle analysiert hat.

            Meine Kontrollstrukturen per if/else haben sich jahrzehntelang bewährt. Eben weil sie überschaubar und auch einfach erweiterbar sind. Wie bereits festgestellt, Kontollstrukturen dieser Art prüfen nur ob ein bestimmter Parameter gesetzt ist. Ein Switch hingegen vergleicht Strings. Abhängigkeiten unter Parametern sind über ein Switch nur schwer handelbar. Ebenso kann es ja auch mal mehr als einen Schlüsselparameter geben wie z.B. hier, sowas ist über native Kontrollstrukturen einfacher zu lösen als mit Switch.

            MFG

            1. Hallo pl,

              Eben weil sie überschaubar und auch einfach erweiterbar sind

              Ihr seid beide mit dem falschen Argument unterwegs. Es geht darum, ob die Ausgabemodi CSV, HTML und PDF sich gegenseitig ausschließen oder nicht.

              Schließen sie sich gegenseitig aus: format=<enum>

              Tun sie es nicht: csv=<bool>&html=<bool>&pdf=<bool>

              Schnittstellen werden nicht von Programmiervorlieben oder -fähigkeiten bestimmt, sondern von der fachlichen Anforderung. Und die programmiert man dann, so gut und auf die Art, wie man es kann und mag (oder soll, falls man Richtlinien zu beachten hat).

              Rolf

              --
              sumpsi - posui - clusi
              1. Tach!

                Schließen sie sich gegenseitig aus: format=<enum>

                Tun sie es nicht: csv=<bool>&html=<bool>&pdf=<bool>

                Ja, so sieht das besser aus. Andererseits kann man den Querystring auch so gestalten: ?format=csv&format=html, womit das dann im Prinzip äquivalent zu Variante 2 ist. Nun kommt es darauf an, wie der URL-Parser arbeitet und die Werte der Weiterverarbeitung zur Verfügung stellt. Der erste gewinn, der letzte gewinnt, oder alle werden in einem Array übergeben.

                dedlfix.

          2. Hello,

            Tach!

              if( $this->param('html') ){}     # HTML ausgeben
              else if( $this->param('csv') ){} # CSV ausgeben
              else if( $this->param('pdf') ){} # PDFausgeben usw.
              else{} # unbekannter Parameter
            

            Für jeden weiteren Wert ein erneuter Funktionsaufruf. switch existiert und kommt mit einem Funktionsaufruf aus (im Falle von format=xxx), ist auch nicht unübersichtlich und zeigt zudem deutlicher, dass ein einzelner Parameter auf verschiedene Inhalte geprüft wird, und es sich nicht um möglicherweise mehrere unabhängige Bedingungen handelt. Das weiß man bei den if-else-Verkettungen erst nachdem man alle analysiert hat.

            Wenn man die if-else-Strukturen sauber formatiert niederschreibt, kann man die genauso leicht lesen, wie switch-break-default.

            Bei Switch muss man schließlich auch erst überprüfen, ob alle breaks vorhanden sind.

            Glück Auf
            Tom vom Berg

            --
            Es gibt nichts Gutes, außer man tut es!
            Das Leben selbst ist der Sinn.
            1. Bei Switch muss man schließlich auch erst überprüfen, ob alle breaks vorhanden sind.

              Nicht nur das. Wie schon gesagt, es kann auch Beziehungen zwischen Schlüsselparametern geben, Z.B.

              if( param('x') && param('y') )
              if( param('x') || param('y') )
              

              Sowas kann man mit einem Switch gar nicht auflösen. Eine Kontrollstruktur über Schlüsselparameter hingegen reduziert sich auf Boolsche Algebra.

              MFG

              1. Tach!

                Bei Switch muss man schließlich auch erst überprüfen, ob alle breaks vorhanden sind.

                Trotzdem macht switch schon semantisch deutlicher, dass eine Variable auf verschiedene Werte untersucht werden soll, als es unabhängige if-Einzelprüfungen machen können.

                Nicht nur das. Wie schon gesagt, es kann auch Beziehungen zwischen Schlüsselparametern geben, Z.B.

                if( param('x') && param('y') )
                if( param('x') || param('y') )
                

                Sowas kann man mit einem Switch gar nicht auflösen.

                Dieses Beispiel ist anders als der besprochene Fall. Dass es solche Fälle gibt, hat keinen Einfluss auf die Argumente für Switch im eigentlich besprochenen Fall.

                Unterschiedliche Fälle rechtfertigen unterschiedliche Lösungswege. Dass es mehr oder weniger ähnliche Fälle gibt, rechtfertigt aber nicht per se den Ausschluss von sinnvolleren Lösungen in einigen davon.

                dedlfix.

              2. Hallo pl,

                diese Argumentation missachtet ein grundlegendes Designprinzip: das Einlesen von Daten und ihre Verarbeitung sind getrennte Teile der Programmlogik. Requestparameter sind auch Daten.

                Herzliche Grüße
                EVA

                --
                sumpsi - posui - clusi
  5. Hello,

    per eMail, oder per HTTP?

    Glück Auf
    Tom vom Berg

    --
    Es gibt nichts Gutes, außer man tut es!
    Das Leben selbst ist der Sinn.