Database file flat [chiuso]


120

Quali sono le migliori pratiche per creare strutture di database di file flat in PHP?

Ci sono molti framework di file flat PHP più maturi là fuori che cerco di implementare la sintassi di query simile a SQL che è sopra le righe per i miei scopi nella maggior parte dei casi. (A quel punto userei solo un database).

Esistono trucchi eleganti per ottenere buone prestazioni e funzionalità con un piccolo overhead di codice?


1
Vorrei aggiungere che qui c'è un pacchetto per il database di file flat github.com/tmarois/Filebase So che questa è una vecchia domanda, ma questo pacchetto è il più recente compilato e mantenuto, oltre a pieno di funzionalità che la maggior parte trascura di includere .
tmarois

Sto sviluppando un CMS e utilizzo un database di testo di file di testo piatto. Ci sono volute molte ore per fare e molte ore per rifrangere ma funziona perfettamente. Le query verranno eseguite molto più velocemente con un database completamente indicizzato e ottimizzato. Tuttavia, evito la necessità di query archiviando metadati e con un'attenta organizzazione e struttura. Quando ho bisogno di dati, li ottengo senza for loop(a meno che non stia usando tutti i dati nella cartella), quindi funziona molto più velocemente di un database. Vorrei entrare nei dettagli e dare una risposta molto buona ma purtroppo questa domanda è chiusa.
Dan Bray

Risposte:


75

Ebbene, qual è la natura dei database piatti. Sono grandi o piccoli. Sono semplici array con array al loro interno? se è qualcosa di semplice, dì userprofiles costruito come tale:

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

e per salvare o aggiornare il record db per quell'utente.

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

e per caricare il record per l'utente

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

ma ancora una volta questa implementazione varierà in base all'applicazione e alla natura del database necessario.


48

Potresti considerare SQLite . È semplice quasi quanto i file flat, ma ottieni un motore SQL per le query. E funziona bene con PHP troppo.


6
SQLite era integrato in 5.0+ per impostazione predefinita, ma scontato (!) Da PHP 5.4+ in poi !!! Mentre scrivo questo nel luglio 2012, SQLite non funzionerà più su sistemi aggiornati per impostazione predefinita. Comunicato ufficiale qui
Sliq

L'installazione del driver SQLite PDO è piuttosto banale se si dispone dell'accesso al server. Su Ubuntu / Debian che esegue Apache2 basta eseguire apt-get install php5-sqlite service apache2 restart
siliconrockstar

4
In reazione al commento di @Sliq, affermare che "SQLite è stato ... interrotto" è una specie di vero: l'estensione denominata "SQLite" è stata interrotta e "SQLite3" è ora abilitato per impostazione predefinita. php.net/manual/en/sqlite.installation.php "Poiché PHP 5.0 questa estensione è stata fornita in bundle con PHP. A partire da PHP 5.4, questa estensione è disponibile solo tramite PECL." php.net/manual/en/sqlite3.installation.php "L'estensione SQLite3 è abilitata per impostazione predefinita a partire da PHP 5.3.0." "Questa estensione era brevemente un'estensione PECL, ma quella versione è consigliata solo per uso sperimentale".
Paul van Leeuwen

Non hai risposto alla domanda
JG Estiot

20

Secondo me, l'utilizzo di un "database di file flat" nel senso che intendi (e la risposta che hai accettato) non è necessariamente il modo migliore per fare le cose. Prima di tutto, l'uso di serialize()e unserialize()può causare GRANDI mal di testa se qualcuno entra e modifica il file (possono, infatti, inserire codice arbitrario nel tuo "database" da eseguire ogni volta.)

Personalmente, direi: perché non guardare al futuro? Ci sono state così tante volte che ho avuto problemi perché ho creato i miei file "proprietari" e il progetto è esploso al punto in cui ha bisogno di un database, e sto pensando "sai, vorrei L'avevo scritto per iniziare un database "- perché il refactoring del codice richiede troppo tempo e fatica.

Da questo ho imparato che la prova futura della mia applicazione in modo che quando diventa più grande non devo andare e passare giorni a refactoring è il modo per andare avanti. Come faccio a fare questo?

SQLite. Funziona come un database, usa SQL ed è abbastanza facile passare a mySQL (specialmente se stai usando classi astratte per la manipolazione del database come faccio io!)

Infatti, specialmente con il metodo della "risposta accettata", può ridurre drasticamente l'utilizzo della memoria della tua app (non devi caricare tutti i "RECORD" in PHP)


È vero. serialize()può essere molto utile anche per questo. Penso che il trucco per creare un sistema praticabile sia trovare un modo per indicizzare i nodi di dati senza ucciderti con la complessità.
saint_groceon

