Domanda

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

Molti dei framework di file flat PHP più maturi che vedo là fuori tentano di implementare una sintassi di query simile a SQL, che nella maggior parte dei casi è esagerata per i miei scopi (a quel punto userei semplicemente un database).

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

È stato utile?

Soluzione

Bene, qual è la natura dei database piatti.Sono grandi o piccoli?Sono array semplici con array al loro interno?se è qualcosa di semplice, dì profili utente costruiti come tali:

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

e per salvare o aggiornare il registrazione 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 documentazione 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.

Altri suggerimenti

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

A mio parere, utilizzare un "database di file flat" nel senso che intendi (e nella risposta che hai accettato) non è necessariamente il modo migliore per affrontare le cose.Prima di tutto, usare serialize() E unserialize() può causare GRANDI mal di testa se qualcuno entra e modifica il file (può, infatti, inserire codice arbitrario nel tuo "database" per essere eseguito ogni volta.)

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

Da questo ho imparato che rendere la mia applicazione a prova di futuro in modo che quando diventerà più grande non debba andare a passare giorni a fare refactoring è la strada da percorrere.Come faccio a fare questo?

SQLite.Funziona come un database, utilizza SQL ed è abbastanza semplice passare a mySQL (soprattutto se utilizzi classi astratte per la manipolazione del database come faccio io!)

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

Un framework che sto prendendo in considerazione sarebbe per una piattaforma di blogging.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 ciascun nodo inclusi

/tags  
/authors  
/comments  

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

Ciò consentirebbe un semplice PHP glob() call (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 includono tutti gli articoli contrassegnati con "divertente".

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 un file separato, che abbiamo trovato sufficientemente efficiente per l'uso (non vengono caricati dati non necessari ed è più veloce da salvare).

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

Ho scritto due semplici funzioni progettate per memorizzare i dati in un file.Puoi giudicare tu stesso 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;
}

Se desideri un risultato leggibile dall'uomo, puoi anche utilizzare 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).

Questo è stimolante come soluzione pratica:
https://github.com/mhgolkar/FlatFire
Utilizza molteplici strategie per gestire i 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

IMHO, hai due opzioni se vuoi evitare di preparare 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 moltissimo PDO con MySQL.Proverò a farlo su un progetto attuale.

  2. XML

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

Sto solo sottolineando 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 delle celle contiene un "|" o un " n" quindi i dati andranno persi.A volte sarebbe più semplice dividere per combinazioni di lettere che la maggior parte delle persone non utilizzerebbe.

Per esempio:

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

Divisore di riga: ^&* (Shift+678)

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

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

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

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top