Des milliers d'images, comment dois-je organiser la structure de répertoire? (Linux)

StackOverflow https://stackoverflow.com/questions/900512

  •  23-08-2019
  •  | 
  •  

Question

Je reçois des milliers de photos téléchargées par des milliers d'utilisateurs sur mon serveur Linux, qui est hébergé par 1and1.com (je crois qu'ils utilisent CentOS, mais je ne suis pas sûr de la version). C'est une langue agnostique question, cependant, pour votre référence, je suis en utilisant PHP.

Ma première pensée était de les jeter tout simplement dans le même répertoire, cependant, je me souviens il y a quelque temps, il y avait une limite au nombre de fichiers ou répertoires peuvent être déposés dans un répertoire.

Ma deuxième pensée a été de diviser les fichiers dans les répertoires basés sur l'adresse e-mail des utilisateurs (comme il est ce que je suis en utilisant le nom d'utilisateur de toute façon), mais je ne veux pas courir dans la limite pour les répertoires dans un répertoire. ...

Quoi qu'il en soit, pour les images de user@domain.com, je vais faire ceci:

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

Est-ce intelligent à faire, si des milliers d'utilisateurs ont dit « gmail » peut-être que je pourrais même aller plus loin, comme ceci

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

pour mike@gmail.com il serait ...

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

Est-ce une mauvaise approche? Qu'est-ce que tout le monde fait? Je ne veux pas un problème avec trop de répertoires aussi ...


Related:

Était-ce utile?

La solution

Je ferais ce qui suit:

  1. Prendre un hachage MD5 de chaque image comme il vient.
  2. Ecrire ce hachage MD5 dans la base de données où vous garder une trace de ces choses.
  3. les stocker dans une structure de répertoire où vous utilisez les deux premiers octets de la chaîne hexagonale de hachage MD5 comme nom de dir. Donc, si le hachage est 'abcdef1234567890' vous enregistrer comme 'a / b / abcdef1234567890.

L'utilisation d'un hachage permet également de fusionner la même image plusieurs fois téléchargé.

Autres conseils

pour élargir l'approche de Joe Beda:

    base de données
  • base de données
  • base de données

si vous vous souciez de regroupement ou de trouver des fichiers par l'utilisateur, le nom de fichier d'origine, la date d'envoi, photo prise sur la date (EXIF), etc., stocker ces métadonnées dans une base de données et utiliser les requêtes appropriées pour choisir les fichiers appropriés .

Utilisez la clé primaire de base de données - si un hachage de fichier, ou un numéro de autoincrementing - pour localiser des fichiers au sein d'un ensemble fixe de répertoires (alternativement, utilisez un fixe maximale de nombre de fichiers N par répertoire, et quand vous remplissez aller à la suivante, par exemple k e photo doit être conservé à {somepath}/aaaaaa/bbbb.jpg où aaaaaa = étage (k / N), formaté en décimal ou hexadécimal, et bbbb = mod (k, N), mis en forme comme décimal ou hexadécimal. Si c'est une hiérarchie pour vous trop plat, utilisez quelque chose comme {somepath}/aa/bb/cc/dd/ee.jpg)

Ne pas exposer la structure des répertoires directement à vos utilisateurs. Si elles utilisent des navigateurs Web pour accéder à votre serveur via HTTP, donnez-leur une url comme clé www.myserver.com/images/{primary} et encoder le type de fichier approprié dans l'en-tête Content-Type.

Voici deux fonctions que j'ai écrit un certain temps pour exactement cette situation. Ils ont été utilisés depuis plus d'un an sur un site avec des milliers de membres, dont chacun a beaucoup de fichiers.

En substance, l'idée est d'utiliser les derniers chiffres de base de données unique de chaque membre ID pour calculer une structure de répertoire, un répertoire unique pour tout le monde. En utilisant les derniers chiffres, plutôt que le premier, assure une répartition plus homogène des répertoires. Un répertoire distinct pour chaque membre signifie des tâches de maintenance sont beaucoup plus simples, plus vous pouvez voir où est la substance des gens est (comme dans visuellement).

// 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 () est une fonction de support pour l'entrée et de lavage assurant qu'il est numérique, $ GLOBALS [ « de chemin_site »] est le chemin absolu pour le serveur. Si tout va bien, ils seront explicites autrement.

Qu'est-ce que j'ai utilisé pour une autre exigence, mais qui peut répondre à vos besoins est d'utiliser une simple convention.

Incrémenter de 1 et obtenir la longueur du nouveau numéro, et le préfixe puis avec ce numéro.

Par exemple:

Supposons 'a' est une var qui est réglée avec le dernier identifiant.

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

Ensuite, vous pouvez utiliser un horodatage pour le répertoire, en utilisant la convention suivante:

20092305 (yyyymmdd)

Ensuite, vous pouvez exploser votre chemin comme ceci:

2009/23/05/3565.jpg

(ou plus)

Il est intéressant parce que vous pouvez garder un ordre de tri par date et par numéro en même temps (parfois utile) Et vous pouvez toujours décomposer votre chemin dans plusieurs répertoires

La réponse de Joe Beda est presque parfait, mais s'il vous plaît noter que le MD5 a été prouvé être collidable en IIRC 2 heures sur un ordinateur portable?

Cela dit, si vous réellement utiliser le hachage MD5 du fichier de la manière décrite, votre service deviendra vulnérable aux attaques. Comment l'attaque ressemble?

  1. Un pirate n'aime pas une photo particulière
  2. Il assure que ce MD5 simple que vous utilisez (MD5 de l'image + secret_string peut lui faire peur)
  3. Il utilise une méthode magique d'entrer en collision une image (utilisez votre imagination ici) hash avec la photo qu'il n'aime pas
  4. Il télécharge la photo comme il le ferait normalement
  5. Votre service remplace l'ancien avec le nouveau et affiche à la fois

Quelqu'un dit: nous allons écraser pas alors. Ensuite, s'il est possible de prédire que quelqu'un va télécharger quelque chose (F.E. une image populaire sur le web peut se téléchargé), il est possible de prendre le « hash place » le premier. L'utilisateur serait heureux lors du téléchargement d'une photo d'un chat, il trouverait qu'il apparaît effectivement comme (utilisez votre imagination ici). Je dis: utiliser SHA1, comme il a été prouvé être piratable dans IIRC 127 ans par un groupe de 10.000 ordinateurs

?

peut être en retard dans le jeu à ce sujet. Mais une solution (si elle correspond à votre cas d'utilisation) pourrait être le hachage de nom de fichier. Il est un moyen de créer un chemin de fichier facilement reproductible en utilisant le nom du fichier, tout en créant une structure de répertoires bien répartis. Par exemple, vous pouvez utiliser les octets de hashcode du nom de fichier comme son chemin:

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

Cela se traduirait par le chemin étant:

/172/029/cat.gif

Vous pouvez alors trouver cat.gif dans la structure de répertoire en reproduisant l'algorithme.

Utilisation HEX comme les noms de répertoire serait aussi facile que la conversion des valeurs de int:

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

Entraînant:

/AC/1D/cat.gif

J'ai écrit un article à ce sujet il y a quelques années et a récemment déménagé à moyen. Il a un peu plus de détails et un exemple de code: Nom du fichier Hashage: Création d'une structure Hashed Directory. Espérons que cela aide!

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top