Düz dosya veritabanları [kapalı]


120

PHP'de düz dosya veritabanı yapıları oluşturmaya yönelik en iyi uygulamalar nelerdir?

SQL benzeri sorgu sözdizimini uygulamaya çalıştığım ve çoğu durumda amacım için en üstte olan bir çok daha olgunlaşmış PHP düz dosya çerçevesi var. (O noktada sadece bir veritabanı kullanırdım).

Küçük bir kod ek yüküyle iyi performans ve özellikler elde etmek için herhangi bir zarif numara var mı?


1
Burada Düz Dosya Veritabanı için bir paket olduğunu eklemek isterim github.com/tmarois/Filebase Bunun eski bir soru olduğunu biliyorum, ancak bu paket en yeni derleme ve bakımı, ayrıca dahil edilmesi en çok ihmal edilen özelliklerle dolu .
tmarois

Bir CMS geliştiriyorum ve düz metin dosyası metin veritabanı kullanıyorum. Yapılması saatler, kırılması saatler sürüyor ama mükemmel çalışıyor. Tamamen dizine alınmış ve optimize edilmiş bir veritabanı ile sorgular çok daha hızlı gerçekleştirilecektir. Bununla birlikte, meta verileri depolayarak ve dikkatli bir organizasyon ve yapı ile sorgu ihtiyacını ortadan kaldırıyorum. Veriye ihtiyacım olduğunda, onu bir olmadan for loopalıyorum (klasördeki tüm verileri kullanmıyorsam), bu nedenle bir veritabanından çok daha hızlı çalışıyor. Detaylara girip çok güzel bir cevap verirdim ama maalesef bu soru kapandı.
Dan Bray

Yanıtlar:


75

Peki, düz veri tabanlarının doğası nedir? Büyük mü küçük mü? İçlerinde diziler olan basit diziler mi? basit bir şeyse kullanıcı profilleri böyle oluşturulmuşsa:

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

ve o kullanıcı için db kaydını kaydetmek veya güncellemek için .

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

ve kullanıcı için kaydı yüklemek

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

ancak yine bu uygulama, ihtiyacınız olan veritabanının uygulamasına ve niteliğine göre değişiklik gösterecektir.


48

SQLite'ı düşünebilirsiniz . Neredeyse düz dosyalar kadar basit, ancak sorgulama için bir SQL motoru elde edersiniz. Bu PHP ile iyi çalışıyor da.


6
SQLite varsayılan olarak 5.0+ sürümünde oluşturuldu, ancak PHP 5.4+ sürümünden itibaren indirimli (!) !!! Bunu Temmuz 2012'de yazdığım için, SQLite artık varsayılan olarak güncel sistemlerde çalışmayacak. Resmi açıklama burada
Sliq

Sunucu erişiminiz varsa SQLite PDO sürücüsünü kurmak oldukça önemsizdir. Apache2 çalıştıran Ubuntu / Debian'da apt-get install php5-sqlite hizmeti apache2 restart yapın
siliconrockstar

4
@Sliq'in yorumuna tepki olarak, "SQLite ... durduruldu" ifadesinin bir tür doğru olduğunu belirtmek: "SQLite" adlı uzantı durduruldu ve "SQLite3" artık varsayılan olarak etkinleştirildi. php.net/manual/en/sqlite.installation.php "PHP 5.0'dan beri bu uzantı PHP ile birlikte paketlenmiştir. PHP 5.4'ten itibaren, bu uzantı yalnızca PECL aracılığıyla kullanılabilir." php.net/manual/en/sqlite3.installation.php "SQLite3 uzantısı, PHP 5.3.0'dan itibaren varsayılan olarak etkindir." "Bu uzantı kısaca bir PECL uzantısıydı, ancak bu sürüm yalnızca deneysel kullanım için önerilmektedir."
Paul van Leeuwen

Soruyu cevaplamadınız
JG Estiot

20

Benim düşünceme göre, anlamınız (ve kabul ettiğiniz yanıtı) anlamında bir "Düz Dosya Veritabanı" kullanmak, her şeyi yapmanın en iyi yolu olmayabilir. Her şeyden önce, kullanmak serialize()ve unserialize()birisi dosyayı alırsa ve düzenlerse MAJOR baş ağrısına neden olabilir (aslında her seferinde çalıştırmak için "veritabanınıza" keyfi kod koyabilirler.)

Şahsen şunu söyleyebilirim - neden geleceğe bakmıyoruz? O kadar çok sorun yaşadım ki, kendi "tescilli" dosyalarımı oluşturuyordum ve proje bir veritabanına ihtiyaç duyduğu bir noktaya kadar patladı ve "bilirsiniz, keşke Bunu bir veritabanı için yazdım "- çünkü kodun yeniden düzenlenmesi çok fazla zaman ve çaba gerektiriyor.

Bundan, başvurumu gelecekte kanıtlamanın, büyüdüğünde gidip yeniden düzenlemeye günler harcamak zorunda kalmamam için ileriye gitmenin yolu olduğunu öğrendim. Bunu nasıl yaparım?

SQLite. Bir veritabanı olarak çalışır, SQL kullanır ve MySQL'e geçmek oldukça kolaydır (özellikle benim yaptığım gibi veritabanı manipülasyonu için soyutlanmış sınıflar kullanıyorsanız!)

