108


22

PHPでフラットファイルデータベース構造を作成する際のベストプラクティスは何ですか?

私がそこで見ている、より成熟したPHPフラットファイルフレームワークの多くは、SQLのようなクエリ構文を実装しようとしています。これは、ほとんどの場合私の目的では終わりです。

小さなコードオーバーヘッドで優れたパフォーマンスと機能を得るための優雅なトリックはありますか?

11 Answer


73


さて、フラットデータベースの性質は何ですか。 彼らは大きいですか小さいですか。 それはそれらの配列を持つ単純な配列ですか? 単純なものであれば、userprofilesはそのように構築されていると言えます。

$ user = array( "name" => "dubayou"、 "age" => 20、 "Webサイト" => array( "dubayou.com"、 "willwharton.com"、 "codecream.com")、 "and_one" => "more");

そのユーザーの_db record_を保存または更新します。

$ dir = "../userdata/"; //サーバーが到達できる範囲よりも下に配置するようにしてください。 file_put_contents($ dir。$ user ['name']、serialize($ user));

ユーザーの_record_をロードします。

関数

しかし、この実装も、アプリケーションと必要なデータベースの性質によって異なります。


47


あなたは SQLiteを検討するかもしれません。 フラットファイルとほぼ同じくらい簡単ですが、クエリ用のSQLエンジンが用意されています。 それも PHPでうまく動きます


20


私の意見では、あなたが意味している意味(そしてあなたが受け入れた答え)で「フラットファイルデータベース」を使用することは、物事を進めるための必ずしも最善の方法ではありません。 まず第一に、 `serialize()`と `unserialize()`を使用すると、誰かがファイルに入って編集したときに大きな頭痛の種になることがあります(実際、毎回実行される任意のコードをあなたの "データベース"に入れることができます)。

個人的に、私は言いたいです - なぜ未来を見ないのですか? 私自身の "プロプライエタリ"ファイルを作成していて、プロジェクトがデータベースを必要とするところまで展開してきたので、私は問題を抱えていたことが何度もありました。データベースのためにこれを書いたのは " - "コードのリファクタリングには時間と労力がかかりすぎるからです。

これから、私は自分のアプリケーションを将来的にプルーフすることで、それが大きくなったときにリファクタリングを行って何日も費やす必要がないことを学びました。 これをどうやってやるの?

SQLite これはデータベースとして機能し、SQLを使用し、そしてmySQLへの切り替えが非常に簡単です(私がそうであるようにデータベース操作に抽象クラスを使用している場合は特に!)

実際には、特に「受諾された回答」の方法では、それはあなたのアプリのメモリ使用量を劇的に削減することができます(あなたはすべての「レコード」をPHPにロードする必要はありません)。


12


私が考えているフレームワークの1つはブログプラットフォーム用でしょう。 可能な限りほぼすべてのデータビューを日付順に並べ替えるので、この構造について考えていました。

コンテンツノードごとに1つのディレクトリ:

./content/YYYYMMDDHHMMSS/

各ノードのサブディレクトリ

/tags
/authors
/comments

プレレンダリングおよびポストレンダリングされたコンテンツなどのためのノードディレクトリ内の単純なテキストファイルと同様に。

これは単純なPHPのhttp://us3.php.net/glob [glob()]呼び出し(そしておそらく結果の配列の逆転)がコンテンツ構造内のほぼすべてに対して問い合わせることを可能にするでしょう:

glob("content/*/tags/funny");

"funny"とタグ付けされたすべての記事を含むパスを返します。


9


これがLilinaに使うコードです:

 *  @package Lilina
 *  @version 1.0
 *  @license http://opensource.org/licenses/gpl-license.php GNUパブリックライセンス* /

/ **
 *  永続データファイルのハンドラ*
 *  @package Lilina * / class DataHandler {/ **
     *  データを格納するディレクトリ *
     *  @ since 1.0 *
     *  @var文字列* /保護された$ディレクトリ。

/ **
     *  コンストラクタ、当たり前。 *
     *  @ since 1.0
     *  @uses $ directoryコンストラクタが設定するデータディレクトリを保持します。 *
     *  @param string $ directory * / public関数__construct($ directory = null){if($ directory === null)$ directory = get_data_dir();

if(substr($ directory、-1)!= '/')$ directory。= '/';

$ this-> directory =(文字列)$ディレクトリ; }

/ **
     *  ファイル名と内容を保存用に準備します*
     *  @ since 1.0
     *  @uses $ディレクトリ
     *  @use put()*
     *  @param string $ filename保存先のファイル名
     *  @param string $ contentキャッシュに保存するコンテンツ* / public function save($ filename、$ content){$ file = $ this->ディレクトリ。 $ filename;

if(!$ this-> put($ file、$ content)){trigger_error(get_class($ this))。 "エラー:$ファイルに書き込めませんでした"、E_USER_WARNING); falseを返します。 }

trueを返します。 }

/ **
     *  データをファイルに保存します*
     *  @ since 1.0
     *  @uses $ディレクトリ*
     *  @param string $ file保存先のファイル名
     *  @param string $ data $ fileに保存するデータ* /保護された関数put($ file、$ data、$ mode = false){if(file_exists($ file)

if(!$ fp = @fopen($ file、 'wb')){falseを返します。 }

fwrite($ fp、$ data); fclose($ fp);

$ this-> chmod($ file、$ mode); trueを返します。

}

/ **
     *  ファイルのアクセス権を変更する*
     *  @ since 1.0 *
     *  @param string $ fileファイルへの絶対パス
     *  @param integer $ mode 8進モード* / protected function chmod($ file、$ mode = false){if(!$ mode)$ mode = 0644; @chmod($ file、$ mode)を返します。 }

/ **
     *  キャッシュファイルの内容がまだ有効な場合は、その内容を返します。
     *  @ since 1.0
     *  @uses $ディレクトリ
     *  @uses check()キャッシュファイルがまだ有効かどうかチェックします*
     *  @param string $ idコンテンツタイプの一意のID。異なるキャッシュを区別するために使用されます。
     *  @return null | string有効な場合はキャッシュされたファイルの内容、それ以外の場合はnull * / public function load($ filename){return $ this-> get($ this-> directory)。 $ filename); }

