Pergunta

Estou recebendo milhares de imagens enviadas por milhares de usuários no meu servidor Linux, que é hospedado pelo 1and1.com (eu acredito que eles usam CentOS, mas tenho certeza da versão). Esta é uma pergunta agnóstico linguagem, no entanto, para sua referência, estou usando PHP.

Meu primeiro pensamento foi apenas para despejá-los todos no mesmo diretório, no entanto, lembro-me há pouco tempo, havia um limite de quantos arquivos ou diretórios poderia ser descartado em um diretório.

Meu segundo pensamento foi para particionar os arquivos dentro diretórios com base no endereço de e-mail aos usuários (como é o que eu estou usando o nome de usuário de qualquer forma), mas eu não quero correr para o limite para diretórios em um diretório. ...

De qualquer forma, para imagens de user@domain.com, eu estava indo para fazer isso:

/images/domain.com/user/images...

É este inteligente a fazer, o que se milhares de usuários não dizer 'gmail' talvez eu poderia até mesmo ir mais fundo, como este

/images/domain.com/[first letter of user name]/user/images...

então para mike@gmail.com seria ...

/images/domain.com/m/mike/images...

Esta é uma abordagem ruim? O que está todo mundo fazendo? Eu não quero ter problemas com muitos diretórios também ...


Relacionado:

Foi útil?

Solução

Eu faria o seguinte:

  1. Faça um hash MD5 de cada imagem, uma vez que vem em.
  2. Write que hash MD5 no banco de dados onde você está mantendo o controle dessas coisas.
  3. armazená-los em uma estrutura de diretórios onde você usar o primeiro par de bytes da cadeia de hash MD5 hexadecimal como o nome dir. Então, se o hash é 'abcdef1234567890' você armazená-lo como 'a / b / abcdef1234567890'.

Usando um hash também permite mesclar a mesma imagem carregada várias vezes.

Outras dicas

para expandir a abordagem de Joe Beda:

  • banco de dados
  • banco de dados
  • banco de dados

Se você se preocupa com o agrupamento ou encontrar arquivos pelo usuário, nome do arquivo original, data de upload, foto-tomada-on data (EXIF), etc., guarde este metadados em um banco de dados e usar as consultas apropriadas para escolher os arquivos apropriados .

Use a chave primária do banco de dados - se um hash do arquivo, ou um número autoincrementável - para localizar arquivos entre um conjunto fixo de diretórios (em alternativa, utilizar um máximo-número-de-arquivos fixos N por diretório, e quando você encher ir para a próxima, por exemplo, o k th foto deve ser armazenado a {somepath}/aaaaaa/bbbb.jpg onde aaaaaa = andar (k / N), formatado como decimal ou hexadecimal, e bbbb = mod (k, N), formatado como decimal ou hexadecimal. Se isso é muito plana uma hierarquia para você, use algo como {somepath}/aa/bb/cc/dd/ee.jpg)

Não exponha a estrutura de diretórios diretamente para seus usuários. Se eles estão usando navegadores para acessar o servidor via HTTP, dar-lhes uma url como chave www.myserver.com/images/{primary} e codificar o filetype adequada no cabeçalho Content-Type.

Aqui são duas funções que eu escrevi uma volta enquanto para exatamente esta situação. Eles têm sido em uso por mais de um ano em um site com milhares de membros, cada um dos quais tem lotes de arquivos.

Em essência, a idéia é usar os últimos dígitos do ID do banco de dados único de cada membro para calcular a estrutura de diretórios, com um diretório único para todos. Usando os últimos dígitos, em vez do primeiro, garante uma distribuição mais uniforme de diretórios. Um diretório separado para cada tarefas meios membro de manutenção são muito mais simples, mais você pode ver onde está o material das pessoas é (como no visual).

// checks for member-directories & creates them if required
function member_dirs($user_id) {

    $user_id = sanitize_var($user_id);

    $last_pos = strlen($user_id);
    $dir_1_pos = $last_pos - 1;
    $dir_2_pos = $last_pos - 2;
    $dir_3_pos = $last_pos - 3;

    $dir_1 = substr($user_id, $dir_1_pos, $last_pos);
    $dir_2 = substr($user_id, $dir_2_pos, $last_pos);
    $dir_3 = substr($user_id, $dir_3_pos, $last_pos);

    $user_dir[0] = $GLOBALS['site_path'] . "files/members/" . $dir_1 . "/";
    $user_dir[1] = $user_dir[0] . $dir_2 . "/";
    $user_dir[2] = $user_dir[1] . $dir_3 . "/";
    $user_dir[3] = $user_dir[2] . $user_id . "/";
    $user_dir[4] = $user_dir[3] . "sml/";
    $user_dir[5] = $user_dir[3] . "lrg/";

    foreach ($user_dir as $this_dir) {
        if (!is_dir($this_dir)) { // directory doesn't exist
            if (!mkdir($this_dir, 0777)) { // attempt to make it with read, write, execute permissions
                return false; // bug out if it can't be created
            }
        }
    }

    // if we've got to here all directories exist or have been created so all good
    return true;

}

