Flatfile-Datenbanken [geschlossen]

120

Was sind die Best Practices zum Erstellen von Flatfile-Datenbankstrukturen in PHP?

Es gibt viele ausgereiftere PHP-Flatfile-Frameworks, bei denen ich versuche, eine SQL-ähnliche Abfragesyntax zu implementieren, die für meine Zwecke in den meisten Fällen übertrieben ist. (Ich würde zu diesem Zeitpunkt nur eine Datenbank verwenden).

Gibt es irgendwelche eleganten Tricks, um eine gute Leistung und Funktionen mit einem kleinen Code-Overhead zu erzielen?

saint_groceon
quelle
1
Ich möchte hinzufügen, dass es hier ein Paket für die Flat File-Datenbank gibt. Github.com/tmarois/Filebase Ich weiß, dass dies eine alte Frage ist, aber dieses Paket ist das neueste Build und wird gewartet und enthält viele Funktionen, die am meisten vernachlässigt werden .
Tmarois
Ich entwickle ein CMS und verwende eine flache Textdatei-Textdatenbank. Die Herstellung dauert viele Stunden und die Brechung viele Stunden, aber es funktioniert perfekt. Abfragen werden mit einer vollständig indizierten und optimierten Datenbank viel schneller ausgeführt. Ich vermeide jedoch die Notwendigkeit von Abfragen, indem ich Metadaten speichere und sorgfältig organisiere und strukturiere. Wenn ich Daten benötige, erhalte ich diese ohne for loop(es sei denn, ich verwende alle Daten im Ordner), daher ist die Leistung viel schneller als bei einer Datenbank. Ich würde ins Detail gehen und eine sehr gute Antwort geben, aber leider ist diese Frage geschlossen.
Dan Bray

Antworten:

75

Nun, was ist die Natur der flachen Datenbanken. Sind sie groß oder klein? Sind es einfache Arrays mit Arrays? Wenn es etwas Einfaches ist, sagen Sie, dass Benutzerprofile als solche erstellt wurden:

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

und um den Datenbankdatensatz für diesen Benutzer zu speichern oder zu aktualisieren .

$dir = "../userdata/";  //make sure to put it bellow what the server can reach.
file_put_contents($dir.$user['name'],serialize($user));

und um den Datensatz für den Benutzer zu laden

function &get_user($name){
    return unserialize(file_get_contents("../userdata/".$name));
}

Diese Implementierung hängt jedoch wiederum von der Anwendung und der Art der benötigten Datenbank ab.

w-ll
quelle
48

Sie könnten SQLite in Betracht ziehen . Es ist fast so einfach wie Flatfiles, aber Sie erhalten eine SQL-Engine zum Abfragen. Es funktioniert auch gut mit PHP .

Yukondude
quelle
6
SQLite wurde standardmäßig in 5.0+ integriert, aber ab PHP 5.4+ nicht mehr (!) Abgesetzt !!! Während ich dies im Juli 2012 schreibe, funktioniert SQLite standardmäßig nicht mehr auf aktuellen Systemen. Offizielle Erklärung hier
Sliq
Die Installation des SQLite PDO-Treibers ist ziemlich trivial, wenn Sie Serverzugriff haben. Unter Ubuntu / Debian, auf dem Apache2 ausgeführt wird, muss nur der php5-sqlite-Dienst apache2 neu
gestartet werden
4
Als Reaktion auf den Kommentar von @Sliq ist die Aussage, dass "SQLite ... eingestellt wurde", sozusagen wahr: Die Erweiterung mit dem Namen "SQLite" wurde eingestellt und "SQLite3" ist jetzt standardmäßig aktiviert. php.net/manual/en/sqlite.installation.php "Seit PHP 5.0 wurde diese Erweiterung mit PHP gebündelt. Ab PHP 5.4 ist diese Erweiterung nur über PECL verfügbar." php.net/manual/en/sqlite3.installation.php "Die SQLite3-Erweiterung ist ab PHP 5.3.0 standardmäßig aktiviert." "Diese Erweiterung war kurz eine PECL-Erweiterung, aber diese Version wird nur für experimentelle Zwecke empfohlen."
Paul van Leeuwen
Sie haben die Frage nicht beantwortet
JG Estiot
20

