pl: Demo: JavaScript und Binärdateien, Multimedia

Zum Ausprobieren Hier die Demo; interessanterweise erkennen sowohl Chrome als auch FF PDF als application/force-download, aber das kann ja in der Tabelle geändert werden (für die Vorschau).

Chrome auf meiner alten Kiste spielt bis zu Dateigrößen von ca 100 MB mit. Der Algorithmus ist recht einfach und portierbar in beliebige PL's. Der zu speichernde abstrakte Datentype ist nach dem bewährten Entity-Attribute-Value Muster und mit diesem Algorithmus binary safe transportfähig.

Eine schlanke Alternative übrigens zu mutlipart/form-data ;)

  1. Wichtig für einen Filetransfer Algorithmus ist vor allem eines: ist er streambar. Nur dann kann er mit einem schlanken Memory-Footprint unterwegs sein. Auf dem Client kann man einen fetten Footprint noch tolerieren, auf einem Webserver mit hoher Last ist es kaum hinnehmbar, wenn ein Request eben mal 400 MB weggurgelt.

    Ich habe mich noch nicht damit befasst wie die einzelnen Serverumgebungen solche Requests handeln, das multipart-formdata Layout gibt streaming jedenfalls her.

    Dein Gegenvorschlag auch?

    Und eines zeigt sich an den inhärenten Problemen von multipart-formdata auf jeden Fall: es ist nicht für den Transfer großer Datenmengen erfunden worden. HTTP wurde für Dokumente konzipiert. GET, PUT, POST - alles eigentlich für Einzeldokumente. Formdata ist schon eine Erweiterung, Multipart erst recht. Für Dateien hat man eigentlich FTP gedacht. HTTP für Massentransfers ist mMn Zweckentfremdung, was man sofort bemerkt wenn man sich die Mühe ansieht, die man investieren muss um große Mengen zu übertragen ohne den Server lahmzulegen.

    Rolf

    1. Hallo,

      HTTP wurde für Dokumente konzipiert. GET, PUT, POST - alles eigentlich für Einzeldokumente.

      viel entscheidender ist IMO, dass bei HTTP das Haupt-Augenmerk auf den Download, also den Transfer vom Server zum Client, gelegt wurde.

      Formdata ist schon eine Erweiterung, Multipart erst recht.

      Ja, mag sein - aber nicht unbedingt, weil HTTP an der Stelle Schwächen hat. Theoretisch könnte man auch einen gewöhnlichen POST-Request bauen und genau wie beim GET-Response beliebige Daten im Request-Body mitgeben. Ein passender Content-Type dazu, fertig. Verarbeiten kann man die Daten dann stream-orientiert über php://stdin. EDIT: Sorry, das heißt wohl php://input /EDIT

      Allerdings täuscht das den Programmierer leicht darüber hinweg, dass der gesamte Request-Body schon zum Server übertragen und zwischengespeichert wird, bevor das PHP-Script überhaupt gestartet wird (auch bei multipart/form-data). Das mag bei anderen Scriptsprachen anders sein.

      Das Problem ist also nicht HTTP, sondern die Implementierung gängiger Scriptsprachen.

      Für Dateien hat man eigentlich FTP gedacht. HTTP für Massentransfers ist mMn Zweckentfremdung, was man sofort bemerkt wenn man sich die Mühe ansieht, die man investieren muss um große Mengen zu übertragen ohne den Server lahmzulegen.

      Naja, zumindest der Download großer Datenmengen über HTTP ist ziemlich unproblematisch.

      So long,
       Martin

      --
      Nothing travels faster than the speed of light with the possible exception of bad news, which obeys its own special laws.
      - Douglas Adams, The Hitchhiker's Guide To The Galaxy
      1. Naja, zumindest der Download großer Datenmengen über HTTP ist ziemlich unproblematisch.

        Weil Server und Browser ihn streamen. Es sei denn, ich erzeuge die Response aus einem Script heraus und baue sie erstmal komplett im RAM auf - letzteres macht ein Web von mir hier im Betrieb, weil es derzeit nicht anders geht.

        Rolf

    2. Wichtig für einen Filetransfer Algorithmus ist vor allem eines: ist er streambar. Nur dann kann er mit einem schlanken Memory-Footprint unterwegs sein. Auf dem Client kann man einen fetten Footprint noch tolerieren, auf einem Webserver mit hoher Last ist es kaum hinnehmbar, wenn ein Request eben mal 400 MB weggurgelt.

      Ich habe mich noch nicht damit befasst wie die einzelnen Serverumgebungen solche Requests handeln, das multipart-formdata Layout gibt streaming jedenfalls her.

      Dein Gegenvorschlag auch?

      Selbstverständlich und meinen Parser hab ich dafür um einen eigenen Content-Type erweitert, damit Legacy Code erhalten bleibt. D.h., der Parser stellt anhand des gesendeten Enctype die gesendete Datenstruktur wieder her und $self->param('parametername') wird wie gewohnt verwendet. Vorteile gegenüber multipart/form-data siehe Demo (mit progressbar).

      Danke für Deine Nachfrage ;)

      PS: Algorithmus verbessert, der Serializer ist etwas RAM-gefälliger, die Datenstruktur bleibt jedoch dieselbe.

      1. Wichtig für einen Filetransfer Algorithmus ist vor allem eines: ist er streambar.

        Selbstverständlich

        Ich glaube dir das zwar, aber hinter dem Link findet sich leider keine Antwort, die auf die Frage passt.

        und meinen Parser hab ich dafür um einen eigenen Content-Type erweitert

        Ein Parser ist per Definition eine Funktion von Strings oder Token-Streams in einen Syntaxbaum unter Berücksichtigung gegebener Grammatik-Regeln. In dieser Terminologie ist ein Content-Type als Name für eine bestimmte Grammatik zu verstehen. Ein Parser ist also immer nur für genau eine Grammatik verantwortlich. Die Auswahl eines geeignete Parsers für eine eine solche Grammatik ist selber nicht Bestandteil des Parsings. Dieser Bearbeitungsschritt findet logischerweise vor dem eigentlichen Parsing statt.

        Man kann natürlich einen Parser zu einem Parser-Constructor erweitern, indem man die Grammatik nicht fixiert, sondern als zusätzlichen Parameter entgegennimmt. Das wäre aber zum Nachteil der Performance, da das Erzeugen eines Parsers komplexitätstheoretisch schwieriger ist als das Parsing. Das hast du aber auch nicht gemeint.

        Um den Satz dennoch einen Sinn zu verleihen, könnte man sagen, du hast deine Webapplikation um ein Modul erweitert, das einen benutzerdefinierten Content-Type parsen kann.

        1. Um den Satz dennoch einen Sinn zu verleihen, könnte man sagen, du hast deine Webapplikation um ein Modul erweitert, das einen benutzerdefinierten Content-Type parsen kann.

          Um Dein Verständnis zu fördern: Das war in Perl bezüglich application/x-www-form-urlencoded oder multipart/form-data schon immer so, dass der Parser ein eigenständigs Modul ist.

          Siehe auch: Schichtenmodell

          Der erste brauchbare Parser übrigens fand sich in der cgi-lib.pl von Steven E. Brenner, für SELFHTML hab ich mal einen Artikel über diese Lib -- die älteste Perl-Library überhaupt geschrieben.

        2. Hallo,

          Ein Parser ist per Definition eine Funktion von Strings oder Token-Streams in einen Syntaxbaum unter Berücksichtigung gegebener Grammatik-Regeln.

          Um den Satz dennoch einen Sinn zu verleihen,

          apropos, könntest du bitte

          Gruß
          Kalk

          1. Ein Parser ist per Definition eine Funktion von Strings oder Token-Streams in einen Syntaxbaum unter Berücksichtigung gegebener Grammatik-Regeln.

            Um den Satz dennoch einen Sinn zu verleihen,

            apropos, könntest du bitte

            Wie könnte ich diesen Wunsch abschlagen?

            Parser haben ein theoretisches Fundament, dieses lässt relativ wenig Spielraum für die Interpreation seiner Aufgaben. Ein Parser ist demnach eine Software-Komponente, die Text einliest und ihm eine Struktur verleiht.

            Das ist nichts schwieriges, wir machen es ständig unterbewusst wenn wir Texte lesen. Manchmal machen wir es auch bewusst: Zum Beisiel als wir in der Grundschule Subjekt/Prädikat/Objekt im Satz unterscheiden mussten: "Papa liebt Mama".

            Genau das macht auch ein formaler Parser. Er zerlegt Texte in seine einzelnen Bausteine. Statt Text spricht ein/e Theoretiker/in aber lieber von Strings oder Token-Streams. Statt von einem Baustein lieber von einer Token-Klasse. Darin ist eine kleine vereinfachende Annahme versteckt: Man kümmert sich nicht um die Details: Das Wort "Apfel" ist für einen Parser keine Aneinanderreihung von fünf Buchstaben, sondern nur ein einzelnes Token. Ein Token kann man sich als ein gestempeltes Wort vorstellen. Eine Token-Klasse wäre dann der Stempel (der Vergleich hinkt leider, sobald man ihn vertiefen möchte).

            Die Ähnlichkeit mit der Linguistik ist dabei kein Zufall. Der Satz "Papa liebt Mama" weist ein relativ flache Strutkur auf: Der Satz "Papa hat Mama geheiratet" ist strukturell interessanter, weil das Prädikat zweiteilig ist. Diese Strukturen lassen sich sehr schön als Bäume veranschaulichen: Die sogenannten Syntax-Bäume. Trotzdem gilt es die Analogien mit der Linguistik nicht zu weit zu spinnen. Formale Sprachen sind in der Regel sehr viel tiefer verschachtelt als natürliche Sprachen.

            Das alles geschieht natürlich auf Grundlage einer vorgegebenen Grammatik. Unzweifelthaft liegt den beiden Beispielen die deutsche Grammatik zu Grunde. Die Regeln für formale Sprachen sind typischerweise noch sehr viel einfacher. Wir sprechen wirklich von extrem einfachen Dingen, auch wenn wir sie manchmal kompliziert Ausdrücken.

            Genauso ist es auch nur sehr kompliziert ausgedrückt, wenn ich sage: Ein Parser ist eine Funktion von Token-Streams in einen Syntaxbaum. Damit meine ich nur, dass ein Parser einen Text als Eingabe bekommt und einen Syntaxbaum als Ausgabe erzeugt. Warum überhaupt kompliziert, wenn es auch einfach geht? Weil wir Theoretiker uns oft selber zu gerne zuhören und weil wir manchmal eine gewisse Präzision einfordern müssen, um Missverständnisse zu vermeiden. Wenn wir miteinander diskutieren, würde ich den ersten Punkt natürlich nie zugeben und immer alles mit dem zweiten Teil begründen.

            1. Und das Ganze nun mit einer abstrakten Denkweise ergänzen: So ist auch Text nur eine Bytesequenz. Oder anders ausgedrückt: Ein Parser liest nicht nur Text sondern Bytesequenzen. Und Bytes kennen keine Token, Zeichen oder gar Zeichenkodierungen -- genau das ist das was der Parser wissen muss und das ergibt einen bestimmten Algorithmus, z.B.

              1. lese 4 byte
              2. die ergeben als Big Endian einen 32Bit-integer
              3. dieser integer sagt dir wieviele bytes du lesen musst, um an den Inhalt zu kommen

              wiederhole 1..3 solange, bis es nichts mehr zu lesen gibt. Nun mach aus den Inhalten ein Array, oder fasse jeweils immer 2 Array-Elemente als key => value auf. Oder nimm immer 3 Elemente als Entity-Attribute-Value ... meine Güte, das hat sogar meine Frau verstanden ;)

              1. Und das Ganze nun mit einer abstrakten Denkweise ergänzen: So ist auch Text nur eine Bytesequenz. Oder anders ausgedrückt: Ein Parser liest nicht nur Text sondern Bytesequenzen. Und Bytes kennen keine Token, Zeichen oder gar Zeichenkodierungen -- genau das ist das was der Parser wissen muss und das ergibt einen bestimmten Algorithmus, z.B.

                1. lese 4 byte
                2. die ergeben als Big Endian einen 32Bit-integer
                3. dieser integer sagt dir wieviele bytes du lesen musst, um an den Inhalt zu kommen

                wiederhole 1..3 solange, bis es nichts mehr zu lesen gibt. Nun mach aus den Inhalten ein Array, oder fasse jeweils immer 2 Array-Elemente als key => value auf. Oder nimm immer 3 Elemente als Entity-Attribute-Value ... meine Güte, das hat sogar meine Frau verstanden ;)

                PS: In einem ArrayBuffer gibt es keine Token. Da ist sequentielles Lesen empfohlen und gerade das ist in JS ziemlich umständlich zu machen. Es wäre schon ein Riesenfortschritt, wenn es ArrayBuffer.shift() geben würde.

              2. Und das Ganze nun mit einer abstrakten Denkweise ergänzen: So ist auch Text nur eine Bytesequenz. Oder anders ausgedrückt: Ein Parser liest nicht nur Text sondern Bytesequenzen.

                Du sagst "Abstraktion" und meinst damit genau das Gegenteil. Grammatiken, Token, Syntaxbäume sind doch bereits im mathematischen Sinne abstrakte Objekte. Bytesequenzen dagegen liegen auf der imaginären Strecke zwischen "Abstraktion" und "Realisierung" am anderen Ende. Für die Entwicklung eines Parsers lassen durch Argumentation auf Byteebene keine zusätzlichen Erkenntnisse gewinnen (außer vielleicht Mikro-Optimierungen). Die wirklichen™ Probleme, die sich bei der Entwicklung eines Parsers stellen, sind völlig anderer Natur. Typische Fragen sind dabei: Ist die Grammatik eindeutig? D.h. gibt es zu einer Eingabe überhaupt einen eindeutigen Ableitungsbaum? Oder gibt es vielleicht Mehrdeutigkeiten? Wie gehe ich überhaupt vor: Baue ich eine Links-Ableitung oder Rechts-Ableitung auf? Leite ich bottom-up oder top-down ab? Wieviel Lookahead benötigt der Parser für eine gegebene Grammatik mit der jeweiligen Methode? Selbst für die Implementierung spielen Bits und Bytes noch keine Rolle: Man gibt sich damit zufrieden einen abstraken Automaten anzugeben, der das Wortproblem für die Grammatik lösen kann. Diese Automaten dann in ausführbaren Code zu transformieren ist nur ein kleiner Schritt. Und wie ich bereits angedeutet habe, ist es möglich Parser voll automatisch von Parser-Generatoren erzeugen zu lassen. Falls du an den theoretischen Grundlagen interessiert sein solltest, kann ich dir die erste Hälfte unserer Compilerbau-Vorlesung sehr empfehlen.

                1. Hallo 1unitedpower,

                  Falls du an den theoretischen Grundlagen interessiert sein solltest, kann ich dir die erste Hälfte unserer Compilerbau-Vorlesung sehr empfehlen.

                  Oder, wie ich auch schonmal in einem ähnlichen Zusammenhang schrieb, das Dragon Book. Oder, wenn es unbedingt von Wirth sein muss, Grundlagen und Techniken des Compilerbaus.

                  LG,
                  CK

            2. Hallo,

              Genauso ist es auch nur sehr kompliziert ausgedrückt, wenn ich sage: Ein Parser ist eine Funktion von Token-Streams in einen Syntaxbaum.

              Vielen Dank für deine weiteren Ausführungen!
              Mit meinem "könnte du bitte" versuchte ich auszudrücken, dass ich deinen Satz nicht parsen konnte, da ich der Meinung bin, er sei nicht komplett. Durch deine quasi Wiederholung erkenne ich, dass du in dem Satz wohl keinen Teil versehentlich vergessen hast. Trotzdem tu ich mich schwer mit dem Konstrukt.

              Gruß
              Kalk

    3. Und eines zeigt sich an den inhärenten Problemen von multipart-formdata auf jeden Fall: es ist nicht für den Transfer großer Datenmengen erfunden worden.

      Beim Upload mit multipart/form-data ist es nicht möglich, einem Part weitere Eigenschaften hinzuzufügen oder gegebene Eingenschaften zu ändern.

      Aber guck Dir meinen Serializer an, bSerialize.array2bin() implementiert den Basic Algorithm: Stets wird ein Array serialisiert wobei auch null-Elemente transportiert werden (hierfür wird ein Byte gesetzt mit 0, ansonsten 1).

      In Perl sieht das dann so aus

      # Kleinste atomare Einheit
      sub val2bin{
          my $self = shift;
          my $val = shift;
      
          return pack('NC',0,0) if ! defined $val;
          
          my %cache = %{$self->{valcache}};
          return $cache{$val} ? $cache{$val} : do{
              my $bs = pack('NC', length($val), 1).$val; 
              $cache{$val} = $bs;
              $bs;
          };
      }
      

      und in PHP nicht viel Anders. Das Byte für undef//defined hat die Schablone 'C'. Auf diese Art und Weise werden Array-Elemente in der resultierenden Sequenz einfach nur aneinandergehängt.

      Aus der Sequenz jedoch lassen sich außer einem einfachen Array auch assoziative Arrays wiederherstellen, wenn nämlich immer 2 Elemente als key => value aufgefasst werden.

      Für einen abstrakten Datentyp EAV gehören auf diese Art und Weise immer 3 Array-Elemente aus der Sequenz zusammen -- die Bytesequenz bleibt dieselbe. Streamfähig ist die Sequenz insofern, als dass bereits beim Eintreffen des ersten Byte sofort mit dem Lesen (z.B. aus STDIN) begonnen werden kann und die Sequenz unendlich lang sein kann ohne in sich geschlossen zu sein.

      Und für die Theoretiker unter uns: Nicht die Datei präsentiert einen bestimmten abstrakten Datentyp (Datenstruktur, Arry, Hash, Hash of Hashes...) sondern der Serialize-Algorithmus... das mag für XML-Experten eine Überraschung sein ;)

      Mehr dazu auf meinen Seiten.

      MfG

      1. Und eines zeigt sich an den inhärenten Problemen von multipart-formdata auf jeden Fall: es ist nicht für den Transfer großer Datenmengen erfunden worden.

        Beim Upload mit multipart/form-data ist es nicht möglich, einem Part weitere Eigenschaften hinzuzufügen oder gegebene Eingenschaften zu ändern.

        Was hat mein Satz mit Deiner Stellungnahme zu tun? Der Aussagenscope beider Sätze scheint mir 100% disjunkt.

        Aber guck Dir meinen Serializer an, (...) In Perl sieht das dann so aus:

        (...) pack('NC',0,0) (...) pack('NC', length($val), 1).$val; (...)
        

        Streamfähig heißt, dass der Upload nicht im RAM des Servers zwischengespeichert werden muss, sondern direkt aus dem STDIN Datenstrom in das Filesystem des Servers übertragen werden kann. Ich kann kein Perl, aber deine Implementierung erweckt einen anderen Eindruck. Es kann natürlich andere, streamende Implementierungen geben, wenn der übertragene Datenstrom dafür geeignet gestaltet ist.

        In PHP ist das bei multipart/form-data so gelöst, dass anhängende Uploads vom Server automatisch als Temp-Dateien gespeichert und nicht im RAM gehalten werden. Allerdings deute ich die Hinweise auf die RAM-Limitierung in der PHP-Doku so, dass auch PHP eine einzelne Datei erstmal im RAM montiert bevor sie in den TEMP-Ordner kommt. Aus Sicht der RAM-Nutzung des Servers ist ein multipart-Upload von 10 Dateien zu je 100 MB also besser als eine Codierung dieser 10 Dateien in einen 1GB Klotz.

        Bei unbekannten Content-Typen sagt das PHP Handbuch, dass es auf die SAPI-Implementierung ankäme, ob die POST Daten gepuffert würden oder nicht. Ungepuffert würde bedeuten: sie bleiben als IP Pakete auf der Leitung (und der Client wartet), bis das PHP losläuft und sie liest. Aus Sicht des Speicherverbrauchs wäre das optimal. Was gepuffert bedeutet, mag vom Webserver abhängen. Dazu kann ich keine Aussagen machen. Hoffentlich schreibt er bei größeren Uploads eine Temp-Datei...

        Was macht PERL? Liest es die POST Daten erstmal komplett in den RAM?

        Und für die Theoretiker unter uns: Nicht die Datei präsentiert einen bestimmten abstrakten Datentyp (Datenstruktur, Arry, Hash, Hash of Hashes...) sondern der Serialize-Algorithmus... das mag für XML-Experten eine Überraschung sein ;)

        Hä? Eine von vielen Formulierungen deinerseits, bei denen ich mich frage, ob Du einfach zu abgehoben denkst, dass man Dich nicht versteht, oder ob Du einfach nur 50% deiner Gedanken niederschreibst und darum die Hälfte zum Verständnis fehlt. Die dritte Alternative, dass Du nämlich aus Spaß an der Freud vorsätzlich Bullshit ausspuckst, will ich mal ausschließen (auch wenn die pl-Basher hier das vielleicht anders sehen).

        Rolf

        1. Streamfähig heißt, dass der Upload nicht im RAM des Servers zwischengespeichert werden muss, sondern direkt aus dem STDIN Datenstrom in das Filesystem des Servers übertragen werden kann.

          Richtig, genau das gibt ja meine Sequenz her wie ich schon ausführlich schrieb.

          Was macht PERL? Liest es die POST Daten erstmal komplett in den RAM?

          Es kommt darauf an, wie der Parser arbeitet. Da CGI.pm schon seit Jahren total veraltet ist, hab ich ein eigenes Schichtenmodell entwickelt, was sich am gesendeten Content-Type orientiert. Und der Parser legt über IO::String eine eigene Kopie von STDIN im RAM an. Ausschlaggebend dafür ist nicht die Request-Methode sondern die Umgebungsvariable CONTENT_LENGTH nach CGI/1.1

          XML ... und der Dateibegriff nach N. Wirth

          Hä? Eine von vielen Formulierungen deinerseits, bei denen ich mich frage, ob Du einfach zu abgehoben denkst, dass man Dich nicht versteht, oder ob Du einfach nur 50% deiner Gedanken niederschreibst und darum die Hälfte zum Verständnis fehlt.

          Nunja, solche Themen sind schon etwas komplex zu erklären aber die Grundlagen sind immer dieselben, nämlich der Dateibegriff als Bytesequenz nach Niklaus Wirth (um 1980).

          Konkret: Datenstrukturen sind das was im RAM ist und nicht das was eine Datei präsentiert. Von daher präsentiert eine XML Datei eben keine Datenstruktur sondern eine Bytesequenz, Punkt.

          Gerade an meinem letzten Beispiel wird das ja deutlich: Aus einer Sequenz können verschieden aufgebaute Datenstrukturen (abstrakte Datentypen) erzeugt werden wobei der Informationsgehalt dersselbe, jedoch nur die Zugriffsmethoden unterschiedlich sind.

          Eine Sequenz wird immer sequentiell gelesen, es ist nur noch die Frage, ob der der Anwendung ein Stück vom Stream reicht (mp3 Player) oder ob eine Anwendung den gesamten Stream braucht.

          MfG

          1. Streamfähig heißt, dass der Upload nicht im RAM des Servers zwischengespeichert werden muss, sondern direkt aus dem STDIN Datenstrom in das Filesystem des Servers übertragen werden kann.

            Und der Parser legt über IO::String eine eigene Kopie von STDIN im RAM an.

            Also kein Streaming.

            1. Streamfähig heißt, dass der Upload nicht im RAM des Servers zwischengespeichert werden muss, sondern direkt aus dem STDIN Datenstrom in das Filesystem des Servers übertragen werden kann.

              Und der Parser legt über IO::String eine eigene Kopie von STDIN im RAM an.

              Also kein Streaming.

              Hat CGI.pm im Fall multipart/form-data auch nicht gmacht, erst die einzelnen Dateien werden temporär auf die Platte geschrieben -- nach dem parsen.

              Im Fall von application/x-www-form-urlencoded or multipart/form-data abweichenden Enctypes legt auch CGI.pm eine Kopie der aus STDIN gelesenen Daten in den RAM (als Parameter 'POSTDATA' oder 'PUTDATA').

              1. Ok, jetzt weiß ich was Du mit Datei und Datenstruktur gemeint hast. Die Datei (in diesem Fall der Content des POST-Requests) ist eine physische Manifestation der clientseitigen Datenstruktur und Streamingfähigkeit bedeutet, dass der Server nicht gezwungen ist, die komplette clientseitige Struktur erstmal im RAM zu reproduzieren, sondern nur die gerade unbedingt benötigten Teile davon (Dateiname und einige KB der Datei für den nächsten Schreibzugriff in die Upload-Datei). Insofern sind Datenstruktur UND gewählte Serialisierungstechnik wichtig für eine effiziente Lösung. Wenn ich den Content zunächst in eine Hierarchie aus Hashtables lade, muss ich aber erstmal alles lesen. Das ist kein Streaming.

                Dass CGI.pm es auch nicht macht (wobei ich keine Ahnung habe was CGI.pm ist) macht die Sache nicht besser. Kein Streaming heißt, dass ein viele parallele Uploads großer Dateien schnell den Server überlasten und einen DoS Vektor eröffnen. Deswegen hat PHP ja ein Limit für die Dateigröße bei Uploads (und PERL garantiert auch). Das Problem durch ein irgendwie geartetes Containerformat zu verschärfen, kann demnach nicht die Lösung sein. Große Dateien gehören nicht auf einen HTTP Datenstrom, der von einer Script-Engine oder vom Script selber im RAM gepuffert wird. Oder - schlimmer noch - von einem weiteren Abstraktionslayer nochmals dupliziert wird. Darauf wollte ich hinaus, auf sonst nichts. Und ich will auch keinen Vergleich PHP - PERL lostreten, denn PHP macht es ja auch nicht sonderlich besser. Es geht mir um die grundsätzliche Vorgehensweise, effizient und multiuserfest eine größere Datenmenge zum Server zu bekommen.

                D.h. für große Uploads, die aus JS heraus initiiert werden, muss man irgendwie die Behauptung aus dem MDN zum Fliegen bekommen, dass XMLHttpRequest auch einen FTP-Transfer kann (was lt. Google eine Herausforderung zu sein scheint und wofür man Cross-Domain Hürden überwinden muss), oder man braucht eine serverseitige URL, die hinreichend low-level verarbeitet wird, dass der Server NICHTS puffert. Das PL Framework scheint mir dafür ungeeignet. Eine PHP-Standardlösung auch. Ob in Perl oder PHP eine effiziente Lösung grundsätzlich möglich ist, kann ich nicht sagen.

                Rolf

                1. Ok, jetzt weiß ich was Du mit Datei und Datenstruktur gemeint hast. Die Datei (in diesem Fall der Content des POST-Requests) ist eine physische Manifestation der clientseitigen Datenstruktur und Streamingfähigkeit bedeutet, dass der Server nicht gezwungen ist, die komplette clientseitige Struktur erstmal im RAM zu reproduzieren, sondern nur die gerade unbedingt benötigten Teile davon (Dateiname und einige KB der Datei für den nächsten Schreibzugriff in die Upload-Datei). Insofern sind Datenstruktur UND gewählte Serialisierungstechnik wichtig für eine effiziente Lösung. Wenn ich den Content zunächst in eine Hierarchie aus Hashtables lade, muss ich aber erstmal alles lesen. Das ist kein Streaming.

                  Streamfähig heiß, dass die Sequenz unendlich sein kann, nicht in sich geschlossen ist und somit sofort nach dem Eintreffen der ersten Bytes am Zielort mit dem Lesen begonnen werden kann. Im Fall der von mir erzeugten Datenstruktur beeinhaltet der erste 4-Byte-Big-Endian die Länge des ersten Array-Elements, egal wieviele Array-Elements noch kommen. Somit ergibt die Sequenz eine zyklische Datenstruktur wobei auch der Serializer einen bestimten Lesevorgang solange wiederholt, bis die Sequenz vollständig sequentiell abgearbeitet ist.

                  Zyklisch kann auch heißen: Anstatt Array-Elemente sind es Objekte. Natürlich müssen für ein Objekt ein paar mehr Bytes gelesen werden als nur vier. Siehe auch Wikipedia.

                  Dass CGI.pm es auch nicht macht (wobei ich keine Ahnung habe was CGI.pm ist) macht die Sache nicht besser. Kein Streaming heißt, dass ein viele parallele Uploads großer Dateien schnell den Server überlasten und einen DoS Vektor eröffnen. Deswegen hat PHP ja ein Limit für die Dateigröße bei Uploads (und PERL garantiert auch). Das Problem durch ein irgendwie geartetes Containerformat zu verschärfen, kann demnach nicht die Lösung sein.

                  Fakt ist, dass multipart/form-data sehr speicherintensiv und CPU-lastig ist beim Wiederherstellen der Einzelkomponenten. Warum das so ist, hab ich auf meinen Seiten ausführlich beschrieben.

                  Für ein im Serverseitigen Prozess zu setzendes Limit ist allein die Umgebungsvariable CONTENT_LENGTH relevant und nicht etwa die der Content-Type oder die Request-Method. Auch das ist in CGI.pm eine der Altlasten weil es dort falsch implementiert ist ( CGI.pm ist praktisch der Perl-Standard ).

                  Ein böser Client könnte auch mit Request-Methode 'GET' BigData im Message Boby senden und dafür einen Content-Type: text/plain deklarieren oder gar eine Request-Methode benennen, die der Server gar nicht kennt. Mit Perl oder PHP kannste solche LowLevel Clients bauen und damit Deine Serverchen testen ;)

                  D.h. für große Uploads, die aus JS heraus initiiert werden, muss man irgendwie die Behauptung aus dem MDN zum Fliegen bekommen, dass XMLHttpRequest auch einen FTP-Transfer kann (was lt. Google eine Herausforderung zu sein scheint und wofür man Cross-Domain Hürden überwinden muss), oder man braucht eine serverseitige URL, die hinreichend low-level verarbeitet wird, dass der Server NICHTS puffert. Das PL Framework scheint mir dafür ungeeignet. Eine PHP-Standardlösung auch. Ob in Perl oder PHP eine effiziente Lösung grundsätzlich möglich ist, kann ich nicht sagen.

                  Na, dann guck mal hier, das Teil ist echt der Hammer: Upload via PUT und da wird serverseitig überhaupt nichts mehr geparst -- der Content-Type im Request-Header entspricht dem Inhalt. Diese schicke Anwendung schickt also jede Datei einzeln.

                  Eine FTP Emulation via HTTP nach diesem Prinzip hab ich vor ein paar Jahren mal mit Perl gebaut, Du brauchst ein zweites Socket (z.B. auf einem anderen Port) damit für jeden Chunk bzw. gesendeten Puffer bei einer offenen Verbindung zurückgeliefert werden kann dass er angekommen ist. Ob ein XHR-Objekt zwei Verbindungen auf verschiedenen Ports offenhalten kann, wäre zu prüfen ;)

                  Teste mal meinen UploadManager, 400 Dateien hochzuladen is kein Thema und das macht die Anwendung ohne Aufsicht (unattended). Privacy ist gegeben, serverseitig speichert diese DEMO nichts.

                  MfG

                2. D.h. für große Uploads, die aus JS heraus initiiert werden, muss man irgendwie die Behauptung aus dem MDN zum Fliegen bekommen, dass XMLHttpRequest auch einen FTP-Transfer kann (was lt. Google eine Herausforderung zu sein scheint und wofür man Cross-Domain Hürden überwinden muss), oder man braucht eine serverseitige URL, die hinreichend low-level verarbeitet wird, dass der Server NICHTS puffert. Das PL Framework scheint mir dafür ungeeignet. Eine PHP-Standardlösung auch. Ob in Perl oder PHP eine effiziente Lösung grundsätzlich möglich ist, kann ich nicht sagen.

                  Alternative Chunked Upload (Demo). Auch hier kein serverseitiges Parsen erforderlich, weil jeder Chunk => PUT-Content ist.

                  Rolf

        2. Hallo,

          Streamfähig heißt, dass der Upload nicht im RAM des Servers zwischengespeichert werden muss, sondern direkt aus dem STDIN Datenstrom in das Filesystem des Servers übertragen werden kann.

          Streaming heißt für mich, dass die übermittelten Daten direkt verarbeitet werden und gar nicht zwischengespeichert werden müssen. Deine obige Aussage deckt sich daher nur dann mit meiner Ansicht, wenn das Speichern als Datei der eigentliche Zweck der Operation ist.

          Ansonsten sind Audio- oder Videodaten typische Kandidaten für Streaming: Sie können nach dem Empfang direkt wiedergegeben werden, ohne sie erst als Datei zu speichern. Dass eine kleine Datenmenge doch zwischengespeichert wird (einerseits um Transfer-Unterbrechungen auszubügeln, andererseits zum Decodieren der Daten), ändert nichts am Konzept an sich.

          In PHP ist das bei multipart/form-data so gelöst, dass anhängende Uploads vom Server automatisch als Temp-Dateien gespeichert und nicht im RAM gehalten werden. Allerdings deute ich die Hinweise auf die RAM-Limitierung in der PHP-Doku so, dass auch PHP eine einzelne Datei erstmal im RAM montiert bevor sie in den TEMP-Ordner kommt.

          Woraus liest du das ab? AFAIK gibt es für PHP generell ein einstellbares Speicherlimit, das die verfügbare RAM-Menge pro Script begrenzt. Das hat aber mit File-Uploads nichts zu tun. Und dann gibt es ein Größenlimit für Uploads, das aber IMO nicht darauf schließen lässt, dass die Daten zunächst im RAM gehalten werden.

          Aus Sicht der RAM-Nutzung des Servers ist ein multipart-Upload von 10 Dateien zu je 100 MB also besser als eine Codierung dieser 10 Dateien in einen 1GB Klotz.

          Hmm. Ich würd' mal sagen, das macht keinen Unterschied.

          Bei unbekannten Content-Typen sagt das PHP Handbuch, dass es auf die SAPI-Implementierung ankäme, ob die POST Daten gepuffert würden oder nicht.

          Schade, dass du die Stelle nicht verlinkt hast. Ich vermute nämlich, du hast das missverstanden.

          Ungepuffert würde bedeuten: sie bleiben als IP Pakete auf der Leitung (und der Client wartet), bis das PHP losläuft und sie liest.

          Nein, das läuft so nicht. AFAIK nimmt der Webserver den vollständigen POST-Request entgegen, bevor er den PHP-Prozess überhaupt startet.

          Aus Sicht des Speicherverbrauchs wäre das optimal.

          Ja. Aber das gibt PHP AFAIK nicht her.

          So long,
           Martin

          --
          Nothing travels faster than the speed of light with the possible exception of bad news, which obeys its own special laws.
          - Douglas Adams, The Hitchhiker's Guide To The Galaxy
          1. Hi,

            Streaming heißt für mich, dass die übermittelten Daten direkt verarbeitet werden (...) (Ansicht deckt sich nur), wenn das Speichern als Datei der eigentliche Zweck der Operation ist.

            Ja, so hatte ich das aufgefasst. Upload auf einen Server zum Zweck der Multimedia-Wiedergabe ist wohl eher ein Sonderfall. Und ich habe Streaming nicht auf Audio/Video beschränkt gesehen, es ging mir um den Umgang mit dem Datenstrom. Ich denke, unsere Ansichten decken sich.

            In PHP ist das bei multipart/form-data so gelöst, dass anhängende Uploads vom Server automatisch als Temp-Dateien gespeichert und nicht im RAM gehalten werden. Allerdings deute ich die Hinweise auf die RAM-Limitierung in der PHP-Doku so, dass auch PHP eine einzelne Datei erstmal im RAM montiert bevor sie in den TEMP-Ordner kommt.

            Woraus liest du das ab? AFAIK gibt es für PHP generell ein einstellbares Speicherlimit, das die verfügbare RAM-Menge pro Script begrenzt. Das hat aber mit File-Uploads nichts zu tun. Und dann gibt es ein Größenlimit für Uploads, das aber IMO nicht darauf schließen lässt, dass die Daten zunächst im RAM gehalten werden.

            Einmal diese grundsätzlichen Infos zum Upload per POST. Das $_FILES Array enthält einen Temp-Namen, also gibt's auch eine Temp-Datei :)

            Dass PHP die Datei im Speicher montiert bevor es sie schreibt schließe ich hieraus. Da steht, dass das Limit der Dateigröße 2 MB beträgt und man bei Erhöhen der upload_max_filesize eventuell das memory_limit anpassen muss.

            Aus Sicht der RAM-Nutzung des Servers ist ein multipart-Upload von 10 Dateien zu je 100 MB also besser als eine Codierung dieser 10 Dateien in einen 1GB Klotz.

            Hmm. Ich würd' mal sagen, das macht keinen Unterschied.

            Wenn's einer macht, nicht. Unter diesem Gesichtspunkt betrachten viele Entwickler ihr Web. Aber das Schlimmste, was dann passieren kann, ist der Erfolg der Webseite. Auf einmal kracht es, weil die Requests zu viele Ressourcen verbraten. Wenn aber 500 Leute eine 100MB Datei hochladen (z.B. zu einem Fotobuch-Hersteller, kurz vor Weihnachten), werden auf einmal 50GB RAM nur zum Puffern gebraucht. Es geht also letztlich darum, wieviele Webserver man in den Cluster stellen muss, um X User bedienen zu können. Wenn jeder Request nur 100KB Streaming-Buffer hält, reicht für den Beispielfall ein Server (naja ok, bei soviel Last habe ich eh einen zweiten als Backup). Wenn aber alles in den RAM muss, brauche ich schnell 4 oder 8 Kisten.

            Bei unbekannten Content-Typen sagt das PHP Handbuch, dass es auf die SAPI-Implementierung ankäme, ob die POST Daten gepuffert würden oder nicht.

            Schade, dass du die Stelle nicht verlinkt hast. Ich vermute nämlich, du hast das missverstanden.

            Hier, die Note zu php://input.

            Ungepuffert würde bedeuten: sie bleiben als IP Pakete auf der Leitung (und der Client wartet), bis das PHP losläuft und sie liest.

            Nein, das läuft so nicht. AFAIK nimmt der Webserver den vollständigen POST-Request entgegen, bevor er den PHP-Prozess überhaupt startet.

            Ok, jetzt drehen wir den Bratspieß mal um. Kannst Du dafür eine Quelle angeben? :)

            Rolf

            1. Hallo,

              Streaming heißt für mich, dass die übermittelten Daten direkt verarbeitet werden (...) (Ansicht deckt sich nur), wenn das Speichern als Datei der eigentliche Zweck der Operation ist.

              Ja, so hatte ich das aufgefasst. Upload auf einen Server zum Zweck der Multimedia-Wiedergabe ist wohl eher ein Sonderfall.

              natürlich, aber ich hatte das nicht auf Uploads beschränkt gemeint.

              Ich denke, unsere Ansichten decken sich.

              Zumindest in diesem Punkt. ;-)

              In PHP ist das bei multipart/form-data so gelöst, dass anhängende Uploads vom Server automatisch als Temp-Dateien gespeichert und nicht im RAM gehalten werden. Allerdings deute ich die Hinweise auf die RAM-Limitierung in der PHP-Doku so, dass auch PHP eine einzelne Datei erstmal im RAM montiert bevor sie in den TEMP-Ordner kommt.

              Woraus liest du das ab? AFAIK gibt es für PHP generell ein einstellbares Speicherlimit, das die verfügbare RAM-Menge pro Script begrenzt. Das hat aber mit File-Uploads nichts zu tun. Und dann gibt es ein Größenlimit für Uploads, das aber IMO nicht darauf schließen lässt, dass die Daten zunächst im RAM gehalten werden.

              Einmal diese grundsätzlichen Infos zum Upload per POST. Das $_FILES Array enthält einen Temp-Namen, also gibt's auch eine Temp-Datei :)

              Ja, das war mir klar, und das ist ja auch dokumentiert. Die allgemeinen Infos, die du gefunden hast, sind allerdings schwammig. Ich finde beispielsweise keinen Hinweis darauf, was denn genau passiert, wenn MAX_FILE_SIZE tatsächlich überschritten wird.
              Aber dass eine solche Überprüfung überhaupt stattfindet, heißt doch zwingend, dass die Datei(en) komplett übertragen werden, bevor das PHP-Script losrennt. Denn vorher ist die Dateigröße ja noch nicht bekannt.

              Dass PHP die Datei im Speicher montiert bevor es sie schreibt schließe ich hieraus. Da steht, dass das Limit der Dateigröße 2 MB beträgt und man bei Erhöhen der upload_max_filesize eventuell das memory_limit anpassen muss.

              Der mehrfache Hinweis auf memory_limit deutet tatsächlich stark darauf hin.

              Bei unbekannten Content-Typen sagt das PHP Handbuch, dass es auf die SAPI-Implementierung ankäme, ob die POST Daten gepuffert würden oder nicht.

              Schade, dass du die Stelle nicht verlinkt hast. Ich vermute nämlich, du hast das missverstanden.

              Hier, die Note zu php://input.

              Hmm. Das verstehe ich so, dass diese Anmerkung nur vor PHP-Versionen vor 5.6 gilt, und dass bei diesen älteren Versionen die Daten von POST-Requests gespeichert wurden und daher mehrfaches, unabhängiges Öffnen von php://input möglich ist, bei anderen Request-Methoden jedoch nicht. Für PHP ab 5.6 gibt es dazu anscheinend nichts mehr zu beachten, php://input unterstützt da sogar seek-Operationen - was auch wieder bedeutet, dass die Daten vorher gespeichert wurden.

              Ungepuffert würde bedeuten: sie bleiben als IP Pakete auf der Leitung (und der Client wartet), bis das PHP losläuft und sie liest.

              Nein, das läuft so nicht. AFAIK nimmt der Webserver den vollständigen POST-Request entgegen, bevor er den PHP-Prozess überhaupt startet.

              Ok, jetzt drehen wir den Bratspieß mal um. Kannst Du dafür eine Quelle angeben? :)

              Nein, das ist reine logische Schlussfolgerung (siehe oben).

              So long,
               Martin

              --
              Nothing travels faster than the speed of light with the possible exception of bad news, which obeys its own special laws.
              - Douglas Adams, The Hitchhiker's Guide To The Galaxy
              1. Ok, lassen wir's dabei bewenden. Wir haben unsere Kenntnisse ausgetauscht, der Rest ist Spekulatius und den gibt's erst zum Advent :)

                Rolf

                1. Hallo Rolf b,

                  Ok, lassen wir's dabei bewenden. Wir haben unsere Kenntnisse ausgetauscht, der Rest ist Spekulatius und den gibt's erst zum Advent :)

                  Für manche ist es schon Winter.

                  Für mich nicht.

                  Bis demnächst
                  Matthias

                  --
                  Dieses Forum nutzt Markdown. Im Wiki erhalten Sie Hilfe bei der Formatierung Ihrer Beiträge.
                    1. Hallo Rolf b,

                      Oder so

                      Bis Staffel 7 dauert es noch. 😣

                      Bis demnächst
                      Matthias

                      --
                      Dieses Forum nutzt Markdown. Im Wiki erhalten Sie Hilfe bei der Formatierung Ihrer Beiträge.
              2. Tach!

                Streaming heißt für mich, dass die übermittelten Daten direkt verarbeitet werden (...) (Ansicht deckt sich nur), wenn das Speichern als Datei der eigentliche Zweck der Operation ist.

                Ja, so hatte ich das aufgefasst. Upload auf einen Server zum Zweck der Multimedia-Wiedergabe ist wohl eher ein Sonderfall.

                natürlich, aber ich hatte das nicht auf Uploads beschränkt gemeint.

                Du beschränkst dich an der Stelle auf Datenaustausch zwischen Servern und Clients über ein Netzwerk. Streams kommen aber nicht nur da vor, sondern auch innerhalb eines Rechners oder gar Programms. Auch da im Kleinen findet Kommunikation statt, und auch da muss man nicht den gesamten Batzen auf einmal hinstellen und entgegennehmen, sondern man kann einen Stream verwenden, der häppchenweise überträgt.

                dedlfix.

          2. Hallo Martin,

            Ungepuffert würde bedeuten: sie bleiben als IP Pakete auf der Leitung (und der Client wartet), bis das PHP losläuft und sie liest.

            Nein, das läuft so nicht. AFAIK nimmt der Webserver den vollständigen POST-Request entgegen, bevor er den PHP-Prozess überhaupt startet.

            Das ist hochgradig Server-spezifisch. Apache ist nicht der einzige Server.

            Und jetzt wollte ich gerade schreiben, dass Apache das so auch nicht tut und meine Erinnerung im Sourcecode schnell verifizieren, um dann festzustellen, dass die Architektur von Apache sich massiv geändert hat seit ich dafür entwickelt habe. Jetzt habe ich fast eine Stunde darauf verwenden müssen um festzustellen, wo sich was geändert hat und dann zu merken, dass das nicht so ohne weiteres beantwortbar ist 😜

            Per Default liest der Apache nicht zuerst den POST-Request, bevor er das CGI-Script startet, sondern er streamt den Request in chunks. Das Herz-Stück ist dabei diese Code-Stelle:

                        /* read */
                        apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ);
            
                        if (conf->logname && dbpos < conf->bufbytes) {
                            int cursize;
            
                            if ((dbpos + len) > conf->bufbytes) {
                                cursize = conf->bufbytes - dbpos;
                            }
                            else {
                                cursize = len;
                            }
                            memcpy(dbuf + dbpos, data, cursize);
                            dbpos += cursize;
                        }
            
                        /* Keep writing data to the child until done or too much time
                         * elapses with no progress or an error occurs.
                         */
                        rv = apr_file_write_full(script_out, data, len, NULL);
            
            

            Dieser Code wird in einer Loop aufgerufen, Apache liest also den Body in Blöcken der Maximal-Größe APR_BLOCK_READ aus dem Bucket und schreibt ihn ins STDIN des CGI. Ein Bucket ist dabei eine Abstraktion einer I/O-Schnittstelle, und hier kommt dann auch das Problem zum tragen: Apache hat sog. Filters, das ist ein Stück Software, dass sowohr VOR dem Request als auch nach dem Request über die Daten laufen kann, und die, klar, nacheinander ab. Es ist also prinzipiell möglich, dass ein Filter den Request vor der Verarbeitung liest.

            Das ist aber, wie gesagt, in der Default-Konfiguration nicht der Fall!

            LG,
            CK

            1. Moin Christian,

              AFAIK nimmt der Webserver den vollständigen POST-Request entgegen, bevor er den PHP-Prozess überhaupt startet.

              Das ist hochgradig Server-spezifisch. Apache ist nicht der einzige Server.

              aber vermutlich der meistverbreitete. Egal, mir ist hinterher auch klar geworden, dass ich mich hier vermutlich geirrt habe.

              Per Default liest der Apache nicht zuerst den POST-Request, bevor er das CGI-Script startet, sondern er streamt den Request in chunks. Das Herz-Stück ist dabei diese Code-Stelle:

                          /* read */
                          apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ);
              
                          if (conf->logname && dbpos < conf->bufbytes) {
                              int cursize;
              
                              if ((dbpos + len) > conf->bufbytes) {
                                  cursize = conf->bufbytes - dbpos;
                              }
                              else {
                                  cursize = len;
                              }
                              memcpy(dbuf + dbpos, data, cursize);
                              dbpos += cursize;
                          }
              
                          /* Keep writing data to the child until done or too much time
                           * elapses with no progress or an error occurs.
                           */
                          rv = apr_file_write_full(script_out, data, len, NULL);
              
              

              Dieser Code wird in einer Loop aufgerufen, Apache liest also den Body in Blöcken der Maximal-Größe APR_BLOCK_READ aus dem Bucket und schreibt ihn ins STDIN des CGI.

              Ja, an diesen Mechanismus (also dass das CGI die Daten durch stdin erhält) habe ich mich dann auch erinnert, und da spricht natürlich nichts dagegen, den CGI-Prozess quasi sofort zu starten und ihm dann die Daten zu streamen. Im Gegenteil, das wäre sogar deutlich effizienter als hier schon zu puffern.

              Ein Bucket ist dabei eine Abstraktion einer I/O-Schnittstelle, und hier kommt dann auch das Problem zum tragen: Apache hat sog. Filters, das ist ein Stück Software, dass sowohr VOR dem Request als auch nach dem Request über die Daten laufen kann, und die, klar, nacheinander ab. Es ist also prinzipiell möglich, dass ein Filter den Request vor der Verarbeitung liest.

              Das ist aber, wie gesagt, in der Default-Konfiguration nicht der Fall!

              Dann ist es wohl der PHP-Prozess, der die Daten zwischenspeichert, bevor er das eigentliche Script startet. Denn das muss er, wie ich schon an anderer Stelle argumentiert habe, damit er bei File-Uploads die maximale Dateigröße prüfen kann. Nicht die Gesamtgröße des POST-Requests, die könnte man ja auch aus dem Content-Length-Header holen, sondern die "Nettogröße" der hochgeladenen Datei(en).

              Und das ist der eigentliche Punkt, auf den ich hinaus wollte: Wenn das PHP-Script startet, ist der Request schon vollständig zum Server übermittelt worden.

              So long,
               Martin

              --
              Nothing travels faster than the speed of light with the possible exception of bad news, which obeys its own special laws.
              - Douglas Adams, The Hitchhiker's Guide To The Galaxy
              1. Hallo Martin,

                Dann ist es wohl der PHP-Prozess, der die Daten zwischenspeichert, bevor er das eigentliche Script startet.

                Das ist ein Beispiel für einen solchen Filter, ja ;-)

                Denn das muss er, wie ich schon an anderer Stelle argumentiert habe, damit er bei File-Uploads die maximale Dateigröße prüfen kann. Nicht die Gesamtgröße des POST-Requests, die könnte man ja auch aus dem Content-Length-Header holen, sondern die "Nettogröße" der hochgeladenen Datei(en).

                Das ist richtig, jedoch legt PHP bei multipart/form-data die Daten ab einer bestimmten Grösse in einer temporären Datei ab; es ist also nicht so, dass der gesamte Request erstmal im RAM liegt.

                Und das ist der eigentliche Punkt, auf den ich hinaus wollte: Wenn das PHP-Script startet, ist der Request schon vollständig zum Server übermittelt worden.

                Das ist richtig.

                LG,
                CK

                1. Danke für diese ausführliche Erklärung auf Lötkolben-Ebene. Habt ihr das auch im PHP Source gegengecheckt? (SCHERZ!)

                  Rolf

  2. Um die Aussage, dass eine bestimmte Datentruktur keineswegs an einen bestimmten Dateiaufbau gebunden ist, zu unterstreichen erbringe ich hier den Beweis ;)

    Schönes Wochenende, falls ihr noch in EF seid, in WE ist Zwiebelmarkt.

    1. Hallo pl,

      Schönes Wochenende, falls ihr noch in E[r]F[urt] seid, in WE[imar] ist Zwiebelmarkt.

      Danke. Ja, ich hab mich ein kleines bisschen geärgert. Dann wäre nämlich das Kulturprogramm gerettet gewesen.

      Bis demnächst
      Matthias

      --
      Dieses Forum nutzt Markdown. Im Wiki erhalten Sie Hilfe bei der Formatierung Ihrer Beiträge.
    2. Hallo pl,

      Schönes Wochenende, falls ihr noch in EF seid

      Ein Selftreffen ist doch kein Elternabend.

      Bis demnächst
      Matthias

      --
      Dieses Forum nutzt Markdown. Im Wiki erhalten Sie Hilfe bei der Formatierung Ihrer Beiträge.
    3. Du hast Recht mit der Aussage, dass man aus einer gegebenen Bytefolge unterschiedlichste in-Memory Datenstrukturen ableiten kann und dass eine gegebene in-Memory Datenstruktur auf die unterschiedlichste Art serialisiert und als Symbolfolge (Beispiel für ein Symbol: eine Zahl von 0-255, technisch repräsentiert als ein Byte) abspeichert werden kann.die Struktur nicht mitserialisiere, geht Information verloren. Diese muss ich beim Deserialisieren irgendwie rekonstruieren. Wenn die Struktur nicht in der Datei steckt, dann muss ich Struktur aus dem Nichts synthetisieren. Mein Deserialisierer muss sie auf Grund von Annahmen, die er über die vorgefundene Datei trifft, festlegen.

      Das ist nicht unbedingt leicht. Wenn ich eine EAV Struktur transportiere, dann geht es noch. Dann sind

      Das vernachlässigt aber den Aspekt, dass Struktur, die Daten innewohnt, eine Bedeutung hat. Wenn ich es immer Werte-Tripel, die zusammenzufassen sind. Es gibt aber bereits da schon ein Abgrenzungsproblem: Ich muss das Zeichen, das ich als Worttrenner benutze, maskieren wenn es Teil der übermittelten Werte ist, und ich muss die Entities voneinander abgrenzen, damit der Deserialisierer weiß wo eine neue Entity beginnt.

      Will ich beliebige Strukturen übermitteln, wird es aufwändiger. Vor allem wenn komplexere Objektreferenzen auftauchen oder beliebige Schachtelungen von Arrays und Objekten. Ohne jede Strukturinformation in der übertragenen Datei geht es dann gar nicht mehr (zumindest brauche ich Angaben, um das Ende von Arrays und Objekten zu finden). Und für jede Struktur schreibe und TESTE ich einen eigenen Deserialisierer.

      Um mir das zu vereinfachen, KÖNNTE ich sagen, dass ich beliebige Strukturen vor der Übertragung auf EAV transformiere und nach Deserialisierung es von EAV auf meine Zielstruktur zurücktransformiere. Das würde ich aber als gemogelt ansehen, denn jetzt schreibe und TESTE ich schon zwei Transformatoren, nur um einen einheitlichen Serialisierer und Deserialisierer nutzen zu können.

      Bei JSON und XML steckt die Struktur automatisch mit in der Datei. Da muss keiner mehr eine Annahme treffen, um eine Hierarchie von anonymen Objekten erzeugen zu können. Die Tools zum Lesen und Schreiben von JSON und XML sind vorhanden und getestet. Für XML gibt es mit XPATH eine Abfragesprache auf XML Dokumente. Natürlich MUSS ich das nicht benutzen. Aber bevor ich meine Zeit in das Entwickeln von Basistechnik stecke, die längst schon existiert, nutze ich sie lieber für Aktivitäten, mit denen ich Geld verdienen kann. Meinem Kunden ist es nämlich komplett egal, ob ich JSON, XML, EAV oder WAV-Files mit Trommeltönen übertrage. Der will seine Daten sehen. Zu der Frage, wie ich die transportiere, hat mein Kunde nur eine Meinung: ZUVERLÄSSIG. Und im Fall eines Netzes aus Services, die interoperabel sein müssen: EINHEITLICH.

      Und deswegen nutze ich etablierte Standards, statt das Rad neu zu erfinden. Es wird MIR nämlich nicht gelingen, meine Eigengewächse auf der Welt als neuen Standard zu etablieren. Dir auch nicht. Ich bin zwar deutlich bedeutungsloser als Du (weil Du immerhin eine Webseite zu deinen Themen publizierst, während ich nur in diesem Forum herumplärre), aber so sehr an Dunning-Kruger leide ich hoffentlich auch nicht, um zu erkennen, dass Deine Reichweite dafür auch nicht genügen wird.

      Rolf