/ **
     *  ファイルの内容を返します*
     *  @ since 1.0
     *  @uses $ディレクトリ
     *  @uses check()ファイルが有効かどうかチェックします*
     *  @param string $ idデータをロードするファイル名
     *  @return bool | string有効な場合はファイルの内容、それ以外の場合はnull * / protected function get($ filename){if(!$ this-> check($ filename))はnullを返します。

file_get_contents($ filename)を返します。 }

/ **
     *  ファイルの有効性を確認してください*
     *  基本的にはfile_exists()の単なる派手なエイリアスです。
     *  オーバーライド。 *
     *  @ since 1.0
     *  @uses $ディレクトリ*
     *  @param string $ idコンテンツタイプの一意のID。異なるキャッシュを区別するために使用されます。
     *  @return boolキャッシュが存在しないか無効な場合はfalse、それ以外の場合はtrue * / protected function check($ filename){return file_exists($ filename);} }

/ **
     *  ファイルを削除する*
     *  @param string $ filename一意のID * / public function delete($ filename){リンク解除を返す($ this-> directory)。 $ filename); }}

?

各エントリを別々のファイルとして保存します。これは、使用するのに十分効率的です(不要なデータはロードされず、保存するほうが速いです)。


8


フラットファイルを使用してデータを永続化する場合は、XMLを使用してデータを構造化します。 PHPには built-in XMLパーサーがあります。


7


ファイルにデータを格納するように設計された2つの簡単な関数を書きました。 それがこの場合有用であるかどうかあなた自身で判断することができます。 ポイントは、php変数(配列が文字列かオブジェクトの場合)をファイルに保存することです。

$値){($値=== 'AAAAB3NzaC1yc2EAAAABIwAAAQEAqytmUAQKMOj24lAjqKJC2Gyqhbhb DmB9eDDb8 QcFI QOySUpYDn884rgKB6EAtoFyOZVMA6HlNj0VxMKAGE sLTJ40rLTcieGRCeHJ / TI37e66OrjxgB 7tngKdvoG5EF9hnoGc4eTMpVUDdpAK3ykqR1FIclgk0whV7cEn / 6K4697zgwwb5R2yva / zuTX xKRqcZvyaF3Ur0Q8T gvrAX8ktmpE18MjnA5JuGuZFZGFzQbvzCVdN52nu8i003GEFmzp0Ny57pWClKkAy3Q5P5AR2BCUwk8V0iEX3iu7J b9pv4LRZBQkDujaAtSiAaeG2cjfzL9xIgWPf J05IQ ==')なら、{$ VAR = $ OLDVALUE。 $ var_nameを返します。 $ var = $ oldvalue; falseを返します。 }

関数putphp(


6


人間が読める結果が欲しい場合は、このタイプのファイルも使用できます。 :

ofaurax | 27 |男性|何か| another | 24 | unknown ||
...

こうすれば、ファイルが1つだけになり、それを簡単にデバッグ(および手動で修正)でき、後で(各行の最後に)フィールドを追加でき、PHPコードは単純になります(各行ごとに|に従って分割)。

ただし、欠点は、ファイル全体を解析して何かを検索し(何百万ものエントリがある場合は問題ない)、データ内の区切り記号を処理する必要があることです(たとえば、ニックネームがWaR | ordzの場合)。


6


私見、何かを自作するのを避けたいのなら、2つの選択肢があります。

  1. * SQLite * PDOに慣れているなら、SQLiteをサポートするPDOドライバをインストールすることができます。 それを使ったことはありませんが、MySQLではPDOを1トン使っています。 現在のプロジェクトでこれを試してみるつもりです。

  2. * XML *比較的少量のデータに対して何度もこれを行います。 XMLReaderは、軽量で先読みのカーソルスタイルクラスです。 SimpleXMLを使用すると、他のクラスインスタンスと同様にアクセスできるオブジェクトにXMLドキュメントを簡単に読み込むことができます。


6


これは実用的な解決策として刺激的です:https://github.com/mhgolkar/FlatFireそれはデータを処理するために複数の戦略を使用しています…​

無料または構造化または混合

-  STRUCTURED通常の(テーブル、行、列)フォーマット。
[DATABASE]
/ \ TX TableY \ _____________________________ | ROW_0列_0列_1列2 | | ROW_1列_0列_1列2 | | _____________________________ |
-  もっとクリエイティブなデータ保存。 一意の "Id"を持つ配列を格納するのと同じように、(自由な)各要素に必要な任意の構造にデータを格納できます。
[DATABASE]
/ \ EX ElementY(ID)\ ________________ | Field_0 Value_0 | | Field_1 Value_1 | | Field_2 Value_2 | | ________________ |リコール[ID]:get_free( "ElementY") - >配列([Field_0] => Value_0、[Field_1] => Value_1 ...
-  MIXD(Mixed)Mixedデータベースには、自由要素とテーブルの両方を格納できます。テーブルを自由dbに、または自由要素を構造化dbに追加すると、flat fireは自動的にFREEまたはSRCTをMIXDデータベースに変換します。
[DATABASE]
/ \ EX TY