qb is a blog system by Tim 'Scytale' Weber for people who:

  • don't want to install a database server for a blog that sees a new post every two months
  • want performance nevertheless
  • like to be able to send entries via SCP, cronjobs or other obscure methods
  • maybe want to hack on the code together with a friendly, enthusiastic developer and some contributors

Warning: Since October 12, 2008, qb has no maintainer and is not actively developed or supported. However, the current codebase works fine and there are no known security issues. You are encouraged to become qb's new maintainer if you think it is worth it.

There was once a mailing list which is now discontinued. The list is archived at Gmane, Google and mail-archive.com. If you need to contact the former developer, for example because you found a security bug or want to take over maintainership, please use one of the ways described on contacting Scytale. Please don't ask for support, my spare time (or the lack of it) doesn't allow for this.

System Requirements

"Not tested" doesn't mean it's not going to work, just give it a try. If you managed to run qb on something "not tested", drop us a note.

Getting qb

qb's official web site is at http://scytale.name/proj/qb/. There are several possibilities available to get the code:

You can have a look at the developer's changelog or the version control changelog.


Warning: This documentation is updated while qb's development goes on. If you are reading this file online, keep in mind that the information herein describes qb's current "bleeding edge" Git version. If you downloaded a release tarball, please refer to the README.html that's included there instead.

Copy all files into a directory somewhere inside the Document Root of your webserver. You can use a subdirectory or the Document Root itself. If you're running Apache, you may want to move the htaccess file to .htaccess or create a symlink to it. Lighttpd users may instead want to delete it, although you might as well simply ignore the file.

