2008-10-22 6 views
0

Я пытаюсь найти лучший способ хранения загруженных пользователем файлов в файловой системе. Файлы варьируются от личных файлов до вики-файлов. Конечно, БД будет указывать на эти файлы каким-то образом, которые мне еще предстоит выяснить.Как сохранить загруженные файлы в файловой системе?

Основные требования:

  • Fairy Достойный безопасности так люди не могут Угадайте имена файлов (Picture001.jpg, Picture002.jpg, Music001.mp3 не является большой нет нет)
  • легко скопировано & Mirrorable (я предпочитаю такой способ, поэтому мне не нужно копировать весь жесткий диск каждый раз, когда я хочу сделать резервную копию. Мне нравится идея создания резервных копий только самых новых элементов, но я гибкий с вариантами здесь.)
  • Масштабируемость для миллионов файлов на нескольких серверах, если это необходимо.

ответ

3

Один из способов - хранить данные в файлах, названных в честь хеша (SHA1) их содержимого. Это не так легко догадаться, любая программа резервного копирования должна быть в состоянии справиться с ней, и она легко опечатана (путем хранения хэшей, начиная с 0 на одной машине, хэшей, начиная с 1 на следующем и т. Д.).

База данных будет содержать сопоставление между назначенным именем пользователя и хэшем SHA1 содержимого.

+0

Хеш-контент? Не хотел бы этого делать, слишком ресурсоемкий ... – KristoferA 2008-10-22 10:25:34

1

SHA1 хэш имени файла + соль (или, если хотите, содержимого файла), что упрощает обнаружение дубликатов файлов, а также повышает нагрузку на сервер). Это может потребовать некоторой настройки, чтобы быть уникальной (т. Е. Добавить Uploaded UserID или Timestamp), и соль должна сделать ее недопустимой.

Структура папок затем по частям хэша.

Например, если хэш «2fd4e1c67a2d28fced849ee1bb76e7391b93eb12», то папки могут быть:

/2 
/2/2f/ 
/2/2f/2fd/ 
/2/2f/2fd/2fd4e1c67a2d28fced849ee1bb76e7391b93eb12 

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

0

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

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

3

Гиды для имен файлов, автоматически расширяющие иерархию папок, содержащую не более нескольких тысяч файлов/папок в каждой папке. Резервное копирование новых файлов выполняется путем создания резервных копий новых папок.

Вы не указали, какую среду и/или язык программирования вы используете, но вот C# /.чистый пример/Windows:

using System; 
using System.IO; 
using System.Xml.Serialization; 

/// <summary> 
/// Class for generating storage structure and file names for document storage. 
/// Copyright (c) 2008, Huagati Systems Co.,Ltd. 
/// </summary> 

public class DocumentStorage 
{ 
    private static StorageDirectory _StorageDirectory = null; 

    public static string GetNewUNCPath() 
    { 
     string storageDirectory = GetStorageDirectory(); 
     if (!storageDirectory.EndsWith("\\")) 
     { 
      storageDirectory += "\\"; 
     } 
     return storageDirectory + GuidEx.NewSeqGuid().ToString() + ".data"; 
    } 

    public static void SaveDocumentInfo(string documentPath, Document documentInfo) 
    { 
     //the filestream object don't like NTFS streams so this is disabled for now... 
     return; 

     //stores a document object in a separate "docinfo" stream attached to the file it belongs to 
     //XmlSerializer ser = new XmlSerializer(typeof(Document)); 
     //string infoStream = documentPath + ":docinfo"; 
     //FileStream fs = new FileStream(infoStream, FileMode.Create); 
     //ser.Serialize(fs, documentInfo); 
     //fs.Flush(); 
     //fs.Close(); 
    } 

