フラットファイルデータベース[終了]


120

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

多くの場合、私がSQLのようなクエリ構文を実装しようとしている、成熟したPHPフラットファイルフレームワークがたくさんあります。(その時点でデータベースを使用するだけです)。

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


1
ここにフラットファイルデータベース github.com/tmarois/Filebase用のパッケージがあることを追加したいと思います。これは古い質問であることはわかっていますが、このパッケージは最新のビルドとメンテナンスであり、ほとんどの機能が含まれていません。
tmarois 2017

私はCMSを開発しており、フラットテキストファイルのテキストデータベースを使用しています。作るのに何時間もかかり、骨折するのにも何時間もかかりますが、それは完璧に働きます。完全にインデックス化され、最適化されたデータベースを使用すると、クエリがはるかに高速に実行されます。ただし、メタデータを格納し、注意深く編成および構造化することにより、クエリの必要性を回避します。データが必要な場合、for loop(フォルダー内のすべてのデータを使用している場合を除いて)データがないため、データベースよりもはるかに高速に実行されます。詳細を調べて非常に良い答えを出しますが、残念ながらこの質問は締め切られました。
Dan Bray、

回答:


75

まあ、フラットデータベースの性質は何ですか。それらは大きいか小さいか。中に配列がある単純な配列ですか?その単純なものは、そのように構築されたユーザープロファイルと言います

$user = array("name" => "dubayou", 
              "age" => 20,
              "websites" => array("dubayou.com","willwharton.com","codecream.com"),
              "and_one" => "more");

また、そのユーザーのdbレコードを保存または更新します。

$dir = "../userdata/";  //make sure to put it bellow what the server can reach.
file_put_contents($dir.$user['name'],serialize($user));

ユーザーのレコードをロードする

function &get_user($name){
    return unserialize(file_get_contents("../userdata/".$name));
}

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


48

SQLiteを検討するかもしれません。これはフラットファイルとほとんど同じくらい簡単ですが、クエリ用のSQLエンジンを取得します。これは、PHPでうまく動作すぎ。


6
SQLiteはデフォルトで5.0以降に組み込まれていましたが、PHP 5.4以降から割引(!)2012年7月にこれを書いているので、SQLiteはデフォルトでは最新のシステムでは動作しなくなります。ここの
スリック

サーバーにアクセスできる場合、SQLite PDOドライバーのインストールは簡単です。Apache2を実行しているUbuntu / Debianでは、apt-get install php5-sqlite service apache2 restartを実行するだけ
シリコンロックスター

4
@Sliqからのコメントに対する反応として、「SQLiteは...廃止されました」は真実であると述べています。「SQLite」という名前の拡張が廃止され、「SQLite3」がデフォルトで有効になりました。 php.net/manual/en/sqlite.installation.php "PHP 5.0以降、この拡張機能はPHPにバンドルされていました。PHP5.4以降、この拡張機能はPECL経由でのみ利用可能です。" php.net/manual/en/sqlite3.installation.php「SQLite3 拡張機能は、PHP 5.3.0以降、デフォルトで有効になっています。」「この拡張機能は簡単にPECL拡張機能でしたが、そのバージョンは実験的な使用にのみ推奨されます。」
Paul van Leeuwen、2016

あなたは質問に答えませんでした
JG Estiot 19/07/18

20

私の意見では、「フラットファイルデータベース」をあなたが意味する意味で(そしてあなたが受け入れた答えで)使用することは、物事を進めるための最良の方法であるとは限りません。まず、serialize()and を使用するとunserialize()、誰かがファイルにアクセスして編集した場合にメジャーな問題が発生する可能性があります(実際、「データベース」に任意のコードを挿入して毎回実行することができます)。

個人的には、私は言うでしょう-未来を見つめてみませんか?独自の「独自の」ファイルを作成していて、プロジェクトがデータベースを必要とするところまで爆発しているので、何度も問題が発生してきました。私はこれをデータベースの最初から作成しました」-コードのリファクタリングに時間と労力がかかりすぎるためです。

このことから、アプリケーションが将来大きくなる場合に備えて、アプリケーションが大きくなったときに、何日もかけてリファクタリングを行う必要がないようにすることを学びました。どうすればよいですか?

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

実際、特に「受け入れられた回答」の方法では、アプリのメモリ使用量を大幅に削減できます(すべての「レコード」をPHPにロードする必要はありません)。


それは本当だ。serialize()そのためにもかなり役立ちます。実行可能なシステムを思い付くコツは、複雑さを犠牲にせずにデータノードにインデックスを付ける方法を見つけることだと思います。
saint_groceon 2008

12

私が検討しているフレームワークの1つは、ブログプラットフォーム用です。必要なデータのほぼすべてのビューが日付順に並べ替えられるため、この構造について考えていました。

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

./content/YYYYMMDDHHMMSS/

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

