Question

Quelles sont les meilleures pratiques en matière de création de structures de bases de données de fichiers plats en PHP ?

La plupart des frameworks de fichiers plats PHP les plus matures que je vois tentent d'implémenter une syntaxe de requête de type SQL, ce qui est exagéré pour mes besoins dans la plupart des cas (j'utiliserais simplement une base de données à ce stade).

Existe-t-il des astuces élégantes pour obtenir de bonnes performances et fonctionnalités avec une petite surcharge de code ?

Était-ce utile?

La solution

Eh bien, quelle est la nature des bases de données plates.Sont-ils grands ou petits.S'agit-il de simples tableaux contenant des tableaux ?si c'est quelque chose de simple, dites des profils d'utilisateurs construits comme tels :

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

et pour enregistrer ou mettre à jour le enregistrement de base de données pour cet utilisateur.

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

et pour charger le enregistrer pour l'utilisateur

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

mais encore une fois, cette implémentation variera en fonction de l'application et de la nature de la base de données dont vous avez besoin.

Autres conseils

Vous pourriez envisager SQLite.C'est presque aussi simple que des fichiers plats, mais vous disposez d'un moteur SQL pour les requêtes.Il fonctionne bien avec PHP aussi.

À mon avis, utiliser une "base de données de fichiers plats" dans le sens que vous entendez (et la réponse que vous avez acceptée) n'est pas nécessairement la meilleure façon de procéder.Tout d’abord, en utilisant serialize() et unserialize() peut causer des maux de tête MAJEURS si quelqu'un entre et modifie le fichier (il peut, en fait, mettre du code arbitraire dans votre "base de données" pour qu'il soit exécuté à chaque fois.)

Personnellement, je dirais : pourquoi ne pas regarder vers l’avenir ?Il y a eu tellement de fois que j'ai eu des problèmes parce que j'ai créé mes propres fichiers "propriétaires", et le projet a explosé à un point tel qu'il a besoin d'une base de données, et je me dis "vous savez, j'aimerais J'avais écrit ceci pour commencer une base de données" - parce que la refactorisation du code prend beaucoup trop de temps et d'efforts.

De cela, j'ai appris que la pérennité de mon application afin que lorsqu'elle grandit, je n'ai pas à passer des jours à refactoriser est la voie à suivre.Comment puis-je faire cela?

SQLite.Il fonctionne comme une base de données, utilise SQL et est assez facile à passer à MySQL (surtout si vous utilisez des classes abstraites pour la manipulation de bases de données comme je le fais !)

En fait, notamment avec la méthode "réponse acceptée", cela peut réduire considérablement l'utilisation de la mémoire de votre application (vous n'avez pas besoin de charger tous les "ENREGISTREMENTS" dans PHP)

Un cadre que j'envisage serait celui d'une plateforme de blogs.Étant donné que presque toutes les vues possibles des données que vous souhaiteriez seraient triées par date, je pensais à cette structure :

Un répertoire par nœud de contenu :

./content/YYYYMMDDHHMMSS/

Sous-répertoires de chaque nœud comprenant

/tags  
/authors  
/comments  

Ainsi que de simples fichiers texte dans le répertoire du nœud pour le contenu pré- et post-rendu, etc.

Cela permettrait à un simple PHP glob() appel (et probablement une inversion du tableau de résultats) pour interroger à peu près n'importe quoi dans la structure de contenu :

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

Renvoierait des chemins incluant tous les articles étiquetés « drôle ».

Voici le code que nous utilisons pour 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);
    }
}

?>

Il stocke chaque entrée dans un fichier séparé, ce qui, selon nous, est suffisamment efficace pour être utilisé (aucune donnée inutile n'est chargée et sa sauvegarde est plus rapide).

Si vous envisagez d'utiliser un fichier plat pour conserver les données, utilisez XML pour structurer les données.PHP a un analyseur XML intégré.

J'ai écrit deux fonctions simples conçues pour stocker des données dans un fichier.Vous pouvez juger par vous-même si c'est utile dans ce cas.Le but est de sauvegarder une variable php (s'il s'agit d'un tableau, d'une chaîne ou d'un objet) dans un fichier.

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

Si vous souhaitez un résultat lisible par l'homme, vous pouvez également utiliser ce type de fichier :

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

De cette façon, vous n'avez qu'un seul fichier, vous pouvez le déboguer (et le réparer manuellement) facilement, vous pouvez ajouter des champs plus tard (à la fin de chaque ligne) et le code PHP est simple (pour chaque ligne, divisé selon |).

Cependant, l'inconvénient est que vous devez analyser l'intégralité du fichier pour rechercher quelque chose (si vous avez des millions d'entrées, ce n'est pas bien) et vous devez gérer le séparateur de données (par exemple si le pseudo est WaR|ordz).

Celle-ci est inspirante en tant que solution pratique :
https://github.com/mhgolkar/FlatFire
Il utilise plusieurs stratégies pour gérer les données...
[Copié à partir du fichier Lisezmoi]

Libre ou Structuré ou Mixte

- 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

À mon humble avis, vous avez deux options si vous voulez éviter de faire quelque chose de homebrewing :

  1. SQLite

    Si vous êtes familier avec PDO, vous pouvez installer un pilote PDO prenant en charge SQLite.Je ne l'ai jamais utilisé, mais j'ai beaucoup utilisé PDO avec MySQL.Je vais essayer ceci sur un projet en cours.

  2. XML

    Cela a été fait plusieurs fois pour des quantités de données relativement petites. Lecteur XML est une classe légère, à lecture directe, de style curseur. SimpleXML simplifie la lecture d'un document XML dans un objet auquel vous pouvez accéder comme n'importe quelle autre instance de classe.

Je souligne simplement un problème potentiel avec une base de données de fichiers plats avec ce type de système :

data|some text|more data

row 2 data|bla hbalh|more data

...etc

Le problème est que les données cellulaires contient un "|" ou un " n" alors les données seront perdues.Parfois, il serait plus facile de diviser par combinaisons de lettres que la plupart des gens n'utiliseraient pas.

Par exemple:

Séparateur de colonnes : #$% (Shift+345)

Séparateur de rangées : ^&* (Shift+678)

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

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

Ou quoi que ce soit dans ce sens.De plus, je pourrais ajouter que les bases de données de fichiers plats conviennent aux systèmes avec de petites quantités de données (c.-à-d.moins de 20 lignes), mais deviennent d'énormes monopolisateurs de mémoire pour les bases de données plus volumineuses.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top