drew.d.lenhart

programming, software, technology, anything on my mind...

PHP Flat-File Blog System Demo

2015/07/07

Last year, around the time I created this blog, I was really looking into Flat-File blog systems. I was looking to create this blog into something really small in size, easy to use, and easy to update. I did a lot of research and found many options as well as an article proclaiming 2014 Will Be the Year of the Flat-File CMS. Although there is a lot out there, I don't think 2014 was the year of the Flat-File CMS. As you probably notice I eventually went with Wordpress.

There are TONS of Flat File CMS's out there, to name a few: Kirby Stacey Jekyll

What is it?

A Flat-File CMS or blog is a system where the content, such as pages or posts are stored in flat files, such as text files or mark down.

So whats the advantage? Small size, NO database, fast loading, and portable! I also think since there is no database involved, that is a huge advantage with the site being more secure.

Code

Well being the way that I am, I always tend to "re-invent the wheel" when I approach new projects. Seriously, the best way to learn something is to re-create the process! The code for this tutorial is a stripped down version of the code that I continue to update now and then (hey, it's been an ongoing project), but the core functionality of reading posts from files is here.

See a quick DEMO here.

I basically created two classes, one for displaying a list of posts in the "Posts" folder (the main listings page), and the other for reading the individual posts. All posts will be kept in the "/posts/" as .txt.

list.class.php

<?php
## Desc: lib/list.class.php - Class for reading posts dir & returning values in array
## Auth: Drew D. Lenhart
## http://www.drewlenhart.com
## 07/05/15

class listArticle {

    private $directory;
    public $article;
    public $dir;
    protected $file;
    public $output;

    public function __construct($file) {
        $this->file = $file;
    }

    public function indexCont($directory) {

        $dir = opendir($directory);
        //store filenames in array
        $results_array = array();

        while (($file = readdir($dir)) !== false) {

            $filename = $directory . $file;

            $info = new SplFileInfo($filename);
            $res = $info->getExtension();

            //make sure its a .txt file
            $type = filetype($filename);
            if ($type == 'file' && $res == 'txt') {
                //If its a file and its type is txt
                //store filenames in array
                $results_array[] = $filename;
            }

        }
        closedir($dir);

        $articles = array();

        foreach ($results_array as $filename){
            //get the contents of each file.. store in $articles array and return

            //open file
            $open = fopen($filename, 'r');

            //get the contents of the file
            $content = stream_get_contents($open);

            //get the json meta data.
            $content = explode("#content#", $content);
            $raw = array_shift($content);

            //decode json meta data in each .txt
            $json = json_decode($raw,true);

            //now implode, and grab after #content#.
            $content = implode("#content#", $content);

            $title = $json['title'];

            $author = $json['author'];
            $date = $json['date'];

            //$content = $json['content'];
            $slug = $json['slug'];

            //store everything in an array.
            $articles[$filename] = array('auth' => "$author",
                                             'title' => "$title",
                                             'date' => "$date",
                                            'slug' => "$slug",
                                            'content' => "$content");
        }
        //Return all articles in $articles array
        return $articles;
    }   
}
?>

posts.class.php

<?php
## Desc: lib/posts.class.php - Class to Display individual posts
## Auth: Drew D. Lenhart
## http://www.drewlenhart.com
## 07/05/15

class listPost {

    public $directory;
    public $article;
    public $dir;
    protected $file;
    public $output;

    public function __construct($file) {
        $this->file = $file;
    }

    public function readPosts($dir , $article) {
        $extention = ".txt";
        $filename = $dir . "/" . $article . $extention;

        //open file
        $open = fopen($filename, 'r');

        //get the contents of the file
        $content = stream_get_contents($open);

        //get the json meta data.
        $content = explode("#content#", $content);
        $raw = array_shift($content);

        //decode json meta data in each .txt
        $json = json_decode($raw,true);

        //now implode, and grab after #content#.
        $content = implode("#content#", $content);

        $title = $json['title'];

        $author = $json['author'];
        $date = $json['date'];

        $output = "<h2>" . $title . "</h2>";
        $output .= "By: " . $author . " - " . $date . "<br /><br />";

        $output .= $content;

        return $output;

    }
}
?>

index.php - Display a listing of posts

<?php
## Desc: index.php - Display all posts
## Auth: Drew D. Lenhart
## http://www.drewlenhart.com
## 07/05/15

require_once("lib/list.class.php");
include("includes/header.php");

$reader = new listArticle();

//get the article list from controller
//posts are in the posts dir
$rc = $reader->indexCont("posts/");
?>

<?php
//loop out each article and display accordingly
foreach ($rc as $articles){
    $output = "<h2>" . $articles['title'] . "</h2>";
    $output .= "By: <em>" . $articles['auth'] . "</em> - " . $articles['date'] . "<br /><br />";

    //only list first 200 characters from content. Also strip tags so it doesnt show html on listing page
    $content = strip_tags($articles['content']);
    $content = substr($content, 0, 200);

    $output .= $content . " <a href='posts.php?post=" . $articles['slug'] . "'>Read More>>></a>";
    $output .= "<hr>";
    echo $output;
}
?>

<?php
include("includes/footer.php");
?>

Post Example

Here is an example of a sample post in text format. Keep all posts in the /posts directory, otherwise change the location when calling methods. Use a simple editor such as Notepad or Textmate to create posts! The PHP class reads the meta data at the top, and content is separated by using the explode() function, see the listPost class above!

{
    "title": "None",
    "author" : "Drew Lenhart",
    "date" : "2015-03-09",
    "slug" : "post3"
}
#content#
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean nisl mi, eleifend laoreet ullamcorper quis, fringilla sit amet odio.

Proin semper luctus dui. Duis malesuada ipsum magna. Praesent faucibus accumsan rutrum. Vivamus sagittis magna nec tortor fermentum tincidunt. Ut nec suscipit lectus. Pellentesque iaculis nulla fringilla sapien pellentesque adipiscing. Vivamus imperdiet fringilla iaculis. Maecenas nisi erat, dapibus id tincidunt vel, feugiat et nunc. Curabitur laoreet massa in tellus consectetur iaculis.

Donec pellentesque elementum dui, non tempor nibh sodales a. Morbi vitae nulla sed sem auctor ornare. Suspendisse potenti. Sed ornare adipiscing porttitor. Vivamus velit nisi, accumsan at adipiscing eu, egestas at sapien. Maecenas diam eros, scelerisque non luctus sed, pharetra a augue. Cras sit amet tortor urna. Maecenas egestas, nibh sit amet dictum dapibus, nibh nulla pellentesque urna, ut suscipit enim dolor id sapien.

Download the code for this project and drop anywhere that runs PHP. Change and alter to meet your needs. Study and learn!

I want to make mention of a similar tutorial on Tuts Plus by Shameer C. He created a Flat File Blog using the Slim framework. I used some of the same flow in my project as well as the post format. Check out Shameer's post, its worth the read!

TODO: *Some items I think need added to make more robust:-Arrange listings by date -URL router (e.g. sitename/posts/postname) -Template system

Download project code - TFFB - The Flat File Blog System

Github!