概述
本文通过 注册用户 功能讲解上传文件功能
官方上传例子:
https://dormousehole.readthedocs.io/en/latest/patterns/fileuploads.html
html代码
<form action="/reg" method="post" enctype="multipart/form-data">
用户名: <input type="text" name="username"><br/>
密码: <input type="password" name="password"><br/>
头像:<input type="file" name="img">
<input type="submit" value="登录">
</form>
注意:
表单必须使用post方法
表单必须添加
enctype="multipart/form-data"属性上传文件的代码是:
<input type="file" name="img">,注意name是img
python代码
# coding=utf-8
from flask import Flask,request
app = Flask(__name__)
'''
指定要上传的文件的最大大小是1M, 超出大小会抛出RequestEntityTooLarge 异常
浏览器显示413错误
'''
app.config['MAX_CONTENT_PATH']=1024*1024
@app.route('/reg',methods=['POST'])
def reg():
username=request.form.get('username')
password=request.form.get('password')
print('username=',username)
print('password=',password)
f=request.files.get('img')
print(app.root_path)
if f.filename!='':
path=os.path.join(app.static_folder,f.filename)
f.save(path)
return '注册成功!'
if __name__ == "__main__":
app.run(debug=True)
注意:
代码 f=request.files.get('img') 获取html控件名是img的文件,返回的是 FileStorage 类对象
配置上传文件的最大大小
app.config['MAX_CONTENT_PATH']=1024*1024
指定要上传的文件的最大大小是1M, 超出大小会抛出RequestEntityTooLarge 异常
浏览器显示413错误
配置参见:
http://www.pythondoc.com/flask/config.html
http://docs.jinkan.org/docs/flask/patterns/fileuploads.html
FileStorage类
属性
| 属性名 | 说明 |
|---|---|
| filename | 上传文件的名字 |
| name | html中的控件名,本例中是img |
| headers | 请求头信息 |
| content_length | 文件长度 |
| content_type | 文件类型 |
save()方法
将上传文件保存到指定位置
语法:
save(dst)
参数说明:
- dst:将上传文件保存到指定的位置,路径+文件名
FileStorage 更多信息参见官方网址:https://werkzeug.palletsprojects.com/en/0.15.x/datastructures/#werkzeug.datastructures.FileStorage
比较完美的上传
上例的缺陷:
在上例中,上传文件都保存在工程根目录下,当上传文件较多时,工程根目录下就会特别杂乱
在上例中,什么文件都能上传,如果恶意用户上传 html文件、
.exe病毒,会对服务器造成很严重的损害假设李雷注册时上传头像文件名是:1.jpg,之后韩梅梅注册时上传头像文件名也是:1.jpg,按照上例的写法,就会寒梅梅的1.jpg覆盖李雷的1.jpg
如果恶意用户上传几个G的文件,会严重影响服务器
解决方法:
一般上传文件会单独放在一个文件夹中(如:upload文件夹),这样让工程目录和文件更加清晰
上传时做校验,因为注册时只能上传图片,所以只允许上传 jpg、png 等文件,不允许上传 其他格式文件,尤其是
.exe文件,防止用户上传 病毒保存是将 文件改名,用uuid做文件名,注意:文件后缀不改变
限制上传大小
python代码如下:
# coding=utf-8
from flask import Flask,request,flash
import os,uuid
# 上传文件夹
UPLOAD_FOLDER='upload'
# 允许上传的文件格式
ALLOWED_EXTENSIONS = set(['png', 'jpg', 'jpeg'])
app = Flask(__name__)
'''
上传文件限制为 5 M 。如果上传了大于这个尺寸的文件, Flask 会抛 出一个 RequestEntityTooLarge 异常。
但在本地开发服务器中,可能连接重置,在生产服务器中不会发生这种情况
'''
app.config['MAX_CONTENT_LENGTH'] = 5 * 1024 * 1024
@app.route('/reg',methods=['POST'])
def reg():
username=request.form.get('username')
password=request.form.get('password')
print('username=',username)
print('password=',password)
f=request.files.get('img')
print(f == None)
print(app.root_path)
if f.filename=='' :
return '请上传头像'
if allowed_file(f.filename):
path=os.path.join(app.config['UPLOAD_FOLDER'],get_new_filename(f.filename))
f.save(path)
return '注册成功!'
else:
return '只允许上传 %s 格式的文件'%str(ALLOWED_EXTENSIONS)[1:-1]
def get_upload_folder():
'''
在static目录下,如果upload文件夹不存在就创建
返回上传文件夹路径
'''
path=os.path.join(app.static_folder,UPLOAD_FOLDER)
if not os.path.exists(path):
os.makedirs(path)
return path
def allowed_file(filename):
'''
根据文件名后缀判断,该文件是否运行上传
'''
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
def get_new_filename(filename):
'''
生成新文件名,将uuid作为文件名,后缀不变
'''
id=str(uuid.uuid1()).replace('-','')
newfilename=id+filename[filename.rindex('.'):]
return newfilename
if __name__ == "__main__":
# 将上传文件夹添加到app的config中
app.config['UPLOAD_FOLDER'] = get_upload_folder()
app.run(debug=True)