Python Programming, news on the Voidspace Python Projects and all things techie.

Saving Files with Javascript and a Python CGI

emoticon:envelope Silverlight doesn't have a save file dialog. This may change before Silverlight 1.1 comes out of alpha. In the meantime, it is very easy to provide the same functionality with a hidden form, a bit of Javascript and a Python CGI.

The first step is creating a Python CGI that can receive a filename and data posted to it, and will respond with the correct headers to trigger a save file dialog in the browser.

A save / open dialog from the browser.

The following code should do the trick!

#!/usr/local/bin/python2.4 -u

import sys
import cgitb

import cgi
from urllib import unquote

errorhtml = '<html><head><title>Oops, invalid data...</title></head><p>Oops, invalid data...</p></html>'
serverline = "Content-Type: text/html\r\n\r\n"

responseline = '''Content-Type: application/octet-stream
Content-Disposition: attachment; filename= "%s"
Content-Length: %s

. replace('\n', '\r\n')

def exit():

form = cgi.FieldStorage()

data = {}
for field in form.keys():
   if not isinstance(form[field], list):
      data[field] = form[field].value

if not 'filename' in data or not 'data' in data:

filename = unquote(data['filename'])
file_data = unquote(data['data'])

sys.stdout.write(responseline % (filename, len(file_data)))

The important part in triggering the save file dialog from the browser is the headers sent in responseline. This CGI needs to be sent a 'filename' and a 'data' parameter to work.

So how do we trigger this from our code? We can use a hidden form and trigger a submission from Javascript.

Here is the html for the form:

<form name="saveform" action="/cgi-bin/" method="POST">
    <input type="hidden" name="data" />
    <input type="hidden" name="filename" value="" />

To submit this from Javascript we do the following: = editAreaLoader.getValue('code');

The call to editAreaLoader.getValue('code') is how we get the Python code out of the EditArea code editor - but you can set the hidden input field member value to whatever you want...

Like this post? Digg it or it.

Posted by Fuzzyman on 2007-08-19 19:51:24 | |

Categories: , ,

Akismet 0.1.5

emoticon:pencil Python Akismet 0.1.5 is now available.

Fixed a typo/bug in submit_ham. Thanks to Ian Ozsvald for pointing this out.

Python Akismet is a Python interface to the Akismet, spam blocking web-service. It is aimed at trapping spam comments.

The Python interface comes with an example CGI.

Like this post? Digg it or it.

Posted by Fuzzyman on 2007-02-05 21:00:50 | |

Categories: , ,

Is CGI Dead ?

emoticon:world With the recent rise of web frameworks, like Ruby on Rails, Django, Turbogears and friends, it might be fair to assume that the old workhorse CGI can be put out to pasture.

Well as recently as July [1], Bruce Eckel blogged about Testing Python CGIs.

CGI is a simple protocol that describes how a webserver passes http requests to a program, and how that program makes a response.

The beauty of CGI is it's simplicity. Most of the request [2] is passed on stdin, and the program passes a response back to the server on stdout.

The Python CGI Module makes understanding http requests very easy. To send a response, write to stdout.

CGI is still a very good way of connecting simple programs to the web. It's also a great way of cutting your teeth with web programming, particularly learning about http. In fact WSGI (the new Python protocol that aims to allow components in a webstack to communicate) aims to be a modern evolution of CGI.

Quite sophisticated programs can be written as CGIs, but they are more inefficient than modern web frameworks, as each request is handled by a separate Python process.

I've hacked around with a few CGIs of my own. I've also written a couple of tutorials, if you're interested in learning :

[1]Ok, so I'm a bit late with this entry. Smile
[2]But not authentication headers unfortunately.

Like this post? Digg it or it.

Posted by Fuzzyman on 2006-10-08 19:07:24 | |

Categories: ,

Voidspace Server Move

emoticon:lighton After sticking with the same host for around a year (almost a record for Voidspace I think), I've changed server again. Smile

I've moved to Webfaction, the hosting company run by Remi who created CherryPy.

Instead of having root login on my own virtual server, I now have a Shared-2 Account. Although technically I can do less with this account than I could before, I don't have to maintain my own server. On top of this, deploying dynamic applications from Webfaction looks very easy. At some point in the next ten years I hope to find time to play with Django or Turbogears. Wink

Setting everything up was pretty straightforward (with a bit of help from Remi), for the several domains and email addresses I've moved over there. The only hiccup was a bit of time trying to work out how to point both and to point to the same place. Realising that the list of subdomains in the 'website' part of the control panel supported multi-selection was a big help.

I had some fun with my CGI scripts. It seems that Apache running CGIs with SuExec is pretty finicky about permissions. Additionally, the Webfaction servers don't have sendmail. I've changed a lot of my scripts to use smtp [1] rather than sendmail (resulting in a minor bugfix to my contact form CGI).

Unfortunately I still have an authentication problem. Razz

Changing server always causes problems, so I've come off quite lightly. Currently my contact form is down and I lost a few days worth of stats on my page views. Not too bad.

[1]They use cgiutils, which has code very similar to the example show in the Webfaction email FAQ.

Like this post? Digg it or it.

Posted by Fuzzyman on 2006-10-07 16:01:36 | |

Categories: , ,

Writing CGI Programs, Part II

emoticon:pen_book A while ago I wrote a two part series [1] on Writing CGI Applications with Python, for PyZine.

They published the first part in issue 8 (free to read) :

Writing Web Applications as CGI - Part One [2]

Unfortunately since then PyZine has ground to a halt, so they have given me permission to publish part II here on Voidspace :

Writing Web Applications as CGI - Part Two

CGI programs are very easy to write, and can be the simplest (or only on some hosting accounts) way of delivering dynamic content using Python. These articles introduce you to the subject, and give you a good start writing your own scripts. No AJAX though. Wink

[1]Or at least a two part introduction to the subject. Smile
[2]Part II uses functions defined in part I. PyZine is sometimes offline. You can usually find a google cache at Cached Version of Part I

Like this post? Digg it or it.

Posted by Fuzzyman on 2006-06-08 23:02:59 | |

Categories: , ,

New CGI Repository

emoticon:tooth Once again, thanks to the folk at, there is another Subversion repository for some of the Voidspace Python Projects.

This one is for my CGI Projects, and can be found at :

This contains the following projects (each in their own folder on the trunk [1]) :

  • downman

    File download Manager.

  • guestbook

    The Voidspace Python Guestbook.

  • logintools

    An authentication and user account framework for CGI applications.

  • Other

    Containing :


      Interface to the Akismet anti-spam web service. It includes an example CGI.

    • approx

      A Python CGI proxy with a couple of related programs.

    • contact

      A simple script to provide a contact/feedback form on a website. Undocumented, but easy to use.

    • HTTP

      • Upload Scripts

        A CGI script/module for receiving uploads from a web form.

        Also a module for uploading files by HTTP, using urllib2.

      • HTTP Test

        An example script showing cookie handling, basic authentication, fetching URLs and understanding HTTP headers and the CGI environment variables.

    • Nanagram

      An online anagram server script.

    • protectedpage

      A simple example that shows how to use the logintools framework. This examples protects static html files behind a login.

    • randlink

      A couple of scripts that can redirect users to a randomly chosen URL.

    • skimpy

      A CGI search engine that uses the Yahoo Web Services. Undocumented, but the code is well commented.

    • webcounter

      A simple script that counts visitors to a webpage.

Of particular interest may be the following :

  • Guestbook

    The version in SVN has several improvements over the latest released version. It has a couple of bugfixes, uses the interface, and has additional anti-spam measures.

  • skimpy and contact

    Both of these are previously unreleased. I was going to wait until I had time to write documentation and make a few improvements, but in the meantime...

A lot of this code is quite old, Nanagram-CGI was one of the first programs I wrote. Despite this, my CGI page is one of the most popular on my site. It got around five thousand visits in March. Smile

The reason for getting the repository is that I will be writing an application soon(-ish) that will integrate logintools and downman. Although that won't be Open Source, it ought to lead to considerable improvements in both.

I also need to do a new release of the guestbook before giving it the complete refactor it needs (which will add an administrative interface, amongst other things). I'm not sure when this will happen though.

[1]There are also copies of released versions, where appropriate, in tags.

Like this post? Digg it or it.

Posted by Fuzzyman on 2006-04-08 22:03:50 | |

Categories: , ,

Another Python Web Framework

emoticon:film I'm seriously tempted to switch my web application work to This smallish web 'framework' is much more like a library than other ones, and has already gained notoriety as the framework used to port from Lisp to Python.

The main advantage I would get is that I could (apparently) seamlessly migrate my apps. from CGI to FastCGI, mod_python, or WSGI.

My eventual goal is to use Twisted, because it is asynchronous rather than threaded. It looks like the focus of WSGI is for threaded applications. (Although I did hear rumours of the Twisted folk supporting it). I don't yet have an application in mind (one recent opportunity slipped through my fingers), so I don't have to make a decision any time now...

Like this post? Digg it or it.

Posted by Fuzzyman on 2006-01-09 09:20:03 | |

Categories: ,

Python Search Engine

emoticon:python The Python Search Engine now searches from over fifteen hundred domains and has served over nineteen hundred queries.

I need to add Next and Previous buttons to allow deeper searches, and then I'll release the code.

Like this post? Digg it or it.

Posted by Fuzzyman on 2005-12-20 16:36:30 | |

Categories: , , ,

Killing the Guestbook Spammers

emoticon:world I've added the akismet anti-spam stuff to the Voidspace Guestbook. Cool

I was getting several spam messages a day, so it should be very easy to tell if it works or not. (My changes worked first time as well - so far so good anyway).

Assuming it works, I'll put all the previous entries back on and do a new release. I'm also working on a version 2 which has a full web interface for editing the templates/entries. It uses logintools for the user account/authentication stuff. This will enable guestbook owners to mark entries as spam and report false positives back to akismet. It may be a while before it's done, but it will get there eventually. Very Happy

Like this post? Digg it or it.

Posted by Fuzzyman on 2005-12-20 16:31:22 | |

Categories: , , ,

Python Search Engine

emoticon:globesearch I've been hacking around with the Yahoo Search API. It returns results a lot faster than the google one.

I've put together (by fair means and foul) a list of nearly nine hundred domains relevant to Python programming.

I've also cobbled together a CGI search engine that only returns results from a specific set of domains.

Try the Python Search Engine.

It's only a bit of fun - but it does mean that with a list of relevant domains you can roll your own search engine. Smile

At some point I'll package the source code for you all to play with....

Like this post? Digg it or it.

Posted by Fuzzyman on 2005-11-09 12:44:04 | |

Categories: , ,

logintools Critical Bugfix

emoticon:bugs I recently updated logintools and jalopy to be compatible with the new pythonutils code. This was the 0.6.0 releases.

Embarrassingly, I didn't update the email calls to use the new function signature in cgiutils. Embarassed

New user sign-ups have been thoroughly broken since. sigh

The application I use logintools for doesn't allow new user signups. It only has administrator created accounts, so I didn't notice the broken code.

This is now fixed and anyone who wants jalopy or logintools to work should download the new release. Razz


Since the update, a fellow hacker has created the Hacker's Diet Tracker, which uses logintools. cool Very Happy

Like this post? Digg it or it.

Posted by Fuzzyman on 2005-11-05 17:18:48 | |

Categories: , ,

Hosted by Webfaction