웹 애플리케이션에서 파일을 업로드하려면 HTML 폼의 enctype 속성을 반드시 multipart/form-data로 설정해야 합니다. 이 속성이 없으면 브라우저가 파일 데이터를 서버로 제대로 전송할 수 없습니다. 또한 type이 file인 input 태그를 사용하면 파일을 선택할 수 있는 "찾아보기(Browse)" 버튼이 자동으로 생성됩니다.
1. 파일 업로드용 HTML 폼 작성
<html> <body> <form enctype = "multipart/form-data" action = "save_file.py" method = "post"> <p>File: <input type = "file" name = "filename" /></p> <p><input type = "submit" value = "Upload" /></p> </form> </body> </html>
2. 실행 결과
위 코드를 실행하면 다음과 같은 업로드 폼이 화면에 표시됩니다.

참고로 위 예제는 불특정 다수가 데모 서버에 파일을 올리는 것을 막기 위해 의도적으로 비활성화되어 있습니다. 하지만 여러분은 자신의 서버 환경에서 위 코드를 그대로 실행해 볼 수 있습니다.
3. 파일 업로드 처리 스크립트: save_file.py
업로드된 파일은 서버 측 스크립트에서 받아 저장해야 합니다. 다음은 CGI 방식으로 파일 업로드를 처리하는 save_file.py의 전체 코드입니다.
#!/usr/bin/python
import cgi, os
import cgitb; cgitb.enable()
form = cgi.FieldStorage()
# Get filename here.
fileitem = form['filename']
# Test if the file was uploaded
if fileitem.filename:
# strip leading path from file name to avoid
# directory traversal attacks
fn = os.path.basename(fileitem.filename)
open('/tmp/' + fn, 'wb').write(fileitem.file.read())
message = 'The file "' + fn + '" was uploaded successfully'
else:
message = 'No file was uploaded'
print """\
Content-Type: text/html\n
<html>
<body>
<p>%s</p>
</body>
</html>
""" % (message,)주요 코드 흐름
cgi.FieldStorage()로 전송된 폼 데이터를 읽어옵니다.form['filename']으로 업로드된 파일 항목(fileitem)을 가져옵니다.fileitem.filename이 존재하면 실제로 파일이 업로드된 것입니다.os.path.basename()으로 경로 정보를 제거해 디렉터리 순회(directory traversal) 공격을 방지합니다./tmp디렉터리에 바이너리 모드('wb')로 파일을 저장하고 성공 메시지를 출력합니다.- 파일이 없으면 "No file was uploaded" 메시지를 반환합니다.
4. 운영체제별 주의 사항
위 스크립트를 Unix/Linux에서 실행할 경우, Windows 클라이언트에서 전송된 파일 이름에 포함된 역슬래시(\\) 구분자를 슬래시(/)로 변환한 뒤 basename을 적용해야 합니다. Windows 환경에서는 별도의 처리 없이 open() 문이 그대로 정상 동작합니다.
fn = os.path.basename(fileitem.filename.replace("\\", "/" ))참고: 최신 Python 버전 사용 시
cgi 모듈은 Python 3.11부터 지원 중단(deprecated)되었으며, Python 3.13에서는 완전히 제거되었습니다. 따라서 새 프로젝트에서는 Flask나 Django 같은 웹 프레임워크가 제공하는 파일 업로드 기능을 사용하는 것이 안전하고 권장됩니다.