Meiner Meinung nach ist die Verwendung einer "Flat File Database" in dem Sinne, wie Sie es meinen (und die Antwort, die Sie akzeptiert haben), nicht unbedingt der beste Weg, um Dinge zu erledigen. Zuallererst kann die Verwendung von serialize()und unserialize()kann MAJOR Kopfschmerzen verursachen, wenn jemand in die Datei eindringt und sie bearbeitet (er kann tatsächlich jedes Mal willkürlichen Code in Ihre "Datenbank" einfügen, der ausgeführt wird.)

Persönlich würde ich sagen - warum nicht in die Zukunft schauen? Es gab so viele Male, dass ich Probleme hatte, weil ich meine eigenen "proprietären" Dateien erstellt habe und das Projekt so weit explodiert ist, dass es eine Datenbank benötigt, und ich denke "Sie wissen, ich wünschte Ich hatte dies für eine Datenbank geschrieben, um mit "zu beginnen - weil das Refactoring des Codes viel zu viel Zeit und Mühe kostet.

Daraus habe ich gelernt, dass die Zukunftssicherung meiner Anwendung, damit sie nicht tagelang umgestaltet werden muss, wenn sie größer wird, der Weg in die Zukunft ist. Wie mache ich das?

SQLite. Es funktioniert als Datenbank, verwendet SQL und ist ziemlich einfach auf mySQL umzustellen (insbesondere, wenn Sie abstrahierte Klassen für die Datenbankmanipulation verwenden, wie ich es tue!).

Insbesondere mit der Methode "Akzeptierte Antwort" kann die Speichernutzung Ihrer App drastisch reduziert werden (Sie müssen nicht alle "RECORDS" in PHP laden).

Mez
quelle
Das ist richtig. serialize()kann auch dafür ziemlich nützlich sein. Ich denke, der Trick, um ein funktionsfähiges System zu entwickeln, besteht darin, einen Weg zu finden, die Datenknoten zu indizieren, ohne sich selbst mit Komplexität zu töten.
Saint_groceon
12

Ein Framework, das ich in Betracht ziehe, wäre eine Blogging-Plattform. Da fast jede mögliche Ansicht von Daten, die Sie möchten, nach Datum sortiert wäre, habe ich über diese Struktur nachgedacht:

Ein Verzeichnis pro Inhaltsknoten:

./content/YYYYMMDDHHMMSS/

Unterverzeichnisse jedes Knotens einschließlich

/tags  
/authors  
/comments  

Sowie einfache Textdateien im Knotenverzeichnis für vor- und nachgerenderte Inhalte und dergleichen.

Dies würde es einem einfachen PHP- glob()Aufruf (und wahrscheinlich einer Umkehrung des Ergebnisarrays) ermöglichen, nahezu alles innerhalb der Inhaltsstruktur abzufragen:

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

Würde Pfade zurückgeben, einschließlich aller Artikel, die mit "lustig" markiert sind.

saint_groceon
quelle
9

Hier ist der Code, den wir für Lilina verwenden:

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

?>

Jeder Eintrag wird als separate Datei gespeichert, die für die Verwendung effizient genug ist (es werden keine nicht benötigten Daten geladen und das Speichern ist schneller).

Ryan McCue
quelle
8

Wenn Sie eine flache Datei verwenden, um Daten zu speichern, verwenden Sie XML, um die Daten zu strukturieren. PHP verfügt über einen integrierten XML-Parser .

Jason
quelle
Befolgen Sie die XML-Regeln für die Lesbarkeit, oder verwenden Sie Serialisierung oder JSON oder ähnliches.
Ben
Sehr schlechter Rat. XML sollte niemals verwendet werden. Es ist eine fette Aberration.
JG Estiot
@ JGEstiot Möchtest du es weiter erklären?
UncaughtTypeError
7

