次のように定義されたモデルの一部があります。
logo_image = models.ImageField(upload_to=lambda i, fn: "logo_%s"%(fn), height_field="logo_image_height", width_field="logo_image_width")
upload_to 関数について質問がありました。
django の FileField.upload_to のドキュメントによると、2 番目のパラメーターfilename
は「ファイルに最初に指定されたファイル名」です。
現在、HTTP、ファイルのアップロードなどについて知っているので、エンド ユーザーのクライアントはファイル名を簡単に偽造できます。具体的には、たとえば、エンド クライアントが「/etc/passwd」というファイルをアップロードできなかった場合、単純なコード ( lambda i, fn: "logo_%s"%(fn)
) を使用すると、結果のファイルが にアップロードされ/etc/passwd
ませんか? filename
パラメータをエスケープする必要がありますか?
#using django's example of using full paths in settings module,
#MEDIA_ROOT="/tmp/media"
>>> os.path.join("/tmp/media/", "apple.jpg")
'/tmp/media/apple.jpg'
>>> os.path.join("/tmp/media/", "/etc/passwd")
'/etc/passwd'
提案/回答/説明をありがとう。
編集
注目すべき重要なメソッドは、files.py の 272 行目付近にあります。
272 def get_directory_name(self):
273 return os.path.normpath(force_unicode(datetime.datetime.now().strftime(smart_str(self.upload_to))))
274
275 def get_filename(self, filename):
276 return os.path.normpath(self.storage.get_valid_name(os.path.basename(filename)))
277
278 def generate_filename(self, instance, filename):
279 return os.path.join(self.get_directory_name(), self.get_filename(filename))
カスタムを定義すると、次のように()upload_to
が置き換えられます。generate_filename
226 if callable(upload_to):
227 self.generate_filename = upload_to
次に、save() メソッドで:
89 def save(self, name, content, save=True):
90 name = self.field.generate_filename(self.instance, name)
91 self.name = self.storage.save(name, content)
そして、返されたファイル名はストレージ クラスに渡され、最終的に _os.py util モジュールsafe_joinで django 置換関数が呼び出されます。
その機能は私の恐怖を軽減するようです:
24 def safe_join(base, *paths):
25 """
26 Joins one or more path components to the base path component intelligently.
27 Returns a normalized, absolute version of the final path.
28
29 The final path must be located inside of the base path component (otherwise
30 a ValueError is raised).
31 """