Henk: Fileuploadscript

Hallo,

hier ein perlscript, das

1. eine datei auf den server hochläd,
2. eine mailbenachrichtigung mit namen und emailadresse des hochladenden an den administrator schickt.

(Es ist etwas länger, deshalb habe ich es nicht direkt in die Nachricht kopiert, sorry!)

Das ganze baut auf einem skript auf, das Frank Schönmann vor geraumer zeit hier gepostet hat. http://www.teamone.de/selfhtml/sfarchiv/1998_4/t01332.htm

Das skript wird von einem formular aufgerufen, das außer dem dateifeld noch je ein feld für Name und email des absenders enthält: Siehehttp://www.skimboards.de/pics.html

Ich hoffe, Ihr könnt was damit anfangen.
Ansonsten freue ich mich über verbesserungsvorschläge (vor allem was die überprüfung des dateiformats betrifft!)
und vor allem über mac und unixuser, die es testen, denn bisher konnte ich es nur mit windowsbrowsern testen!

Gruß

Henk

Ach ja, adresse des skripts ist http://www.skimboards.de/cgi-bin/upload.cgi

Anmerkung: Nach meiner erfahrung funktioniert die überprüfung von dateigröße (maxlength=xx) genausowenig wie die mimetype-einschränkung (accept="yy"), und zwar weder bei IE noch bei NS...

Deshalb muß man leider erst die datei übertragen, damit dann das skript eine fehlermeldung auswerfen kann.

  1. Auf Wunsch von Frank gibt's jetzt doch noch den Quellcode...

    #!/usr/bin/perl

    Pfad des Upload-Verzeichnisses am Server:

    $uploaddir = "/home/strobel/public_html/skimboards/uploads/";

    max. Dateigröße [bytes]

    $maxsize = 512000;

    Mailadresse des Administrators, für die Benachrichtigung

    $adminemail = "hstrobel@x-spect.de";

    Pfad zum Mailprogramm

    $mailprogramm = "/usr/lib/sendmail";

    #############################################

    Jetzt geht's los:

    binmode STDIN;

    read STDIN, $Daten, $ENV{'CONTENT_LENGTH'};

    @Teile = split /-----------------------------.{9}/, $Daten;

    @Name = split /\n/, $Teile[1], 5;
    @Email = split /\n/, $Teile[2], 5;
    @Datei = split /\n/, $Teile[3], 5;

    $Teile[1] enthält den Namen,

    $Teile[2] enthält die Emailadresse,

    $Teile[3] enthält Dateiinformationen,

    while ($Datei[1] =~ /\/)  #
    {         #
      $Datei[1] =~ s/^.*\//;   # Der Verzeichnis-Pfad wird entfernt,
    }        # der Dateiname bleibt übrig...
            #
    $Datei[1] =~ s/"//;    #

    chop $Datei[1];  #
    chop $Datei[4];  # Letzes Zeichen entfernen...
    chop $Datei[4];  #

    Überprüfung des dateiformats und der dateigröße:

    if($Datei[1] =~ /.jpg$/i  && length $Datei[4] > 100)  
    {
      if (length $Datei[4] < $maxsize )
      {
        # dateinamen ermitteln

    $filename = $Datei[1];  
    

    # datei speichern:

    open DATEI, ">$uploaddir$filename";  
    binmode DATEI;  
    print DATEI $Datei[4];  
    close DATEI;  
    

    # Überprüfung, ob datei vorhanden
      
       if(open(DATEINEU, "<$uploaddir$filename") eq 'false')
       {
            print "Location: ../error1.html\n\n"; die;
       }
          else { print "Location: ../thanxpic.html\n\n"; }
      }
      else { print "Location: ../error2.html\n\n"; die; }
    }
    else { print "Location: ../error3.html\n\n"; die; }

    Emailbenachrichtigung:

    open(MAIL,"$mailprogramm -t") die "Mailprogramm nicht gefunden!";

    print MAIL "To: $adminemail\n";
    print MAIL "From: Auto file upload notification\n";
    print MAIL "Subject: Fileupload auf www.skimboards.de!\n\n";

    print MAIL "Upload der Datei "$filename"\n";
    print MAIL "von $Name[3] ( $Email[3] )\n\n";
    print MAIL "http://members.pop-hannover.de/~strobel/skimboards/uploads/";
    close(MAIL);

    1. @Teile = split /-----------------------------.{9}/, $Daten;

      Und wenn genau diese Zeichenkette im Inhalt der Datei enthalten ist?

      Führe mal selbst so einen Upload durch und gib dabei den Inhalt der Environment-Variablen CONTENT_TYPE aus.
      Am Ende dieses Inhalts steht - nach meiner Erfahrung - die Angabe "boundary=" und danach die exakte Zeichenkette zum Trennen der Multipart-Komponenten (also die vielen Minuszeichen und die konkrete neunstellige Zahl) *ohne* die beiden ersten Minuszeichen. (Deshalb: Siehe unten.)

      Wenn Du diese Zeichenkette verwendest, etwa mit
          #--------------------------------------------------------------------------
          # Aus der Environment-Variablen CONTENT_TYPE u. a. die Separator-Zeichenkette
          # zwischen den einzelnen Multipart-Komponenten herausschneiden
          (my $boundary = $ENV{CONTENT_TYPE}) =~ s/^.*boundary=(.*)$/\1/;
          #--------------------------------------------------------------------------
          # Die gesamten Eingabedaten unter Verwendung dieser Separator-Zeichenkette
          # in eine Liste von Teilen zerschneiden
          @pairs = split (/--$boundary/, $raw_data);
      #--------------------------------------------------------------------------,

      dann verwendet das Skript die m. E. beste verfügbare Information über den Multipart-Trenner.

      Sollte mal irgend ein komischer Browser eine andere Zeichenkette als Trenner verwenden, würde Dein Skript *dann* auch damit fertig werden.

      P.S.: Nicht meine Idee, sondern aus einem mir vor ca. einem Jahr "zugelaufenen" Perl-Skript, das damals offenbar eine Vorstufe des heutigen CGI::-Moduls realisiert hat.

      1. Besten Dank,

        ich hab's mal so probiert: (Mit Windows-Browsern geht's):

        (...)

        #############################################

        Jetzt geht's los:

        binmode STDIN;

        read STDIN, $Daten, $ENV{'CONTENT_LENGTH'};

        $envct = $ENV{'CONTENT_TYPE'};

        $envct =~ s/^.+boundary=//;

        @Teile = split (/$envct/, $Daten);

        (...)

        Rest wie gehabt...

        Aber: leider noch keine Testergebnisse mit MAC und UNIX-Browsern. Will denn keiner? :-(

        Siehe:
        http://www.skimboards.de/pics.html

        Henk

        1. hi!

          ich hab's mal so probiert: (Mit Windows-Browsern geht's):

          Ich krieg mit Linux 2.2.11 + Netscape 4.51 immer angezeigt, ich würde keine gültige JPG-Datei hochladen, auch nicht, wenn die Erweiterung stimmt und ich das Bild verwende, das auf der angegebenen Seite zu sehen ist.

          bye, Frank!

          1. Hi,

            da haben wir den salat...

            mac und linuxbrowser scheinen den "Datenstrom" beim abschicken des Formulars anders zu formatieren als die windowsprogramme. Wo bei IE und NS für win der lokale pfad mit dateiname steht, heißt es bei mac und linux:

            Content-Disposition: form-data; name=datei"; filename="macmade-wht.JPG"

            Hat jemand eine Ahnung, wo man genauere angaben darüber bekommen kann, wie dieser Datenstrom denn nun wirklich aussieht?????

            Henk