12

ユーザーのファイルを自分の名前のディレクトリに保存します

/username/file01.jpg
/username/file02.mp4
/username/file03.mp3

しかし、より多くのユーザーが来て、より多くのファイルをアップロードすると、一部または多数のユーザーが別のドライブに移行することになるため、問題が発生します。ファイル名を混在させたくないため、最初にユーザー名ディレクトリ ソリューションを選択します。ファイル名も変更したくありません。また、別のユーザーが同じファイル名をアップロードすると、ファイルが元の名前で保存されている場合に問題が発生します。

これを行う最善の方法は何でしょうか。私には 1 つの解決策がありますが、コミュニティに尋ねたいのは、これが最善の方法です。

順次フォルダーを使用し、ファイル名を非常に一意のものにハッシュして、ディレクトリに保存します。私がすることは、ファイルの元の名前とユーザー名をデータベースに保存し、ファイル名のハッシュ値をディスクに保存することです。

誰かがそのファイルにアクセスしたいときは、php を介してそのファイルを読み取り、名前を置き換えるか、その時点で何かを実行して、ファイルが元のファイル名としてダウンロードされるようにします。

私はこの提案された解決策だけを念頭に置いています。これ以外にいいのありますか?

編集:

私もフォルダーシステムを使用していますが、おそらく2番目の方法では仮想フォルダーを使用します。私のデータベースはMongoDBです

みんな、あなたのすべての答えは素晴らしく、本当に役に立ちました。私は皆に報奨金を与えたかったので、コミュニティが自動的に提供できるように残しました。回答ありがとうございます。本当に感謝しています。

4

10 に答える 10

7

データベースでファイル メタデータを処理し、UUID を使用してファイルを取得します。私がすることは:

  1. コンテンツベースの識別
    1. ファイルのコンテンツからの MD5
    2. ユーザーの uuid とファイルの md5 に基づいて一意の識別子を生成する名前空間 UUID:v5。
    3. 「実名」に基づいてパスを生成するカスタム関数。
    4. データベースに保存します: uuid、originalname (アップロードされた名前)、realname (生成された名前)、filesize、および mime。(オプションの dateAdded、および md5)
  2. ファイルの取得。
    1. メタデータを取得する UUID。
    2. 実名に基づいてファイルパスを再生成します。
    3. Originalname は、ファイルをダウンロードするユーザーにわかりやすい名前を表示するために使用されます。

名前空間付きの UUID をデータベースの主キーとして割り当ててファイルの名前を処理し、ユーザーとファイル名に基づいてパスを生成します。前提条件は、ユーザーに uuid が割り当てられていることです。次のコードは、データベースでの ID の競合を回避し、その内容によってファイルを識別するのに役立ちます (必ずしもファイル名ではなく重複した内容を見つける方法が必要な場合)。

$fileInfo = pathinfo($_FILE['file']['name']);
$extension = (isset($fileInfo['extension']))?".".$fileInfo['extension']:"";

$md5Name = md5_file($_FILE['file']['tmp_name']); //you could use other hash algorithms if you are so inclined.

$realName = UUID::v5($user->uuid, $md5Name) . $extension; //UUID::v5(namespace, value).

関数を使用して、いくつかのカスタム パラメーターに基づいてファイル パスを生成します。$username と $realname を使用できます。これは、ファイル命名スキームまたは任意のカスタム スキームで分割された分散フォルダー構造を実装する場合に役立ちます。

function generateBasePath($realname, $customArgsArray){
    //Process Args as your requirements.
    //might as well be  "$FirstThreeCharsFromRealname/"
    //or a checksum that helps you decide which drive/volume/mountpoint to use.
    //like some files on the local disk and some other from an Amazon::S3 mountpoint.
    return $mountpoint.'/'.$generatedPath; 
}

追加のボーナスとして、これも:

  1. 置換されたファイル (uuid) のファイルのレコードに属性を追加すると、バージョン管理されたファイル リポジトリを維持するのに役立ちます。
  2. 「所有者」および/または「グループ」の属性を追加する場合は、アプリケーションのアクセス制御リストを作成します
  3. 単一のフォルダー構造でも機能します。

注: この質問のタグに基づいて、ファイル ソースの例として php の $_FILE を使用しました。任意のファイル ソースまたは生成されたコンテンツから取得できます。

于 2013-04-20T20:49:14.877 に答える
5

すでに MongoDB を使用しているため、GridFS を確認することをお勧めします。これは、MongoDB コレクションに (16 MB を超えるファイルであっても) ファイルを格納できるようにする仕様です。

スケーラブルなので、別のサーバーを追加しても問題ありません。メタデータも保存され、ファイルをチャンクで読み取ることができ、バックアップ機能も組み込まれています。

于 2013-04-21T14:23:37.930 に答える
3

ファイル名のハッシュ、アップロードの日時、およびファイル名のユーザー名に基づいて GUID を生成し、これらの値と、後で使用するためにデータベース内のファイルへのパスを保存します。このような GUID を生成すると、ファイル名を推測できなくなります。

例として、ユーザー Daniel Steiner (私) が、2013 年 4 月 23 日午前 12 時 37 分に resume.doc というファイルをサーバーにアップロードしたとします。これにより、Daniel_Steiner+2013/23/04+00:37+resume.doc の基本値が得られ、MD5 ハッシュ 05c2d2f501e738b930885d991d136f1e になります。ファイルが適切なプログラムで開かれるようにするために、後で適切なファイル末尾を追加し、http://link.to/your/site/05c2d2f501e738b930885d991d136f1e.docのようなものを取得します ユーザーアカウントに既にユーザー ID がある場合、それらを URL に追加できます。たとえば、私のユーザー ID が 123145 の場合、URL はhttp://link.to/your/site/123145/05c2d2f501e738b930885d991d136f1e.docになります。

