ファイルのアップロード
はい、ファイルアップロードの古き良き問題です。 ファイルのアップロードの基本的な考え方は、実際には非常に単純です。 基本的には次のように機能します。
<form>
タグはenctype=multipart/form-data
でマークされ、<input type=file>
はその形式で配置されます。- アプリケーションは、リクエストオブジェクトの
files
ディクショナリからファイルにアクセスします。 - ファイルの
save()
メソッドを使用して、ファイルをファイルシステムのどこかに永続的に保存します。
優しい紹介
特定のアップロードフォルダにファイルをアップロードし、ユーザーにファイルを表示する非常に基本的なアプリケーションから始めましょう。 アプリケーションのブートストラップコードを見てみましょう。
したがって、最初にいくつかのインポートが必要です。 ほとんどは簡単なはずです。werkzeug.secure_filename()
については少し後で説明します。 UPLOAD_FOLDER
はアップロードされたファイルを保存する場所であり、ALLOWED_EXTENSIONS
は許可されたファイル拡張子のセットです。
許可される拡張機能を制限するのはなぜですか? サーバーがクライアントにデータを直接送信している場合は、ユーザーがそこにすべてをアップロードできないようにする必要があります。 これにより、ユーザーがXSSの問題を引き起こす可能性のあるHTMLファイルをアップロードできないようにすることができます(クロスサイトスクリプティング(XSS)を参照)。 また、サーバーが.php
ファイルを実行する場合は、必ず許可しないようにしてください。ただし、サーバーにPHPがインストールされているのは誰ですか。 :)
次に、拡張子が有効かどうかをチェックし、ファイルをアップロードして、アップロードされたファイルのURLにユーザーをリダイレクトする関数は次のとおりです。
では、そのsecure_filename()
関数は実際に何をするのでしょうか? ここで問題となるのは、「ユーザー入力を絶対に信用しない」という原則があるということです。 これは、アップロードされたファイルのファイル名にも当てはまります。 送信されたすべてのフォームデータは偽造される可能性があり、ファイル名は危険な場合があります。 今のところ覚えておいてください。ファイルシステムに直接保存する前に、常にその関数を使用してファイル名を保護してください。
プロのための情報
それで、あなたはそのsecure_filename()
関数が何をするのか、そしてあなたがそれを使わない場合の問題は何であるのかに興味がありますか? したがって、誰かが次の情報を filename としてアプリケーションに送信すると想像してみてください。
../
の数が正しく、これをUPLOAD_FOLDER
と結合すると、ユーザーはサーバーのファイルシステム上のファイルを変更できない可能性があります。 これには、アプリケーションがどのように見えるかについての知識が必要ですが、私を信じてください、ハッカーは忍耐強いです:)
次に、その関数がどのように機能するかを見てみましょう。
アップロードされたファイルをユーザーがダウンロードできるように提供できるようにしたいと考えています。 download_file
ビューを定義して、アップロードフォルダー内のファイルを名前で提供します。 url_for("download_file", name=name)
はダウンロードURLを生成します。
ミドルウェアまたはHTTPサーバーを使用してファイルを提供している場合は、download_file
エンドポイントをbuild_only
として登録して、url_for
が表示機能なしで機能するようにすることができます。
アップロードの改善
バージョン0.6の新機能。
では、Flaskはアップロードをどのように正確に処理しますか? ファイルが適度に小さい場合はWebサーバーのメモリに保存され、そうでない場合は一時的な場所に保存されます(tempfile.gettempdir()
によって返されます)。 しかし、アップロードが中止されるまでの最大ファイルサイズをどのように指定しますか? デフォルトでは、Flaskは無制限のメモリ量でファイルのアップロードを受け入れますが、MAX_CONTENT_LENGTH
構成キーを設定することでそれを制限できます。
上記のコードは、最大許容ペイロードを16メガバイトに制限します。 より大きなファイルが送信されると、FlaskはRequestEntityTooLarge
例外を発生させます。
接続リセットの問題
ローカル開発サーバーを使用すると、413応答ではなく接続リセットエラーが発生する場合があります。 本番WSGIサーバーでアプリを実行すると、正しいステータス応答が得られます。
この機能はFlask0.6で追加されましたが、リクエストオブジェクトをサブクラス化することで、古いバージョンでも実現できます。 詳細については、ファイル処理に関するWerkzeugのドキュメントを参照してください。
プログレスバーをアップロードする
しばらく前、多くの開発者は、受信ファイルを小さなチャンクで読み取り、アップロードの進行状況をデータベースに保存して、クライアントからJavaScriptを使用して進行状況をポーリングできるようにすることを考えていました。 クライアントは5秒ごとにサーバーに送信量を尋ねますが、これはすでに知っておくべきことです。
より簡単なソリューション
現在、より高速に動作し、より信頼性の高い、より優れたソリューションがあります。 プログレスバーの作成を容易にするフォームプラグインを備えた jQuery のようなJavaScriptライブラリがあります。
ファイルアップロードの共通パターンは、アップロードを処理するすべてのアプリケーションでほとんど変更されていないため、アップロードを許可するファイル拡張子を制御できる本格的なアップロードメカニズムを実装するFlask拡張機能もいくつかあります。