Schrift
[thread]10964[/thread]

Problem mit File Upload

Leser: 3


<< |< 1 2 3 >| >> 30 Einträge, 3 Seiten
Gast Gast
 2007-12-06 12:20
#103499 #103499
Hi @all,
hab ein kleines Problem mit einem Upload script.

Ich möchte in dem Formular über ein 'hidden' Feld einen Pfad mitsenden in den ich die Dateien laden möchte.


Das script welches ich benutze liegt hier:

www.srmiles.com/freestuff/ajax_file_uploader/

Oben in der cgi-datei werden die Vars definiert:

Code: (dl )
1
2
3
4
5
6
7
8
9
## Get Unique ID Passed from PHP
my $sid = (split(/[&=]/,$ENV{QUERY_STRING}))[1];
$sid =~ s/[^a-zA-Z0-9]//g;   

## Define Directory Paths (Must be Absolute Paths)

my $upload_dir = $ENV{'DOCUMENT_ROOT'}."/upload_fraeszentrum/";
my $tmp_dir = $ENV{'DOCUMENT_ROOT'}."/tmp/";
my $session_dir = $tmp_dir.$sid;


wenn ich nun :
Code: (dl )
my $upload_dir = $ENV{'DOCUMENT_ROOT'}."/upload_fraeszentrum/test/";

eingebe funktioniert das ganze auch.

aber das:
Code: (dl )
1
2
my $pfad = param('pfad');
my $upload_dir = $ENV{'DOCUMENT_ROOT'}."/upload_fraeszentrum/".$pfad."/";


geht nicht.
der pfad ist zwar da, aber weiter unten im code:

Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
################################################################################ 
## Process Uploaded File
################################################################################
if(-d $session_dir){
my $query = new CGI;
my $file_name = $query->param("filename");
$file_name =~ s/.*[\/\\](.*)/$1/;
my $upload_file_path = $upload_dir.$file_name;
my $upload_filehandle = $query->upload("filename");
my $tmp_filename = $query->tmpFileName($upload_filehandle);
close($upload_filehandle);
print "Moving File to Upload Directory -> ";
if ( rename($tmp_filename, $upload_file_path) ) {
print "<b style='color:green;'>Success</b><br>";
} else {
print "<font color='red'>Failure</font><br>";
}

}


bei 'rename' kommt ein fehler.
herausgefunden hab ich, das dann immer $tmp_filename fehlt. warum auch immer.

kann mir bitte jemand sagen wie ich das machen muß, so das es geht?


Gruß Mathi
GwenDragon
 2007-12-06 13:43
#103501 #103501
User since
2005-01-17
14548 Artikel
Admin1
[Homepage]
user image
1) Du schließt doch die temporäre Datei.

Ist tmpFileName() nicht eine undokumentierte (interne) Methode?
Eigentlich sollte eineR nur offizielle Methoden benutzen.

Warum lässt du denn die temporäre Uploaddatei nicht auf und kopierst sie dann um und schließt dann die temporäre Uploaddatei?

Weißt du was ich meine? ;)

Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
if(-d $session_dir){ 
        my $query = new CGI;
        my $file_name = $query->param("filename");
        $file_name = (split(/[\/\\]/,$file_name))[-1];
        my $upload_file_path = $upload_dir.$file_name;
        my $upload_filehandle = $query->upload("filename");

        print 'Moving File to Upload Directory -> ';
        my ($tmpfh2, $buffer);
        if ( open($tmpfh2, '>', $upload_file_path ) ) { 
                flock($tmpfh2, LOCK_EX);
                while (my $bytesread = read($upload_filehandle, $buffer, 1024)) {
                        print $tmpfh2 $buffer;
                }
                if( close($upload_filehandle) and close($tmpfh2) {
                        print $query->b({-style=>'color:green'}, "Success"), $query->br();       
                } else { 
                        print $query->b({-style=>'color:red'}, "Failure"),$query->br();
                }
        } else { 
            print $query->b({-style=>'color:red'}, "Failure"),$query->br();
        }
    }


2) Beim Erzeugen des Dateinamens verwendest du nur / und \ als Trenner. Was ist mit Macs? Die haben nämlich einen anderen Trenner.


3) Du solltest bei deinen Parameter pfad und filename überprüfen, ob das zusammengesetzte Konstrukt nicht Zeichen enthält, wo böswillge Leute auch Dateien außerhalb DOCUMENT_ROOT überschreiben können!