Aslında, özellikle "kabul edilen yanıt" yöntemiyle, uygulamanızın bellek kullanımını büyük ölçüde azaltabilir (tüm "KAYITLARI" PHP'ye yüklemeniz gerekmez)


Bu doğru. serialize()bunun için de oldukça faydalı olabilir. Bence uygulanabilir bir sistem bulmanın püf noktası, karmaşıklıkla kendinizi öldürmeden veri düğümlerini indekslemenin bir yolunu bulmaktır.
saint_groceon

12

Düşündüğüm bir çerçeve, bir blog platformu için olacaktır. Hemen hemen isteyebileceğiniz herhangi bir olası veri görünümü tarihe göre sıralanacağından, şu yapıyı düşünüyordum:

İçerik düğümü başına bir dizin:

./content/YYYYMMDDHHMMSS/

Dahil olmak üzere her düğümün alt dizinleri

/tags  
/authors  
/comments  

Önceden ve sonradan oluşturulmuş içerik ve benzerleri için düğüm dizinindeki basit metin dosyalarının yanı sıra.

Bu, basit bir PHP glob()çağrısının (ve muhtemelen sonuç dizisinin tersine çevrilmesinin) içerik yapısı içindeki hemen hemen her şeyi sorgulamasına izin verir :

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

"Komik" etiketli tüm makaleleri içeren yolları döndürür.


9

Lilina için kullandığımız kod:

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

?>

Her girişi, kullanım için yeterince verimli bulduğumuz ayrı bir dosya olarak depolar (gereksiz veri yüklenmez ve kaydetmesi daha hızlıdır).


8

Verileri kalıcı hale getirmek için düz bir dosya kullanacaksanız, verileri yapılandırmak için XML kullanın. PHP'nin yerleşik bir XML ayrıştırıcısı vardır .


Ve insan tarafından okunabilir xml kurallarına uyun, yoksa serileştirme veya json veya başka bir şey de kullanabilirsiniz.
Ben

Çok kötü bir tavsiye. XML asla kullanılmamalıdır. Bu şişman bir sapmadır.
JG Estiot

@JGEstiot Daha fazla açıklama yapmak ister misiniz?
UncaughtTypeError

7

İnsan tarafından okunabilir bir sonuç istiyorsanız, şu dosya türünü de kullanabilirsiniz:

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

Bu şekilde, yalnızca bir dosyanız olur, kolayca hata ayıklayabilir (ve manuel olarak düzeltebilirsiniz), daha sonra alanlar ekleyebilirsiniz (her satırın sonuna) ve PHP kodu basittir (her satır için | 'ye göre bölün).

Bununla birlikte, dezavantajları, bir şeyi aramak için tüm dosyayı ayrıştırmanız (milyonlarca girişiniz varsa, bu iyi değildir) ve verilerdeki ayırıcıyı işlemenizdir (örneğin, nick WaR | ordz ise).


7

Verileri bir dosyada saklamak için tasarlanmış iki basit işlev yazdım. Bu durumda işe yarayıp yaramayacağına kendiniz karar verebilirsiniz. Amaç, bir php değişkenini (diziyse, dizge veya nesne) bir dosyaya kaydetmektir.

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

Bunu ilginç buldum ve bu DAHA İYİ yol, çünkü biçimlendirilmiş diziyi bir dosyaya döküyoruz. Tekrar inşa etmemize gerek yok, sadece okuyun. Ayrıca, değişkenleri düzenlemek biraz kolaydır. Bunu asla büyük verileri depolamak için kullanmayacağım, ancak program modüllerini veritabanı olmadan saklamayı pratik buldum. Teşekkür ederim.
m3nda

7

Bu, pratik bir çözüm olarak ilham vericidir:
https://github.com/mhgolkar/FlatFire
Verileri işlemek için birden fazla strateji kullanır ...
[Benioku Dosyasından kopyalandı]

Serbest veya Yapılandırılmış veya Karışık

- 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

7

IMHO, evde bira yapmaktan kaçınmak istiyorsanız iki seçeneğiniz var:

  1. SQLite

    PDO'ya aşina iseniz, SQLite'ı destekleyen bir PDO sürücüsü kurabilirsiniz. Hiç kullanmadım, ama PDO'yu MySQL ile bir ton kullandım. Bunu güncel bir proje için deneyeceğim.

  2. XML

    Bunu nispeten küçük miktarlarda veri için birçok kez yaptım. XMLReader hafif, ileri okunan, imleç tarzı bir sınıftır. SimpleXML , bir XML belgesini diğer sınıf örnekleri gibi erişebileceğiniz bir nesneye okumayı kolaylaştırır.


5

Bu tür bir sistemde düz bir dosya veritabanında olası bir soruna işaret etmek için:

data|some text|more data

row 2 data|bla hbalh|more data

...vb

Sorun, hücre verilerinin bir "|" içermesidir. veya "\ n" ise veriler kaybolur. Bazen çoğu insanın kullanmayacağı harf kombinasyonlarına göre bölmek daha kolay olurdu.

Örneğin:

Sütun ayırıcı: #$% (Shift+345)

Satır ayırıcı: ^&* (Shift+678)

Metin dosyası: test data#$%blah blah#$%^&*new row#$%new row data 2

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

Veya bu çizgilerdeki herhangi bir şey. Ayrıca, düz dosya veritabanlarının küçük miktarda veriye (yani 20 satırdan az) sahip sistemler için iyi olduğunu, ancak daha büyük veritabanları için çok büyük bellek domuzları haline geldiğini ekleyebilirim.


Güzel nokta. Bunu bir adım öteye götürerek, PHP JSON'u gerçekten kolayca serileştirebilir. Girişten kaçmak çok daha basittir, bu nedenle dosyanın daha okunaklı olması için komik dize kombinasyonları kullanmanıza gerek yoktur.
Cypher
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.