下面的代码采用HTTP请求(Ajax)中发送的文件并将其保存到服务器。代码是由其他人编写的,但我最近必须修改它以向文件添加唯一标识符,以便不会覆盖具有相同名称的现有文件。基本上,我添加了以下几行:
#uid is a GUID
if os.path.isfile(destination):
destination = os.path.splitext(destination)[0] + str(uid) + os.path.splitext(destination)[1]
name = os.path.splitext(name)[0] + str(uid) + os.path.splitext(name)[1]
我现在看到的问题是有时我将UID添加到文件名的文件以保证唯一性,最终被破坏。它并不总是发生 - 大多数情况下文件保存正确但在过去7天中至少4个案例中的11个案例中,文件已损坏且只发生在添加了UID的文件中将名称保存到文件系统之前的名称。此代码是否有任何错误可能导致文件损坏?
以下是使用方法的完整上下文:
if form.is_valid():
id = request.REQUEST.get('id','')
file = request.FILES['file']
chunk = request.REQUEST.get('chunk','0')
chunks = request.REQUEST.get('chunks','0')
name = request.REQUEST.get('name','')
destination = settings.MEDIA_ROOT+'/files/%s' % name
# If the code goes into the below IF, the file MAY get corrupted.
if os.path.isfile(destination):
destination = os.path.splitext(destination)[0] + str(uid) + os.path.splitext(destination)[1]
name = os.path.splitext(name)[0] + str(uid) + os.path.splitext(name)[1]
with open(destination, ('wb' if chunk == '0' else 'ab')) as f:
for content in file.chunks():
f.write(content)
if int(chunk) + 1 >= int(chunks):
if not Attachment.objects.filter(uuid=uid,user=username,name=name):
form.save(name,username,uid,id)
response = HttpResponse(json.dumps({"jsonrpc" : "2.0", "result" : None, "id" : "id"}), mimetype='text/plain; charset=UTF-8')
return response
答案 0 :(得分:1)
问题似乎是文件uid
的生命周期。对于单个文件上载,这不是问题,但在使用代码的分块上传功能时会出现问题。
因为每个请求生成uid
并且每个文件块都在单独的请求中上传,所以每个块都会收到不同的uid
。这反过来导致块1 将文件1 ,块2 转移到文件2 ,从而导致损坏。< / p>
一种解决方法是根据会话密钥设置uid
,可通过request.session.session_key
获取。由于会话密钥的加密属性,它也应该“合理地唯一”用于此目的。
但请注意,如果文件路径暴露给Web,或者即使/media/
可以在目录中列出,也存在潜在的安全风险,因为您正在将会话密钥公开给Web(会话) key是唯一可以保护对活动会话的访问的方式。)
另一种更安全的方法是通过会话变量为每个会话分配唯一的UUID。这可能最好在middleware中完成:
class SessionUUIDMiddleware(object):
def process_request(request):
session_uuid = request.session.get('uuid', None)
if not session_uuid:
session_uuid = uuid.uuid1()
request.session['uuid'] = session_uuid
这会断开会话密钥中的唯一ID。