Flaskを使用してファイルを安全にアップロードし、元の名前でダウンロードできる機能を実装する方法をご紹介します。この方法は、werkzeug.utilsモジュールのsecure_filenameを活用して、セキュリティを考慮したファイル名の管理を実現します。
目次
- Flaskでのファイルアップロードの仕組み
- 安全なファイル名を作る
secure_filenameの役割 - ファイルアップロードとダウンロードの具体的な実装
- 実行例と注意点
1. Flaskでのファイルアップロードの仕組み
Flaskでは、request.filesを使用してクライアントから送信されたファイルを取得できます。取得したファイルはfile.save(path)メソッドでサーバーに保存可能です。ただし、ユーザーが指定したファイル名をそのまま使うと、セキュリティ上のリスクがあります。
例えば、「../../etc/passwd」のような名前のファイルをアップロードされると、サーバー内部のディレクトリ構造にアクセスされる可能性があります。これを防ぐために、secure_filenameで安全なファイル名に変換することが重要です。
2. 安全なファイル名を作るsecure_filenameの役割
secure_filenameは、ファイル名を安全な形式に変換してくれる便利な関数です。以下のように、特殊文字やディレクトリトラバーサル攻撃を防ぎます。
変換例
| 元のファイル名 | 変換後のファイル名 |
|---|---|
../../etc/passwd |
etc_passwd |
hello world!.jpg |
hello_world.jpg |
my<script>.png |
my_script_.png |
3. ファイルアップロードとダウンロードの具体的な実装
必要なモジュールをインポート
以下のモジュールをインポートします。
from flask import Flask, request, send_from_directory, jsonify from werkzeug.utils import secure_filename import os
サーバーの基本設定
保存先のフォルダを指定し、初期設定を行います。
app = Flask(__name__) UPLOAD_FOLDER = 'uploads' app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER os.makedirs(UPLOAD_FOLDER, exist_ok=True)
ファイルアップロードの実装
ファイルをアップロードし、安全な名前に変換して保存する処理を実装します。
@app.route('/upload', methods=['POST']) def upload_file(): if 'file' not in request.files: return jsonify({"error": "No file part"}), 400 file = request.files['file'] if file.filename == '': return jsonify({"error": "No selected file"}), 400 original_filename = file.filename secure_name = secure_filename(original_filename) save_path = os.path.join(app.config['UPLOAD_FOLDER'], secure_name) file.save(save_path) return jsonify({ "message": "File uploaded successfully", "original_name": original_filename, "saved_name": secure_name }), 200
ファイルダウンロードの実装
アップロードされたファイルを元の名前でダウンロードする処理を実装します。
@app.route('/download/<filename>', methods=['GET']) def download_file(filename): secure_name = secure_filename(filename) file_path = os.path.join(app.config['UPLOAD_FOLDER'], secure_name) if not os.path.exists(file_path): return jsonify({"error": "File not found"}), 404 return send_from_directory( app.config['UPLOAD_FOLDER'], secure_name, as_attachment=True, download_name=filename # Flask 2.0以降 )
4. 実行例と注意点
実行例
ファイルアップロード
curl -X POST -F "file=@example.txt" http://localhost:5000/upload
ファイルダウンロード
curl -O http://localhost:5000/download/example.txt
注意点
- ファイル名の管理: サーバーに保存された名前と元の名前のマッピングが必要な場合は、データベースやJSONファイルを利用するのがおすすめです。
- セキュリティ:
secure_filenameを必ず使用して、不正なファイル名を排除しましょう。
まとめ
Flaskでのファイルアップロードとダウンロードを実装する際、secure_filenameを活用することでセキュリティを向上させることができます。また、ユーザーにとって使いやすい元の名前でのファイルダウンロードも簡単に実現できます。
ぜひこの方法を活用して、安全で便利なファイル操作機能を作成してみてください!