Kartotekowa baza danych

głosy
101

Jakie są najlepsze praktyki wokół tworzenia płaskich struktur baz danych plików w PHP?

Dużo bardziej dojrzałych PHP płaski plików ram widzę tam próbować wdrożyć SQL-jak składnia kwerendy, która jest na wierzchu dla moich celów w większości przypadków (Chciałbym po prostu korzystać z bazy danych w tym punkcie).

Czy są jakieś eleganckie sztuczek tam, aby uzyskać dobrą wydajność i funkcje z niewielkim narzutem kodu?

Utwórz 01/08/2008 o 15:19
źródło użytkownik
W innych językach...                            


12 odpowiedzi

głosy
11

Jeden ramy Zastanawiam byłoby dla blogosferę. Od niemal każdym możliwym świetle danych, co chcesz by być sortowane według daty, myślałem o tej struktury:

Jeden katalog na węzeł zawartości:

./content/YYYYMMDDHHMMSS/

Podkatalogi każdego węzła w tym

/tags  
/authors  
/comments  

Jak również prostych plików tekstowych w katalogu węzłów dla przed- i po-renderowane treści i tym podobne.

Pozwoliłoby to prosty PHP glob()połączenia (i prawdopodobnie odwrócenie tablicy wynik) do kwerendy na czegokolwiek w strukturze partnerskiej:

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

Zwróciłby ścieżek w tym wszystkich artykułów otagowanych „śmieszne”.

Odpowiedział 01/08/2008 o 15:26
źródło użytkownik

głosy
15

To prawda. serialize()może być bardzo przydatna, że dobrze.

Myślę, że podstęp się wymyślanie rentownego systemu jest znalezienie jakiś sposób indeksować węzłów danych bez zabijania się ze złożonością.

Odpowiedział 01/08/2008 o 15:58
źródło użytkownik

głosy
68

Cóż, jaka jest natura płaskich baz danych. Są one duże czy małe. Jest to proste tablice z tablicami w nich? jeśli jej coś powiedzieć userprofiles proste zbudowane jako takie:

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

i zapisać lub zaktualizować rekord db dla tego użytkownika.

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

i załadować rekord dla użytkownika

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

ale znowu ta implementacja będzie różnić się w zależności od zastosowania i rodzaju danych potrzebnych.

Odpowiedział 01/08/2008 o 18:45
źródło użytkownik

głosy
46

Można rozważyć SQLite . To prawie tak proste jak pliki płaskie, ale dostaniesz silnik SQL dla zapytań. To działa dobrze z PHP zbyt.

Odpowiedział 09/08/2008 o 00:00
źródło użytkownik

głosy
8

Jeśli masz zamiar użyć pliku płaskiego do utrwalania danych, należy użyć XML struktury danych. PHP posiada wbudowany parser XML .

Odpowiedział 18/09/2008 o 07:40
źródło użytkownik

głosy
6

Jeśli chcesz rezultat w postaci czytelnej dla człowieka, można również korzystać z tego typu pliku:

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

W ten sposób można mieć tylko jeden plik, można debugować go (i ręcznie naprawić) łatwo można dodać pola później (na końcu każdej linii) oraz kod PHP jest prosty (dla każdej linii, podzielone według |).

Jednak wadą jest to, że należy przeanalizować cały plik, aby szukać czegoś (jeśli masz miliony wpisu, to nie jest w porządku) i należy obchodzić się separator w danych (na przykład, jeśli nick jest wojna | ordz).

Odpowiedział 18/09/2008 o 08:51
źródło użytkownik

głosy
20

Moim zdaniem, za pomocą „kartotekowa baza danych” w tym sensie jesteś znaczenie (i odpowiedź już zaakceptowane) nie jest neccesarily najlepszym sposobem, aby przejść o rzeczach. Przede wszystkim, przy użyciu serialize()i unserialize()może spowodować poważne bóle głowy, jeśli ktoś dostanie się i edytuje plik (mogą one w rzeczywistości, umieścić kod arbritrary w swojej „bazy”, aby uruchomić za każdym razem).

