[Zope] ANN: Serving PHP/Perl from Zope update

Bill Welch bill@carbonecho.com
Wed, 6 Sep 2000 14:56:09 +0000 (GMT)


I had to dig a level deeper to support phorum (www.phorum.org), a PHP
message board app.  Here's my update to handle cookies, redirection, POST
variables, and relative links. I'm new to python, so if I've done anything
awkwardly, please let me know the more elegant way. 

First, a patch to Client.py - first part doesn't die on redirects and
returns (instead of raising 'Redirect') so cookies and base can be set,
second part opens a hole to pass headers into Client (for cookies)

224c224
<         if ec==200: return (headers,response)
---
>         if ec==200 or ec==302: return (headers,response)
342,344c342,344
< def call(url,username=None, password=None, **kw):
<     
<     return apply(Function(url,username=username, password=password), (), kw)
---
> def call(url,username=None, password=None, headers={}, **kw):
>     F = apply(Function, (url, (), None, username, password, None), headers)
>     return apply(F, (), kw)

Then there's the rewrite of the code in the how-to. Here's the whole thing
(I use just one .py)

site = 'http://www.carbonecho.com/zforum'

from string import join
def DirectToPHP( self ):
    if self.REQUEST.path:
        # Build up a list of what is contained in self.REQUEST.path since
        # you are going to redirect the user to /PHPContent/index_html. Start
        # by adding the way you can access the PHP tree outside of Zope
        originalRequestPath = [site]
	# keep the original path to override base when serving
        origPath = []
        # is the user asking for a php script?
        if self.REQUEST.path[0][-4:] == '.php': # I use .php, not .php3

            # pop paths of REQUEST.path until its empty
            while self.REQUEST.path:
                # Remember the path components before you pop them
                # hang on to passed in path to set as base when served
                originalRequestPath.append( self.REQUEST.path[-1] )
                origPath.append( self.REQUEST.path[-1] )
                self.REQUEST.path.pop()

            # Create a full url to pass to index_html
            phpScript = join( originalRequestPath, '/' )
            origScript = join( origPath, '/' )
            # Is there a query string being passed to the script also?
            if self.REQUEST.environ.has_key('QUERY_STRING'):
                phpScript = phpScript + '?' + self.REQUEST.environ['QUERY_STRING']
                origScript = origScript + '?' + self.REQUEST.environ['QUERY_STRING']

            # self.REQUEST.path is now empty so the user is going to be
            # directed to /forum/index_html. That method needs to
            # know what the original request is, so pass it a REQUEST
            # variable
            self.REQUEST.set('phpScript', phpScript)
            self.REQUEST.set('origScript', origScript)
        # you also may want to redirect image requests to the PHP tree
        elif self.REQUEST.path[0][-3:] in ['gif', 'png', 'jpg']:
	    originalRequestPath = [site]
            while self.REQUEST.path:
                originalRequestPath.append(self.REQUEST.path[-1])
                self.REQUEST.path.pop()

            # This is an image, so give it to a DTMLMethod that will
            # just serve up images
            self.REQUEST.path.append('ServeImage')
            self.REQUEST.set('imagePath', join(originalRequestPath, '/'))

from ZPublisher import Client
from string import split

def ServePHP(self, username=None, password=None):
    req = self.REQUEST

    if req.environ.has_key('HTTP_COOKIE'):
        headers = {'Cookie' : req.environ['HTTP_COOKIE']}
    else:
        headers = {}
        
    if req.environ['REQUEST_METHOD'] == 'POST':
 	rTuple =  apply(Client.call, (req['phpScript'], username, password, headers), req.form)
    else:
 	rTuple = Client.call(req['phpScript'], username, password, headers)

    resp = req['RESPONSE']
    for cookie in rTuple[0].getallmatchingheaders('Set-Cookie'):
        cookie = cookie[:-1]
        apply(resp.setHeader, split(cookie, ':', 1))

    # not a particularly strong test, maybe Client should pass back status 
    if rTuple[0].has_key('location'):
	# override base so that relative references work
    	resp.base = rTuple[0]['location']
	raise 'Redirect', resp.base

    #override base so that relative references work
    resp.base = 'http://www.carbonecho.com/forum/' + req['origScript']

    return rTuple[1]

from ZPublisher import Client

def ServeImage(self):
    return Client.call(self.REQUEST['imagePath'])[1]