元のファイル名をデータベースに保存すると、サーバー上に別のファイル名がある場合でも、ダウンロード用に元のファイル名をファイルに提供する downloadscript を後で提供することもできます。

シンボリック リンクを使用できる場合は、ファイルを別のハードディスクに再配置することも問題になりません。

必要に応じて、PHP の例を考え出すこともできます。コードが多すぎないようにしてください。

于 2013-04-22T22:40:32.483 に答える
2

もう 1 つの戦術は、ディレクトリの最初のレベルがユーザー名の最初の 2 文字であり、2 番目のレベルが残りの文字である 2 次元構造を作成することです (Git が SHA-1 オブジェクト ID を保存する方法と同様)。例えば:

/files/jr/andomuser/456.jpg

ユーザー「jrandomuser」の場合。

ユーザー名は SHA-1 値ほどランダムに配布されない可能性が高いため、後で別のレベルを追加する必要がある場合があることに注意してください。しかし、それを疑ってください。

于 2013-04-19T18:51:17.373 に答える
2

次のデータベース構造を使用することをお勧めします。

ここに画像の説明を入力

テーブルFileには少なくとも次のものがあります。

ここに画像の説明を入力

IDFileauto_increment列/主キーです 。外部キーですUserIDnullable

FK_File_User私が提案するのは:

ON UPDATE NO ACTION -- IDUser is auto_increment too. No changes need to be tracked.
ON DELETE SET NULL  -- If user deleted, then File is not owned. Might be deleted
                    -- with CRON job or something else.

それでも、別の列がFileテーブルに追加される場合があります。

  1. 実際のアップロード日時
  2. 実際の MIME タイプ
  3. 実際の保管場所 (分散ストレージ システムの場合)
  4. ダウンロード数 (別の表の方が適切な解決策になる場合があります)

等...

いくつかの利点:

  1. 1 回のデータベース操作で取得できるため、ファイル サイズ、ハッシュ、拡張子、またはファイル メタを計算する必要はありません。
  2. File各ユーザーのファイル数/使用スペース/テーブルに書き込んだものの統計を単一のSELECT ... GROUP BY ... WITH ROLLUPステートメントで取得でき、複数のストレージデバイスに分散している可能性のある実際のファイルの分析よりも高速です。
  3. さまざまなユーザーにファイル アクセス許可を適用できます。テーブル構造データベースの大幅な変更には費用がかかりません。

次の 2 つの理由から、保存時に元のファイル名が必要であるというオプションは考慮しません。

  1. ファイルには、キリル文字など、サーバー OS ファイルシステムで正しくサポートされていない名前が付いている場合があります。
  2. 2 つの異なるファイルが完全に同一の名前を持つ場合があるため、そのうちの 1 つが別のファイルによって上書きされる可能性があります。

したがって、解決策があります:

IDFile1) ファイルがテーブルからアップロードされるときにファイルの名前を変更INSERTFileます。安全で、重複はありません。

2) ファイルが必要になったときやダウンロードされたときに、次のようにファイルの名前を復元します。

// peform query to "File" table by given ID

list($name, $ext, $size, $md5) = $result->fetch_row();

$result->free();

header('Content-Length: ' . $size);
header('Content-MD5: ' . $md5);
header('Accept-Ranges: bytes');
header('Connection: close');
header('Content-Type: application/force-download');
header('Content-Disposition: attachment; filename="' . $name . '.' . $ext . '"');

// flush file content

3)実際のファイルは、単一のディレクトリ(IDFile安全であるため)およびIDUser-名前付きのサブディレクトリ-状況に応じて保存される場合があります。

4)IDFile直接シーケンスと同様に、ファイルの一部が失われた場合、実際のファイル名シーケンスの欠落セグメントを評価することでデータベース メタを取得できます。次に、「所有者に通知する」、「ファイル メタを削除する」、またはこの両方のアクションを実行できます。


私は、実際の大きなファイルを DBMS 自体にバイナリ コンテンツとして格納するという考えには反対です

DBMS はデータと分析に関するものであり、FileSystem ではありません。私の謙虚な意見が重要である場合は、決してそのように使用しないでください。

于 2013-04-23T08:18:52.967 に答える
1

LDAP サーバーをインストールできます。LDAP ルックアップは、負荷の高い読み取り操作用に高度に最適化されているため、非常に高速です。データを照会することもできます

LDAP は、データをツリー状に編成します。

「ユーザー→IPアドレス→フォルダ→ファイル名」のようにデータを整理できます。この方法では、ファイルが物理的/地理的に分散する可能性があり、場所を非常に迅速に取得できます。

標準の LDAP クエリを使用してクエリを実行することもできます。たとえば、特定のユーザーのファイルのすべてのリストを取得したり、フォルダー内のファイルのリストを取得したりできます。

于 2013-04-23T11:21:48.827 に答える
0
  1. 実際のファイル名 (例: myImage.jpg) とその他の属性 (例: MIME タイプ) を保存する Mongodb、および$random-text.jpg以下の 2. & 3. から

  2. いくつかを生成します$random-text。例:base_convert(mt_rand(), 10, 36)またはuniqid($username, true);

  3. ファイルを次のように物理的に保存します$random-text.jpg- 常に同じ拡張子を維持するのに適しています

  4. 注:filter_var()入力ファイル名が Mongodb にセキュリティ リスクをもたらさないことを確認するために使用します。

Amazon S3 は信頼性が高く安価です。S3 の "Eventual Concurrency" に注意してください。

于 2013-04-18T23:48:13.120 に答える