You are not logged in Log in Join
You are here: Home » Members » Mamey » Serve PHP/Perl within Zope

Log in
Name

Password

 

Serve PHP/Perl within Zope

As you migrate your site to Zope, you may want to embed a previously created PHP or Perl directory tree within Zope. Or perhaps you found a nifty web application that is coded in PHP/Perl and want to serve it within your Zope site.

This differs from the intent of the Serving Zope and other content from Apache How-To written by Michel Pelletier. In that How-To, you are using Apache RewriteRules to bypass Zope and serve the PHP/Perl tree directly to the user. This How-To deals with the case where you want to serve that tree within Zope so you can achieve a consistent look to your site. That is, you want to wrap the PHP/Perl output with <standard_html_header> or whatever other dtml code you want. Although, in principle, the methods presented should work with either PHP or Perl, we have only tested them with PHP. So we will stick to using PHP in our examples. If you have success serving Perl with these methods or modified versions of them, let us know so we can include your work here.

There are two ways that you could do this. The first method was devised by myself with help from the Zope mailing list. It stores the PHP code in the server's filesystem and uses Apache, the SiteAccess product, and a Zope API call. The second method was devised by Joseph Wayne Norton. It cleverly stores the PHP code within the ZODB allowing it to call DTML code.

Serving PHP code stored in the filesystem

  • Advantages
    • Few modifications to PHP code.
    • Authorization allowed.
  • Disadvantages
    • PHP cannot access Zope internals.
    • PHP must be in standalone tree.
    • Cookies don't work.

This solution uses three Zope resources: (1) the SiteAccess product by Evan Simpson of 4AM Productions Inc., (2) the tip presented by Loren Stafford in Using ZClient to Access Another Server and (3) Pelletier's How-To.

You'll also need a web server that can serve Zope as well as the PHP/Perl tree. We use Apache, and that is what this How-To will use as an example.

So let's begin. We have our wonderful Zope site located at www.mysite.com. Within our site, we want to embed a PHP_Nifty_Tree. So let's create a folder "PHPContent" so users can go to www.mysite.com/PHPContent.

Install the SiteAccess product in your Zope source tree. And after restarting Zope, go to the PHPContent folder and add a SiteRoot object with the path set to "/PHPContent".

We now want to attach an AccessRule to the folder that will transparently redirect users to the PHP tree. The solution offered here is based on the assumption that the PHP tree will have relative links to other php scripts within it. However, we want the user to always end up within the index_html object, so we'll strip any requests for those relative links from REQUEST.path and pass the original request as a REQUEST variable to index_html.

Begin, by placing the following script, DirectToPHPContent.py, within the Extensions folder of your Zope source tree:

from string import join

def DirectToPHPContent( 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 = ['http://www.mysite.com/PathToPHPtreeInServerFileSystem']

         # is the user asking for a php script?
         if self.REQUEST.path[0][-5:] == '.php3':

              # pop paths of REQUEST.path until its empty
              while self.REQUEST.path:
                   # Remember the path components before you pop them
                   originalRequestPath.append( self.REQUEST.path[-1] )
                   self.REQUEST.path.pop()

              # Is there a query string being passed to the script also?
              if self.REQUEST.environ['QUERY_STRING']:
                   originalRequestPath[ -1 ] = originalRequestPath[ -1 ] + '?' \
                                               + self.REQUEST.environ['QUERY_STRING']

              # Create a full url to pass to index_html
              phpScript = join( originalRequestPath, '/' )

              # self.REQUEST.path is now empty so the user is going to be
              # directed to /PHPContent/index_html. That method needs to
              # know what the original request is, so pass it a REQUEST
              # variable
              self.REQUEST.set('phpScript', phpScript)

         # you also may want to redirect image requests to the PHP tree
         elif self.REQUEST.path[0][-3:] in ['gif', 'png']:

              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('ServeImageInPHPTree')
              self.REQUEST.set('imagePath', join(originalRequestPath, '/'))

Now add an ExternalMethod object to /PHPContent that points to the script above, let's be redundant and call it DirectToPHPContent. To finish, use the "Set Access Rule" method and give it the DirectToPHPContent id.

So what have we done so far? Any requests to /PHPContent/whatever/script.php3 are going to be redirected to /PHPContent/index_html by the SiteAccess product. In addition, any requests to /PHPContent/whatever/image.gif will also be redirected to the method ServeImageInPHPTree that we still have to write. Before we do that, let's teach /PHPContent/index_html how to access the external PHP tree. We do this by implementing Stafford's tip within /PHPContent/index_html.

We begin by adding another ExternalMethod object, ServePHPContent. Simplifying Stafford's tip somewhat, ServePHPContent.py in the Extensions folder will be of the form:

from ZPublisher import Client

def ServePHPContent(url="http://www.mysite.com/internalPathToPHPtree", username=None, passwor
d=None):
     return Client.call(url,username,password)[1]
We can now write within /PHPContent/index_html the following code:
<standard_html_header>
        .
        .
        .
<dtml-if "REQUEST.has_key('phpScript')">
        <dtml-var "ServePHPContent(REQUEST['phpScript'])">
</dtml-if>
        .
        .
        .
<standard_html_footer>
To finish off, we add the ServeImageInPHPTree DTMLMethod with the single line:
<dtml-var "ServePHPContent(REQUEST['imagePath'])">
You will probably also want to read Pelletier's Apache How-To to learn how the calls to http://www.mysite.com/internalPathToPHPtreeInServerFileSystem made by Zope can be correctly passed to the external PHP tree and not to Zope!

Serving PHP code stored in the ZODB

  • Advantages
    • PHP stored in ZODB! P or Perl, we have only tested them with PHP. So we will stick to using AÉ
    • Does not use SiteAccess product.
  • Disadvantages
    • Authorization does not work.
    • Some modification of PHP code

This is the simplest method. Its one major drawback - no authorization - must be solvable.

Place all PHP code in the ZODB. But replace all "include" and "require" statements to

<dtml-var url-path>
statements since all your PHP code now exists in the ZODB. You will also need to change their suffix to _php3.

Place the following "require.php3" file in the Apache document root:

<?
 require($PHP3_INCLUDE)
?>

Use Apache's Rewrite Engine to direct PHP requests to "require.php3" with the following rewrite rule:

RewriteRule ^(.*)\.php3 /require.php3 [L,E=PHP3_INCLUDE:http://%{HTTP_HOST}$1_php3?%{QUERY_STRING}]

Calls to any url with .php3 at the end get directed to the "require.php3" script. This then makes a call to the corresponding PHP script in the ZODB. Zope takes care of all includes and requires and returns it to "require.php3" which then does the PHP processing itself.