Cơ sở dữ liệu tệp phẳng [đã đóng]


120

Các phương pháp hay nhất xoay quanh việc tạo cấu trúc cơ sở dữ liệu tệp phẳng trong PHP là gì?

Rất nhiều khuôn khổ tệp phẳng PHP hoàn thiện hơn ngoài kia mà tôi cố gắng triển khai cú pháp truy vấn giống SQL, ở trên cùng cho mục đích của tôi trong hầu hết các trường hợp. (Tôi sẽ chỉ sử dụng một cơ sở dữ liệu tại thời điểm đó).

Có bất kỳ thủ thuật thanh lịch nào để có được hiệu suất và tính năng tốt với chi phí mã nhỏ không?


1
Tôi muốn nói thêm rằng có một gói ở đây cho Cơ sở dữ liệu tệp phẳng github.com/tmarois/Filebase Tôi biết đây là một câu hỏi cũ, nhưng gói này là phiên bản được xây dựng và duy trì gần đây nhất, cộng với đầy đủ các tính năng mà bạn không thể bao gồm nhất. .
tmarois

Tôi đang phát triển CMS và tôi sử dụng cơ sở dữ liệu văn bản tệp văn bản phẳng. Phải mất nhiều giờ để chế tạo và nhiều giờ để khúc xạ nhưng nó hoạt động hoàn hảo. Các truy vấn sẽ được thực hiện nhanh hơn rất nhiều với cơ sở dữ liệu được lập chỉ mục và tối ưu hóa đầy đủ. Tuy nhiên, tôi tránh sự cần thiết của các truy vấn bằng cách lưu trữ dữ liệu meta và với tổ chức và cấu trúc cẩn thận. Khi tôi cần dữ liệu, tôi lấy nó mà không có for loop(trừ khi tôi đang sử dụng tất cả dữ liệu trong thư mục), do đó nó hoạt động nhanh hơn rất nhiều so với cơ sở dữ liệu. Tôi sẽ đi vào chi tiết và đưa ra một câu trả lời rất tốt nhưng rất tiếc câu hỏi này đã bị đóng lại.
Dan Bray

Câu trả lời:


75

Bản chất của cơ sở dữ liệu phẳng là gì. Chúng lớn hay nhỏ. Nó có phải là các mảng đơn giản với các mảng trong đó không? nếu một cái gì đó đơn giản nói rằng userprofiles được xây dựng như vậy:

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

và để lưu hoặc cập nhật bản ghi db cho người dùng đó.

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

và tải hồ sơ cho người dùng

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

nhưng một lần nữa việc triển khai này sẽ khác nhau tùy theo ứng dụng và bản chất của cơ sở dữ liệu bạn cần.


48

Bạn có thể xem xét SQLite . Nó gần như đơn giản như các tệp phẳng, nhưng bạn có một công cụ SQL để truy vấn. Nó cũng hoạt động tốt với PHP .


6
SQLite được xây dựng thành 5.0+ theo mặc định, nhưng được chiết khấu (!) Từ PHP 5.4+ trở đi !!! Khi tôi viết điều này vào tháng 7 năm 2012, SQLite sẽ không hoạt động trên các hệ thống cập nhật theo mặc định nữa. Tuyên bố chính thức tại đây
Sliq

Cài đặt trình điều khiển SQLite PDO khá đơn giản nếu bạn có quyền truy cập máy chủ. Trên Ubuntu / Debian chạy Apache2 chỉ apt-get install php5-sql dịch vụ apache2 restart
siliconrockstar

4
Phản ứng về nhận xét từ @Sliq, việc nói rằng "SQLite đã ... bị ngừng sản xuất" là đúng: phần mở rộng có tên "SQLite" đã bị ngừng và "SQLite3" hiện được bật theo mặc định. php.net/manual/en/sqlite.installation.php "Vì PHP 5.0 nên tiện ích mở rộng này được đóng gói cùng với PHP. Bắt đầu với PHP 5.4, tiện ích mở rộng này chỉ khả dụng qua PECL." php.net/manual/en/sqlite3.installation.php "Phần mở rộng SQLite3 được bật theo mặc định kể từ PHP 5.3.0." "Tiện ích này trong thời gian ngắn là một tiện ích mở rộng PECL nhưng phiên bản đó chỉ được khuyến nghị sử dụng thử nghiệm."
Paul van Leeuwen

