Pregunta

Miles de usuarios suben miles de imágenes a mi servidor Linux, alojado en 1and1.com (creo que usan CentOS, pero no estoy seguro de la versión).Esta es una pregunta independiente del idioma; sin embargo, para su referencia, estoy usando PHP.

Lo primero que pensé fue simplemente volcarlos todos en el mismo directorio; sin embargo, recuerdo que hace un tiempo había un límite en la cantidad de archivos o directorios que se podían colocar en un directorio.

Mi segundo pensamiento fue particionar los archivos dentro de los directorios según la dirección de correo electrónico de los usuarios (ya que es lo que estoy usando para el nombre de usuario de todos modos) pero no quiero encontrarme con el límite de directorios en un directorio....

De todos modos, para imágenes de usuario@dominio.com, iba a hacer esto:

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

¿Es inteligente hacerlo? ¿Qué pasaría si miles de usuarios dijeran 'gmail'? Tal vez podría profundizar más, así

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

entonces para mike@gmail.com sería...

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

¿Es este un mal enfoque?¿Qué están haciendo todos los demás?Tampoco quiero tener problemas con demasiados directorios...


Relacionado:

¿Fue útil?

Solución

Me gustaría hacer lo siguiente:

  1. Tome un hash MD5 de cada imagen a medida que llega.
  2. Escribir que hash MD5 en la base de datos donde se está manteniendo un seguimiento de estas cosas.
  3. Guárdelos en una estructura de directorios en el que utiliza el primer par de bytes de la cadena de hash MD5 hexagonal como el nombre dir. Así que si el hash es 'abcdef1234567890' en que almacena como 'a / b / abcdef1234567890'.

El uso de un hash también le permite fusionar la misma imagen subido varias veces.

Otros consejos

para ampliar el enfoque de Joe Beda:

  • base de datos
  • base de datos
  • base de datos

si se preocupan por la agrupación o la búsqueda de archivos de usuario, nombre de archivo original, fecha de carga, foto-tomada sobre la fecha (EXIF), etc., almacenar estos metadatos en una base de datos y utilizar las consultas apropiadas para seleccionar los archivos correspondientes .

Utilice la clave principal de base de datos - si un hash de archivo, o un número autoincremental - para localizar archivos entre un conjunto fijo de directorios (otra alternativa es utilizar un directorio fijo indica el número máximo de archivos N por, y cuando se llenan ir a la siguiente, por ejemplo, la k th Photo debe ser almacenado a {somepath}/aaaaaa/bbbb.jpg donde aaaaaa = piso (k / N), con el formato decimal o hexadecimal, y bbbb = mod (k, N), con formato como decimal o hexadecimal. Si eso es una jerarquía demasiado plana para usted, usar algo como {somepath}/aa/bb/cc/dd/ee.jpg)

No exponga la estructura de directorios directamente a los usuarios. Si están usando navegadores web para acceder a su servidor a través de HTTP, darles una URL como clave www.myserver.com/images/{primary} y codificar el tipo de archivo apropiado en la cabecera Content-Type.

Aquí hay dos funciones que escribí hace un tiempo por exactamente esta situación. Han estado en uso durante más de un año en un sitio con miles de miembros, cada uno de los cuales tiene un montón de archivos.

En esencia, la idea es utilizar los últimos dígitos de base de datos ID única de cada miembro para el cálculo de una estructura de directorios, con un directorio único para todo el mundo. Utilizando los últimos dígitos, en lugar de la primera, asegura una distribución más equilibrada de los directorios. Un directorio independiente para cada miembro significa tareas de mantenimiento son mucho más simple, además de que puede ver dónde está la materia de la gente es (como en forma 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 () es una función de soporte para el fregado de entrada y asegurar que es numérico, $ GLOBALS [ 'SITE_PATH'] es la ruta absoluta para el servidor. Con suerte, van a ser auto-explicativo de otra manera.

Lo he usado para otro de los requisitos pero que se ajusten a sus necesidades es utilizar una simple convención.

Incremento por 1 y obtener la longitud del nuevo número y, a continuación, el prefijo con este número.

Por ejemplo:

Supongamos 'a' es un VAR que se establece con el último ID.

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

A continuación, puede utilizar una marca de tiempo para el directorio, el uso de esta convención:

20092305 (yyyymmdd)

A continuación, puede explotar su camino como esto:

2009/23/05/3565.jpg

(o más)

Es interesante porque se puede mantener un orden de clasificación por fecha, y por el número al mismo tiempo (a veces útil) Y todavía se puede descomponer su camino en más directorios

La respuesta de Joe Beda es casi perfecta, pero tenga en cuenta que se ha demostrado que el MD5 es colisionable en 2 horas en una computadora portátil.

Dicho esto, si realmente utiliza el hash MD5 del archivo de la forma descrita, su servicio se volverá vulnerable a los ataques.¿Cómo será el ataque?

  1. A un hacker no le gusta una foto en particular
  2. Se asegura de que lo que estás utilizando es el MD5 simple (el MD5 de imagen+cadena_secreta puede asustarlo)
  3. Utiliza un método mágico para hacer colisionar una imagen de (usa tu imaginación aquí) hash con la foto que no le gusta.
  4. Sube la foto como lo haría normalmente.
  5. Su servicio sobrescribe el antiguo con el nuevo y muestra ambos

Alguien dice:Entonces no lo sobrescribamos.Entonces, si es posible predecir que alguien subirá algo (p.e.(es posible que se cargue una imagen popular en la web), es posible tomar el "lugar hash" de la misma primero.El usuario estaría feliz al subir una foto de un gatito. Descubriría que en realidad aparece como (usa tu imaginación aquí).Yo digo:¿Usar SHA1, ya que se ha demostrado que es pirateable en iirc 127 años por un grupo de 10.000 computadoras?

podría ser tarde para el juego en esto. Sin embargo, una solución (caso se ajusta a su caso de uso) podría ser el nombre del archivo de hash. Es una manera de crear una ruta de archivo fácilmente reproducible usando el nombre del archivo al mismo tiempo crear una estructura de directorios bien distribuido. Por ejemplo, puede utilizar los bytes de código hash del nombre de archivo como su trayectoria:

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

Esto daría como resultado el ser ruta:

/172/029/cat.gif

A continuación puede encontrar cat.gif en la estructura de directorios mediante la reproducción del algoritmo.

El uso de HEX como los nombres de directorio sería tan fácil como convertir los valores int:

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

El resultado es:

/AC/1D/cat.gif

escribí un artículo sobre esto hace unos años y recientemente se trasladó a mediano. Tiene unos cuantos más detalles y algunos ejemplos de código: Nombre de archivo de hash: la creación de una estructura de directorios Hash . Esperamos que esto ayude!

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top