Каковы наилучшие методы создания плоских структур баз данных файлов в PHP? Многие из более зрелых фреймворков фрейма PHP, которые я вижу там, пытаются реализовать синтаксис SQL-подобных запросов, который в большинстве случаев находится в верхней части моих целей (я бы просто использовал базу данных в этой точке).
Есть ли какие-нибудь элегантные трюки, чтобы получить хорошую производительность и функции с небольшим накладным кодом, который можно было бы решить, взяв на себя эту проблему в первую очередь?
Ну, какова природа плоских баз данных. Они большие или маленькие. Это простые массивы с массивами в них? если его что-то просто сказать userprofiles, построенный как таковой:
$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)); }
но опять же эта реализация будет зависеть от приложения и характера требуемой базы данных.
Вы можете рассмотреть SQLite . Это почти так же просто, как плоские файлы, но вы получаете SQL-запрос для запросов. Это хорошо работает и с PHP .
По-моему, использование «базы данных с плоским файлом» в том смысле, в котором вы имеете значение (и ответ, который вы приняли), не обязательно является лучшим способом для решения любых задач. Прежде всего, использование serialize()
и unserialize()
может привести к головным болям MAJOR, если кто-то получит и отредактирует файл (они могут, по сути, поместить произвольный код в вашу «базу данных» каждый раз).
Лично я бы сказал – почему бы не смотреть в будущее? Было так много раз, что у меня были проблемы, потому что я создавал свои собственные «проприетарные» файлы, и проект взорвался до такой степени, что ему нужна база данных, и я думаю: «Знаешь, я хочу Я написал это для базы данных, чтобы начать с "- потому что рефакторинг кода занимает слишком много времени и сил.
Из этого я узнал, что будущая проверка моего приложения так, что, когда он станет больше, мне не нужно идти и тратить дни, когда рефакторинг – это способ продвижения вперед. Как мне это сделать?
SQLite. Он работает как база данных, использует SQL, и довольно легко перейти на mySQL (особенно если вы используете абстрактные классы для манипуляций с базами данных, как я!)
Фактически, особенно с помощью метода «принятого ответа», он может резко сократить использование памяти вашего приложения (вам не нужно загружать все «RECORDS» в PHP)
Это правда. serialize()
может быть очень полезен для этого.
Я думаю, что трюк придумать жизнеспособную систему – это найти способ индексирования узлов данных, не убивая себя сложностью.
Одна структура, которую я рассматриваю, будет для платформы для ведения блога. Поскольку практически любой возможный вид данных, которые вы хотели бы отсортировать по дате, я думал об этой структуре:
Один каталог для узла контента:
./content/YYYYMMDDHHMMSS/
Подкаталоги каждого узла, включая
/tags /authors /comments
А также простые текстовые файлы в каталоге узлов для содержимого до и после визуализации и т. П.
Это позволит простому вызову PHP glob()
(и, вероятно, изменению массива результатов) запросить практически что-либо в структуре контента:
glob("content/*/tags/funny");
Будет возвращать пути, включая все статьи, помеченные как «смешные».
Вот код, который мы используем для Лилины:
<?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 имеет встроенный синтаксический анализатор XML .
Я написал две простые функции, предназначенные для хранения данных в файле. Вы можете судить сами, если это полезно в этом случае. Дело в том, чтобы сохранить в файл переменную 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; }
Если вы хотите получить читаемый человеком результат, вы также можете использовать этот тип файла:
ofaurax|27|male|something| another|24|unknown|| ...
-ofaurax|27|male|something| another|24|unknown|| ...
Таким образом, у вас есть только один файл, вы можете легко его отлаживать (и вручную исправлять), вы можете добавлять поля позже (в конце каждой строки), а PHP-код прост (для каждой строки разбивается по |).
Однако недостатки в том, что вы должны разобрать весь файл для поиска чего-либо (если у вас миллионы записей, это не так), и вы должны обрабатывать разделитель в данных (например, если ник является WaR | ordz).
Это вдохновляет как практическое решение:
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
ИМХО, у вас есть два варианта, если вы хотите избежать того, чтобы что-то делать:
SQLite
Если вы знакомы с PDO, вы можете установить драйвер PDO, поддерживающий SQLite. Никогда не использовал его, но я использовал PDO тонну с MySQL. Я собираюсь сделать это в текущем проекте.
XML
Это сделано много раз для относительно небольших объемов данных. XMLReader – это легкий, читаемый, курсорный стиль. SimpleXML упрощает чтение XML-документа в объект, к которому вы можете получить доступ, как и любой другой экземпляр класса.
Просто указывая на потенциальную проблему с плоской файловой базой данных с этим типом системы:
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
Или что-то в этом роде. Кроме того, я могу добавить, что плоские файловые базы данных хороши для систем с небольшим объемом данных (т. Е. Менее 20 строк), но становятся огромными ящиками памяти для больших баз данных.