Markdown Quick Blog

If you've been following my recent antics on the web, you'll know I'm totally insane about Markdown.

It's extremely addictive. Probably because I can write stuff extremely quickly and efficiently, and I love the way it allows me to pop links and stuff in really quickly. And I love the way it displays code:

a [magical link](#) like a **boss**

So here's an idea. Let's write a Markdown quick blog! In a night.

A Markdown Quick Blog. Or mdqblog for short ;)

Structure

The file structure is going to look someting like:

index.php
php /
    Folder with the PHP structure.
theme /
    footer.md
    header.md
    page.php
    write.php

The idea behind page.php is I would like one page as the main reading page, and write.php to be the writing page.

Application

So, after a couple of hours, I've got a stable structure up, and a basic application.php up :)

<?php

    define('HTML_HEAD_TITLE','My Markdown Quick Blog.');
    define('HTML_BODY_HEADER','theme/header.md');
    define('HTML_BODY_FOOTER','theme/footer.md');

    define('USERNAME','');
    define('PASSWORD','');

    define('BASE_URL','http://dev.jdrydn.com/mdqblog/');

    require_once('functions.php');
    require_once('markdown.php');

    class Application {

        private $filename = 'blog.md';

        public function get() {
            if (file_exists($this->filename)) return file_get_contents($this->filename);
            else return null;
        }

        public function load($page,$params=array()) {
            if (!empty($params)) {
                foreach ($params as $key => $value) {
                    ${$key} = $value;
                }
            }
            require("./theme/$page.php");
        }

        public function update($new,$replace) {
            if ($replace) file_put_contents($this->filename,$new);
            else file_put_contents($this->filename,$new,FILE_APPEND);
        }

    }
?>

The constants are pretty important, as these are literally the variables for each "blog".

The methods for Application are fairly simple. A get() that fetches the content. A load() to quickly load pages (inspired by exp0) and an update() method to append / replace content.

functions.php contains short functions designed to make daily PHP tasks easier, like prettyprint() for debugging, redirect() for redirecting to pages, and isLoggedIn() for detecting if the user is logged in.

markdown.php contains Michel Fortin's PHP Markdown implementation that allows PHP to convert Markdown into HTML code. Thanks Michel!

Now, using a clever switch() {} in PHP, I can create a little website:

switch($path[1]) {

    case 'edit':
        $app->load('write',array('content'=>$app->get()));
    break;

    case 'login':
        if (empty($_POST)) $app->load('page',array('login'=>true));
        else {
            if ( ($_POST['username'] == USERNAME) && (sha1($_POST['password']) == PASSWORD) ) {
                $_SESSION['user'] = true;
                redirect(BASE_URL);
            }
            else $app->load('page',array('content'=>'Username / Password incorrect :('));
        }
    break;

    case 'logout':
        session_destroy();
        redirect(BASE_URL);
    break;

    case 'write':
        if (isLoggedIn()) {
            if (empty($_POST)) {
                $app->load('write');
            }
            else {
                $post = stripslashes($_POST['post']);
                if ($_POST['replace'] == 'true') $replace = true;
                else {
                    $post = "\n\n&nbsp;\n\n$post";
                    $replace = false;
                }
                $app->update($post,$replace);
                redirect(BASE_URL); exit();
            }
        }
        else $app->load('page',array('content'=>'Error 403 - You are not authorised to access this page.'));
    break;

    case '':
        $content = $app->get();
        if (empty($content)) {
            $content = 'There is no content... yet!';
        }
        $app->load('page',array('content'=>$content));
    break;

    default:
        $app->load('page',array('content'=>'Error 404 - Page not found.'));
}

And now you can see how the mdqblog works. /write will trigger the case 'write': clause. /login will trigger case 'login':. And so forth.

And with that done, it's time to write the page.php that will display all this stuff.

This is when I can start to use my constants. So:

...
<title><?php echo HTML_HEAD_TITLE;?></title>
...

...
<?php if (file_exists(HTML_BODY_HEADER)) echo Markdown(file_get_contents(HTML_BODY_HEADER)); ?>
...

...
<?php if (file_exists(HTML_BODY_FOOTER)) echo Markdown(file_get_contents(HTML_BODY_FOOTER)); ?>
...

I've also added a little bit of Javascript, so if a user is logged in and viewing their blog, they can click on a light little div and a <textarea></textarea> field will expand and they can write to their hearts content!

Of course, if they want a dedicated writing page, then all they need to do is check out /write, and they can type away!

And if they make a mistake, /edit will load up write.php (just like /write does) and place the blog's current content in the <textarea></textarea> like a ninja*.

Finishing up

It's 1am on Sunday. And that's the first prototype of mdqblog :) I've just posted it on Github if you want to check out the full code.

Bear in mind, this hasn't been tested for any security / stablilty, so it's probably going to be horribly unstable. On the flipside, it could work outta the box.

Possible extensions

 

*Like a pretend ninja. Why would it do it like a proper ninja?