web-dev-qa-db-ja.com

ユーザーがアップロードした画像の保存

ユーザーがアップロードした写真を処理し、それらをデータベースとサーバーに保存するための通常のプラクティスは何ですか?

ユーザープロフィール画像の場合:

  1. ユーザーから画像ファイルを受け取った後、ファイルの名前を<image_id>_<username>に変更します
  2. 画像を/images/userprofileに移動します
  3. first_name, last_name, age, gender, birthdayなどのプロファイルの詳細を含むusersテーブルにimgファイル名を追加します

ユーザーが行ったレビュー用の画像の場合:

  1. ユーザーから画像ファイルを受け取った後、ファイルの名前を<image_id>_<review_id>に変更します
  2. 画像を/images/reviewsに移動します
  3. review_id, review_content, user_id, scoreなどのプロファイルの詳細を含むreviewsテーブルにimgファイル名を追加します。

質問1:ユーザーが特定のレビュー用に複数の写真をアップロードできる場合、画像ファイル名を保存するにはどうすればよいですか?シリアライズ?

質問2:または、画像を追跡するためだけに別のテーブルreview_imagesカラムreview_id, image_id, image_filenameがありますか?このテーブルからimage_filenameを取得するときにJOINを実行すると、パフォーマンスが著しく低下しますか?

質問:すべての画像を単一のフォルダーに保存する必要がありますか?同じフォルダに10万枚の写真がある場合、問題が発生しますか?

これを行うためのより効率的な方法はありますか?

5
Nyxynyx

簡単な答え:画像ファイル名をデータベースに保存する必要はありません。アップロードするファイルの名前をtheirusername.jpgに変更し、/uploads/users/に保存するだけです。以下の長い回答。


質問1:ユーザーが特定のレビュー用に複数の写真をアップロードできる場合、画像ファイル名を保存するにはどうすればよいですか?シリアライズ?

あなたは出来る:

  1. ファイル名をカンマ区切りにして、imagesテーブルの単一のreviewフィールドに保存します。表示する画像を取得する場合、images文字列をカンマで分割し、その配列をループして画像をレイアウトします。 (画像が1つしかない場合でも、これは機能します。)

  2. 2番目の質問で提案するように、imagesまたはreview_imagesという名前の個別のテーブルを作成し、各画像を独自の行に保存します。

質問2:または、画像を追跡するためだけに、review_id、image_id、image_filenameの列を持つ別のテーブルreview_imagesがありますか?このテーブルからimage_filenameを取得するときにJOINを実行すると、パフォーマンスが著しく低下しますか?

単純なJOINを使用しても、パフォーマンスが著しく低下することはほとんどありません。クエリをキャッシュし、静的なHTMLを提供することにより、パフォーマンスの小さなヒットを無効化または削減できます。

質問3:すべての画像を単一のフォルダーに保存する必要がありますか?

次のいずれかをお勧めします。

  1. ユーザーが最初のファイルをアップロードするときに、/uploads/ディレクトリにユーザーごとに1つのフォルダーを作成します。
  2. 毎月(アップロードスクリプトの一部として自動的に)新しいフォルダーを作成し、そこに画像をアップロードします。これは、デフォルトでWordPressが行うことです。

これにより、ファイル数のディレクトリ制限に達する可能性が減少します。

同じフォルダに10万枚の写真がある場合、問題が発生しますか?

おそらく、サーバーが使用するファイルシステムによって異なります。 1つのディレクトリに含めることができるファイルの数には制限があります。たとえば、FAT32には、フォルダーあたり65,535ファイルの制限があります。 Stack Overflowの "ディレクトリ内のファイルが多すぎますか?" を参照してください。上記で提案したようにフォルダを使用すると、ディレクトリの制限に達する危険性が減ることに注意してください。

これを行うためのより効率的な方法はありますか?

単純な規則に従う場合、データベースに画像データを保存する必要はまったくありません。たとえば、ユーザーがプロファイル画像をアップロードする場合、その名前をprofile.jpgに変更し、/uploads/users/username/に保存できます。これで、プロフィール画像を取得するためにユーザーのユーザー名のみが必要になります。データベースへの画像への参照を保存する必要はもうありません。 (または、イメージにtheirusername.jpgという名前を付けて/uploads/users/に保存するだけで、あなたにとって意味のある規則を選択できます。)

同様に、ユーザーがレビュー用の画像をアップロードする場合、/uploads/reviews/13/というフォルダーにそれらの画像を保存できます。末尾の13番はレビューIDです。これは、データベーステーブルに保存されているそのレビューの一意のIDです。これらの画像を表示するには、それらの画像を取得するために必要なのはレビューIDだけです。 (フォルダ内の画像を調べるには、ディレクトリをスキャンします。PHPでは、たとえば scandir() を使用します。)

2
Nick

データベースに関するイメージに関する情報(ユーザー名、イメージID、ファイル名)を保存し、JOINでこれを取得します。

Stack Overflowのこのスレッド は同じアイデアを説明していますが、参照したい正確なスレッドが見つからなかったため、より良い説明が得られます。 Michael Andrewsが 彼のブログ でこのようなスキームを実装する方法の実際の実践について説明しています...

基本的な考え方は、画像の内容をハッシュし、そのハッシュをファイル名として使用して画像を保存することです。

  • ユーザーが「LazyCat.jpg」を画像としてアップロードするとします。
  • そのイメージのSHA1ハッシュは「ac17c9e81fc3789ab6b8c1f3325d789e9aa3daaf」になる可能性があります
  • サーバーには、画像ディレクトリ「images」があります。画像の下には、ハッシュの最初の数桁のサブディレクトリがあります。 「/images/0000」、「/images/0001/」、...、「/images/a3df/」、...、「/images/ffff/」
  • このパターンに従って(ディレクトリ内のファイル数を小さくするため)、ファイルを対応するディレクトリに保存します。この場合、「/ images/ac17/ac17c9e81fc3789ab6b8c1f3325d789e9aa3daaf」
  • データベースに、ユーザーIDと対応するファイル名を保存します。

複数の人が同じ画像をアップロードする場合、サーバーに保存されるのは一度だけです。データベースにそのファイル名への参照がなくなったら、いつでも削除できます。

2
dmsnell