Базы данных плоских файлов [закрыто]

Каковы лучшие практики создания структур баз данных с плоскими файлами в PHP?

Существует множество более зрелых платформ плоских файлов PHP, в которых я пытаюсь реализовать синтаксис SQL-подобных запросов, который в большинстве случаев является чрезмерным для моих целей. (Я бы просто использовал базу данных на этом этапе).

Есть ли какие-нибудь изящные приемы, чтобы получить хорошую производительность и функциональность с небольшим объемом кода?

1.08.2008 14:19:52
Я хотел бы добавить, что здесь есть пакет для базы данных плоских файлов github.com/tmarois/Filebase. Я знаю, что это старый вопрос, но этот пакет является самой последней сборкой и поддержкой, а также полным набором функций, которые в большинстве случаев не учитываются. ,
timothymarois 6.09.2017 13:24:26
Я занимаюсь разработкой CMS и использую текстовую базу данных с текстовыми файлами. Это заняло много часов и много часов, чтобы разобраться, но это работает отлично. Запросы будут выполняться намного быстрее с полностью проиндексированной и оптимизированной базой данных. Тем не менее, я избегаю необходимости запросов, сохраняя метаданные и тщательно продумывая организацию и структуру. Когда мне нужны данные, я получаю их без for loop(если только я не использую все данные в папке), поэтому они работают намного быстрее, чем база данных. Я бы подробно остановился и дал очень хороший ответ, но, к сожалению, этот вопрос закрыт.
Dan Bray 21.10.2018 17:01:58
11 ОТВЕТОВ
РЕШЕНИЕ

Хорошо, какова природа плоских баз данных. Они большие или маленькие. Это простые массивы с массивами в них? если это что-то простое, скажем, userprofiles построен так:

$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));
}

но, опять же, эта реализация будет зависеть от приложения и характера нужной вам базы данных.

75
14.10.2012 12:26:34

Вы могли бы рассмотреть SQLite . Это почти так же просто, как плоские файлы, но вы получаете SQL-движок для запросов. Это хорошо работает и с PHP .

48
8.08.2008 23:00:54
SQLite был встроен в 5.0+ по умолчанию, но со скидкой (!) Из PHP 5.4+ включен !!! Когда я пишу это в июле 2012 года, SQLite больше не будет работать в современных системах по умолчанию. Официальное заявление здесь
Sliq 26.07.2012 21:59:45
Установка драйвера SQLite PDO довольно проста, если у вас есть доступ к серверу. В Ubuntu / Debian под управлением Apache2 просто выполните apt-get install php5-sqlite service apache2 restart
siliconrockstar 2.12.2012 15:39:57
В ответ на комментарий @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 «Расширение SQLite3 включено по умолчанию с версии PHP 5.3.0». «Это расширение было кратко расширением PECL, но эта версия рекомендуется только для экспериментального использования».
Paul van Leeuwen 4.12.2016 20:25:50
Вы не ответили на вопрос
JG Estiot 18.07.2019 15:08:10

На мой взгляд, использование «базы данных плоских файлов» в том смысле, в каком вы имеете в виду (и ответ, который вы приняли), не обязательно является лучшим способом решения проблем. Прежде всего, использование serialize()и unserialize()может вызвать ОСНОВНЫЕ головные боли, если кто-то входит и редактирует файл (фактически, он может поместить произвольный код в вашу «базу данных» для запуска каждый раз.)

Лично я бы сказал - почему бы не заглянуть в будущее? Было так много раз, что у меня были проблемы, потому что я создавал свои собственные "проприетарные" файлы, и проект взорвался до такой степени, что ему нужна база данных, и я думаю: "Вы знаете, я бы хотел Я написал это для базы данных, чтобы начать с "- потому что рефакторинг кода занимает слишком много времени и усилий.

Из этого я узнал, что будущее приложение защищает мое приложение, поэтому, когда оно становится больше, мне не нужно тратить дни на рефакторинг, это путь вперед. Как мне это сделать?

SQLite. Он работает как база данных, использует SQL и довольно легко переключается на mySQL (особенно если вы используете абстрактные классы для манипулирования базой данных, как я!)

Фактически, особенно с помощью метода «принятого ответа», он может резко сократить использование памяти вашего приложения (вам не нужно загружать все «ЗАПИСИ» в PHP)

