Tento text je napsán pro Linux a Apache.
Představme si, že jsme v situaci, kdy potřebujeme napsat CGI skript přistupující např. k MySQL databázi, ale i když je na daném počítači nainstalována a nainstalován je i Python, chybí MySQLdb a, co je ještě horší, i libmysqlclient. Administrátorská práva nemáme a admin nám nechce potřebné knihovny nainstalovat. Jak z toho ven?
Začněme tím jednodušším, tj. MySQLdb. Využijeme toho, že existuje distribuční balík pro naši distribuci a někam ho rozbalíme (to umí třeba Midnight Commander; některé distribuce snad umožňují instalaci balíku do uživatelského adresáře). Cestu do toho adresáře (tj. toho, co obsahuje např. _mysql.so) pak jednoduše přidáme na úplný začátek našeho CGI skriptu do proměnné sys.path. Příklad testovacího skriptu:
#!/usr/bin/python # -*- coding: UTF-8 -*- import cgi import sys # v mysql_python mame MySQLdb sys.path.append('/home/~username/mysql_python') import MySQLdb print 'Content-Type: text/html; charset=UTF-8\n' print '<h1>Hello</h1>' conn = MySQLdb.connect(db=' ... ', passwd=' ... ') conn.set_character_set('utf8') c = conn.cursor() c.execute('select * from clovek') for row in c.fetchall(): print row[1], '<br>' c.close() print '<hr>' form = cgi.FieldStorage() for i in form: print i, form[i].value, '<br>'
Druhý problém je složitější. Podobně jako v prvním případě stáhneme a rozbalíme balíček s libmysqlclient, ale potřebujeme, aby v době spuštění skriptu byl adresář s touto knihovnou v LD_LIBRARY_PATH. Apache má sice direktivu SetEnv, ale na tu je v .htaccess už příliš pozdě. Řešením může být druhý skript, který má název prvního skriptu jako parametr. Ten nastaví LD_LIBRARY_PATH a pak spustí náš skript. Příklad takového skriptu:
#!/usr/bin/python from os import environ import cgitb; cgitb.enable() def print_error(msg): import sys print 'Content-Type: text/html\n' print '<h1>Error</h1>' print '<xmp style="color:red">%s</xmp>' % msg sys.exit() filename = None method = environ['REQUEST_METHOD'] if method == 'GET': import cgi data = cgi.FieldStorage() if data.has_key('script'): filename = data['script'].value elif method == 'POST': for pair in environ['QUERY_STRING'].split('&'): key, value = pair.split('=') if key == 'script': filename = value break if filename: import re if re.match(r'^\w+$', filename): import os filename += '.py' if os.path.exists(filename): from subprocess import Popen, PIPE # podle toho, kde mame libmysqlclient environ["LD_LIBRARY_PATH"] = "/home/~username/lib" p = Popen(('/usr/bin/python', filename), env=environ, stderr=PIPE) if p.wait() <> 0: print_error(p.stderr.read()) else: print_error('Script does not exists!') else: print_error('Script filename must be [a-zA-Z0-9_]+ !') else: print 'Location: http:// .... \n'
To sice už funguje, ale pokud už je aplikace vyvinutá, asi se nám nebude chtít měnit všechna URL z neco.py na run.py?script=neco . To lze vyřešit pomocí modulu rewrite. Příklad .htaccess:
AddHandler cgi-script .py .cgi RewriteEngine On RewriteCond %{QUERY_STRING} ^(.*)$ RewriteRule ^([^run]+?)\.py$ /adresa_nasich_stranek/cgi-bin/run.py?script=$1&%1 [L]
P.S. Nenapadl mě žádný výstižný text této stránky, tak pokud vás políbí můza neváhejte a přejmenujte.