Care sunt cele mai bune practici în ceea ce privește crearea de structuri baze de date cu fișiere plate în PHP? O mulțime de cadre de fișiere PHP mai mature văd acolo încercarea de a implementa sintaxa de interogare asemănătoare SQL, care este în topul scopurilor mele în cele mai multe cazuri (aș folosi doar o bază de date la acel moment).
Există trucuri elegante acolo pentru a obține performanțe bune și caracteristici cu un mic cod deasupra capului pe care ar dori-o să luați această problemă în primul rând?
Un cadru pe care-l iau în considerare ar fi pentru o platformă de blogging. Deoarece aproape orice vizualizare posibilă a datelor pe care le-ați dori ar fi sortată după dată, m-am gândit la această structură:
Un director pe nod de conținut:
./content/YYYYMMDDHHMMSS/
Subdirectoarele fiecărui nod, inclusiv
/tags
/authors
/comments
Pe lângă fișierele text simple din directorul nod pentru conținut pre-și post-redat și altele asemenea.
Acest lucru ar permite un simplu apel glob ()
în PHP (și probabil o inversare a matricea de rezultate) pentru a interoga doar despre orice din structura conținutului:
glob("content/*/tags/funny");
S-ar întoarce căi, inclusiv toate articolele etichetate "amuzant".
Este adevărat. serialize ()
poate fi destul de util pentru asta.
Cred că trucul pentru a veni cu un sistem viabil este găsirea unui mod de a indexa nodurile de date fără a vă ucide cu complexitate.
Care este natura bazelor de date plate? Sunt mari sau mici. Sunt simple mese cu matrice în ele? dacă ceva simplu spune userprofiles construit ca atare:
$user = array("name" => "dubayou",
"age" => 20,
"websites" => array("dubayou.com","willwharton.com","codecream.com"),
"and_one" => "more");
și să salvați sau să actualizați înregistrarea db pentru acel utilizator.
$dir = "../userdata/"; //make sure to put it bellow what the server can reach.
file_put_contents($dir.$user['name'],serialize($user));
și pentru a încărca înregistrarea pentru utilizator
function &get_user($name){
return unserialize(file_get_contents("../userdata/".$name));
}
dar din nou această implementare va varia în funcție de aplicația și natura bazei de date de care aveți nevoie.
Puteți lua în considerare SQLite . Este aproape la fel de simplu ca fișierele plate, dar obțineți un motor SQL pentru interogare. funcționează bine și cu PHP .
Dacă intenționați să utilizați un fișier plat pentru a persista datele, utilizați XML pentru a structura datele. PHP are un parser XML încorporat .
Dacă doriți un rezultat care poate fi citit-uman, puteți utiliza, de asemenea, acest tip de fișier:
ofaurax|27|male|something|
another|24|unknown||
...
În acest fel, aveți un singur fișier, îl puteți depana (și remediați manual) ușor, puteți adăuga mai târziu câmpuri (la sfârșitul fiecărei linii), iar codul PHP este simplu (pentru fiecare rând, împărțit în funcție de |).
Cu toate acestea, dezavantajele sunt că ar trebui să parse întregul fișier pentru a căuta ceva (dacă aveți milioane de intrări, nu este bine) și ar trebui să se ocupe de separator în date (de exemplu, dacă porecla este WaR | ordz).
După părerea mea, folosirea unei "baze de date de fișiere plate" în sensul în care înțelegeți (și răspunsul pe care l-ați acceptat) nu este în mod necesar cel mai bun mod de a face lucrurile. Mai întâi de toate, folosirea serialize ()
și unserialize ()
poate cauza dureri majore dacă cineva intră și editează fișierul "baza de date" care trebuie rulată de fiecare dată.)
Personal, aș spune - de ce nu te uiți în viitor? Au fost atâtea ori că am avut probleme pentru că mi-am creat propriile fișiere "proprietare", iar proiectul a explodat până la un punct în care are nevoie de o bază de date și mă gândesc "știi tu, doresc Am scris acest lucru pentru ca o bază de date să înceapă cu "- pentru că refactorizarea codului durează prea mult timp și efort.
Din aceasta am invatat ca viitoarele probe de aplicare mea, astfel incat atunci cand devine mai mare nu trebuie sa merg si sa petreaca zile refactoring este calea de a merge mai departe. Cum pot face acest lucru?
SQLite. Funcționează ca o bază de date, utilizează SQL și este destul de ușor să se schimbe în MySQL (espescially dacă folosiți clase abstracte pentru manipularea bazei de date ca mine!)
De fapt, espescially cu metoda "acceptat răspuns", poate reduce drastic utilizarea memoriei aplicației dvs. (nu trebuie să încărcați toate "RECORDS" în PHP)
Iată codul pe care îl folosim pentru Lilina:
* @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);
}
}
?>
Se stochează fiecare intrare ca fișier separat, pe care am descoperit că este suficient de eficient pentru utilizare (nu se încarcă date care nu sunt necesare și este mai rapid de salvat).
IMHO, aveți două opțiuni dacă vreți să evitați ceva inițial:
SQLite
If you're familiar with PDO, you can install a PDO driver that supports SQLite. Never used it, but I have used PDO a ton with MySQL. I'm going to give this a shot on a current project.
XML
Done this many times for relatively small amounts of data. XMLReader is a lightweight, read-forward, cursor-style class. SimpleXML makes it simple to read an XML document into an object that you can access just like any other class instance.
Am scris două funcții simple concepute pentru a stoca date într-un fișier. Puteți judeca singur dacă este util în acest caz. Ideea este să salvați o variabilă php (dacă este vorba de un șir sau de un obiect) într-un fișier.
$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,'
Doar subliniind o problemă potențială cu o bază de date cu fișiere plate cu acest tip de sistem:
data|some text|more data
row 2 data|bla hbalh|more data
... etc
Problema este că datele de celule conțin un "|" sau "\ n" atunci datele vor fi pierdute. Uneori ar fi mai ușor să se împartă prin combinații de scrisori pe care majoritatea oamenilor nu le-ar folosi.
De exemplu:
Column splitter: #$% (Shift+345)
Row splitter: ^&* (Shift+678)
Text file: test data#$%blah blah#$%^&*new row#$%new row data 2
Then use: explode("#$%", $data); use foreach, the explode again to separate columns
Sau ceva în acest sens. De asemenea, aș putea adăuga că bazele de date cu fișiere plate sunt bune pentru sistemele cu cantități mici de date (adică, mai puțin de 20 de rânduri), dar devin grave de memorie pentru bazele de date mai mari.
This one is inspiring as a practical solution:
https://github.com/mhgolkar/FlatFire
It uses multiple strategies to handling data...
[Copied from Readme File]
- 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