题
我一直在试图作出"最佳做法"方法来管理文件上载有Turbogears2和迄今没有真正发现的任何例子。我已经想出了一个办法实际上载的文件,但我不知道该如何可靠它我们。
此外,这将是一个很好的方式来获得上载的文件的名字吗?
file = request.POST['file']
permanent_file = open(os.path.join(asset_dirname,
file.filename.lstrip(os.sep)), 'w')
shutil.copyfileobj(file.file, permanent_file)
file.file.close()
this_file = self.request.params["file"].filename
permanent_file.close()
因此,假如我的理解正确的话,会像这样的东西避免核心'名'的问题?id=usb驱.
file = request.POST['file']
permanent_file = open(os.path.join(asset_dirname,
id.lstrip(os.sep)), 'w')
shutil.copyfileobj(file.file, permanent_file)
file.file.close()
this_file = file.filename
permanent_file.close()
解决方案
@mhawke - 你是对的,你必须处理 - 取决于你所使用的文件做什么,如果没有问题,如果有一个名称冲突比如你只关心一些数据的最新版本,那么那里有大概没有问题,或者如果文件名不是真正重要的只是文件的内容,但它仍然是不好的做法。
您可以在TMP目录使用命名临时文件,然后将文件一旦通过验证其最终位置。或者你可以检查文件名不存在,像这样:
file.name = slugify(myfile.filename)
name, ext = os.path.splitext(file.name)
while os.path.exists(os.path.join(permanent_store, file.name)):
name += '_'
file.name = name + ext
raw_file = os.path.join(permanent_store, file.name)
在slugify方法将用于整理文件名...
其他提示
我只是想让任何人来到这里寻找答案,要知道, Allesandro Molina's伟大的图书馆 库 是的最好回答这个问题。
它解决了两个命名和复制的问题,并将很好地为您的TurboGears应用程序。你可以用它与MongoDB GridFS,因为在这个例子:
from depot.manager import DepotManager
# Configure a *default* depot to store files on MongoDB GridFS
DepotManager.configure('default', {
'depot.backend': 'depot.io.gridfs.GridFSStorage',
'depot.mongouri': 'mongodb://localhost/db'
})
depot = DepotManager.get()
# Save the file and get the fileid
fileid = depot.create(open('/tmp/file.png'))
# Get the file back
stored_file = depot.get(fileid)
print stored_file.filename
print stored_file.content_type
或者你可以很容易地创造附件领域中的你 SQLAlchemy 模型,如:
from depot.fields.sqlalchemy import UploadedFileField
class Document(Base):
__tablename__ = 'document'
uid = Column(Integer, autoincrement=True, primary_key=True)
name = Column(Unicode(16), unique=True)
content = Column(UploadedFileField)
...然后,储存文件与附件(来源可以是文件或字节)变得容易,因为:
doc = Document(name=u'Foo', content=open('/tmp/document.xls'))
DBSession.add(doc)
仓库支持 LocalFileStorage
, MongoDB's GridFSStorage
, 和亚马逊的 S3Storage
.而且,至少是对文件存储在本地,并在S3, fileid
将产生 uuid.uuid1()
.
我不很了解的TurboGears知道它是否能提供一切努力避免以下,但在我看来,这个代码是充满了危险。有可能的恶意用户覆盖(或创建)的任何文件,所述的TurboGears蟒过程必须写访问。
如果什么asset_dirname
是/tmp
,file.filename
的内容是../../../../../../../etc/passwd
和文件root::0:0:root:/root:/bin/bash
的内容?在UNIX环境中,该代码(权限待定)将打开截断模式的文件/tmp/../../../../../../../etc/passwd
然后复制上传文件到它的内容 - 有效覆盖系统密码文件,并指定root用户没有密码。想必有一些可以做一个Windows机器太讨厌的东西。
行,这是一个极端的例子,需要蟒正在作为root
(没有一个这样做,是吗?)。即使蟒运行为低priveleged用户,以前上传的文件可以在将被覆盖。
要概括,不信任用户的输入,在这种情况下,用户提供的文件名是在file.filename
可用。
是不是TurboGears的只是演员挂架?你可能出现退房的帮助:
http://wiki.pylonshq.com/display/pylonsdocs /表格+处理#文件的上载
但是,仍含有潜在的安全漏洞,mhawke提到:
os.path.join(permanent_store, myfile.filename.lstrip(os.sep))
与上述相同,如果真的莫名其妙的文件名是../../../../../etc/passwd
那么你可以替换该文件...
所以,你可以只得到实际的文件名,像这样:
os.path.join(permanent_store, myfile.filename.split(os.sep).pop())
WERKZEUG具有很好的辅助函数用于固定所谓的 secure_filename 。我想你可以采纳和使用它。
有关如何走,我第二次已经给了很好的答案。
这是我的2便士,对存储的文件命名。
的确节省使用原来的名称可能会导致一个漏洞的文件。 在仅使用I使原来的名称的,如果在所有,是暗示的mime类型检测。
反正文件保存应给予唯一的名称,由创纪录的身份或类似的东西,和应用程序目录的拥有者,谁是一个普通用户,或者在其他一些存储服务的控制下保持在一个地方,作为上述贮存库等
它的跨语言良好的系统设计的问题:)