3) Du solltest eigentlich auch testen, ob die hochzuladene Datei schon vorhanden ist, damit unerlaubt oder aus Versehen nichts wichtiges gelöscht wird.

4) Ein paar mehr Meldungen an STDERR oder eine eigene Logdatei, warum was nicht geklappt hat wäre auch nützlich.

Viel Erfolg beim Verbessern und Erweitern.
die Drachin, Gwendolyn


Unterschiedliche Perl-Versionen auf Windows (fast wie perlbrew) • Meine Perl-Artikel

Gast Gast
 2007-12-06 19:36
#103526 #103526
hi GwenDragon,
danke für deine mühe.

aber ich bekomm es einfach nicht hin. vielleicht hätte ich besser dazuschreiben müssen, das ich mit perl noch nie gearbeitet habe. (mach eigentlich nur php)
aber in dem fall brauche ich den upload um auch größere dateien hochladen zu können und in verbindung mit ajax einen statusbalken auszugeben.


.. wenn ich das so nehme wie du schreibst kommt leider ein server error.


das script habe ich auch nur 'gefunden' bei:

http://www.srmiles.com/projects/ajax_file_uploader/

mir fehlt einfach nur die möglichkeit im formular den ordner mitzusenden in den die daten dann geladen werden sollen. mehr nicht.

(der ganze upload ist zus. noch passwordgeschützt, also nur wer eingeloggt ist, der kann daten hochladen)

Gruß Mathi
GwenDragon
 2007-12-06 21:25
#103528 #103528
User since
2005-01-17
14548 Artikel
Admin1
[Homepage]
user image
Vielleicht sendet dein Skript keinen Header.

Füge mal vor zeile 8 folgendes ein
print $query->header();
die Drachin, Gwendolyn


Unterschiedliche Perl-Versionen auf Windows (fast wie perlbrew) • Meine Perl-Artikel

Gast Gast
 2007-12-06 22:45
#103531 #103531
immer noch...

Serverfehler!

Die Anfrage kann nicht beantwortet werden, da im Server ein interner Fehler aufgetreten ist.

Fehlermeldung:
Premature end of script headers: upload.cgi

Sofern Sie dies für eine Fehlfunktion des Servers halten, informieren Sie bitte den Webmaster hierüber.
GwenDragon
 2007-12-06 22:58
#103532 #103532
User since
2005-01-17
14548 Artikel
Admin1
[Homepage]
user image
magst du mir nicht dein Skript an info @ gwendragon . de
senden, dann schau ich es morgen mal an.
die Drachin, Gwendolyn


Unterschiedliche Perl-Versionen auf Windows (fast wie perlbrew) • Meine Perl-Artikel

Gast Gast
 2007-12-06 23:13
#103533 #103533
ja, das mach ich doch gern...

Danke dir :-)
morph
 2007-12-07 00:50
#103535 #103535
User since
2007-12-06
79 Artikel
BenutzerIn
[Homepage] [default_avatar]
Hi Mathi.

Biite immer daran denken: Die meisten Angriffe kommen aus dem eigegen Netzwerk. Soll heißen, dass auch authorisierte Benutzer böse Menschen sein können, die ihren Schabernack treiben wollen.

Gast+2007-12-06 11:20:58--
Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
use strict;
use warnings;
use CGI::Carp qw/fatalsToBrowser/;
use CGI qw/:cgi/;

# Schon hier oben muss CGI instanziert werden, weil es automatisch auch den
# QureyString zerlegt. Siehe weiter unten.

my $SID = "PHPSESSID"; # Hier dann Eintragen was die PHP Anwendnung verwendet.
my $cgi = new CGI;

## Get Unique ID Passed from PHP

# Also erst mal Directory Traversal Attacks abchecken !!!
# Und natürlich auch im Dateinamen, weil ein Angreifer das in seinem
# Tool dort geschickt einbaut.

exit if (
   $cgi->param($SID)       =~ |/\.\./| or
   $cgi->param('filename') =~ |/\.\./| 
);

# Und aussteigen wenn das einer versucht, denn dann braucht Dein
# Skript überhaupt nichts mehr machen. Solche Sachen am besten
# gleich zu Anfang des Skriptes, noch vor den Variablen Insitialisierung.


# Und den split hier kann man sich dann sparen, weil der die RegEx Engine 
# jetzt nochmal anwirft.
# my $sid = (split(/[&=]/,$ENV{QUERY_STRING}))[1];
$cgi->param($SID) =~ s/[^a-zA-Z0-9]//g;   

