Hello Zopistas, I have updated the HOW-TO: Serve PHP/Perl within Zope with a nifty alternative by Joseph Wayne Norton. His suggestion allows PHP to call Zope methods. Check it out at www.zope.org/Members/Mamey/PHP. The methods presented in the HOW-TO still have some deficiencies with regards to Authorization and Cookies so suggestions and improvements are very much welcome. ------------------------------------------------------ Andres Corrada-Emmanuel Email: andres@corrada.com ------------------------------------------------------
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]
Got authorization to work! First, another patch to Client.py to raise 'Unauthorized' when 401 is returned by PHP/Perl: after line that starts with if ec==200 add if ec==401: raise 'Unauthorized' Second, numerous changes to the external method that makes the request and receives the response. Here's the whole thing def ServePHP(self): req = self.REQUEST (username, password) = req._authUserPW() headers = {} if req.environ.has_key('HTTP_COOKIE'): headers = {'Cookie' : req.environ['HTTP_COOKIE']} if req.environ.has_key('HTTP_USER_AGENT'): headers = {'User-Agent' : req.environ['HTTP_USER_AGENT']} 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'] # the first element of the return tuple is dervied from rfc822 for cookie in rTuple[0].getallmatchingheaders('Set-Cookie'): cookie = cookie[:-1] # remove \n - is there an idiom for this? 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:10080/forum/' + req['origScript'] return rTuple[1]
oops! that should be username, password = req._authUserPW()
oops, again :-( headers = {} if req.environ.has_key('HTTP_COOKIE'): headers['Cookie'] = req.environ['HTTP_COOKIE'] if req.environ.has_key('HTTP_USER_AGENT'): headers['User-Agent'] = req.environ['HTTP_USER_AGENT'] Also on my member page - http://zope.org/Members/billw/morePHP
Last bug. Promise. # user might not have signed in yet try: username, password = req._authUserPW() except: username = password = None
participants (2)
-
andresï¼ corrada.com -
Bill Welch