// accompanying function to above
function make_path_from_id($user_id) {

    $user_id = sanitize_var($user_id);

    $last_pos = strlen($user_id);
    $dir_1_pos = $last_pos - 1;
    $dir_2_pos = $last_pos - 2;
    $dir_3_pos = $last_pos - 3;

    $dir_1 = substr($user_id, $dir_1_pos, $last_pos);
    $dir_2 = substr($user_id, $dir_2_pos, $last_pos);
    $dir_3 = substr($user_id, $dir_3_pos, $last_pos);

    $user_path = "files/members/" . $dir_1 . "/" . $dir_2 . "/" . $dir_3 . "/" . $user_id . "/";
    return $user_path;

}

sanitize_var () é uma função de suporte para lavagem de entrada e garantindo a sua numérico, $ GLOBALS [ 'SITE_PATH'] é o caminho absoluto para o servidor. Felizmente, eles vão ser auto-explicativo contrário.

O que eu utilizado para outro requisito, mas que pode atender às suas necessidades é usar uma simples convenção.

Incremento por 1 e obter o comprimento do novo número e, em seguida, prefixo com este número.

Por exemplo:

Suponha que 'a' é um var que é definido com o último id.

a = 564;
++a;
prefix = length(a);
id = prefix + a; // 3565

Em seguida, você pode usar um timestamp para o diretório, usando esta convenção:

20092305 (yyyymmdd)

Depois, você pode explodir o seu caminho como este:

2009/23/05/3565.jpg

(ou mais)

É interessante porque você pode manter uma ordem de classificação por data e por número, ao mesmo tempo (às vezes útil) E você ainda pode decompor o seu caminho em mais diretórios

A resposta de Joe Beda é quase perfeito, mas por favor note que o MD5 tem sido provado ser Colisão em IIRC duas horas em um laptop?

Dito isto, se você realmente vai usar hash MD5 do arquivo na forma descrita, o serviço vai se tornar vulnerável a ataques. Como será a aparência ataque como?

  1. Um hacker não gosta de um determinado foto
  2. Ele assegura que este é MD5 claro que você está usando (MD5 da imagem + secret_string pode assustá-lo fora)
  3. Ele usa um método mágico de colidir uma imagem de (Use sua imaginação aqui) hash com a foto ele não gosta
  4. Ele carrega a foto que ele faria normalmente
  5. O seu serviço substitui o antigo com o novo e exibe tanto

Alguém diz: não vamos substituí-lo então. Então, se é possível prever que alguém vai fazer upload de algo (F. E. uma imagem popular na web pode ter carregado), é possível tomar o "hash lugar" do primeiro. Usuário ficaria feliz ao fazer upload de uma foto de um gatinho, ele iria achar que ele realmente aparece como (Use sua imaginação aqui). Eu digo: use SHA1, como tem sido provado ser hackable em IIRC 127 anos por um grupo de 10.000 computadores

?

Pode ser tarde para o jogo sobre este assunto. Mas uma solução (se ele se adequa ao seu caso de uso) poderia ser um nome de arquivo de hash. É uma maneira de criar um caminho de arquivo facilmente reproduzível usando o nome do arquivo ao mesmo tempo, criando uma estrutura de diretório bem distribuído. Por exemplo, você pode usar os bytes de código hash do nome de arquivo, pois é caminho:

String fileName = "cat.gif";
int hash = fileName.hashCode();
int mask = 255;
int firstDir = hash & mask;
int secondDir = (hash >> 8) & mask;

O resultado seria o ser caminho:

/172/029/cat.gif

Você pode então encontrar cat.gif na estrutura de diretórios, reproduzindo o algoritmo.

Usando HEX como os nomes de diretório seria tão fácil como converter os valores int:

String path = new StringBuilder(File.separator)
        .append(String.format("%02x", firstDir))
        .append(File.separator)
        .append(String.format("%02x", secondDir)
        .toString();

Resultando em:

/AC/1D/cat.gif

Eu escrevi um artigo sobre isso há alguns anos e recentemente mudou-se para Médio. Tem mais alguns detalhes e um código de exemplo: Nome do Arquivo Hashing: Criando uma estrutura Diretório hash. Espero que isso ajude!

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top