Kurt: IO bzw. CGI.pm Upload speichern

Hi

hab jetzt mal ne Frage, schreibe ein Uploadscript mit CGI.pm und bekomme dann von upload() das Filehandle eines temporären Files geliefert.

Um dieses temporäre File nun an seinem Ziel abzulegen, finde ich im Netz nur Beispielcode der das tempfile in 1K-Blöcke einliest und in das Zielfile schreibt...

z.B.
http://perldoc.perl.org/CGI.html#CREATING-A-FILE-UPLOAD-FIELD

  
 # Copy a binary file to somewhere safe  
 open (OUTFILE,">>/usr/local/web/users/feedback");  
 while ($bytesread=read($filename,$buffer,1024)) {  
    print OUTFILE $buffer;  
 }  

($filename ist hier ein Filenhandle)

Ist das Effizient???

Wärs nicht besser das Tempfile direkt vom OS umkopieren zu lassen statt es Häppchenweise durchs Script zu tunneln???

Wie bekomme ich eigentlich den Pfad eines Filehandles wieder raus wenn es zu einem File gehört?

bye
 Kurt

  1. Moin Moin!

    Wärs nicht besser das Tempfile direkt vom OS umkopieren zu lassen statt es Häppchenweise durchs Script zu tunneln???

    Wenn Du "Private Temp Files" einschaltest (und dich nicht gerade mit Windows oder ähnlichen Krücken rumschlägst), kommt außer deinem CGI kein anderes Programm mehr an die Temp-Files heran, weil sie zwar noch als File existieren, aber kein Verzeichniseintrag mehr auf die Files verweist.

    Und rate mal, wie das "Betriebssystem" Dateien kopiert. Richtig, blockweise kopieren, nur die Blockgröße variiert je nach Kopiermethode.

    Wie bekomme ich eigentlich den Pfad eines Filehandles wieder raus wenn es zu einem File gehört?

    Ein Filehandle hat keinen Pfad. Was möchtest Du? Von einem Handle auf einen Dateinamen schließen? Das geht nicht, u.a. wegen Hardlinks. Von einem CGI-Upload-Filehandle-Objekt den Namen der Temp-Datei erfahren, sofern "Private Temp Files" abgeschaltet ist? Das steht in der Doku zum CGI-Modul. Ohne nachzusehen meine ich mich zu erinnern, dass das Objekt den Strinigfy-Operator überlädt um den Temp-File-Namen zurückzugeben. "".$tempfile oder "$tempfile" müßten es tun.

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".
    1. Hey Alexander.

      Als ich Deine Signatur gelesen habe, war mir einiges klar. In diesem Sinne: Welcome back!

      Siechfred

      --
      Wir vom Moderatorenteam haben keinerlei Humor, von dem wir wüssten.
      1. Moin Moin!

        Als ich Deine Signatur gelesen habe, war mir einiges klar. In diesem Sinne: Welcome back!

        Wer sagt denn, dass ich die nicht einfach geklaut habe? ;-)

        Aber ja, ich bin wieder da.

        Alexander

        --
        Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".
    2. Moin Moin!

      remoin!

      Wärs nicht besser das Tempfile direkt vom OS umkopieren zu lassen statt es Häppchenweise durchs Script zu tunneln???

      Wenn Du "Private Temp Files" einschaltest (und dich nicht gerade mit Windows oder ähnlichen Krücken rumschlägst),

      hab ich nich. weder noch.

      kommt außer deinem CGI kein anderes Programm mehr an die Temp-Files heran, weil sie zwar noch als File existieren, aber kein Verzeichniseintrag mehr auf die Files verweist.

      mag ja sein, aber ich will das File nicht kopieren sondern per verschieben. Sprich einen Hardlink anlegen. In perl akzeptiert "link" aber keine Filehandles. Und ein shell "mv" kann ich auch nicht ausführen.

      Und rate mal, wie das "Betriebssystem" Dateien kopiert. Richtig, blockweise kopieren, nur die Blockgröße variiert je nach Kopiermethode.

      jep, ist klar, in meinem FS liegt die Blockgröße bei 4096.
      Aber abgesehen davon dass ich ja nicht kopieren möchte, bezweifle ich dass Perl das annähernd so performant macht wie das OS.

      Wie bekomme ich eigentlich den Pfad eines Filehandles wieder raus wenn es zu einem File gehört?

      Ein Filehandle hat keinen Pfad. Was möchtest Du? Von einem Handle auf einen Dateinamen schließen? Das geht nicht, u.a. wegen Hardlinks.

      stimmt ... leider ... eine FS-Funktion die mir die Pfade aller Hardlinks zu einem Handle ausspuckt wär wirklich nett...schöner Traum...

      Von einem CGI-Upload-Filehandle-Objekt den Namen der Temp-Datei erfahren, sofern "Private Temp Files" abgeschaltet ist? Das steht in der Doku zum CGI-Modul.

      ach! wo? ich hab die perldoc zigmal durchforst

      Ohne nachzusehen meine ich mich zu erinnern, dass das Objekt den Strinigfy-Operator überlädt um den Temp-File-Namen zurückzugeben. "".$tempfile oder "$tempfile" müßten es tun.

      also sowas?

      my  $upload_fh = $query->upload($name);
       print h1("[".$upload_fh."]");

      das liefert mir den Filenamen auf der Clientseite, nicht das tempfile auf dem Server!

      Ich danke für deine (charmanten) Infos! :)

      Tschau
        Kurt

      1. Moin Moin!

        weil sie zwar noch als File existieren, aber kein Verzeichniseintrag mehr auf die Files verweist.

        mag ja sein, aber ich will das File nicht kopieren sondern per verschieben. Sprich einen Hardlink anlegen. In perl akzeptiert "link" aber keine Filehandles.

        In der darunter liegenden Kernel-Schnittstelle (link(2)) auch nicht.

        Und ein shell "mv" kann ich auch nicht ausführen.

        Nicht ohne den Namen der Datei, richtig. Würde ich aber ohnehin nicht machen, denn das CGI-Modul ist sehr bestrebt, die Temp-Files wieder zu löschen. Und statt mv aufzurufen, würde ich ganz generell lieber File::Copy::move() benutzen.

        Und rate mal, wie das "Betriebssystem" Dateien kopiert. Richtig, blockweise kopieren, nur die Blockgröße variiert je nach Kopiermethode.

        jep, ist klar, in meinem FS liegt die Blockgröße bei 4096.

        Was aber nichts mit der Puffergröße im kopierenden Programm zu tun haben muß. dd nimmt 512 Bytes, cp macht ohnehin, was es will, und eine Kopierfunktion auf Kernel-Ebene gibt es meines Wissens nicht.

        Aber abgesehen davon dass ich ja nicht kopieren möchte, bezweifle ich dass Perl das annähernd so performant macht wie das OS.

        Das OS *kann* keine Kopien anfertigen, das machen Hilfsprogramme wie cp und dd. Und die machen abwechselnd read() und write() auf einen einmal angelegten Buffer. Exakt das macht Perl auch, mit unwesentlich mehr overhead. Wenn Du Angst hast, dass die while-Schleife dich ausbremst, erhöhe die Puffergroße. 32K oder 64K RAM hast Du vermutlich noch über. Gegen das Puffern in print hilft syswrite, dabei mußt Du dann allerdings à la C Dich selbst darum kümmern, dass alles geschrieben wurde.

        Kennst Du File::Copy::copy()? Das sollte Dir die ganze Kopiererei abnehmen. Und es kopiert in bis zu 2 MB großen Blöcken.

        Wie bekomme ich eigentlich den Pfad eines Filehandles wieder raus wenn es zu einem File gehört?

        Ein Filehandle hat keinen Pfad. Was möchtest Du? Von einem Handle auf einen Dateinamen schließen? Das geht nicht, u.a. wegen Hardlinks.

        stimmt ... leider ... eine FS-Funktion die mir die Pfade aller Hardlinks zu einem Handle ausspuckt wär wirklich nett...schöner Traum...

        Aus OS-Sicht wäre das ein Alptraum. Spätestens mit Hardlinks auf Directories.

        Stell Dir im folgenden vor, dass die Verzeichnisse mit x und y am Ende jeweils Hardlinks auf das selbe Verzeichnis sind, und alle Dateien der selbe Hardlink:

        /home/example/ax/bx/cx/dx/file1
        /home/example/ay/by/cy/dy/file2
        /home/example/file3

        Für dieses blöde Beispiel gäbe es 17 verschiedene Pfade, Symlinks und ähnliche Späße noch gar nicht mit eingerechnet.

        Du müßtest eine Funktion aufrufen, die ein Array of Strings zurückliefert. Dummerweise kann C aber weder Arrays zurückliefern noch hat es Strings (jaja, C-Programmierer springen mir jetzt an die Kehle). Strings sind als Array of Characters definiert, und Arrays wiederum als einfacher Zeiger irgendwo in den Speicher.

        Also endest Du bei einer kuscheligen Funktion, die einen Zeiger auf einen Speicherblock annimmt, in dem weitere Zeiger auf weitere Speicherblöcke liegen, und befüllt. Damit das Ganze sicher funktioniert, brauchst Du noch eine Zeigerarray-Größe und eine Puffergröße für jeden String. Den Funktionsprototypen mag ich gar nicht aufschreiben.

        Oder Du nutzt aus, dass ASCII NUL in Dateinamen nicht erlaubt ist und definierst die Funktion so, dass sie die Dateinamen als langen Puffer voller Namen zurückgibt, die mit ASCII NUL voneinander getrennt und mit einem leeren Namen terminiert sind. Dann mußt Du nur noch über den Buffer iterieren. Auch nicht lustig in C.

        Von einem CGI-Upload-Filehandle-Objekt den Namen der Temp-Datei erfahren, sofern "Private Temp Files" abgeschaltet ist? Das steht in der Doku zum CGI-Modul.

        ach! wo? ich hab die perldoc zigmal durchforst

        Hab ich auch gerade mal gemacht, ist tatsächlich nicht drin. Sorry.

        Ohne nachzusehen meine ich mich zu erinnern, dass das Objekt den Strinigfy-Operator überlädt um den Temp-File-Namen zurückzugeben. "".$tempfile oder "$tempfile" müßten es tun.

        also sowas?

        my  $upload_fh = $query->upload($name);
        print h1("[".$upload_fh."]");

        das liefert mir den Filenamen auf der Clientseite, nicht das tempfile auf dem Server!

        Wie gesagt: "ohne nachzusehen" ;-)

        Die Fh-Klasse in CGI.pm gibt sich alle Mühe, den Namen zu verstecken. $query->tmpFileName($upload_fh) sollte den Namen der Temp-Datei ausgeben, wie ich das auf die Schnelle sehe. Die DESTROY-Methode gibt sich aber alle Mühe, Dateien unter Kontrolle von CGI.pm zu löschen, entweder per Handle oder per Namen.

        Alexander

        --
        Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".
        1. Hi

          danke für die ausführliche Antwort, hier kann man ja tatsächlich noch richtig was dazulernen! ;-)

          mag ja sein, aber ich will das File nicht kopieren sondern per verschieben. Sprich einen Hardlink anlegen. In perl akzeptiert "link" aber keine Filehandles.

          In der darunter liegenden Kernel-Schnittstelle (link(2)) auch nicht.

          Tja aber den Grund dafür kann ich nicht nachvollziehen ...

          Nicht ohne den Namen der Datei, richtig. Würde ich aber ohnehin nicht machen, denn das CGI-Modul ist sehr bestrebt, die Temp-Files wieder zu löschen. Und statt mv aufzurufen, würde ich ganz generell lieber File::Copy::move() benutzen.

          ohne es jetzt wieder nachschlagen zu wollen ... ok cut und paste geht schneller ;)
          "Note that passing in files as handles instead of names may lead to loss of information on some operating systems; it is recommended that you use file names whenever possible. "

          Das OS *kann* keine Kopien anfertigen, das machen Hilfsprogramme wie cp und dd. Und die machen abwechselnd read() und write() auf einen einmal angelegten Buffer. Exakt das macht Perl auch, mit unwesentlich mehr overhead.

          Hast dus gebenchmarkt? Na das glaub ich dir jetzt mal.

          Kennst Du File::Copy::copy()? Das sollte Dir die ganze Kopiererei abnehmen. Und es kopiert in bis zu 2 MB großen Blöcken.

          ups das Zitat oben war von File::Copy::copy(). Move will einen Namen für den Sourceparameter.

          The "move" function also takes two parameters: the current name and the intended name of the file to be moved.

          stimmt ... leider ... eine FS-Funktion die mir die Pfade aller Hardlinks zu einem Handle ausspuckt wär wirklich nett...schöner Traum...

          Aus OS-Sicht wäre das ein Alptraum. Spätestens mit Hardlinks auf Directories.

          Ok zugegeben, an die Dir-hardlinks hab ich jetzt nicht gedacht...

          Hab ich auch gerade mal gemacht, ist tatsächlich nicht drin. Sorry.

          Naja du warst ja scheinbar lange weg, die Freude macht übermütig mit dem "RTFM" ;)

          Die Fh-Klasse in CGI.pm gibt sich alle Mühe, den Namen zu verstecken. $query->tmpFileName($upload_fh) sollte den Namen der Temp-Datei ausgeben, wie ich das auf die Schnelle sehe. Die DESTROY-Methode gibt sich aber alle Mühe, Dateien unter Kontrolle von CGI.pm zu löschen, entweder per Handle oder per Namen.

          OK, aber wir sind uns einig das ein umbenennen des Tempfiles immer noch sauberer ist als umkopieren. In einen idealen Welt hätte CGI.pm eine Methode link_tmpfile($dest_path).

          In der Doc steht noch was vom UPLOAD_HOOK und das ein unspezifizierter Parameter $buffer geliefert wird ?!?
          Mit Verweis auf Apache::Upload Objekte. Und siehe da , hier gibts ne Methode link().

          http://search.cpan.org/~joesuf/libapreq-1.3/Request/Request.pm#link
          To avoid recopying the spool file on a *nix-like system, link will create a hard link to it:

          Ich halte ein move bzw link immer noch für den sauberen Ansatz, beherzige aber Damian Conways Ratschlag erst zu benchmarken bevor man zu optimieren anfängt. Wenn keinen die Kopiererei stört, lass ichs mal gut sein.

          Bye
           Kurt

          1. Moin Moin!

            mag ja sein, aber ich will das File nicht kopieren sondern per verschieben. Sprich einen Hardlink anlegen. In perl akzeptiert "link" aber keine Filehandles.

            In der darunter liegenden Kernel-Schnittstelle (link(2)) auch nicht.

            Tja aber den Grund dafür kann ich nicht nachvollziehen ...

            int link(const char * oldpath, const char * newpath)

            newpath muß ein Name sein, alles andere würde keinen Sinn machen. Ein Handle bekommt man nur mit einem bereits existierenden File, und genau das will man ja erst anlegen.

            oldpath könnte theoretisch ein Handle sein, dieses Handle zeigt über ein paar Umwege auf ein File, und dann könnte man auch von da aus einen zweiten Verzeichniseintrag für das File anlegen.

            Ein Design-Prinzip (zumindest für Unixe) ist, den Kernel so einfach wie möglich zu halten und den Rest in die libc zu stopfen. Ein fhlink(int oldfh, const char * newpath) wäre ein klassischer Fall für einen libc-Wrapper.

            Nur ist nicht alles, was ein Handle ist, auch ein File. Sockets sind auch Handles und können wie File-Handles benutzt werden, nur haben sie keine Entsprechung im Dateisystem.

            Und woher kannst Du ein File-Handle bekommen? Von open(), von create(), oder von dem Prozess, der Deinen Prozess angelegt hat. In den beiden ersten Fällen hast Du den Dateinamen, im letzten Fall geht er Dich nichts an. Wenn Dein Elternprozess gewollt hätte, dass Du den Dateinamen kennst, hätte er ihn Deinem Prozess mitgegeben. fhlink(int oldfh, const char * newpath) ist also arbeitlos.

            "Note that passing in files as handles instead of names may lead to loss of information on some operating systems; it is recommended that you use file names whenever possible. "

            (Wie Du selbst bemertk hast, ist das der Text für copy().)

            Richtig, das spielt auf Dateiattribute (chmod), inode-Nummern und exotisches Zeug wie OS/2 Extended Attributes und NTFS Alternative File Streams an. Nichts, was das CGI-Modul benutzt.

            Das OS *kann* keine Kopien anfertigen, das machen Hilfsprogramme wie cp und dd. Und die machen abwechselnd read() und write() auf einen einmal angelegten Buffer. Exakt das macht Perl auch, mit unwesentlich mehr overhead.

            Hast dus gebenchmarkt? Na das glaub ich dir jetzt mal.

            Kennst Du File::Copy::copy()? Das sollte Dir die ganze Kopiererei abnehmen. Und es kopiert in bis zu 2 MB großen Blöcken.

            Mal überlegen, was beim Umkopieren eines Uploads bis 2 MB in aller Regel passiert?

            bufsize=min(filesize(src),2*1024*1024);
            seek(src,0,0);
            /* error-handling */
            /* Perl: Go to Next OP */
            dest=open("name","wb");
            if (!dest) errorHandling();
            /* Perl: Go to Next OP */
            buf=calloc(bufsize,1);
            /* Perl: Go to Next OP */
            count=read(src,buf,bufsize);
            /* error handling */
            /* Perl: Go to Next OP */
            write(dest,buf,count);
            /* error handling */
            close(dest);

            read() und write() sind hier die Killer: 2 MByte auf die Platte schreiben dauert, ebenso das Lesen von der Platte. Der Rest sind ein paar lausige if(x!=0)-Abfragen, die in Perl vielleicht ein paar CPU-Zyklen länger dauern.

            Wenn Du nur einen Upload hast (wie allgemein üblich), und Dein Server genügend RAM frei hat, liegt der Upload sehr wahrscheinlich noch komplett im Buffer Cache. read() muß also nur 2 MB im RAM kopieren. write() wird auch wieder erst in den Buffer Cache schreiben, 2 MB von RAM zu RAM. Und irgendwann nach close(), wenn gerade nichts besseres zu tun ist oder sync() aufgerufen wurde, schreibt der Server den Buffer Cache in den Cache der Festplatte, die wiederum macht daraus irgendwann ein magnetisches Muster auf der Scheibe.

            Die Fh-Klasse in CGI.pm gibt sich alle Mühe, den Namen zu verstecken. $query->tmpFileName($upload_fh) sollte den Namen der Temp-Datei ausgeben, wie ich das auf die Schnelle sehe. Die DESTROY-Methode gibt sich aber alle Mühe, Dateien unter Kontrolle von CGI.pm zu löschen, entweder per Handle oder per Namen.

            OK, aber wir sind uns einig das ein umbenennen des Tempfiles immer noch sauberer ist als umkopieren. In einen idealen Welt hätte CGI.pm eine Methode link_tmpfile($dest_path).

            Wer sagt Dir denn, dass die Tempfiles auf dem gleichen Dateisystem liegen wie die endgültigen Dateien? /tmp ist gerne mal eine eigene Platte oder sogar mit dem Swap und dem RAM kombiniert (tmpfs unter Linux, Solaris). Und genau da mag CGI sein Zeug gerne hinschreiben.

            Dann gewinnst Du gar nichts gegenüber dem direkten copy()-Aufruf, im Gegenteil, Du mußt noch etliche Zyklen verbrennen, um herauszufinden, dass rename() nicht funktionieren wird.

            In der Doc steht noch was vom UPLOAD_HOOK und das ein unspezifizierter Parameter $buffer geliefert wird ?!?
            Mit Verweis auf Apache::Upload Objekte. Und siehe da , hier gibts ne Methode link().

            Hilft Dir aber nicht. Denn es ist kein Apache::Upload-Objekt, es bietet nur eine ÄHNLICHE Schnittstelle.

            Ich halte ein move bzw link immer noch für den sauberen Ansatz, beherzige aber Damian Conways Ratschlag erst zu benchmarken bevor man zu optimieren anfängt. Wenn keinen die Kopiererei stört, lass ichs mal gut sein.

            Ich hab in den letzten 8 Jahren mit der Kopiermethode jedenfalls keine Performance-Probleme gehabt. Gemault haben die Kunden natürlich immer, aber nicht über Datei-Uploads, sondern über pervers lange laufende Reports (nicht aus meiner Feder).

            Alexander

            --
            Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".
            1. Hi

              OK, aber wir sind uns einig das ein umbenennen des Tempfiles immer noch sauberer ist als umkopieren. In einen idealen Welt hätte CGI.pm eine Methode link_tmpfile($dest_path).

              Wer sagt Dir denn, dass die Tempfiles auf dem gleichen Dateisystem liegen wie die endgültigen Dateien? /tmp ist gerne mal eine eigene Platte oder sogar mit dem Swap und dem RAM kombiniert (tmpfs unter Linux, Solaris). Und genau da mag CGI sein Zeug gerne hinschreiben.

              Nee, CGI möchte es bevorzugt in ein tmp-verzeichnis im Home des ausführenden users schreiben. (RTFM ...SCNR ;)

              "1. if the current user (e.g. "nobody") has a directory named              "tmp" in its home directory, use that (Unix systems only)"

              Man sollte also das Home des Users auf der gleichen Platte wie die Uploads haben.

              Ich bleibe dabei, CGI.pm wäre besser wenn es eine link() Methode hätte. Die Schnittstelle würde den häufigsten Anwendungsfall von Uploads erschlagen [*] , es wäre Performanter und der Anwender bräuchte sich darüber keinen Kopp zu machen. Außerdem könnte CGI so die Sonderfälle der "tmpfileverbergen"-Problematik besser greifen.

              Hilft Dir aber nicht. Denn es ist kein Apache::Upload-Objekt, es bietet nur eine ÄHNLICHE Schnittstelle.

              Tja aber ich werde mich auch hüten eine undokumentierte Routine von CGI zu nutzen um ans Tmpfile zu kommen... ;)

              bye
               Kurt

              [*] OK ...vielleicht ist das Ablegen in Datenbanken häufiger ...

              1. Moin Moin!

                Nee, CGI möchte es bevorzugt in ein tmp-verzeichnis im Home des ausführenden users schreiben. (RTFM ...SCNR ;)

                "1. if the current user (e.g. "nobody") has a directory named              "tmp" in its home directory, use that (Unix systems only)"

                grep nobody /etc/passwd
                nobody:x:99:99:nobody:/:

                Und nur mal so am Rande läuft der Apache nicht unbedingt als nobody:

                grep www /etc/passwd
                www:x:97:97:Apache run account:/:/bin/false

                Nun, da wir die Home-Verzeichnisse von nobody und www kennen, sag mir doch bitte mal, wie der absolute Pfad von "'tmp' in its home directory" ist.

                Man sollte also das Home des Users auf der gleichen Platte wie die Uploads haben.

                Falsch. Man sollte nicht davon ausgehen, dass die Temp-Dateien an irgendeiner nützlichen Stelle liegen.

                Ich bleibe dabei, CGI.pm wäre besser wenn es eine link() Methode hätte.

                link() funktioniert nur innerhalb eines Dateisystems, und längst nicht auf jeder Plattform.

                Die Schnittstelle würde den häufigsten Anwendungsfall von Uploads erschlagen [*] , es wäre Performanter und der Anwender bräuchte sich darüber keinen Kopp zu machen. Außerdem könnte CGI so die Sonderfälle der "tmpfileverbergen"-Problematik besser greifen.

                In der Tat wäre eine andere Schnittstelle hilfreich. Insgesamt hat sich im CGI-Modul jede Menge Chaos und krampfhafte Rückwärtskompatibilität zu kaputten Scripten angesammelt, und einige Techniken sind mindestens problematisch (Mischen von Konfiguration, Parametern und File-Parametern in einem Hash, Hilfsklassen ohne CGI::-Prefix, ...). Ich habe in den letzen Monaten mehrmals überlegt, das CGI-Modul von Grund auf neu zu schreiben, mit annähernd gleicher Schnittstelle zum Script, aber mit mehr Ordnung und Struktur hinter den Kulissen.

                Hilft Dir aber nicht. Denn es ist kein Apache::Upload-Objekt, es bietet nur eine ÄHNLICHE Schnittstelle.

                Tja aber ich werde mich auch hüten eine undokumentierte Routine von CGI zu nutzen um ans Tmpfile zu kommen... ;)

                Das haben schon viele andere getan, was mit eine Ursache für die Probleme des CGI-Moduls ist. So lange Du die Umgebung kontrollieren kannst, hätte ich dabei keine Skrupel. Wenn Dich die Paranoia beißt, schreibst Du am Anfang des Scriptes sowas wie CGI->can("tmpFileName") or die "Oooops, CGI.pm is broken.\n";

                Alexander

                --
                Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".
                1. Hi

                  Nun, da wir die Home-Verzeichnisse von nobody und www kennen, sag mir doch bitte mal, wie der absolute Pfad von "'tmp' in its home directory" ist.

                  Der "current user" soll weder www noch nobody noch www-data sein. Es tummeln sich mehrere Leute auf dem Server und ich halte es auch generell nicht für ne gute Idee Dateizugriffe mit nem Defaultuser zu machen. Und dem spendiere ich doch sehr gerne ein home-dir.

                  Man sollte also das Home des Users auf der gleichen Platte wie die Uploads haben.

                  Falsch. Man sollte nicht davon ausgehen, dass die Temp-Dateien an irgendeiner nützlichen Stelle liegen.

                  Das Tmp-dir wird wohl kaum im Wochenrhythmus umziehen, m.a.W. testen solte man sein CGI zumindest einmal schon. (ich schreibe kein Modul sonderne eine Anwendung...)

                  link() funktioniert nur innerhalb eines Dateisystems, und längst nicht auf jeder Plattform.

                  das Missverständnis war absehbar, nennen wir es also move() analog zum shell-mv wird entweder ein rename gemacht oder auf ne andere Platte kopiert.

                  Ich habe in den letzen Monaten mehrmals überlegt, das CGI-Modul von Grund auf neu zu schreiben, mit annähernd gleicher Schnittstelle zum Script, aber mit mehr Ordnung und Struktur hinter den Kulissen.

                  VIEL ERFOLG! :)

                  ...mir sind auch schon Bugs aufgefallen!

                  es wird gemunkelt Perl6 käme 2008 raus, in dem Umfeld könntest du mit einem CGI::Reloaded oder CGI::Revolutions bestimmt punkten.

                  Tja aber ich werde mich auch hüten eine undokumentierte Routine von CGI zu nutzen um ans Tmpfile zu kommen... ;)

                  So lange Du die Umgebung kontrollieren kannst, hätte ich dabei keine Skrupel.

                  na gut aber erst mal benchmarken dann entscheiden ob sich die Komplikation lohnt.

                  bye
                   Kurt

                  1. Moin Moin!

                    Nun, da wir die Home-Verzeichnisse von nobody und www kennen, sag mir doch bitte mal, wie der absolute Pfad von "'tmp' in its home directory" ist.

                    Der "current user" soll weder www noch nobody noch www-data sein. Es tummeln sich mehrere Leute auf dem Server und ich halte es auch generell nicht für ne gute Idee Dateizugriffe mit nem Defaultuser zu machen. Und dem spendiere ich doch sehr gerne ein home-dir.

                    Der Punkt ist, dass CGI.pm nicht gezielt für Dich entwickelt wurde, sondern für Leute, die *irgendwo* ein CGI laufen lassen wollen.

                    Man sollte also das Home des Users auf der gleichen Platte wie die Uploads haben.

                    Falsch. Man sollte nicht davon ausgehen, dass die Temp-Dateien an irgendeiner nützlichen Stelle liegen.

                    Das Tmp-dir wird wohl kaum im Wochenrhythmus umziehen, m.a.W. testen solte man sein CGI zumindest einmal schon. (ich schreibe kein Modul sonderne eine Anwendung...)

                    Und Module testest Du nicht? Oder wie soll ich das verstehen?

                    Wie gesagt: Das CGI-Modul geht davon aus, dass jeder Server etwas anders ist. Es hat außer Perl 5.x und einem Webserver mit CGI-Schnittstelle sehr wenige Voraussetzungen, und es macht über sehr wenige Dinge konkrete Annahmen. Deswegen funktioniert es in so ziemlich jeder CGI-Umgebung mit Perl-Interpreter. Das dürfte einer der Gründe für die weite Vebreitung des CGI-Moduls sein. Wenn Deine Anwendung mehr Dinge voraussetzt, hindert Dich niemand, bestimmte Annahmen zu machen. Das bedeutet aber auch, dass Deine Anwendung nicht überall da laufen wird, wo auch das CGI-Modul funktioniert.

                    Wenn Du Dich auf bestimmte Einschränkungen einläßt, kannst Du auch das Verhalten des CGI-Moduls ändern. Entweder, indem Du eine Kopie des CGI-Moduls an Deine Bedürfnisse anpaßt und dafür sorgst, dass *Dein* CGI-Modul vor dem Standard-Modul gefunden wird, oder indem Du vom CGI-Modul erbst und die Anpassungen durch Vererbung vornimmst. Oder Du änderst das Verhalten des CGI-Moduls zur Laufzeit, in dem Du bestehende Funktionen und Methoden gegen eigene austauschst. Ich habe alle drei Varianten durchgespielt, die letztere ist recht erfolgreich, um den UTF-8-Support deutlich zu verbessern. Per Vererbung oder Laufzeit-Patch lassen sich einige Dinge (z.B. XHTML-Bevorzugung) leider nicht komplett ändern, so dass ich letztlich doch eine gepatchte Kopie weit vorne in @INC platziert habe.

                    link() funktioniert nur innerhalb eines Dateisystems, und längst nicht auf jeder Plattform.

                    das Missverständnis war absehbar, nennen wir es also move() analog zum shell-mv wird entweder ein rename gemacht oder auf ne andere Platte kopiert.

                    Das läßt sich leicht in einen Wrapper packen. Wenn Du das CGI-Modul nicht anfassen willst, wirst Du um einen Wrapper kaum herumkommen.

                    Ich habe in den letzen Monaten mehrmals überlegt, das CGI-Modul von Grund auf neu zu schreiben, mit annähernd gleicher Schnittstelle zum Script, aber mit mehr Ordnung und Struktur hinter den Kulissen.

                    VIEL ERFOLG! :)

                    ...mir sind auch schon Bugs aufgefallen!

                    http://search.cpan.org/~lds/CGI.pm-3.29/CGI.pm#BUGS

                    es wird gemunkelt Perl6 käme 2008 raus, in dem Umfeld könntest du mit einem CGI::Reloaded oder CGI::Revolutions bestimmt punkten.

                    Perl6 kommt, wenn es fertig ist. Und bis es zu relvanten Hostern durchschlägt, wird es seeeeeehr lange dauern. Es gibt immer noch Hoster mit Perl 5.005. Ich bezweifle sehr, dass sich die Leute nach dem Release von Perl 6 sofort darauf stürzen und feierlich ihre Perl-5-Bücher verbrennen. Perl 6 ist so drastisch anders, dass es im Idealfall eine sanfte Migration geben wird. Im schlimmsten Fall wird Perl6 der größte Flop aller Zeiten.

                    Alexander

                    --
                    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".
                    1. Hi Alexander

                      Der "current user" soll weder www noch nobody noch www-data sein. Es tummeln sich mehrere Leute auf dem Server und ich halte es auch generell nicht für ne gute Idee Dateizugriffe mit nem Defaultuser zu machen. Und dem spendiere ich doch sehr gerne ein home-dir.

                      Der Punkt ist, dass CGI.pm nicht gezielt für Dich entwickelt wurde, sondern für Leute, die *irgendwo* ein CGI laufen lassen wollen.

                      Was ich sagen wollte: will man aus Performancegründen per "link" die Datei "kopieren", dann kann man dafür sorgen, dass das tmp auf der gleichen Platte liegt.

                      Natürlich sollte eine Kopierfunktion von sich aus so robust sein den Fall 2er Platten abzufangen und dann die Daten rüberzuschaufeln.

                      Tschau
                        Kurt

  2. Hi

    kleiner Nachtrag CGI::Simple erlaubt es den Zielpfad eines Uploads direkt anzugeben.

    Grüße
     Kurt

    http://search.cpan.org/~jfreeman/Cgi-Simple-0.077/Simple.pm

    1. kleiner Nachtrag CGI::Simple erlaubt es den Zielpfad eines Uploads direkt anzugeben.

      und macht dann nichts anderes als du uns gezeigt hast, es kopiert die Temporäre Datei (es nutzt dazu IO::File).

      Struppi.

      1. und macht dann nichts anderes als du uns gezeigt hast, es kopiert die Temporäre Datei (es nutzt dazu IO::File).

        sieht so aus ...
         Kurt