2015-08-04 4 views
1

Я позаимствовал этот код для сохранения потока файлов на диск и работает, за исключением тех случаев, когда размер файла меньше 1kb. Я получаю эту ошибку:cStringIO.StringO не удается сохранить загруженный поток файлов, когда файл меньше 1kByte

in stuff_uploaded: 
copy(theFile.file.name, './tmp/'+theFile.filename) #saves temporary file to /cp2/tmp/ 

AttributeError: объект «cStringIO.StringO» не имеет «имя» атрибут

@cherrypy.expose 
@cherrypy.tools.noBodyProcess() 
def stuff_uploaded(self, theFile=None): 
    import cgi 
    import tempfile 
    # convert the header keys to lower case 
    lcHDRS = {key.lower():val for key, val in cherrypy.request.headers.iteritems()} 
    class myFieldStorage(cgi.FieldStorage): 
     """uses a named temporary file instead of the default non-named file; keeping it visibile (named), allows us to create a 
     2nd link after the upload is done, thus avoiding the overhead of making a copy to the destination filename.""" 
     def make_file(self, binary=None): 
      return tempfile.NamedTemporaryFile() 
    formFields = myFieldStorage(fp=cherrypy.request.rfile, 
           headers=lcHDRS, 
           environ={'REQUEST_METHOD':'POST'}, 
           keep_blank_values=True) 
    theFile = formFields['theFile'] 
    # we now create a 2nd link to the file, using the submitted filename. 
    from shutil import copy 
    copy(theFile.file.name, './tmp/'+theFile.filename) #saves temporary file 
    msgs = csv_to_survey.match_fieldnames('./tmp/'+theFile.filename) 
    return './tmp/'+theFile.filename 

Так что я могу сделать, чтобы гарантировать, что cStringIO.StringO обрабатывает небольшие загружаемые файлы ?

+1

Получайте удовольствие от таких имен файлов, как '../../../ etc/passwd' ... –

ответ

2

Просто откройте и написать файл непосредственно:

with open('./tmp/'+theFile.filename, "w") as f: 
    f.write(theFile.file.getvalue()) 

Или иметь дело с ним, независимо от того, является ли файл на диске или StringIO, использовать его в качестве файлового типа объекта:

import shutil 

with open('./tmp/'+theFile.filename, "w") as f: 
    # If the file pointer might not be at the beginning of theFile.file, add: 
    # theFile.file.seek(0) 
    shutil.copyfileobj(theFile.file, f) 
    # While: 
    #  f.write(theFile.file.read()) 
    # would work most of the time, it involves holding the whole contents of the 
    # file in memory at once (which you want to avoid; that's why CherryPy 
    # uses temp files for larger data). shutil.copyfileobj does block by 
    # block copies, which have fixed peak memory usage while still running 
    # (almost) as fast 

Примечание. Это (и ваше оригинальное решение) небезопасно, так как загрузка одного и того же файла дважды перезапишет предыдущий файл и (в зависимости от фильтров сервера на именах) имена файлов могут пересекать файловую систему, чтобы перезаписать непреднамеренные файлы вне каталога tmp.

+0

, вы имеете в виду небезопасность в том смысле, что файлы не защищены от перезаписи или потому что могут быть использованы некоторые способы ? Если бы я добавил случайную строку к имени файла, что бы решить проблему перезаписи файлов дважды. –

+1

@MarcMaxson Использование случайного уникального имени файла действительно намного лучше, чем использование пользовательского ввода, которое может содержать даже слэш! Лучше даже не рассматривать предоставленное пользователем имя файла, ему нельзя доверять –

+0

Что делать, если я сохранил только буквы ascii и пробелы из имени файла? Это всегда используется администратором в любом случае и за паролем, поэтому он не очень опасен, но всегда хорош, чтобы избежать возможных дыр. –

 Смежные вопросы

  • Нет связанных вопросов^_^