Bạn đã không trả lời câu hỏi
JG Estiot

20

Theo ý kiến ​​của tôi, sử dụng "Cơ sở dữ liệu tệp phẳng" theo ý bạn (và câu trả lời bạn đã chấp nhận) nhất thiết không phải là cách tốt nhất để giải quyết vấn đề. Trước hết, việc sử dụng serialize()unserialize()có thể gây đau đầu CHÍNH nếu ai đó xâm nhập và chỉnh sửa tệp (trên thực tế, họ có thể đưa mã arbritrary vào "cơ sở dữ liệu" của bạn để chạy mỗi lần.)

Cá nhân, tôi muốn nói - tại sao không nhìn về tương lai? Đã rất nhiều lần tôi gặp sự cố vì tôi đã tạo các tệp "độc quyền" của riêng mình và dự án đã bùng nổ đến mức nó cần một cơ sở dữ liệu và tôi đang nghĩ "bạn biết đấy, tôi ước Tôi đã viết điều này cho một cơ sở dữ liệu để bắt đầu với "- bởi vì việc tái cấu trúc mã tốn quá nhiều thời gian và công sức.

Từ điều này, tôi đã học được rằng việc kiểm chứng ứng dụng của mình trong tương lai để khi nó lớn hơn, tôi không phải đi và dành nhiều ngày để cấu trúc lại là cách để tiếp tục. Làm thế nào để tôi làm điều này?

SQLite. Nó hoạt động như một cơ sở dữ liệu, sử dụng SQL và khá dễ dàng để thay đổi sang mySQL (đặc biệt là nếu bạn đang sử dụng các lớp trừu tượng để thao tác cơ sở dữ liệu như tôi!)

Trên thực tế, đặc biệt với phương pháp của "câu trả lời được chấp nhận", nó có thể cắt giảm đáng kể mức sử dụng bộ nhớ của ứng dụng của bạn (bạn không phải tải tất cả "RECORDS" vào PHP)


Đúng. serialize()cũng có thể khá hữu ích cho việc đó. Tôi nghĩ rằng mẹo để tạo ra một hệ thống khả thi là tìm ra cách nào đó để lập chỉ mục các nút dữ liệu mà không khiến bản thân trở nên phức tạp.
Holy_groceon

12

Một khuôn khổ mà tôi đang xem xét sẽ dành cho một nền tảng blog. Vì bất kỳ chế độ xem dữ liệu nào có thể có mà bạn muốn sẽ được sắp xếp theo ngày, tôi đã suy nghĩ về cấu trúc này:

Một thư mục cho mỗi nút nội dung:

./content/YYYYMMDDHHMMSS/

Các thư mục con của mỗi nút bao gồm

/tags  
/authors  
/comments  

Cũng như các tệp văn bản đơn giản trong thư mục nút cho nội dung kết xuất trước và sau và những thứ tương tự.

Điều này sẽ cho phép một glob()lệnh gọi PHP đơn giản (và có thể là sự đảo ngược của mảng kết quả) để truy vấn về bất kỳ thứ gì trong cấu trúc nội dung:

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

Sẽ trả về đường dẫn bao gồm tất cả các bài báo được gắn thẻ "vui nhộn".


9

Đây là mã chúng tôi sử dụng cho 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);
    }
}

?>

Nó lưu trữ mỗi mục nhập dưới dạng một tệp riêng biệt, mà chúng tôi thấy là đủ hiệu quả để sử dụng (không tải dữ liệu không cần thiết và lưu nhanh hơn).


8

Nếu bạn định sử dụng tệp phẳng để lưu giữ dữ liệu, hãy sử dụng XML để cấu trúc dữ liệu. PHP có trình phân tích cú pháp XML tích hợp sẵn .


Và tuân theo các quy tắc xml về khả năng đọc của con người hoặc bạn cũng có thể sử dụng tuần tự hóa hoặc json hoặc một cái gì đó.
Ben

Lời khuyên rất kém. XML không bao giờ được sử dụng. Đó là một quang sai chất béo.
JG Estiot

@JGEstiot Chăm sóc để giải thích thêm?
UncaughtTypeError

7

