Database file datar [ditutup]

120

Apa praktik terbaik dalam membuat struktur database file datar di PHP?

Banyak kerangka kerja file datar PHP yang lebih matang di luar sana yang saya coba untuk mengimplementasikan sintaks kueri seperti SQL yang berada di atas untuk tujuan saya dalam banyak kasus. (Saya hanya akan menggunakan database pada saat itu).

Apakah ada trik elegan di luar sana untuk mendapatkan kinerja dan fitur yang baik dengan sedikit biaya tambahan?

saint_groceon
sumber
1
Saya ingin menambahkan bahwa ada paket di sini untuk Basis Data File Datar github.com/tmarois/Filebase Saya tahu ini adalah pertanyaan lama, tetapi paket ini adalah yang paling baru dibangun dan dipelihara, ditambah penuh dengan fitur yang paling diabaikan untuk disertakan .
tmarois
Saya mengembangkan CMS dan saya menggunakan database teks file teks datar. Butuh waktu berjam-jam untuk membuatnya dan berjam-jam untuk membiaskan tetapi bekerja dengan sempurna. Kueri akan dilakukan jauh lebih cepat dengan database yang diindeks dan dioptimalkan sepenuhnya. Namun, saya menghindari kebutuhan kueri dengan menyimpan meta data dan dengan organisasi dan struktur yang cermat. Ketika saya membutuhkan data, saya mendapatkannya tanpa for loop(kecuali saya menggunakan semua data di folder), oleh karena itu performanya jauh lebih cepat daripada database. Saya akan menjelaskan secara detail dan memberikan jawaban yang sangat bagus tetapi sayangnya pertanyaan ini sudah ditutup.
Dan Bray

Jawaban:

75

Nah, apa sifat dari flat database. Apakah mereka besar atau kecil. Apakah itu array sederhana dengan array di dalamnya? jika itu sesuatu yang sederhana katakanlah profil pengguna dibangun seperti itu:

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

dan untuk menyimpan atau memperbarui data db untuk pengguna tersebut.

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

dan memuat rekaman untuk pengguna

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

tetapi sekali lagi implementasi ini akan berbeda-beda pada aplikasi dan sifat database yang Anda butuhkan.

w-ll
sumber
48

Anda mungkin mempertimbangkan SQLite . Ini hampir sesederhana file datar, tetapi Anda mendapatkan mesin SQL untuk membuat kueri. Ia bekerja dengan baik dengan PHP juga.

yukondude
sumber
6
SQLite dibangun menjadi 5.0+ secara default, tetapi didiskon (!) Dari PHP 5.4+ hingga !!! Saat saya menulis ini pada Juli 2012, SQLite tidak akan berfungsi pada sistem terbaru lagi secara default. Pernyataan resmi di sini
Sliq
Menginstal driver PDO SQLite cukup sepele jika Anda memiliki akses server. Pada Ubuntu / Debian yang menjalankan Apache2 cukup lakukan apt-get install php5-sqlite service apache2 restart
siliconrockstar
4
Menanggapi komentar dari @Sliq, menyatakan bahwa "SQLite telah ... dihentikan" adalah benar: ekstensi bernama "SQLite" telah dihentikan dan "SQLite3" sekarang diaktifkan secara default. php.net/manual/en/sqlite.installation.php "Sejak PHP 5.0 ekstensi ini dibundel dengan PHP. Dimulai dengan PHP 5.4, ekstensi ini tersedia hanya melalui PECL." php.net/manual/en/sqlite3.installation.php "Ekstensi SQLite3 diaktifkan secara default pada PHP 5.3.0." "Ekstensi ini secara singkat merupakan ekstensi PECL tetapi versi itu hanya disarankan untuk penggunaan eksperimental."
Paul van Leeuwen
Anda tidak menjawab pertanyaan
JG Estiot
20

Menurut pendapat saya, menggunakan "Flat File Database" dalam arti yang Anda maksud (dan jawaban yang Anda terima) bukanlah cara terbaik untuk melakukan sesuatu. Pertama-tama, menggunakan serialize()dan unserialize()dapat menyebabkan sakit kepala MAYOR jika seseorang masuk dan mengedit file (mereka sebenarnya dapat menempatkan kode arbitrer di "database" Anda untuk dijalankan setiap saat.)

Secara pribadi, menurut saya - mengapa tidak melihat ke masa depan? Sering kali saya mengalami masalah karena saya telah membuat file "berpemilik" saya sendiri, dan proyek tersebut telah meledak ke titik di mana ia membutuhkan database, dan saya berpikir "Anda tahu, saya harap Saya telah menulis ini untuk database untuk memulai dengan "- karena refactoring kode membutuhkan terlalu banyak waktu dan tenaga.

Dari sini saya telah belajar bahwa pembuktian masa depan aplikasi saya sehingga ketika semakin besar saya tidak perlu pergi dan menghabiskan berhari-hari refactoring adalah cara untuk maju. Bagaimana saya melakukan ini?

SQLite. Ini berfungsi sebagai database, menggunakan SQL, dan cukup mudah untuk diubah ke mySQL (terutama jika Anda menggunakan kelas abstrak untuk manipulasi database seperti yang saya lakukan!)

Faktanya, terutama dengan metode "jawaban yang diterima", metode ini dapat secara drastis memotong penggunaan memori aplikasi Anda (Anda tidak perlu memuat semua "RECORDS" ke dalam PHP)

