平面文件数据库[关闭]


120

在PHP中创建平面文件数据库结构的最佳实践是什么?

许多更成熟的PHP平面文件框架在那里,我尝试实现类似SQL的查询语法,在大多数情况下,对于我而言,这是最重要的。(那时我只会使用数据库)。

是否有任何优雅的技巧可以在不增加代码开销的情况下获得良好的性能和功能?


1
我想补充一点,这里有一个用于平面文件数据库 的程序包github.com/tmarois/Filebase我知道这是一个老问题,但是此程序包是最新的构建和维护程序,并且具有许多功能,这些功能是大多数人忽略的,包括。
tmarois

我正在开发CMS,并且使用平面文本文件文本数据库。制造需要花费许多时间,并且要花费很多时间才能使其破裂,但是效果很好。使用完全索引和优化的数据库,查询将更快地执行。但是,我通过存储元数据以及精心组织和结构来避免查询。当我需要数据时,我不需要它for loop(除非我正在使用文件夹中的所有数据),因此它的执行速度比数据库快得多。我会详细介绍并给出一个很好的答案,但不幸的是,这个问题已经结束。
丹·布雷

Answers:


75

好吧,平面数据库的本质是什么。他们是大还是小。它是其中包含数组的简单数组吗?如果很简单,则说用户配置文件是这样构建的:

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

并保存或更新该用户的数据库记录

$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将不再在最新系统上运行。官方声明在这里
Sliq

如果您具有服务器访问权限,则安装SQLite PDO驱动程序非常简单。在运行Apache2的Ubuntu / Debian上,只需执行apt-get install php5-sqlite服务apache2 restart
Siliconrockstar,2012年

4
在回应@Sliq的评论时,指出“ SQLite已...已终止”是正确的:名为“ SQLite”的扩展名已终止,并且默认情况下已启用“ SQLite3”。 php.net/manual/en/sqlite.installation.php “自PHP 5.0起,此扩展与PHP捆绑在一起。从PHP 5.4开始,此扩展仅可通过PECL使用。” php.net/manual/en/sqlite3.installation.php “默认情况下,从PHP 5.3.0开始,SQLite3扩展已启用。” “此扩展只是PECL扩展,但仅建议将该版本用于实验用途。”
Paul van Leeuwen

你没有回答这个问题
JG Estiot

20

以我的观点,在某种意义上使用“平面文件数据库”(以及您已经接受的答案)不一定是解决问题的最佳方法。首先,如果有人进入并编辑文件,使用serialize()unserialize()可能会引起重大的麻烦(实际上,他们可以在每次运行的“数据库”中放入任意代码)。

我个人会说-为什么不展望未来?因为我一直在创建自己的“专有”文件,所以出现了很多次问题,并且该项目已经发展到需要数据库的地步,我在想“您知道,我希望我将其写成数据库的开头”,因为代码的重构花费了太多的时间和精力。

由此我了解到,将来可以对我的应用程序进行验证,这样,当应用程序变得更大时,我就不必花很多时间进行重构。我该怎么做呢?

SQLite。它可以作为数据库使用SQL,并且很容易转换为mySQL(特别是如果您像我一样使用抽象类进行数据库操作!)

实际上,尤其是使用“可接受的答案”的方法,它可以大大减少应用程序的内存使用(您不必将所有“ RECORDS”都加载到PHP中)


确实如此。serialize()对此也非常有用。我认为,提出一个可行的系统的诀窍是找到某种方法来索引数据节点,而又不致于因复杂性而丧命。
saint_groceon

12

我正在考虑的一个框架是博客平台。由于您想要的几乎所有数据视图都将按日期排序,因此我在考虑以下结构:

每个内容节点一个目录:

./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之类的东西。
2016年

非常糟糕的建议。不应该使用XML。这是一个肥胖的畸变。
JG Estiot

@JGEstiot Care进一步解释吗?
UncaughtTypeError

7

如果您希望获得人类可读的结果,也可以使用以下类型的文件:

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

这样,您只有一个文件,可以轻松调试(和手动修复),以后可以添加字段(在每一行的末尾),PHP代码很简单(每一行,根据|拆分)。

但是,缺点是您应该解析整个文件以搜索某些内容(如果您有数百万个条目,那就不行了),并且应该处理数据中的分隔符(例如,如果昵称是WaR | ordz)。


7

我编写了两个简单的函数,旨在将数据存储在文件中。您可以自己判断这种情况是否有用。关键是将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

7

这是一个令人鼓舞的实用解决方案:
https : //github.com/mhgolkar/FlatFire
它使用多种策略来处理数据...
[从自述文件复制]

自由或结构化或混合

- 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

恕我直言,如果您想避免自制东西,您有两种选择:

  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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.