Frage

Was sind die best practices rund um die Erstellung von flat-file-Datenbank-Strukturen in PHP?

Viele der reiferen PHP-flat-file-frameworks sehe ich da draußen versuchen zu implementieren SQL-like query syntax, die über der Oberseite für meine Zwecke in den meisten Fällen (ich möchte nur eine Datenbank verwenden, die an diesem Punkt).

Gibt es irgendwelche elegante tricks gibt, um eine gute Leistung und features, mit einem kleinen code-overhead?

War es hilfreich?

Lösung

Gut, was ist die Natur der flache Datenbanken.Sind Sie groß oder klein.Ist es einfache arrays mit arrays in Ihnen?wenn Ihr etwas einfaches sagen userprofiles gebaut als solche:

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

und speichern oder aktualisieren Sie die db-Datensatz für diesen Benutzer.

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

und zum laden der Datensatz für den Benutzer

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

aber wieder diese Umsetzung wird je nach Anwendung und Art der Datenbank, die Sie brauchen.

Andere Tipps

Sie überlegen, SQLite.Es ist fast so einfach wie das flat-Dateien, aber Sie erhalten eine SQL-engine, die zum Abfragen.Es funktioniert gut mit PHP zu.

Meiner Meinung nach, mit einer "Flat-File-Datenbank" im Sinne von " du bist der Sinn (und die Antwort, die Sie angenommen haben) ist nicht neccesarily der beste Weg zu gehen über die Dinge.Erste von alle, mit serialize() und unserialize() können GROßE Kopfschmerzen verursachen, wenn jemand steigt ein und bearbeitet die Datei (Sie können in der Tat stellen arbritrary code in Ihre "Datenbank" werden jedes mal ausgeführt.)

Persönlich, würde ich sagen - warum nicht in die Zukunft schauen?Es gab so viele Male, dass ich habe Probleme, weil ich habe meine eigene "eigene Dateien" und hat das Projekt explodiert zu einem Punkt, wo es benötigt eine Datenbank, und ich denken, "wissen Sie, ich wünschte, ich hätte dies geschrieben für eine Datenbank zu starten, die mit" - weil das refactoring des Codes dauert viel zu viel Zeit und Mühe.

Aus diesem habe ich gelernt, dass die Zukunft proofing meine Anwendung so, dass, wenn es wird größer, ich nicht haben, zu gehen und verbringen Tage refactoring ist der Weg, vorwärts zu gehen.Wie mache ich das?

SQLite.Es funktioniert wie eine Datenbank, mit SQL und ist ziemlich leicht zu wechseln, um mySQL (insbesondere wenn Sie mit abstrahierten Klassen für Datenbank-manipulation wie ich es machen!)

In der Tat, insbesondere die mit "akzeptierte Antwort"'s Methode ist, können Sie drastisch schneiden Sie die Speichernutzung der app (Sie müssen nicht zum laden der "AUFZEICHNUNGEN" in PHP)

Einen Rahmen, den ich überlege mir, wäre für eine blogging-Plattform.Da gerade über jeden möglichen Blick auf die Daten, die Sie würde wollen, würde nach Datum sortiert, dachte ich über diese Struktur:

Ein Verzeichnis pro Knoten Inhalt:

./content/YYYYMMDDHHMMSS/

Unterverzeichnisse der einzelnen Knoten einschließlich

/tags  
/authors  
/comments  

Auch als einfache Textdateien im Knoten-Verzeichnis für pre - und post-gerenderten Inhalt und die wie.

Dies würde es erlauben, eine einfache PHP glob() rufen Sie (und wahrscheinlich eine Umkehrung von dem Ergebnis-array), um die Abfrage auf nur über alles, was innerhalb der content-Struktur:

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

Würde return-Wege-einschließlich aller Artikel mit den Tags "lustig".

Hier ist der code, den wir verwenden für 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);
    }
}

?>

Es speichert jeden Eintrag eine eigene Datei, die wir gefunden haben, ist effizient genug für die Verwendung (keine nicht mehr benötigte Daten geladen wird und es schneller zu sparen).

Wenn Sie verwenden eine flache Datei zum speichern von Daten, verwenden die XML-Struktur der Daten.PHP hat eine built-in XML-parser.

Ich geschrieben habe zwei einfache Funktionen zum speichern von Daten in einer Datei.Sie können für sich selbst beurteilen, wenn es in diesem Falle sinnvoll.Der Punkt ist das speichern einer php-variable (wenn es entweder ein array ein string oder ein Objekt) in eine Datei.

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

Wenn Sie möchten, eine für den Menschen lesbare Ergebnis, Sie können auch verwenden diese Art von Datei :

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

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

Allerdings sind die Nachteile ist, dass Sie sollten Parsen der gesamten Datei suchen etwas (wenn Sie Millionen von Eintrag, es ist nicht in Ordnung), und Sie sollte behandeln Sie das Trennzeichen in den Daten (für Beispiel, wenn der nick ist Krieg|ordz).

Dieser ist inspirierend, wie eine praktische Lösung:
https://github.com/mhgolkar/FlatFire
Es verwendet mehrere Strategien zum Umgang mit Daten...
[Kopiert aus der Readme-Datei]

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

IMHO, Sie haben zwei Möglichkeiten, wenn Sie möchten, um zu vermeiden, Selbstbau etwas:

  1. SQLite

    Wenn Sie vertraut sind mit PDO, können Sie eine PDO-Treiber, die Unterstützung für SQLite.Es nie benutzt, aber ich habe verwendet PDO eine Tonne mit MySQL.Ich werde ihm eine Chance geben auf ein Aktuelles Projekt.

  2. XML

    Das oft getan für relativ kleine Mengen von Daten. XMLReader ist ein leichtes, Lesen, vorwärts, cursor-Stil-Klasse. SimpleXML macht es einfach zu Lesen ein XML-Dokument in ein Objekt, das Sie zugreifen können, genau wie jede andere Klasse Instanz.

Nur darauf hin ein potenzielles problem mit einem flat-file-Datenbank, die mit dieser Art von system:

data|some text|more data

row 2 data|bla hbalh|more data

...etc

Das problem ist, dass die Zelle, die Daten enthält, die ein "|" oder " ", dann sind die Daten verloren.Manchmal, es wäre einfacher, geteilt durch Kombinationen von Buchstaben, die die meisten Menschen nicht.

Zum Beispiel:

Spalte splitter: #$% (Shift+345)

Zeile splitter: ^&* (Shift+678)

Text-Datei: test data#$%blah blah#$%^&*new row#$%new row data 2

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

Oder etwas entlang dieser Linien.Auch, möchte ich hinzufügen, dass die flat-file-Datenbanken sind gut für Systeme mit geringen Mengen von Daten (dh.weniger als 20 Zeilen), aber große Speicherfresser für größere Datenbanken.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top