Mez
sumber
Itu benar. serialize()bisa sangat berguna untuk itu juga. Saya pikir trik untuk menghasilkan sistem yang layak adalah menemukan beberapa cara untuk mengindeks node data tanpa membunuh diri Anda sendiri dengan kerumitan.
saint_groceon
12

Satu kerangka kerja yang saya pertimbangkan adalah untuk platform blogging. Karena hampir semua kemungkinan tampilan data yang Anda inginkan akan diurutkan berdasarkan tanggal, saya memikirkan tentang struktur ini:

Satu direktori per node konten:

./content/YYYYMMDDHHMMSS/

Subdirektori dari setiap node termasuk

/tags  
/authors  
/comments  

Serta file teks sederhana di direktori node untuk konten pra-dan pasca-render dan sejenisnya.

Ini akan memungkinkan glob()panggilan PHP sederhana (dan mungkin pembalikan larik hasil) untuk menanyakan apa saja di dalam struktur konten:

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

Akan mengembalikan jalur termasuk semua artikel yang ditandai "lucu".

saint_groceon
sumber
9

Berikut kode yang kami gunakan untuk Lilina:

<?php
/**
 * Handler for persistent data files
 *
 * @author Ryan McCue <[email protected]>
 * @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);
    }
}

?>

Ini menyimpan setiap entri sebagai file terpisah, yang kami temukan cukup efisien untuk digunakan (tidak ada data yang tidak diperlukan dimuat dan lebih cepat disimpan).

Ryan McCue
sumber
8

Jika Anda akan menggunakan file datar untuk mempertahankan data, gunakan XML untuk menyusun data. PHP memiliki parser XML bawaan .

Jason
sumber
Dan ikuti aturan xml tentang keterbacaan manusia atau Anda mungkin juga menggunakan serialisasi atau json atau semacamnya.
Ben
Saran yang sangat buruk. XML tidak boleh digunakan. Ini adalah penyimpangan lemak.
JG Estiot
@JGEstiot Perawatan untuk menjelaskan lebih lanjut?
UncaughtTypeError
7

Jika Anda menginginkan hasil yang dapat dibaca manusia, Anda juga dapat menggunakan jenis file ini:

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

Dengan cara ini, Anda hanya memiliki satu file, Anda dapat men-debugnya (dan memperbaikinya secara manual) dengan mudah, Anda dapat menambahkan kolom nanti (di akhir setiap baris) dan kode PHP sederhana (untuk setiap baris, pisahkan menurut |).

Namun, kekurangannya adalah Anda harus mengurai seluruh file untuk mencari sesuatu (jika Anda memiliki jutaan entri, tidak masalah) dan Anda harus menangani pemisah dalam data (misalnya jika nama panggilannya adalah WaR | ordz).

ofaurax.dll
sumber
7

Saya telah menulis dua fungsi sederhana yang dirancang untuk menyimpan data dalam sebuah file. Anda dapat menilai sendiri apakah itu berguna dalam kasus ini. Intinya adalah menyimpan variabel php (jika itu berupa array, string atau objek) ke 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;
}
jpcrevoisier.dll
sumber
Saya menemukan itu menarik dan ini adalah cara yang LEBIH BAIK, karena kita baru saja membuang array yang diformat ke file. Kita tidak perlu membangunnya lagi, cukup baca. Juga, edit variabel itu sedikit mudah. Saya tidak akan pernah menggunakannya untuk menyimpan data besar, tetapi saya merasa praktis untuk menyimpan modul program tanpa database. Terima kasih.
m3nda
7

Yang ini menginspirasi sebagai solusi praktis:
https://github.com/mhgolkar/FlatFire
Menggunakan berbagai strategi untuk menangani data ...
[Disalin dari File Readme]

Bebas atau Terstruktur atau Campuran

- 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
omran
sumber
7

IMHO, Anda memiliki dua opsi jika Anda ingin menghindari homebrewing sesuatu:

  1. SQLite

    Jika Anda terbiasa dengan PDO, Anda dapat menginstal driver PDO yang mendukung SQLite. Tidak pernah menggunakannya, tapi saya telah menggunakan PDO satu ton dengan MySQL. Saya akan mencoba proyek ini saat ini.

  2. XML

    Lakukan ini berkali-kali untuk jumlah data yang relatif kecil. XMLReader adalah kelas ringan, baca-maju, dan bergaya kursor. SimpleXML membuatnya mudah untuk membaca dokumen XML menjadi objek yang dapat Anda akses seperti contoh kelas lainnya.

siliconrockstar
sumber
5

Hanya menunjukkan masalah potensial dengan database file datar dengan jenis sistem ini:

data|some text|more data

row 2 data|bla hbalh|more data

... dll

Masalahnya adalah bahwa data sel berisi "|" atau "\ n" maka data akan hilang. Terkadang akan lebih mudah untuk memisahkan dengan kombinasi huruf yang tidak akan digunakan kebanyakan orang.

Sebagai contoh:

Pembagi kolom: #$% (Shift+345)

Pembagi baris: ^&* (Shift+678)

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

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

Atau apa pun di sepanjang garis ini. Selain itu, saya dapat menambahkan bahwa database file datar baik untuk sistem dengan jumlah data yang kecil (yaitu kurang dari 20 baris), tetapi menjadi memori besar untuk database yang lebih besar.

Michael Burt
sumber
Poin bagus. Mengambil langkah lebih jauh, PHP dapat membuat serial JSON dengan sangat mudah. Escaping input jauh lebih sederhana sehingga Anda tidak perlu menggunakan kombinasi string lucu agar file lebih mudah dibaca.
Cypher