Inside the lib directory, copy qb-0.2.conf.dist.php to qb-0.2.conf.php and edit it according to your needs. (Don't be afraid of its name, even if you downloaded a 0.3 release. See qb versioning below.)

You may wish to create your own templates (find them in tpl/) and CSS. The templates to use are specified in qb.cfg.php, the CSS in the template. You can find a list of template tags below.

Make sure your web server can write to the QB_META directory.

Start putting files with your configured suffix (default: .qb) into the src directory.

Content File Syntax

Each content file consists of a header (the first line) and a body (everything else). The header consists of several tags formatted like <NAME:VALUE>, where NAME will be the name of a template variable and VALUE its value.

There are some special things: If you don't supply a NAME, it's the same as setting it to "title", therefore you can supply the entry's title like <:My cool entry> or <title:My cool entry>, it's equivalent.

Then there's the <tags:> tag where you can supply some tags for the entry. Those are available in the template via spantags and ultags, depending on whether you like <span class="tag"> or <ul class="tags"><li>... more. Soon one will be able to search for certain tags as well. Specify the tags as in Flickr, i.e. seperate them with spaces and put double quotes around multi-word tags:

<tags:example documentation boring "all your tags are belong to us" omg>

Last but not least there's the <via:> tag where you can place a link to another blog to cite as source:

<via:<<http://example.com/blog/23-foo.html ExBlog>>>

(See below for the default "link" syntax.) You can also put unlinked text in it:

<via:Fefe's Blog>

There'll probably be a trackback function soon.

You can add other tags if you want to, their values will be available in the templates like any other ones.

The body contains HTML code plus some regex shortcuts. With the default config you can write things like

<<http://example.com/link Description>>

which will then translate to

<a href="http://example.com/link">Description</a>

There's other stuff like <wXX:Lemma Description> which will link to http://XX.wikipedia.org/Lemma. Please note that for those Wikipedia links spaces in the article name (that is, the link target) will have to be replaced by underscores like this: <wen:Linus_Torvalds Inventor of Linux>, which will look like Inventor of Linux.

URL Schema

Suppose you've installed qb in a subdirectory called qb on your web server scytale.name and you've activated the supplied .htaccess file. Now every request that starts with http://scytale.name/qb/ will be handled by qb.

qb will map the path on the web server to its "source" directory (by default src). That means, if someone sends a request to http://scytale.name/qb/foo, qb will search first for a directory src/foo. If it exists, it will display all .qb files in that directory and its subdirectories, ordered by their creation date, newest first. This allows you to organize your files in a flexible way. For example, you can throw all your blog entries directly in the source directory (creative chaos), put them under different directories depending on the content (like coding, politics etc.) or in date-based directories (like 2007/05/30). In the last example, someone requesting http://scytale.name/qb/2007 will see all your entries in the 2007 directory and its subdirectories.

If there's no directory with that name, qb will look for a .qb file matching. For example, the request http://scytale.name/qb/foo will look for src/foo.qb. If that doesn't exist also, an "not found" error message will be sent.

If you are not using the .htaccess file to alias the whole directory to qb, you can also use the qb.php file as the request handler. Your URLs will then look like this: http://scytale.name/qb/qb.php/2008/some-article. No matter if you call qb via qb.php or using the .htaccess, this should be recognized and configured automatically. Contact me if it doesn't, it's a pretty new feature.

There are two other special things that may be passed as "query" part of the URL, i.e. after a question mark. First, you can pass a template name. This is how the Atom feed works: You pass http://scytale.name/qb/?atom10 in the URL, and qb will use the qb.article.atom10 and qb.template.atom10 template files in its source directory, which will output a valid Atom feed instead of HTML data.

Second, if the query part is a positive integer, it will be interpreted as page number. http://scytale.name/qb/?3 will therefore refer to page three of the articles. Page numbers are used if the number of articles that would match a certain request is larger than the maximum number of articles per page set in the config file.

Note that I consider this URL format quite crappy, and it will change in later versions. But rest assured that I will do everything to keep old links from breaking. And I'm quite good at that: My blog exists for several years now and went through two different authoring softwares as well as three different directories and a domain change. And yet even links to the very first article still work.

Meta Information

Since most current Unix systems do not store file creation times (only the modification time), qb uses a dirty workaround that can be seen in the meta directory of a qb installation. In this directory there are .cre files stored for each .qb file in the source directory. Their modification time is used as creation time of the source files. That means that for each .qb file displayed, qb will check whether its .cre file exists. If it doesn't, it is created and its modification time set to that of the .qb file. This timestamp is never changed, in contrast to that of the .qb file when you change it.

The meta directory needs to be writable by the web server for obvious reasons (on a side note, the source directory needs not). It will contain the same subdirectories as the source directory. If you delete or move around files in the source directory, orphaned files will not be automatically deleted or moved to the new location.

Template Tags

qb does nothing to your articles but run some regular expressions over them and aggregate the results. In order to include things like the current page number etc. in the output, there are special strings called "template tags", that look like XML tags. For example, the current page number can be included in a template like this: <qb:thispage/>

Here's a list of available template tags and what they do. All start with the prefix qb:, and I won't explicitly repeat that prefix in the following list.

Number of pages the current view has generated. Useful for "page x of y" constructs.
Same value as numpages, but only set if the number is greater than 1. Allows you for example to only display a pager if there really are other pages than the current one, see ifset below.
The number of the page that is currently being displayed.
If there is a "next" page available (i.e. thispage < numpages), this tag contains its number. Else it is not set, allowing you to only display a "next page" link when there actually is such a thing.
Same as nextpage, but in the other direction. Duh.
The content data. In an article template, this contains the content of the current article, after all regex substitutions have been made. In a page template, this contains the HTML content of all the articles that are to be displayed on this page.
Same value as "content", but XML special characters are replaced by their respective entities.
The tags set for the current article, each contained in a <span class='tag'> tag. Unset in page templates or if there are no tags.
The tags set for the current article, each contained in a <li> tag, wrapped inside an <ul class='tag'>. Unset in page templates or if there are no tags.
The value you set in QB_AUTHOR. At some point in the future, when qb supports multi-author blogs, this will of course contain the author of the current article.
The value you set in QB_BLOGNAME.
A Unix timestamp (seconds since the Epoch). In an article template, this contains the time of the last modification to this article (creation is a modification as well). In a page template, this contains the same value as the youngest article on the current page. In the "article not found" message, this contains a value that represents "now".
A Unix timestamp, existing just in article templates. Contains the article's creation time.
If modified and created contain the same value, this tag is unset. Otherwise it contains the value of modified, enabling you to only display the modification timestamp if a modification really occured.
Only available in an article template. Contains an absolute URL path to the current article. Note that "absolute" means "starting with a slash", not "starting with http://".
A string consisting of http:// (or https://), the server name and port, serving as the basis for building URLs. Does not end in a slash, and the port is only included if it's not the default port of the scheme (80 for http, 443 for https).
The complete URL to the currently displayed page, but without the query string. Useful for building query strings, for example for pagination.
The path where qb is installed, not ending in a slash. Useful for constructing links to CSS files and stuff.
The absolute path to the qb handler, i.e. the script name that will be prepended to the virtual file name. If you're using the supplied .htaccess file, this might as well not end in qb.php but just use the path where qb is installed (and is, in that case, identical to basepath.

There are four special tags you can use that contain not only a value, but perform additional logic:

If you want parts of the template to be included only if a certain tag is available, enclose that part of the template into <qb:ifset:tagname>...</qb:ifset:tagname>. For example, to only show a "modified date" line if the file really has been modified, use something like <qb:ifset:wasmodified>Modified at <qb:wasmodified/></qb:ifset:wasmodified>.
Like ifset, just the other way round.
This can be used to convert a numeric Unix timestamp into any format PHP's date() function supports. The text content of this tag is split into two parts, the first one being all the digits from the start of the string up to the first non-digit, the second one being all the rest (but excluding any leading spaces). These two things are then simply passed to date() as timestamp and format string parameter, respectively. An example would be something like <qb:date><qb:created/> j. n. Y, H:i:s (T)</qb:date>.
Should be put around everywhere you construct a path, for example a combination like <qb:basepath/>/qb.css. In its current version, cleanpath will simply remove double slashes, which is necessary in the above example if the base path is "/". Soon, cleanpath should do things like protect you a bit from path traversal attacks etc. as well.

Additionally, you can create your own article template tags by simply including a new tag name in the article's header line. A sample header line could look like <:Five Years><tags:music Björk song><mood:destructively sad>, and a template construct like <qb:ifset:mood><qb:mood/><qb:ifset:mood> would then display the mood you're in.

The values of created and modified can be specified (as an Epoch integer) in the first line of a content file as well. If they are, they override the actual file metadata. This is useful if you can't, for whatever reason, change the file metadata, but the contents. When overriding, you may choose to specify only one or both of them. Also, you can set modified to the special value ! (just a single exclamation mark), which will instruct qb to set the modified value to that of created, effectively making the entry appear as though it has never been modified at all.

Backing Up and Moving a qb Installation

Since qb is only using plain text files, it's easy to create a backup. You don't have to create database dumps and all that. The only thing you'll have to take care for is to keep the correct time stamps.

If you would like to move a qb installation to a different directory or web server, here are some common pitfalls:

  • Make sure the modification timestamps of your files in the source and meta directory will not be changed. Else you'll lose the timestamp information, and article order will be seriously screwed up.
  • Check the permissions of your meta directory. The web server needs to be able to create new files and directories there.
  • Don't forget the .htaccess file and to check your config file whether they are up to date.


qb versioning

qb is still far from complete (although it does everything that's currently implemented quite well), therefore its version number is still below 1.0. For those interested, here's an overview of the versions that already existed, why they were called that way and what's going to come up next. Details about the changes between various versions are available in the changelog.

The versioning scheme is quite simple: major.minor.revision. There are no "stable" and "unstable" versions like for example in Linux, all releases are (hoped to be) stable.

The current major version is 0, meaning that qb is not feature-complete enough and the internal architecture is not fixed enough yet to be considered a "complete" product. It will change to 1 once I consider qb to be serious competition to Wordpress; feature-wise, not with regards to security bugs. A major number change is expected every few years.

Minor numbers advance every time a major step in development has been finished. This can be one or more new features, internal restructuring of the code, or both. New minor versions are expected to come up every few months.

If something goes wrong in a x.y.0 release (usually some kind of bug), a new release will be published, having the revision number increased by one. They do not contain new features, but rather fix existing ones.

The 0.2 version, for example, saw two revisions right at the same day the original version was released, because not enough testing went into a new feature and it behaved wrong in exceptional cases. I've learned from these mistakes, and for 0.3 there will be beta "releases" and release candidates.

Beta releases (or beta tags, as they should be called more correctly), are not released at all, at least not via the usual "tarball" method. When working on a new release, at some points I consider the current code base quite stable, and to encourage testing I tag those as "0.3.0b1" (meaning "beta 1") or something in Git. People who are running the Git version and looking forward to the new release can then try out this beta version to have an early preview on what the next big things are going to be. If you're a Git user, but too afraid to update to arbitrary commits, you are encouraged to try out the beta versions.

Release candidates are just what the name implies: Something that might end up being a release. That means I have tested it and consider code and documentation to be stable. However, I cannot test all the rare scenarios other people use qb in, and therefore ask kindly for testing of the candidate by every current user, regardless of whether they use Git or just tarball releases. To support this, I build a complete tarball just like for an ordinary release. Depending on the feedback I receive, the final release will appear sooner or later, but not sooner than two weeks after the last release candidate.

Finally, a short story of qb versions:

After working on my own blog software for a day or two and it seemed to be working quite nice on my own web site, I decided to release it to the public, not only because maybe someone else was as fed up with Serendipity as I was, but also because some of my friends asked me to do it (thanks!).
Some days later, the number of articles on my new qb blog had increased up to a point, where the possibility of splitting the output into multiple pages was quite needed. So I took the time to include a pagination feature and comment the code, creating the 0.2 release. Because of some minor bugs in the code I had to rush out two more releases at the same day and decided to do better testing next time.
After 0.2 it became clear that qb needs quite a lot of new features. Unfortunately, this was pretty hard to do with the current, hackish architecture. Therefore I decided to do a complete rewrite and make qb a kind of extremely customizable framework written in object-oriented PHP. But since development should continue while rewriting, enabling users to exploit possible new features, all the new code is placed into the current codebase, replacing it more and more. As soon as the old code has been removed completely, the result will be called qb 0.5. In order to make the transition a little less sudden, version 0.3 was created, that partly uses 0.2 code but also takes advantage of new techniques like auto-detection of the path where qb is installed.
I'm not quite sure whether there will be another intermediate release before 0.5. If it's going to happen, this is what it will be called. Else there will be no version 0.4.
This will be the first completely object oriented, frameworkish release. Feature-wise 0.5 will be quite comparable to the 0.2 releases, e.g. there will still be no comment feature. But the things "under the hood" will have changed quite a lot, and new features should be very easy to integrate by then.