Sample Wiki Engine

This is a sample wiki engine, written in Python. It’s meant as a learning aid, not a real tool: it lacks most functionalities, can serve only to one user at a time and stores all the page contents in memory – so they are gone when you restart it.


#!/usr/bin/python
# -*- coding: utf-8 -*-
import BaseHTTPServer, urllib, re

class Handler(BaseHTTPServer.BaseHTTPRequestHandler):
    template = u"""<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd"><html><head><title>%s</title>
</head><body><h1>%s</h1><pre>%s</pre><form action="" method="POST"
class="editor"><div><textarea name="text">%s</textarea><input type="submit"
value="Save"></div></form></body></html>"""

    def escape_html(self, text):
        """Replace special HTML characters with HTML entities"""
        return text.replace(
            "&", "&amp;").replace(">", "&gt;").replace("<", "&lt;")

    def link_repl(self, match):
        """Return HTML for link"""
        title = match.group(1)
        if title in self.server.pages:
            return u"""<a href="%s">%s</a>""" % (title, title)
        return u"""%s<a href="%s">?</a>""" % (title, title)

    def do_HEAD(self):
        """Send response headers"""
        self.send_response(200)
        self.send_header("content-type", "text/html;charset=utf-8")
        self.end_headers()

    def do_GET(self):
        """Send page text"""
        self.do_HEAD()
        page = self.escape_html(urllib.unquote(self.path.strip('/')))
        text = self.escape_html(self.server.pages.get(page, "Empty..."))
        parsed = re.sub(r"\[\[([^]]+)\]\]", self.link_repl, text)
        self.wfile.write(self.template % (page, page, parsed, text))

    def do_POST(self):
        """Save new page text and display it"""
        length = int(self.headers.getheader('content-length'))
        if length:
            text = self.rfile.read(length)
            page = self.escape_html(urllib.unquote(self.path.strip('/')))
            self.server.pages[page] = urllib.unquote_plus(text[5:])
        self.do_GET()

if __name__ == '__main__':
    server = BaseHTTPServer.HTTPServer(("127.0.0.1", 8080), Handler)
    server.pages = {}
    server.serve_forever()

To try this wiki, just run it with a Python interpreter on your computer, and point your web browser to http://127.0.0.1:8080.

This engine uses build in web server from Python’s standard library, BaseHTTPServer, so that you don’t need to setup your own web server or look for hosting services just to play with it. We provide this server with a custom request handler, that supports three kind of requests:

There is a lot of space for improvement:

I’m also writing down a detailed process in which I came up with this code (minus obvious errors and some frustration with empty POSTs) at Step By Step Wiki Engine.