平面文件数据库
在PHP中创build平面文件数据库结构的最佳做法是什么? 我看到的很多更成熟的PHP平面文件框架试图实现类似于SQL的查询语法,在大多数情况下(我只是使用数据库)在顶端。
是否有任何优雅的技巧,以获得良好的性能和function与小代码的开销,首先要承担这个问题?
那么,平面数据库的性质是什么? 他们是大还是小? 它是简单的数组与arrays在他们? 如果它简单的说userprofilesbuild立如此:
$user = array("name" => "dubayou", "age" => 20, "websites" => array("dubayou.com","willwharton.com","codecream.com"), "and_one" => "more");
并保存或更新该用户的数据库logging 。
$dir = "../userdata/"; //make sure to put it bellow what the server can reach. file_put_contents($dir.$user['name'],serialize($user));
并为用户加载logging
function &get_user($name){ return unserialize(file_get_contents("../userdata/".$name)); }
但是这个实现又会根据你所需要的数据库的应用和性质而有所不同。
你可能会考虑SQLite 。 它几乎和平面文件一样简单,但是你得到一个用于查询的SQL引擎。 它也适用于PHP 。
在我看来,使用“平面文件数据库”这个意义上的意义(以及你所接受的答案)并不是事物发展的最好方式。 首先,如果有人进入并编辑文件,使用serialize()
和unserialize()
会导致MAJOR头痛(事实上,他们可以在你的“数据库”中放入任意代码,以便每次运行)。
就个人而言,我会说 – 为什么不看向未来? 曾经有过很多次我遇到过问题,因为我一直在创build自己的“专有”文件,项目已经爆炸到需要数据库的地步,我想“你知道,我希望我写这个数据库开始“ – 因为代码的重构花费了太多的时间和精力。
从这里我已经了解到,我的应用程序的未来certificate,以便当它变得更大时,我不必去,花费时间重构是前进的方式。 我该怎么做呢?
SQLite的。 它作为一个数据库,使用SQL,很容易转换到MySQL(特别是如果你像我一样使用抽象类进行数据库操作!)
事实上,特别是“接受的答案”的方法,它可以大大减less您的应用程序的内存使用情况(您不必将所有“logging”加载到PHP中)
确实如此。 serialize()
可以是非常有用的。
我想提出一个可行的系统的诀窍是find一些方法来索引数据节点,而不会让复杂性变得复杂。
我正在考虑的一个框架将用于博客平台。 由于几乎任何可能的数据视图,你会希望按datesorting,我想这个结构:
每个内容节点一个目录:
./content/YYYYMMDDHHMMSS/
每个节点的子目录包括
/tags /authors /comments
以及节点目录中的简单文本文件,用于预渲染内容和后渲染内容等。
这将允许一个简单的PHP glob()
调用(可能是结果数组的反转)来查询内容结构中的任何内容:
glob("content/*/tags/funny");
会返回path,包括所有标记为“有趣”的文章。
以下是我们用于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); } } ?>
它将每个条目存储为一个单独的文件,我们发现它是足够高效的(不需要加载不必要的数据,而且保存起来更快)。
如果您打算使用平面文件来保存数据,请使用XML来构造数据。 PHP有一个内置的XMLparsing器 。
我已经写了两个简单的函数来devise将数据存储在一个文件中。 你可以自己判断在这种情况下是否有用。 重点是保存一个PHPvariables(如果它是一个数组string或一个对象)到一个文件。
<?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; }
如果你想要一个可读的结果,你也可以使用这种types的文件:
ofaurax|27|male|something| another|24|unknown|| ...
这样,你只有一个文件,你可以很容易地debugging(和手动修复),你可以稍后(在每行的末尾)添加字段,PHP代码很简单(对于每一行,根据|分割)。
然而,缺点是你应该parsing整个文件来search一些东西(如果你有几百万条logging,那就不好),你应该在数据中处理分隔符(例如,如果缺口是WaR | ordz)。
这一个鼓舞人心的实际解决scheme:
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
恕我直言,你有两个select,如果你想避免homebrewing的东西:
-
SQLite的
如果您熟悉PDO,则可以安装支持SQLite的PDO驱动程序。 从来没有使用它,但我已经使用PDO吨与MySQL。 我打算在现在的项目上给这个镜头一个镜头。
-
XML
做了这么多次相对less量的数据。 XMLReader是一个轻量级的,向前读取的游标式类。 SimpleXML使得将XML文档读入一个可以像其他任何类实例一样访问的对象变得非常简单。
只要指出一个平面文件数据库与这种types的系统的潜在问题:
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
explode("#$%", $data); use foreach, the explode again to separate columns
或者沿着这些线路。 此外,我还可以补充说,平面文件数据库对于有less量数据(即less于20行)的系统是有好处的,但是对于大型数据库却成了巨大的内存消耗。