Flask使用 secure_filename 获取文件名不完整问题

使用secure_filename获取文件名时,中文以及其他特殊字符会被省略。

原因:secure_filename()函数只返回ASCII字符,非ASCII字符会被过滤掉。

1 查看函数原代码

文件路径如下:

源码如下:找到secure_filename(filename)函数。

代码中有一个变量:_filename_ascii_strip_re

代码解释:

根据文件名中的空字符,包括空格、换行(\n)、制表符(\t)等,把文件名分割成列表,然后使用下划线“_”进行连接,再过滤掉正则之外的字符,最后去掉字符串两头的“._”字符,最终生成新的文件名

2 解决文件名问题

2.1 修改源码

建议修改之前对源码进行备份

将secure_filename(filename)函数修改为下方代码:

def secure_filename(filename):
    r"""Pass it a filename and it will return a secure version of it.  This
    filename can then safely be stored on a regular file system and passed
    to :func:`os.path.join`.  The filename returned is an ASCII only string
    for maximum portability.

    On windows systems the function also makes sure that the file is not
    named after one of the special device files.

    >>> secure_filename("My cool movie.mov")
    'My_cool_movie.mov'
    >>> secure_filename("../../../etc/passwd")
    'etc_passwd'
    >>> secure_filename(u'i contain cool \xfcml\xe4uts.txt')
    'i_contain_cool_umlauts.txt'

    The function might return an empty filename.  It's your responsibility
    to ensure that the filename is unique and that you generate random
    filename if the function returned an empty one.

    .. versionadded:: 0.5

    :param filename: the filename to secure
    """
    if isinstance(filename, text_type):
        from unicodedata import normalize
        filename = normalize('NFKD', filename).encode('utf-8', 'ignore')  # 转码
        if not PY2:
            filename = filename.decode('utf-8')  # 解码
    for sep in os.path.sep, os.path.altsep:
        if sep:
            filename = filename.replace(sep, ' ')

    # 正则增加对汉字的过滤	\u4E00-\u9FBF	中文
    # 自定义构建新正则
    _filename_ascii_add_strip_re = re.compile(r'[^A-Za-z0-9_\u4E00-\u9FBF.-]')

    # 使用正则
    # 根据文件名中的空字符,包括空格、换行(\n)、制表符(\t)等,把文件名分割成列表,然后使用下划线“_”进行连接,再过滤掉正则之外的字符,最后去掉字符串两头的“._”字符,最终生成新的文件名
    filename = str(_filename_ascii_add_strip_re.sub('', '_'.join(filename.split()))).strip('._')

    return filename

2.2 使用第三方库(pypinyin),将中文名转换成拼音

pypinyin第三方库安装命令:

pip install pypinyin
import pypinyin

filename = secure_filename(''.join(pypinyin.lazy_pinyin(file.filename)))

2.3 使用uuid模块重命名文件名

python的uuid模块提供UUID类和函数uuid1(), uuid3(), uuid4(), uuid5() 来生成1, 3, 4, 5各个版本的UUID ( 需要注意的是: python中没有uuid2()这个函数)。

import uuid

uuid.uuid1([node[, clock_seq]])  # 基于时间戳
# 使用主机ID, 序列号, 和当前时间来生成UUID, 可保证全球范围的唯一性. 但由于使用该方法生成的UUID中包含有主机的MAC地址, 因此可能危及隐私.
# 该函数有两个参数, 如果 node 参数未指定, 系统将会自动调用 getnode() 函数来获取主机的硬件地址.
# 如果 clock_seq  参数未指定系统会使用一个随机产生的14位序列号来代替.
uuid.uuid3(namespace, name)  # 基于名字的MD5散列值
# 通过计算命名空间和名字的MD5散列值来生成UUID, 可以保证同一命名空间中不同名字的唯一性和不同命名空间的唯一性, 但同一命名空间的同一名字生成的UUID相同.
uuid.uuid4()  # 基于随机数
# 通过随机数来生成UUID. 使用的是伪随机数有一定的重复概率.
uuid.uuid5(namespace, name)  # 基于名字的SHA-1散列值
# 通过计算命名空间和名字的SHA-1散列值来生成UUID, 算法与 uuid.uuid3() 相同.
好的,下面是使用 Flask 实现个人文件管理系统的示例代码: ``` from flask import Flask, render_template, request, redirect, url_for, session, flash from werkzeug.utils import secure_filename import os app = Flask(__name__) app.secret_key = 'your_secret_key' app.config['UPLOAD_FOLDER'] = '/path/to/upload/folder' app.config['ALLOWED_EXTENSIONS'] = set(['txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif']) def allowed_file(filename): return '.' in filename and \ filename.rsplit('.', 1)[1] in app.config['ALLOWED_EXTENSIONS'] @app.route('/') def index(): if 'username' in session: return render_template('index.html', username=session['username']) else: return redirect(url_for('login')) @app.route('/login', methods=['GET', 'POST']) def login(): if request.method == 'POST': username = request.form['username'] password = request.form['password'] # 在此处验证用户输入的用户名和密码是否正确,正确的话将其保存到 session 中 session['username'] = username flash('You were logged in') return redirect(url_for('index')) else: return render_template('login.html') @app.route('/register', methods=['GET', 'POST']) def register(): if request.method == 'POST': username = request.form['username'] password = request.form['password'] # 在此处将用户提交的用户名和密码保存到数据库中 flash('You were registered') return redirect(url_for('login')) else: return render_template('register.html') @app.route('/logout') def logout(): session.pop('username', None) flash('You were logged out') return redirect(url_for('index')) @app.route('/upload', methods=['GET', 'POST']) def upload(): if request.method == 'POST': file = request.files['file'] if file and allowed_file(file.filename): filename = secure_filename(file.filename) file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename)) flash('File uploaded successfully') return redirect(url_for('index')) else: flash('Invalid file type') return redirect(url_for('upload')) else: return render_template('upload.html') @app.route('/download/<filename>') def download(filename): return send_from_directory(app.config['UPLOAD_FOLDER'], filename) if __name__ == '__main__': app.run() ``` 在这个示例中,我们实现了文件的上传、下载、和分类等功能,同时还实现了用户的登录和注册功能。在登录后,用户可以上传文件,并将其保存到服务器上的指定路径下。在下载文件时,用户可以通过文件名获取文件,并将文件下载到本地计算机中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值