平面文件数据库
在PHP中创建平面文件数据库结构的最佳实践是什么?
我看到了许多更成熟的PHP平面文件框架,它们尝试实现类似SQL的查询语法,在大多数情况下,对于我而言,这是最重要的(此时我只会使用数据库)。
是否有任何优雅的技巧可以在不增加代码开销的情况下获得良好的性能和功能?
解决方案:
我正在考虑的一个框架是博客平台。由于我们想要的几乎所有数据视图都将按日期排序,因此我在考虑以下结构:
每个内容节点一个目录:
./content/YYYYMMDDHHMMSS/
每个节点的子目录包括
/tags /authors /comments
以及节点目录中用于预渲染和后渲染内容等的简单文本文件。
这将允许一个简单的PHPglob()
调用(可能会反转结果数组)来查询内容结构中的几乎所有内容:
glob("content/*/tags/funny");
将返回路径,包括所有标记为"有趣"的文章。
确实如此。 serialize()也可以非常有用。
我认为,提出一个可行的系统的诀窍是找到某种方法来索引数据节点,而又不致于因复杂性而丧命。
好吧,平面数据库的本质是什么。他们是大还是小。它是其中包含数组的简单数组吗?如果很简单,则说用户配置文件是这样构建的:
$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)); }
但是同样,此实现也会因我们需要的数据库的应用程序和性质而异。
我们可能会考虑使用SQLite。它几乎与平面文件一样简单,但是我们确实获得了用于查询的SQL引擎。它也适用于PHP。
如果要使用平面文件来保存数据,请使用XML来结构化数据。 PHP具有内置的XML解析器。
如果我们希望获得人类可读的结果,也可以使用以下类型的文件:
ofaurax|27|male|something| another|24|unknown|| ...
这样,我们只有一个文件,可以轻松调试(和手动修复),以后可以添加字段(在每一行的末尾),PHP代码很简单(每一行,根据|拆分)。
但是,缺点是我们应该解析整个文件以搜索某些内容(如果我们有数百万个条目,那就不行了),并且应该处理数据中的分隔符(例如,如果昵称是WaR | ordz)。
我认为,在某种意义上使用"平面文件数据库"(以及我们已经接受的答案)不一定是解决问题的最佳方法。首先,如果有人进入并编辑文件,使用serialize()
和unserialize()
可能会引起严重的麻烦(实际上,他们可以在每次运行的"数据库"中放入任意代码)。
我个人会说为什么不展望未来?因为我一直在创建自己的"专有"文件,所以出现了很多次问题,并且该项目已经发展到需要数据库的地步,我在想"我们知道,我希望我将其编写为数据库的开头",因为代码的重构会花费大量的时间和精力。
从中我了解到,将来可以对我的应用程序进行验证,这样,当它变得更大时,我就不必花几天的时间进行重构了。我该怎么做呢?
SQLite。它可以作为数据库使用SQL,并且很容易转换为mySQL(特别是如果我们像我一样使用抽象类进行数据库操作!)
实际上,尤其是使用"可接受答案"的方法,它可以大大减少应用程序的内存使用(我们不必将所有" RECORDS"都加载到PHP中)
这是我们用于Lilina的代码:
<?php /** * Handler for persistent data files * * @author Ryan McCue <[email protected]> * @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); } } ?>
它将每个条目存储为一个单独的文件,我们发现该文件足够有效地使用(无需加载不需要的数据,并且保存起来更快)。