#!/usr/bin/python2.3 import cgi import cgitb; cgitb.enable() import os import sys import re import Image import random from glob import glob import cPickle as pickle from htmltmpl import TemplateManager, TemplateProcessor def main(): form = cgi.FieldStorage() rweb = Rweb(form) # if there is an id, get it if rweb.record: if int(rweb.record) < rweb.length and int(rweb.record) >= 0: rweb.get() # check the input is secure elif rweb.input and rweb.secure(): # kill the whitespace rweb.input = rweb.killwhitespace(rweb.input) # new input, compute it and save it if rweb.input not in rweb.data: rweb.save() # could be a repeated query, if so, get it else: rweb.record = str(rweb.data.index(rweb.input)) rweb.get() else: rweb.record = -1 # Instructions? # dress the results rweb.ui() class Rweb: def __init__(self, form): self.input = form.getvalue("q", "") self.record = form.getvalue("id", "") self.output = '' self.error = '' self.warranty = '' self.pngs = [] self.oid = 'data.pickle' self._dir = '/home/hendry/projects/r/g' try: self.data = self._loadData(self.oid) except: self.data = [] self.length = len(self.data) def savedir(self, id): return os.path.join(self._dir, id) def compute(self, sdir): precommand = 'postscript(file= "' + os.path.join(sdir, 'Rout.%03d.ps') + '", onefile=FALSE)\n' i, stdout, stderr = os.popen3("/usr/bin/R --no-environ --no-save") i.write(precommand + self.input) i.close() self.output = stdout.read() self.error = stderr.read() def secure(self): attacks = ['unix', 'assign', 'eval', 'read.table', 'call', 'sink', 'write', 'count.field', 'scan', 'system', 'postscript'] exit = 1 for attack in attacks: if attack in self.input: self.output += "Sorry, you may not use the " + attack + " function.\n" exit = 0 return exit def webdir(self, savedir): return re.sub(r'/home/hendry/projects/r', 'http://r.dabase.com', savedir) def get(self): """ Get results """ sdir = self.savedir(self.record) for pngfilename in glob(sdir + '/*.png'): self.pngs.append({'src': self.webdir(sdir) + '/' + os.path.split(pngfilename)[1], 'alt': 'R Graphics Output'}) self.output = open(os.path.join(sdir, 'output.txt')).read() self.input = open(os.path.join(sdir, 'input.txt')).read() errorfile = os.path.join(sdir, 'error.txt') if os.path.isfile(errorfile): self.error = open(errorfile).read() def save(self): """ New query, save results """ self.record = str(self.length) sdir = self.savedir(self.record) if not os.path.isdir(sdir): os.makedirs(sdir) self.compute(sdir) if not self.error: self.convertps2png(sdir) else: open(os.path.join(sdir, 'error.txt'), 'w').write(self.error) self.data.append(self.input) self._saveData(self.oid, self.data) open(os.path.join(sdir, 'output.txt'), 'w').write(self.output) open(os.path.join(sdir, 'input.txt'), 'w').write(self.input) def ui(self): print "Content-Type: text/html" #print "Content-Type: application/xhtml+xml" print template = TemplateManager().prepare("basic.tmpl") tproc = TemplateProcessor() tproc.set("output", self.getwarranty(self.output)) tproc.set("Pngs", self.pngs) tproc.set("input", self.input) tproc.set("error", self.error) tproc.set("last", "%s" % str(self.length)) tproc.set("record", "%s" % self.record) tproc.set("next", "%s" % str(int(self.record)+1)) tproc.set("prev", "%s" % str(int(self.record)-1)) print tproc.process(template) def _makeFilename(self, name): return os.path.join(self._dir, str(name)) def _loadData(self, oid): f = file(self._makeFilename(str(oid)), 'rb') return pickle.load(f) def _saveData(self, oid, data): f = file(self._makeFilename(str(oid)), 'wb') pickle.dump(data, f, pickle.HIGHEST_PROTOCOL) def getwarranty(self, string): """ Matches the warranty """ warranty = re.compile(r'R.+restored]', re.M | re.S) outputps = re.compile(r'> postscript.+FALSE\)', re.M | re.S) output = re.sub(warranty, self.setwarranty, string) output = re.sub(outputps, '', output) return self.killwhitespace(output) def setwarranty(self, matchobj): """ Records the warranty """ self.warranty = repr(matchobj.group(0)) return '' def killwhitespace(self, string): string = re.sub(r'^\s+', '', string) string = re.sub(r' +', ' ', string) string = re.sub(r'\r', '', string) string = re.sub(r'\n+ ?', '\n', string) string = re.sub(r'\n$', '', string) return string def convertps2png(self, sdir): for filename in glob(sdir + '/*.ps'): if open('nothing.ps').read() != open(filename).read(): pngfilename = os.path.splitext(filename)[0] + '.png' os.system('convert -rotate 90 %s %s' % (filename, pngfilename)) self.pngs.append({'src': self.webdir(sdir) + '/' + os.path.split(pngfilename)[1], 'alt': 'R Graphics Output'}) else: os.unlink(filename) if __name__ == "__main__": main() os.umask(002)