POST_FORMAT - index

Internal Post Format

A THIS post (also called an entry or a record) is stored in the database as text, which is weird, we know, but there is a reason for it. The database table is simply an INT named id and a TEXT named body.

See DATABASE for a better explanation of the database design (which includes a discussion of some of it's shortcomings).

The text format is just like the RFC for Mail Transport Something or Other; one or more colon delimited word identifiers and text as a header followed by a blank line followed by body text. Here is an example:

        title: Post Format
        date: Jun-17, 2010

        This post format is too weird!

Now, immediately, several people just yelled at us to put title, date in the database like normal people! Well, we do things differently than everybody else for a reason. Before we justify this, let me explain that the web forms are designed so that one does not have to type posts in this manner. Which means no one is going to have to fill in a TEXTAREA like this:

        +-----------------------------+
        | title: MYSQL                |
        | date: Jun-17, 2010          |
        |                             |
        | Hey, does it work yet?      |
        +-----------------------------+

The form provides an input for the title, and the date is automatically generated, of course. The data is just stored this way in the database.

This is to be able to customize the database without customizing the database.

We repeat, You customize the database without customizing the database.

We provide a real example.

If you want to add a field to the header, say, um, color — you want to add a color to all your posts. To do so requires about three steps:

  1. Modify your web form, to your pleasing, to accept a color.
  2. Modify your web template that displays a post to use the color.

Wait, that's only two. That's right. Two steps. That's all.

"Wait a minute," someone shouts from down the hall. "It can't be that simple!" Well, let's see.

Here is our form:

        <form>
        Title: <input text name="title"><br>
        Post: <textarea name="body"></textarea>
        </form>

Here is our input handler function:

        $data = "date:" . date("M-j, Y\n");
        foreach ($_POST as $name => $value)
        	$data .= "$name:$value\n";

Which collapses all the POST data into a string that looks like this:

        "date:Dec-25, 2012\ntitle:TITLE\nbody:TEXTAREA\n";

Here is our write to the database function:

        mysql_query("INSERT INTO data (body) VALUES ('$data')");

This is our read from the database function:

        mysql_query("SELECT body FROM data WHERE id = 1");

Which reads that string back.

This is the create record function:

        $data = explode("\n",$data);
        foreach ($data as $str) {
        	$header = explode(":",$str);
        	$record[$header[0]] = $header[1];
        }

(There are three obvious problems with this code:

  1. The title input could contain colons;
  2. The body input could too and does have a newline;
  3. This uses "body:" for the body rather than "\n\n".

The real code handles these things, and more, like empty fields. Such code is quite simple but we do not need to see it here.)

And finally, here is our HTML template used to display the record:

        <div>
        <span>{$record['title']}</span>
        <span>{$record['date']}</span>
        <div>{$record['body']}</div>
        </div>

(Which actually has class identifiers and really nice CSS.)

And, here is how you add color.

Modify the form:

        <form>
        Title: <input text name="title">
        Color: <select name="color">
        <option>red</option>
        <option>green</option>
        <option>blue</option></select><br>
        Post: <textarea name="body"></textarea>
        </form>

Modify the template:

        <div style="color:{$record['color']};">
        <span>{$record['title']}</span>
        <span>{$record['date']}</span>
        <span>{$record['body']}</span>
        </div>

That is all.

Our other motto is: Design for data well and your code will be simple.

Of course, you probably see the flaw. There actually are three steps. Which leads to the next section.

Functionality

Let's say you want to add functionality to your posts — and in the case of the colorizing we need to in order to support older posts that would not have the color field.

We need to add some functionality to the code. After the data is read and turned into a record, there is some "post processing" of it to handle situations just like this. For example:

        function processrecord($record) {

        	if (!isset($record['color']))
        		$record['color'] = "red";

        	// whatever else you want here

        	return $record;
        }

(This is also where one would modify stuff, like processing the body to support BBCode.)

Now it's time for some more gritty details.

Now That's Sick!

Someone actually said that to us once, because, we do something really, truly weird here. If a header exists by the name usercode, it's value is used to look up what we call a "user defined function":

        if (isset($record['usercode']))
        	usercode($record);

What the usercode() function does is to read PHP code from an external file and execute it on the record. This usercode is stored in an INI file, like this:

        [red]
        $record['body'] = "<span style='color:red;'>{$record['body']}</span>";

The result is that if there was "usercode:red" in the record header, the record body would be wrapped in HTML that turns the body red.

Someone in the next apartment is banging the wall and shouting, "Why would you possibly want to do that?"

To modify the code without modifying the code.

(I imagine you got that on the first read.)

Typically, when code needs to be modified, one edits a PHP file locally and then uses something like FTP to put that file to the server, overwriting the existing file.

What this usercode thing does is to allow the Admin, via the Admin Web Page, to edit the INI file, add the "[red]" section as outlined above, and, still using the Admin Web Page, edit the two Web Templates as outlined above (with a slight change we'll show) to essentially modify the program, without modifying the program.

(There are, of course, safegaurds in place, and only a post record is allowed to be modified, with temporary copies if something goes wrong, and other stuff like that. And there is more... of course.)

Here is the change to the above form:

        Color: <select name="usercode">

Notes

1. The actual implementation is:

        CREATE TABLE data (id INT AUTO_INCREMENT UNIQUE, body MEDIUMTEXT)

2. Eric S. Raymond: "Under Unix, this is the traditional and preferred textual metaformat for attributed messages or anything that can be closely analogized to electronic mail. More generally, it's appropriate for records with a varying set of fields in which the hierarchy of data is flat (no recursion or tree structure)."
3. Well, actually, you do as Administrator!