/tags  
/authors  
/comments  

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

これにより、単純なPHP glob()呼び出し(およびおそらく結果の配列の反転)で、コンテンツ構造内のほぼすべてのものに対してクエリを実行できます。

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

「おかしい」とタグ付けされたすべての記事を含むパスを返します。


9

Lilinaに使用するコードは次のとおりです。

<?php
/**
 * Handler for persistent data files
 *
 * @author Ryan McCue <cubegames@gmail.com>
 * @package Lilina
 * @version 1.0
 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
 */

/**
 * Handler for persistent data files
 *
 * @package Lilina
 */
class DataHandler {
    /**
     * Directory to store data.
     *
     * @since 1.0
     *
     * @var string
     */
    protected $directory;

    /**
     * Constructor, duh.
     *
     * @since 1.0
     * @uses $directory Holds the data directory, which the constructor sets.
     *
     * @param string $directory 
     */
    public function __construct($directory = null) {
        if ($directory === null)
            $directory = get_data_dir();

        if (substr($directory, -1) != '/')
            $directory .= '/';

        $this->directory = (string) $directory;
    }

    /**
     * Prepares filename and content for saving
     *
     * @since 1.0
     * @uses $directory
     * @uses put()
     *
     * @param string $filename Filename to save to
     * @param string $content Content to save to cache
     */
    public function save($filename, $content) {
        $file = $this->directory . $filename;

        if(!$this->put($file, $content)) {
            trigger_error(get_class($this) . " error: Couldn't write to $file", E_USER_WARNING);
            return false;
        }

        return true;
    }

    /**
     * Saves data to file
     *
     * @since 1.0
     * @uses $directory
     *
     * @param string $file Filename to save to
     * @param string $data Data to save into $file
     */
    protected function put($file, $data, $mode = false) {
        if(file_exists($file) && file_get_contents($file) === $data) {
            touch($file);
            return true;
        }

        if(!$fp = @fopen($file, 'wb')) {
            return false;
        }

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

        $this->chmod($file, $mode);
        return true;

    }

    /**
     * Change the file permissions
     *
     * @since 1.0
     *
     * @param string $file Absolute path to file
     * @param integer $mode Octal mode
     */
    protected function chmod($file, $mode = false){
        if(!$mode)
            $mode = 0644;
        return @chmod($file, $mode);
    }

    /**
     * Returns the content of the cached file if it is still valid
     *
     * @since 1.0
     * @uses $directory
     * @uses check() Check if cache file is still valid
     *
     * @param string $id Unique ID for content type, used to distinguish between different caches
     * @return null|string Content of the cached file if valid, otherwise null
     */
    public function load($filename) {
        return $this->get($this->directory . $filename);
    }

    /**
     * Returns the content of the file
     *
     * @since 1.0
     * @uses $directory
     * @uses check() Check if file is valid
     *
     * @param string $id Filename to load data from
     * @return bool|string Content of the file if valid, otherwise null
     */
    protected function get($filename) {
        if(!$this->check($filename))
            return null;

        return file_get_contents($filename);
    }

    /**
     * Check a file for validity
     *
     * Basically just a fancy alias for file_exists(), made primarily to be
     * overriden.
     *
     * @since 1.0
     * @uses $directory
     *
     * @param string $id Unique ID for content type, used to distinguish between different caches
     * @return bool False if the cache doesn't exist or is invalid, otherwise true
     */
    protected function check($filename){
        return file_exists($filename);
    }

    /**
     * Delete a file
     *
     * @param string $filename Unique ID
     */
    public function delete($filename) {
        return unlink($this->directory . $filename);
    }
}

?>

これは、各エントリを個別のファイルとして保存します。これは、使用するのに十分効率的であることがわかりました(不要なデータが読み込まれず、保存が高速です)。


8

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


人間が読みやすいXMLルールに従うか、シリアル化やJSONなどを使用することもできます。
ベン

非常に貧弱なアドバイス。XMLは使用しないでください。脂肪異常です。
JGエスティオット

@JGEstiot Careはさらに説明しますか?
UncaughtTypeError

7

人間が読める結果が必要な場合は、このタイプのファイルを使用することもできます。

ofaurax|27|male|something|
another|24|unknown||
...

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

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


7

データをファイルに格納するために設計された2つの単純な関数を作成しました。この場合に役立つかどうかは、自分で判断できます。ポイントは、php変数(配列、文字列またはオブジェクトのいずれかである場合)をファイルに保存することです。