20
31.10.2012 13:23:52
Это правда. serialize()может быть довольно полезным для этого. Я думаю, что хитрость в создании жизнеспособной системы состоит в том, чтобы найти способ индексировать узлы данных, не убивая себя сложностью.
saint_groceon 1.08.2008 14:58:15

Одним из основ, который я рассматриваю, будет платформа для блогов. Так как практически любое возможное представление данных, которые вы хотели бы отсортировать по дате, я думал об этой структуре:

Один каталог на узел содержимого:

./content/YYYYMMDDHHMMSS/

Подкаталоги каждого узла, включая

/tags  
/authors  
/comments  

А также простые текстовые файлы в каталоге узла для содержимого до и после визуализации и тому подобное.

Это позволит простому glob()вызову PHP (и, возможно, обращению к массиву результатов) запросить что угодно в структуре содержимого:

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

Возвращает пути, включая все статьи, помеченные как «смешные».

12
24.08.2015 17:19:04

Вот код, который мы используем для 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);
    }
}

?>

Он сохраняет каждую запись в виде отдельного файла, который, по нашему мнению, достаточно эффективен для использования (ненужные данные не загружаются, и его быстрее сохранить).

9
3.05.2015 13:29:02

Если вы собираетесь использовать плоский файл для сохранения данных, используйте XML для структурирования данных. PHP имеет встроенный синтаксический анализатор XML .

8
28.10.2012 07:03:01
И следуйте правилам XML-удобочитаемости, иначе вы можете использовать сериализацию, JSON или что-то еще.
Ben 23.06.2016 07:10:40
Очень плохой совет. XML никогда не должен использоваться. Это жирная аберрация.
JG Estiot 18.07.2019 15:10:49
@JGEstiot Хотите объяснить дальше?
UncaughtTypeError 26.07.2019 13:27:00

Если вам нужен читабельный результат, вы также можете использовать этот тип файла:

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

Таким образом, у вас есть только один файл, вы можете легко отладить его (и исправить вручную), вы можете добавить поля позже (в конце каждой строки), и PHP-код прост (для каждой строки, разделить в соответствии с |).

Однако недостатком является то, что вы должны анализировать весь файл для поиска чего-либо (если у вас есть миллионы записей, это не хорошо), и вы должны обрабатывать разделитель в данных (например, если никнейм равен WaR | ordz).

7
18.09.2008 07:51:30

Я написал две простые функции, предназначенные для хранения данных в файле. Вы можете судить сами, полезно ли это в этом случае. Смысл в том, чтобы сохранить переменную 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;
}
7
19.12.2012 21:17:45
Я нашел это интересным, и это ЛУЧШИЙ способ, потому что мы просто записываем отформатированный массив в файл. Нам не нужно строить его снова, просто прочитайте. Кроме того, редактировать переменные немного проще. Я никогда не буду использовать это для хранения больших данных, но я нашел практичным хранить модули программы без базы данных. Спасибо.
m3nda 23.01.2015 23:08:25

Это вдохновляющее практическое решение:
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.05.2013 13:57:13

ИМХО, у вас есть два варианта, если вы хотите избежать домашнего приготовления чего-либо:

  1. SQLite

    Если вы знакомы с PDO, вы можете установить драйвер PDO, который поддерживает SQLite. Никогда не использовал его, но я использовал PDO тонну с MySQL. Я собираюсь дать этому шанс на текущий проект.

  2. XML

    Сделано это много раз для относительно небольших объемов данных. XMLReader - это легкий класс для чтения и пересылки в стиле курсора. SimpleXML упрощает чтение XML-документа в объект, к которому вы можете получить доступ, как и к любому другому экземпляру класса.

7
24.08.2015 17:50:22

Просто указываю на потенциальную проблему с базой данных плоских файлов в системе такого типа:

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 строк), но становятся огромными затратами памяти для больших баз данных.

5
4.01.2013 00:39:53
Хорошие моменты. Сделав еще один шаг, PHP может очень легко сериализовать JSON. Экранирование ввода намного проще, поэтому вам не нужно использовать забавные комбинации строк, чтобы файл был более читабельным.
Cypher 23.09.2014 17:17:20