## Define Directory Paths (Must be Absolute Paths)
        
# Stings nur dann contantenieren, wenn es sich überhaupt nicht vermeiden
# lässt. Evaluieren muss Perl diese sowieso.
my $upload_dir  = "$ENV{DOCUMENT_ROOT}/upload_fraeszentrum/"; 
my $tmp_dir     = "$ENV{DOCUMENT_ROOT}/cgi-bin/tmp/";
my $session_dir = $tmp_dir.$cgi->($SID);

# Und das tmp würde ich im cgi-bin Verzeichnis anlegen, weil man daraus keine
# statischen Inhalte abrufen kann. So kann da keiner einfach mal reinschnuppern.
# Einer der Gründe warum ich CGI/Perl so liebe. Man braucht sich da keinen Kopf 
# um .htaccess und so 'ne Sachen machen :D


Und dann der eigentliche Upload.

Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
################################################################################ 
## Process Uploaded File
################################################################################
        if(-d $session_dir){ 
                # Das hatten wir oben schon.
                # my $query = new CGI;
                my $file_name = $cgi->param("filename");
                $file_name =~ s/.*[:\/\\](.*)/$1/; # Den Doppelpunkt für die Macs

                my $upload_file_path = $upload_dir.$file_name;
                my $upload_filehandle = $cgi->upload("filename");
                my $tmp_filename = "upl_".$$.$file_name; # TemporärDatei mit der PID
                # close($upload_filehandle);

                use Fcntl qw/:flock/;
                # Fcntl auf flock begrenzen, das spart speicher, weil das eine
                # ausgewachsene Bibliothek ist, die wir nicht in voller Größe
                # brauchen.

                # Maximum Uploadgröße 2MB (oder bei bedarf mehr).
                $CGI::POST_MAX = 1024 * 2048;

                open F, ">", $tmp_filename || &err_msg ( $upl_err."<br>$!" ); # Mein ErrorHandler
                flock F, LOCK_EX; # Datei sperren.
                binmode $tmp_filename; # Zur Sicherheit in den Binärmodus schalten.
                binmode F;
                while ( read $tmp_filename, my $buf, 1024 ) { print F $buf; }
                flock F, LOCK_UN; # Datei wieder freigeben.
                close F;

                # Und ganz wichtig: Den Inhalt der hochgeladenen Datei abprüfen.
                # Entsprechend den Vorgaben, was da hochgeladen werden darf.
                unless ( &chk_filecontent($tmp_filename) ) { exit; }
                else { 
                        use File::Copy;
                        print "Moving File to Upload Directory -> ";
                        if ( move ( $tmp_filename, $upload_file_path ) ) {
                                print "<b style='color:green;'>Success</b><br>"; 
                        }
                        else {
                                print "<font color='red'>Failure</font><br>";
                        }
                } # End unless chk_filecontent
        } # End if -d session_dir

sub chk_fileconent {
    $file = shift || return;
    # Hier jetzt Pseudocode!!!
    return ($file eq "OK") ? 1 : 0;
}


Abschließend:
Man kann zwar Dateien auch mit rename Verschieben, aber es ist nicht wirklich dafür geeignet. Man sollte damit lediglich Dateien umbenennen.
Das Modul CPAN:File::Copy verwendet die tatsächlich zu Grunde liegenden Betriebssystemfunktionmen.

Hoffe ich konnte ein wenig Licht ins Dunkle bringen.

-uw

EDIT:
Habe mir das Skript mal gezogen und angeschaut. Also das gehört in der Tat überarbeitet. ;)

Vielleicht liegt's auch an der Shebang-Teile. Check mal Dienen Webspace, bzw. Server, wo der Perlinterpreter steckt.

-uw
Gast Gast
 2007-12-07 12:07
#103543 #103543
leider immer noch Fehler:

Premature end of script headers: upload.cgi


der perl interpreter is in

/usr/bin/perl



Perl-Version in der Testumgebung: 5.8.6
Perl Version auf dem Richtigen Server: 5.8.8
Gast Gast
 2007-12-07 12:07
#103544 #103544
leider immer noch Fehler:

Premature end of script headers: upload.cgi


der perl interpreter is in

/usr/bin/perl



Perl-Version in der Testumgebung: 5.8.6
Perl Version auf dem Richtigen Server: 5.8.8
<< |< 1 2 3 >| >> 30 Einträge, 3 Seiten



View all threads created 2007-12-06 12:20.