12

Un framework che sto prendendo in considerazione sarebbe per una piattaforma di blog. Poiché quasi ogni possibile visualizzazione dei dati che desideri sarebbe ordinata per data, stavo pensando a questa struttura:

Una directory per nodo di contenuto:

./content/YYYYMMDDHHMMSS/

Sottodirectory di ogni nodo inclusi

/tags  
/authors  
/comments  

Oltre a semplici file di testo nella directory del nodo per contenuto pre e post rendering e simili.

Ciò consentirebbe una semplice glob()chiamata PHP (e probabilmente un'inversione dell'array dei risultati) per interrogare praticamente qualsiasi cosa all'interno della struttura del contenuto:

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

Restituirebbe percorsi che includessero tutti gli articoli contrassegnati come "divertenti".


9

Ecco il codice che usiamo per 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);
    }
}

?>

Memorizza ogni voce come file separato, che abbiamo trovato abbastanza efficiente per l'uso (non vengono caricati dati non necessari ed è più veloce da salvare).


8

Se intendi utilizzare un file flat per rendere persistenti i dati, utilizza XML per strutturare i dati. PHP ha un parser XML integrato .


E segui le regole xml della leggibilità umana o potresti anche usare la serializzazione o json o qualcosa del genere.
Ben

Consiglio molto scarso. XML non dovrebbe mai essere utilizzato. È una grossa aberrazione.
JG Estiot

@JGEstiot Care per spiegare ulteriormente?
UncaughtTypeError

7

Se vuoi un risultato leggibile dall'uomo, puoi anche usare questo tipo di file:

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

In questo modo, hai un solo file, puoi eseguirne il debug (e correggerlo manualmente) facilmente, puoi aggiungere campi in seguito (alla fine di ogni riga) e il codice PHP è semplice (per ogni riga, diviso in base a |).

Tuttavia, lo svantaggio è che dovresti analizzare l'intero file per cercare qualcosa (se hai milioni di voci, non va bene) e dovresti gestire il separatore nei dati (ad esempio se il nick è WaR | ordz).


7

Ho scritto due semplici funzioni progettate per memorizzare i dati in un file. Puoi giudicare da solo se è utile in questo caso. Il punto è salvare una variabile php (se è un array, una stringa o un oggetto) in un file.

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

L'ho trovato interessante e questo è il modo MIGLIORE, perché scarichiamo semplicemente l'array formattato in un file. Non abbiamo bisogno di ricostruirlo, basta leggere. Inoltre, modificare le variabili è un po 'facile. Non lo userò mai per memorizzare dati di grandi dimensioni, ma ho trovato pratico memorizzare i moduli del programma senza database. Grazie.
m3nda

7

Questo è stimolante come soluzione pratica:
https://github.com/mhgolkar/FlatFire
Utilizza più strategie per la gestione dei dati ...
[Copiato dal file Leggimi]

Libero o Strutturato o Misto

- 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

IMHO, hai due opzioni se vuoi evitare di fare qualcosa in casa:

  1. SQLite

    Se hai familiarità con PDO, puoi installare un driver PDO che supporti SQLite. Non l'ho mai usato, ma ho usato PDO un sacco con MySQL. Darò una possibilità a un progetto in corso.

  2. XML

    Fatto molte volte per quantità di dati relativamente piccole. XMLReader è una classe leggera, di lettura in avanti, in stile cursore. SimpleXML semplifica la lettura di un documento XML in un oggetto a cui è possibile accedere proprio come qualsiasi altra istanza di classe.


5

Sto solo evidenziando un potenziale problema con un database di file flat con questo tipo di sistema:

data|some text|more data

row 2 data|bla hbalh|more data

...eccetera

Il problema è che i dati della cella contengono un "|" o una "\ n", i dati andranno persi. A volte sarebbe più facile dividere per combinazioni di lettere che la maggior parte delle persone non userebbe.

Per esempio:

Separatore di colonna: #$% (Shift+345)

Spaccalegna: ^&* (Shift+678)

File di testo: test data#$%blah blah#$%^&*new row#$%new row data 2

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

O qualcosa del genere. Inoltre, potrei aggiungere che i database di file flat sono buoni per i sistemi con piccole quantità di dati (cioè meno di 20 righe), ma diventano enormi divoratori di memoria per database più grandi.


Punti buoni. Facendo un ulteriore passo avanti, PHP può serializzare JSON molto facilmente. L'escape dell'input è molto più semplice, quindi non è necessario utilizzare divertenti combinazioni di stringhe in modo che il file sia più leggibile.
Cypher
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.