Forum: PC-Programmierung Html Upload mit Python-CGI - korrupte files


von Philip K. (philip_k)


Lesenswert?

Hallo,

ich versuche gerade nach einem Beispiel einen lokalen File-Upload per 
Python-CGI zu implementieren. Der Transfer läuft durch und das Script 
meldet einen erfolgreichen Upload - nur leider sind die Files (z.B. 
jpeg-Bilder) danach viel kleiner und lassen sich nicht öffnen.

Server:
1
import http.server
2
PORT = 8080
3
handler = http.server.CGIHTTPRequestHandler
4
httpd = http.server.HTTPServer(("", PORT), handler)
5
print("serving at port", PORT)
6
httpd.serve_forever()

Upload-Form:
1
<div>
2
<form enctype="multipart/form-data" action="cgi-bin/upload.py" method="post">
3
    <p>File: <input type="file" name="file"></p>
4
      <input type="submit" value=" Start Upload ">
5
</form>
6
<div>

CGI:
1
#!C:\Python33\python.exe 
2
#!/usr/bin/env python
3
import cgi, os
4
import cgitb; cgitb.enable()
5
6
try: # Windows needs stdio set for binary mode.
7
    import msvcrt
8
    msvcrt.setmode (0, os.O_BINARY) # stdin  = 0
9
    msvcrt.setmode (1, os.O_BINARY) # stdout = 1
10
except ImportError:
11
    pass
12
13
form = cgi.FieldStorage()
14
15
# A nested FieldStorage instance holds the file
16
fileitem = form['file']
17
18
# Test if the file was uploaded
19
if fileitem.filename:
20
   
21
   # strip leading path from file name to avoid directory traversal attacks
22
   fn = os.path.basename(fileitem.filename)
23
   open('files\\' + fn, 'wb').write(fileitem.file.read())
24
   message = 'The file "' + fn + '" was uploaded successfully'
25
   
26
else:
27
   message = 'No file was uploaded'
28
   
29
print("""\
30
Content-Type: text/html\n
31
<html><body>
32
<p>%s</p>
33
</body></html>
34
""" % (message,))

Hat jemand eine Idee?

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Nur mal so eine Idee: Versuch das file mal zu flushen und korrekt zu 
schließen.
Auch vermisse ich sämtliche Fehlerbhandlung/prüfung/validierung des 
Schreib und Lesevorgangs.

Und wenn du schon ein File hast: Warum nicht verschieben statt zu 
kopieren?

von Philip K. (philip_k)


Lesenswert?

Stimmt, das Schließen des Files fehlt. Scheint aber leider nicht das 
Problem zu sein. Der Aufruf "fileitem.file.read()" liefert schon eine 
Sequenz, die viel kleiner ist als das hochgeladene File. Außerdem ist 
die Größe jedes Mal anders.

> Und wenn du schon ein File hast: Warum nicht verschieben statt zu
> kopieren?
Steh grad auch dem Schlauch...wie meinst Du das?

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Philip K. schrieb:
> Steh grad auch dem Schlauch...wie meinst Du das?

fileitem.file scheint doch shcon ein File zu sein. Wieso also nicht 
diese mit move(? schau halt mal in die API...) ans gewünschte Ziel 
verschieben?

Philip K. schrieb:
> Der Aufruf "fileitem.file.read()" liefert schon eine Sequenz, die viel
> kleiner ist als das hochgeladene File

Lies dir mal die API durch und nimm dir meinen Hinweis bezüglich der 
Rückgabewerte zu Herzen. Ich kenne nun die Python API nicht aber in 
nahezu allen I/O APIs ist es so, das das lesen nicht immer vollständig 
sein muss sondern in "Happen" passiert, d.h. man liest (und schreibt) 
solange bis der "da-kommt-nix-mehr" Marker (siehe API!!) kommt.

von Philip K. (philip_k)


Lesenswert?

fileitem.file ist vom Typ io.BufferedIOBase also ein Stream-Object.

http://docs.python.org/3.3/library/io.html#io.BufferedIOBase

Da steht:
"read(n=-1)¶
Read and return up to n bytes. If the argument is omitted, None, or 
negative, data is read and returned until EOF is reached. An empty bytes 
object is returned if the stream is already at EOF."

Sollte also nach meinem Verständnis so funktionieren. Ein nochmaliger 
Aufruf liefert auch ein leeres bytes-Objekt. Ich habe auch mehrere 
Beispiele zu dem Thema gefunden und in allen wird auf diese Art gelesen.

Vielleicht stimmt ja auch was mit dem Python-Server nicht. Ich werds mal 
auf meinem RPI mit lighttpd testen.

von A. B. (funky)


Lesenswert?

was steht denn danach in deinem Ausgabefile? Etwas was entfernt mit den 
Urprungsdaten zu tun hat, oder evtl. nur eine Fehlermeldung oder einfach 
nur Schrott?

von Philip K. (philip_k)


Lesenswert?

A. B. schrieb:
> was steht denn danach in deinem Ausgabefile? Etwas was entfernt mit den
> Urprungsdaten zu tun hat, oder evtl. nur eine Fehlermeldung oder einfach
> nur Schrott?
Bei Bildern sind manchmal ein paar Zeilen am oberen Rand sichtbar. 
Insofern sind das wohl schon gültige Daten.

von Philip K. (philip_k)


Lesenswert?

Kleine textfiles funktionieren übrigens. Textfiles in der Größenordnung 
40K hab ich noch nicht probiert...

von Philip K. (philip_k)


Lesenswert?

Mit dem RPI/lighttpd funktionierts und ist auch noch wesentlich 
schneller :-\

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.