Welcome, guest | Sign In | My Account | Store | Cart

This is a bare-bones cgi file upload. It will display an upload form and save the uploaded files to disk.

Python, 68 lines
 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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#!/usr/local/bin/python
"""This demonstrates a minimal http upload cgi.
This allows a user to upload up to three files at once.
It is trivial to change the number of files uploaded.

This script has security risks. A user could attempt to fill
a disk partition with endless uploads. 
If you have a system open to the public you would obviously want
to limit the size and number of files written to the disk.
"""
import cgi
import cgitb; cgitb.enable()
import os, sys
try: # Windows needs stdio set for binary mode.
    import msvcrt
    msvcrt.setmode (0, os.O_BINARY) # stdin  = 0
    msvcrt.setmode (1, os.O_BINARY) # stdout = 1
except ImportError:
    pass

UPLOAD_DIR = "/tmp"

HTML_TEMPLATE = """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head><title>File Upload</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head><body><h1>File Upload</h1>
<form action="%(SCRIPT_NAME)s" method="POST" enctype="multipart/form-data">
File name: <input name="file_1" type="file"><br>
File name: <input name="file_2" type="file"><br>
File name: <input name="file_3" type="file"><br>
<input name="submit" type="submit">
</form>
</body>
</html>"""

def print_html_form ():
    """This prints out the html form. Note that the action is set to
      the name of the script which makes this is a self-posting form.
      In other words, this cgi both displays a form and processes it.
    """
    print "content-type: text/html\n"
    print HTML_TEMPLATE % {'SCRIPT_NAME':os.environ['SCRIPT_NAME']}

def save_uploaded_file (form_field, upload_dir):
    """This saves a file uploaded by an HTML form.
       The form_field is the name of the file input field from the form.
       For example, the following form_field would be "file_1":
           <input name="file_1" type="file">
       The upload_dir is the directory where the file will be written.
       If no file was uploaded or if the field does not exist then
       this does nothing.
    """
    form = cgi.FieldStorage()
    if not form.has_key(form_field): return
    fileitem = form[form_field]
    if not fileitem.file: return
    fout = file (os.path.join(upload_dir, fileitem.filename), 'wb')
    while 1:
        chunk = fileitem.file.read(100000)
        if not chunk: break
        fout.write (chunk)
    fout.close()

save_uploaded_file ("file_1", UPLOAD_DIR)
save_uploaded_file ("file_2", UPLOAD_DIR)
save_uploaded_file ("file_3", UPLOAD_DIR)

print_html_form ()

This demonstrates a minimal http upload cgi. This is a self-posting cgi, so it will both display an upload form as well as process any uploaded files. Uploaded files are saved to the UPLOAD_DIR which is currently set to "/tmp".

This script has security risks. A user could attempt to fill a disk partition with endless uploads. If you have a system open to the public you would obviously want to limit the size and number of files written to the disk.

9 comments

Georgy Pruss 20 years ago  # | flag

It seems that on Windows, you have to switch to binary mode to be able to upload binary files like pictures

try:
  import msvcrt,os
  msvcrt.setmode( 0, os.O_BINARY ) # stdin  = 0
  msvcrt.setmode( 1, os.O_BINARY ) # stdout = 1
except ImportError:
  pass
Georgy Pruss 20 years ago  # | flag

Sample. ... and just to share my version: http://zxw.nm.ru/test_w_upload.py.htm

Editor Note (June 2010): The above link no longer exists, it redirects to an inappropriate and unrelated site. The link has been updated to the Internet Archive version. See all archived versions of this URL.

randy 19 years, 7 months ago  # | flag

documentation for upload.cgi ? drats!

this script (as well as the one by Georgy Pruss that's mentioned in the thread) looks easy enough to implement but i'm having no luck.

is there more documentation i can refer to for setting this up? thanks

jitu nair 18 years, 10 months ago  # | flag

file upload problem.

If I choose more than one file to upload only the fisrt file uploads.
I commented the "form = cgi.FieldStorage" line in the "save_uploaded_file" fuction and put it just above the
fuction . now all three file uploads take place.
Chris Arndt 18 years, 8 months ago  # | flag

cgi.FieldStorage instantiation. I guess that's because they way the original script is written, FieldStorage gets instantiated three times, each time the save_upload() function is called. But probably already at the first time the FiledStorgae eats up alls data from sys.stdin where the uploaded files are provided.

So FieldStorage should be instantiated only once and then either made available, as you suggested, as a global variable or handed over as a third argument to the save_upload() function.

Stephen Chappell 18 years, 3 months ago  # | flag

File Transfer. How does the CGI module get a file from a client's computer? Also, how does the CGI module get data from the POST method? I have written a lightweight version of the CGI module, but getting files is something that it cannot do yet. The CGI programs that currently work with it do not specify a method.

Peter Moore 16 years, 5 months ago  # | flag

Example needs work. I think that what is missing in this script is the author's SCRIPT_NAME environment variable. This example will not work otherwise.

Ive tried to set this to the script name itself sys.argv[0] with no luck.. So what is this supposed to be set to ?

Peter Moore 16 years, 5 months ago  # | flag

answered. I got an answer to my own question. The problem I had was that I was using a SimpleHTTPServer python script. This dosn't set a SCRIPT_NAME env variable which Apache sets.

Apache would have set to something like /cgi-bin/upload.cgi if this sctipt was called upload.cgi (presuming that you made your cgi directory cgi_bin

Hanseong Yoo 16 years, 4 months ago  # | flag

Test drive at my linux server. I corrected it as follows to work well....

form=cgi.FieldStorage() # put this before HTML_TEMPLATE definition

... at print_html_form() funtion;

There's no os.environ['SCRIPT_NAME'] --> os.environ

['SCRIPT_FILENAME'], and considering your url...

a='your_web_url_to_cgi/'+os.environ['SCRIPT_FILENAME'].split('/')[-1]

print HTML_TEMPLATE % {'SCRIPT_NAME':a}

... at save_uploaded_file() funtion;

global form

Now it works well...