Nếu bạn muốn một kết quả mà con người có thể đọc được, bạn cũng có thể sử dụng loại tệp này:

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

Bằng cách này, bạn chỉ có một tập tin, bạn có thể gỡ lỗi nó (và sửa theo cách thủ công) dễ dàng, bạn có thể thêm các trường vào sau (ở cuối mỗi dòng) và mã PHP rất đơn giản (cho mỗi dòng, chia theo dấu |).

Tuy nhiên, hạn chế là bạn nên phân tích cú pháp toàn bộ tệp để tìm kiếm thứ gì đó (nếu bạn có hàng triệu mục nhập thì không ổn) và bạn nên xử lý dấu phân tách trong dữ liệu (ví dụ: nếu nick là WaR | ordz).


7

Tôi đã viết hai hàm đơn giản được thiết kế để lưu trữ dữ liệu trong một tệp. Bạn có thể tự đánh giá nếu nó hữu ích trong trường hợp này. Vấn đề là lưu một biến php (nếu nó là một mảng, một chuỗi hoặc một đối tượng) vào một tệp.

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

Tôi thấy điều đó thật thú vị và đây là cách TỐT HƠN, bởi vì chúng tôi chỉ kết xuất mảng được định dạng vào một tệp. Chúng ta không cần phải xây dựng lại nó, chỉ cần đọc vào. Ngoài ra, việc chỉnh sửa các biến cũng hơi dễ dàng. Tôi sẽ không bao giờ sử dụng nó để lưu trữ dữ liệu lớn, nhưng tôi thấy việc lưu trữ các mô-đun của chương trình mà không có cơ sở dữ liệu là thực tế. Cảm ơn bạn.
m3nda

7

Đây là một giải pháp đầy cảm hứng như một giải pháp thực tế:
https://github.com/mhgolkar/FlatFire
Nó sử dụng nhiều chiến lược để xử lý dữ liệu ...
[Sao chép từ tệp Readme]

Miễn phí hoặc Có cấu trúc hoặc Hỗn hợp

- 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, bạn có hai lựa chọn nếu bạn muốn tránh điều gì đó ở nhà:

  1. SQLite

    Nếu bạn đã quen với PDO, bạn có thể cài đặt trình điều khiển PDO hỗ trợ SQLite. Chưa bao giờ sử dụng nó, nhưng tôi đã sử dụng PDO rất nhiều với MySQL. Tôi sẽ thử điều này cho một dự án hiện tại.

  2. XML

    Thực hiện điều này nhiều lần đối với lượng dữ liệu tương đối nhỏ. XMLReader là một lớp kiểu con trỏ nhẹ, đọc-chuyển tiếp. SimpleXML làm cho việc đọc một tài liệu XML thành một đối tượng mà bạn có thể truy cập đơn giản như bất kỳ cá thể lớp nào khác.


5

Chỉ chỉ ra một vấn đề tiềm ẩn với cơ sở dữ liệu tệp phẳng với loại hệ thống này:

data|some text|more data

row 2 data|bla hbalh|more data

...Vân vân

Vấn đề là dữ liệu ô chứa dấu "|" hoặc "\ n" thì dữ liệu sẽ bị mất. Đôi khi sẽ dễ dàng hơn để phân chia theo các tổ hợp chữ cái mà hầu hết mọi người không sử dụng.

Ví dụ:

Bộ tách cột: #$% (Shift+345)

Bộ tách hàng: ^&* (Shift+678)

Tệp văn bản: test data#$%blah blah#$%^&*new row#$%new row data 2

Sau đó sử dụng: explode("#$%", $data); use foreach, the explode again to separate columns

Hoặc bất cứ điều gì dọc theo những dòng này. Ngoài ra, tôi có thể nói thêm rằng cơ sở dữ liệu tệp phẳng rất tốt cho các hệ thống có lượng dữ liệu nhỏ (tức là ít hơn 20 hàng), nhưng trở thành ổ chứa bộ nhớ lớn cho cơ sở dữ liệu lớn hơn.


Điểm tốt. Tiến thêm một bước nữa, PHP có thể tuần tự hóa JSON thực sự dễ dàng. Việc thoát đầu vào đơn giản hơn nhiều vì vậy bạn không cần sử dụng các tổ hợp chuỗi vui nhộn để tệp dễ đọc hơn.
Cypher
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.