    private static string GetStorageDirectory() 
    { 
     string storageRoot = ConfigSettings.DocumentStorageRoot; 
     if (!storageRoot.EndsWith("\\")) 
     { 
      storageRoot += "\\"; 
     } 

     //get storage directory if not set 
     if (_StorageDirectory == null) 
     { 
      _StorageDirectory = new StorageDirectory(); 
      lock (_StorageDirectory) 
      { 
       string path = ConfigSettings.ReadSettingString("CurrentDocumentStoragePath"); 
       if (path == null) 
       { 
        //no storage tree created yet, create first set of subfolders 
        path = CreateStorageDirectory(storageRoot, 1); 
        _StorageDirectory.FullPath = path.Substring(storageRoot.Length); 
        ConfigSettings.WriteSettingString("CurrentDocumentStoragePath", _StorageDirectory.FullPath); 
       } 
       else 
       { 
        _StorageDirectory.FullPath = path; 
       } 
      } 
     } 

     int fileCount = (new DirectoryInfo(storageRoot + _StorageDirectory.FullPath)).GetFiles().Length; 
     if (fileCount > ConfigSettings.FolderContentLimitFiles) 
     { 
      //if the directory has exceeded number of files per directory, create a new one... 
      lock (_StorageDirectory) 
      { 
       string path = GetNewStorageFolder(storageRoot + _StorageDirectory.FullPath, ConfigSettings.DocumentStorageDepth); 
       _StorageDirectory.FullPath = path.Substring(storageRoot.Length); 
       ConfigSettings.WriteSettingString("CurrentDocumentStoragePath", _StorageDirectory.FullPath); 
      } 
     } 

     return storageRoot + _StorageDirectory.FullPath; 
    } 

    private static string GetNewStorageFolder(string currentPath, int currentDepth) 
    { 
     string parentFolder = currentPath.Substring(0, currentPath.LastIndexOf("\\")); 
     int parentFolderFolderCount = (new DirectoryInfo(parentFolder)).GetDirectories().Length; 
     if (parentFolderFolderCount < ConfigSettings.FolderContentLimitFolders) 
     { 
      return CreateStorageDirectory(parentFolder, currentDepth); 
     } 
     else 
     { 
      return GetNewStorageFolder(parentFolder, currentDepth - 1); 
     } 
    } 

    private static string CreateStorageDirectory(string currentDir, int currentDepth) 
    { 
     string storageDirectory = null; 
     string directoryName = GuidEx.NewSeqGuid().ToString(); 
     if (!currentDir.EndsWith("\\")) 
     { 
      currentDir += "\\"; 
     } 
     Directory.CreateDirectory(currentDir + directoryName); 

     if (currentDepth < ConfigSettings.DocumentStorageDepth) 
     { 
      storageDirectory = CreateStorageDirectory(currentDir + directoryName, currentDepth + 1); 
     } 
     else 
     { 
      storageDirectory = currentDir + directoryName; 
     } 
     return storageDirectory; 
    } 

    private class StorageDirectory 
    { 
     public string DirectoryName { get; set; } 
     public StorageDirectory ParentDirectory { get; set; } 
     public string FullPath 
     { 
      get 
      { 
       if (ParentDirectory != null) 
       { 
        return ParentDirectory.FullPath + "\\" + DirectoryName; 
       } 
       else 
       { 
        return DirectoryName; 
       } 
      } 
      set 
      { 
       if (value.Contains("\\")) 
       { 
        DirectoryName = value.Substring(value.LastIndexOf("\\") + 1); 
        ParentDirectory = new StorageDirectory { FullPath = value.Substring(0, value.LastIndexOf("\\")) }; 
       } 
       else 
       { 
        DirectoryName = value; 
       } 
      } 
     } 
    } 
} 
0

Развивая ответ Phill SACRE, другой аспект безопасности заключается в использовании отдельного доменного имени для загрузки файлов (для instante, Wikipedia использует upload.wikimedia.org), и убедитесь, этот домен не может читать файлы cookie вашего сайта. Это не позволяет людям загружать HTML-файл со сценарием, чтобы украсть cookie сеансов ваших пользователей (просто установить заголовок Content-Type недостаточно, потому что some browsers, как известно, игнорируют его и угадывают на основе содержимого файла, он также может быть встроенный в другие типы файлов, поэтому нетривиально проверять HTML и запрещать его).

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