目录
前言
一.文件上传
1.1一些<input>相关上传属性
1.1.1multiple
1.1.2accept
1.2Flask后台接收文件提交
1.3Flask后台接收多个文件
二.保护文件上传
2.1限制文件上传大小
2.2验证文件名
2.3验证文件内容
三.文件下载
3.1使用send_file()方法下载文件
前言
本文旨在记录学习“文件上传/下载”,适合小白
文件上传的方式有很多:“定制一个form表单上传”、“使用按钮+JS上传”等等,本文主要介绍使用“form表单上传”
所使用的表单代码如下:
<!doctype html>
<html>
<head>
<title>File Upload</title>
</head>
<body>
<h1>File Upload</h1>
<form method="POST" action="" enctype="multipart/form-data">
<p><input type="file" name="file"></p>
<p><input type="submit" value="Submit"></p>
</form>
</body>
</html>
注意我们使用表单时:“enctype=‘multipart/form-data’”这表明表单中至少有一个字段是文件字段,因此需要使用该格式,如果没有该格式会出错
效果图:
一.文件上传
1.1一些<input>相关上传属性
1.1.1multiple
可用于允许在单个文件字段中上传多个文件,例如:
<input type="file" name="file" multiple>
1.1.2accept
可用于筛选允许的文件类型,这些文件类型可以通过文件扩展名或媒体类型选择,例如:
<input type="file" name="doc_file" accept=".doc,.docx">
<input type="file" name="image_file" accept="image/*">
1.2Flask后台接收文件提交
“文件字段包含在requests.files中”
可以使用“request.files['发送标签name']”或者“requests.files.get('发送标签name')”将文件储存在某个Python变量中
例如下面一个简单的Flask后台接受文件的代码:
from flask import *
app = Flask(__name__)
@app.route("/",methods=["POST","GET"])
def index():
if request.method == "GET":
return render_template("ceshi.html")
if request.method == "POST":
file = request.files.get("file")
if file.filename:
print(file)
file.save(file.filename)
return "提交成功"
if __name__ == "__main__":
app.run(debug=True)
效果图:
至此,一个简陋的上传文件就制作好了
其中的”filename“用于返回文件的上传名称,如果为空字符串,那么表示没有文件上传
1.3Flask后台接收多个文件
如果我们为<input>标签添加“multiple”属性,那么此时就允许多个文件上传,此时使用:“request.files.getlist("发送标签name")”返回的就是一个列表
from flask import *
app = Flask(__name__)
@app.route("/",methods=["POST","GET"])
def index():
if request.method == "GET":
return render_template("ceshi.html")
if request.method == "POST":
files = request.files.getlist("file")
print(files)
if files[0].filename:
for f in files:
f.save(f.filename)
return "提交成功"
else:
return render_template("ceshi.html")
if __name__ == "__main__":
app.run(debug=True)
效果图:
此时我们可以看到,列表中的每一个元素都是一个file对象,我们可以对列表遍历来实现批量保存
二.保护文件上传
上传文件也为“攻击者”提供了遍历,一般来说,通过“上传接口”,“攻击者”可以使用下面三种方式:
- 攻击者可以上传一个非常大的文件,以至于服务器磁盘空间被填满,从而出现故障
- 攻击者可以使用文件名(../../../.bashrc或类似文件)的上传请求,以试图欺骗服务器重写配置文件达到攻击的目的
- 攻击者可以上传带有病毒或其他类型恶意软件的文件到应用程序需要使用的位置
2.1限制文件上传大小
我们可以使用Flask提供的配置项“MAX_CONTENT_LENGTH”选项限制上传大小
#限制文件最大大小为1MB
app.config['MAX_CONTENT_LENGTH'] = 1* 1024 * 1024
#限制文件最大大小为100MB
app.config['MAX_CONTENT_LENGTH'] = 100 * 1024 * 1024
2.2验证文件名
验证文件名可以使用“werkzeug.utils”提供的“secure_filename”,"secure_filename"用于返回一个“安全的文件名”
>>> from werkzeug.utils import secure_filename
>>> secure_filename('foo.jpg')
'foo.jpg'
>>> secure_filename('/some/path/foo.jpg')
'some_path_foo.jpg'
>>> secure_filename('../../../.bashrc')
'bashrc'
- 如果不想要原本的文件名,可以考虑使用uuid生成一个随机的文件名
2.3验证文件内容
验证文件内容相对复杂,假设我们想要验证上传的文件是一个图片,我们可以使用Python库中的imghdr包验证文件头实际上是一个图像
我们编写一个“valid_image”函数用来判断文件是否是一个图像
该函数以一个字节流作为参数,从流中读出512个字节,然后使用“imghdr.what()”函数查看存储在磁盘上的文件,如果第一个参数是None,那么数据在第二个参数中传递
而使用file.stream可以获得一个流
“imghdr.what()”函数用来检测已知图像格式“jpg、png、gif”,如果未检测到则返回None
import imghdr
def valid_image(stream):
header = stream.read(512)
stream.seek(0)
format = imghdr.what(None, header)
if not format:
return None
return '.' + (format if format != 'jpeg' else 'jpg')
三.文件下载
3.1使用send_file()方法下载文件
Flask框架提供了“send_file()”方法下载文件,它可以发送任何类型的文件,使用也非常简单,只需要提供文件的路径即可
下面,我们创建一个HTML文件用来演示下载:
<!doctype html>
<html>
<head>
<title>File Upload</title>
</head>
<body>
<h1>File Download</h1>
<a href="/download">下载示例文件</a>
</body>
</html>
效果图:
from flask import *
app = Flask(__name__)
#限制文件最大大小为10MB
app.config["MAX_CONTENT_LENGTH"] = 10 * 1024 * 1024
@app.route("/",methods=["POST","GET"])
def index():
if request.method == "GET":
return render_template("ceshi.html")
@app.route("/download")
def donwload():
file_path = "项目.pptx"
return send_file(file_path,as_attachment=True)
if __name__ == "__main__":
app.run(debug=True)
效果图:
可以看到文件成功被下载了
其中参数“as_attachment=True”表示以附件的形式下载文件,即“用户下载完毕文件后不会自动打开”,如果不指定或者设置为False,那么用户下载完毕后,浏览器会尝试自动打开