<?php
function varname(&$var) {
    $oldvalue=$var;
    $var='AAAAB3NzaC1yc2EAAAABIwAAAQEAqytmUAQKMOj24lAjqKJC2Gyqhbhb+DmB9eDDb8+QcFI+QOySUpYDn884rgKB6EAtoFyOZVMA6HlNj0VxMKAGE+sLTJ40rLTcieGRCeHJ/TI37e66OrjxgB+7tngKdvoG5EF9hnoGc4eTMpVUDdpAK3ykqR1FIclgk0whV7cEn/6K4697zgwwb5R2yva/zuTX+xKRqcZvyaF3Ur0Q8T+gvrAX8ktmpE18MjnA5JuGuZFZGFzQbvzCVdN52nu8i003GEFmzp0Ny57pWClKkAy3Q5P5AR2BCUwk8V0iEX3iu7J+b9pv4LRZBQkDujaAtSiAaeG2cjfzL9xIgWPf+J05IQ==';
    foreach($GLOBALS as $var_name => $value) {
        if ($value === 'AAAAB3NzaC1yc2EAAAABIwAAAQEAqytmUAQKMOj24lAjqKJC2Gyqhbhb+DmB9eDDb8+QcFI+QOySUpYDn884rgKB6EAtoFyOZVMA6HlNj0VxMKAGE+sLTJ40rLTcieGRCeHJ/TI37e66OrjxgB+7tngKdvoG5EF9hnoGc4eTMpVUDdpAK3ykqR1FIclgk0whV7cEn/6K4697zgwwb5R2yva/zuTX+xKRqcZvyaF3Ur0Q8T+gvrAX8ktmpE18MjnA5JuGuZFZGFzQbvzCVdN52nu8i003GEFmzp0Ny57pWClKkAy3Q5P5AR2BCUwk8V0iEX3iu7J+b9pv4LRZBQkDujaAtSiAaeG2cjfzL9xIgWPf+J05IQ==')
        {
            $var=$oldvalue;
            return $var_name;
        }
    }
    $var=$oldvalue;
    return false;
}

function putphp(&$var, $file=false)
    {
    $varname=varname($var);
    if(!$file)
    {
        $file=$varname.'.php';
    }
    $pathinfo=pathinfo($file);
    if(file_exists($file))
    {
        if(is_dir($file))
        {
            $file=$pathinfo['dirname'].'/'.$pathinfo['basename'].'/'.$varname.'.php';
        }
    }
    file_put_contents($file,'<?php'."\n\$".$varname.'='.var_export($var, true).";\n");
    return true;
}

興味深いことに、フォーマットされた配列をファイルにダンプするだけなので、これはより良い方法です。再構築する必要はなく、読み込むだけです。また、変数の編集も少し簡単です。大きなデータを格納するためにそれを使用することは決してありませんが、データベースなしでプログラムのモジュールを格納するのが実用的であることがわかりました。ありがとうございました。
m3nda 2015年

7

これは実用的なソリューションとして刺激的です:
https : //github.com/mhgolkar/FlatFire
データを処理するために複数の戦略を使用します...
[Readmeファイルからコピー]

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

- STRUCTURED
Regular (table, row, column) format.
[DATABASE]
/   \
TX  TableY
    \_____________________________
    |ROW_0 Colum_0 Colum_1 Colum_2|
    |ROW_1 Colum_0 Colum_1 Colum_2|
    |_____________________________|
- FREE
More creative data storing. You can store data in any structure you want for each (free) element, its similar to storing an array with a unique "Id".
[DATABASE]
/   \
EX  ElementY (ID)
    \________________
    |Field_0 Value_0 |
    |Field_1 Value_1 |
    |Field_2 Value_2 |
    |________________|
recall [ID]: get_free("ElementY") --> array([Field_0]=>Value_0,[Field_1]=>Value_1...
- MIXD (Mixed)
Mixed databases can store both free elements and tables.If you add a table to a free db or a free element to a structured db, flat fire will automatically convert FREE or SRCT to MIXD database.
[DATABASE]
/   \
EX  TY

7

私見、自家醸造を避けたい場合は、2つのオプションがあります。

  1. SQLite

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

  2. XML

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


5

このタイプのシステムでフラットファイルデータベースの潜在的な問題を指摘するだけです。

data|some text|more data

row 2 data|bla hbalh|more data

...等

問題は、セルデータに「|」が含まれていることです。または「\ n」の場合、データは失われます。ほとんどの人が使用しない文字の組み合わせで分割する方が簡単な場合があります。

例えば:

列スプリッター: #$% (Shift+345)

行スプリッター: ^&* (Shift+678)

テキストファイル: test data#$%blah blah#$%^&*new row#$%new row data 2

次に使用します: explode("#$%", $data); use foreach, the explode again to separate columns

またはこれらの線に沿って何か。また、フラットファイルデータベースは少量のデータ(つまり、20行未満)のシステムには適していますが、大規模なデータベースでは巨大なメモリを消費します。


良い点。これをさらに一歩進めると、PHPはJSONを非常に簡単にシリアライズできます。入力のエスケープははるかに簡単なので、面白い文字列の組み合わせを使用する必要がなく、ファイルが読みやすくなります。
Cypher、2014
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.