Osobiście powiedziałbym - dlaczego nie patrzeć w przyszłość? Nie było tak wiele razy, że miałem problemy, ponieważ byłem tworząc własne „proprietary” pliki, a projekt wybuchła do punktu, w którym potrzebuje bazy danych, i myślę: „Wiesz, chciałbym bym napisał to dla bazy danych na początek”- bo refaktoryzacji kodu zajmuje zbyt wiele czasu i wysiłku.

Z tego Nauczyłem się, że przyszłość proofing mojej aplikacji tak, że kiedy robi się większy nie mam pójść i spędzić kilka dni refaktoryzacji jest droga naprzód. Jak mam to zrobic?

SQLite. Działa jako bazy danych, wykorzystuje SQL, i jest dość łatwe do zmiany na MySQL (espescially jeśli używasz klas wydobywane do manipulacji bazy tak jak ja!)

W rzeczywistości, espescially z „przyjętą odpowiedź” 's metody, może drastycznie obniżyć zużycie pamięci aplikacji (nie trzeba załadować wszystkie «rekordy» w PHP)

Odpowiedział 21/09/2008 o 19:21
źródło użytkownik

głosy
8

Oto kod, którego używamy do 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);
    }
}

?>

Przechowuje każdy wpis jako oddzielny plik, który uznaliśmy jest wystarczająco wydajny do pracy (bez niepotrzebnych danych jest załadowany i to szybciej, aby zapisać).

Odpowiedział 28/10/2008 o 11:45
źródło użytkownik

głosy
6

IMHO, masz dwie opcje, jeśli chcesz uniknąć Piwowarstwo coś:

  1. SQLite

    Jeśli jesteś zaznajomiony z PDO, można zainstalować sterownik PDO, który obsługuje SQLite. Nigdy nie korzystałem, ale użyłem PDO tonę z MySQL. Mam zamiar dać ten strzał na bieżącym projekcie.

  2. XML

    Sporządzono to wiele razy na stosunkowo małych ilości danych. XMLReader jest lekki, czytać do przodu, klasa kursor stylu. SimpleXML ułatwia czytać dokument XML do obiektu, który można uzyskać dostęp, tak jak innych instancji klasy.

Odpowiedział 02/12/2012 o 16:49
źródło użytkownik

głosy
7

Napisałem dwie proste funkcje przeznaczone do przechowywania danych w pliku. Możesz sam ocenić czy jest to przydatne w tym przypadku. Chodzi o to, aby zapisać zmienną PHP (jeśli to albo tablica string lub obiektu) do pliku.

<?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;
}
Odpowiedział 19/12/2012 o 21:48
źródło użytkownik

głosy
4

Wystarczy zwrócić uwagę na potencjalny problem z płaską bazą danych plików z tego typu systemu:

data|some text|more data

row 2 data|bla hbalh|more data

...itp

Problem polega na tym, że dane komórka zawiera „|” lub „\ n”, a następnie dane zostaną utracone. Czasami łatwiej byłoby podzielić przez kombinacje liter, że większość ludzi nie będzie używać.

Na przykład:

splitter kolumna: #$% (Shift+345)

rozdzielacz wiersz: ^&* (Shift+678)

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

Następnie użyj: explode("#$%", $data); use foreach, the explode again to separate columns

Albo coś w tym kierunku. Ponadto dodam, że kartotekowa baza danych są dobre dla systemów z małymi ilościami danych (tj. Mniej niż 20 wierszy), ale stają się ogromne świnie pamięci dla dużych baz danych.

Odpowiedział 04/01/2013 o 01:14
źródło użytkownik

głosy
6

Ten jest inspirujący jako praktyczne rozwiązanie:
https://github.com/mhgolkar/FlatFire
Wykorzystuje wiele strategii do obsługi danych ...
[Skopiowane z Readme]

Wolne lub Structured lub mieszane

- 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
Odpowiedział 02/05/2013 o 14:57
źródło użytkownik

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more