Wenn Sie ein für Menschen lesbares Ergebnis wünschen, können Sie auch diesen Dateityp verwenden:

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

Auf diese Weise haben Sie nur eine Datei, können diese leicht debuggen (und manuell reparieren), später (am Ende jeder Zeile) Felder hinzufügen und der PHP-Code ist einfach (für jede Zeile entsprechend | aufgeteilt).

Der Nachteil ist jedoch, dass Sie die gesamte Datei analysieren sollten, um etwas zu durchsuchen (wenn Sie Millionen von Einträgen haben, ist dies nicht in Ordnung) und das Trennzeichen in Daten behandeln sollten (z. B. wenn der Nick WaR | ordz ist).

ofaurax
quelle
7

Ich habe zwei einfache Funktionen geschrieben, um Daten in einer Datei zu speichern. Sie können selbst beurteilen, ob dies in diesem Fall nützlich ist. Der Punkt ist, eine PHP-Variable (wenn es sich entweder um ein Array, eine Zeichenfolge oder ein Objekt handelt) in einer Datei zu speichern.

<?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;
}
jpcrevoisier
quelle
Ich fand das interessant und dies ist der BESSERE Weg, weil wir das formatierte Array einfach in eine Datei kopieren. Wir müssen es nicht erneut erstellen, sondern nur einlesen. Das Bearbeiten von Variablen ist ebenfalls etwas einfach. Ich werde das nie zum Speichern großer Datenmengen verwenden, aber ich fand es praktisch, Programmmodule ohne Datenbank zu speichern. Danke dir.
m3nda
7

Dieser ist als praktische Lösung inspirierend:
https://github.com/mhgolkar/FlatFire
Es werden mehrere Strategien zum Umgang mit Daten verwendet ...
[Aus Readme-Datei kopiert]

Frei oder strukturiert oder gemischt

- 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
Omran
quelle
7

IMHO, Sie haben zwei Möglichkeiten, wenn Sie vermeiden möchten, etwas selbst zu brauen:

  1. SQLite

    Wenn Sie mit PDO vertraut sind, können Sie einen PDO-Treiber installieren, der SQLite unterstützt. Ich habe es nie benutzt, aber ich habe PDO eine Tonne mit MySQL benutzt. Ich werde dies bei einem aktuellen Projekt ausprobieren.

  2. XML

    Dies wurde für relativ kleine Datenmengen mehrmals durchgeführt. XMLReader ist eine leichte, vorwärtsgelesene Klasse im Cursor-Stil. SimpleXML macht es einfach, ein XML-Dokument in ein Objekt einzulesen, auf das Sie wie auf jede andere Klasseninstanz zugreifen können.

Siliconrockstar
quelle
5

Ich möchte nur auf ein potenzielles Problem mit einer Flatfile-Datenbank mit diesem Systemtyp hinweisen:

data|some text|more data

row 2 data|bla hbalh|more data

...etc

Das Problem ist, dass die Zellendaten ein "|" oder ein "\ n", dann gehen die Daten verloren. Manchmal ist es einfacher, durch Buchstabenkombinationen zu teilen, die die meisten Menschen nicht verwenden würden.

Beispielsweise:

Säulensplitter: #$% (Shift+345)

Zeilensplitter: ^&* (Shift+678)

Textdatei: test data#$%blah blah#$%^&*new row#$%new row data 2

Dann benutze: explode("#$%", $data); use foreach, the explode again to separate columns

Oder irgendetwas in diese Richtung. Ich möchte auch hinzufügen, dass Flatfile-Datenbanken für Systeme mit kleinen Datenmengen (dh weniger als 20 Zeilen) gut sind, für größere Datenbanken jedoch zu großen Speicherfressern werden.

Michael Burt
quelle
Gute Argumente. PHP geht noch einen Schritt weiter und kann JSON sehr einfach serialisieren. Das Escaping von Eingaben ist viel einfacher, sodass Sie keine lustigen Zeichenfolgenkombinationen verwenden müssen, damit die Datei besser lesbar ist.
Cypher