Running PHP on top of Web2Py

940 views
Skip to first unread message

John-Kim Murphy

unread,
Dec 30, 2010, 1:03:51 AM12/30/10
to web...@googlegroups.com
I have been thinking about how to run PHP on top of Web2Py. I'm interested in doing this because I want to augment an existing PHP app via Web2Py (For example, use the T() internationalization object; use Web2Py's auth access control). Also it will be easier to port a PHP application to Web2Py one piece at a time if the rest of the unported application can run as PHP.

Something similar was done with Django: the PHP-based PmWiki and even WordPress were integrated with Django. I've been studying the Python source code, and it looks like this could be used to render PHP from a Web2Py view. I'm trying to imagine how this would fit into Web2Py; perhaps distributed as a plugin:
  1. The PHP code should not be aware it is running on top of Web2Py. Any Web2Py template language is expanded before being sent to the PHP parser. (I just watched the video, and it provides some more details. It looks like the PHP files had to be modified a bit, which I was trying to avoid, if possible.)
  2. The PHP files (possibly with some {{Web2Py template code}} added) seem like views, but a PHP application will not have any associated Web2Py actions. Should there be a Web2Py controller that manages requests for PHP content, picking the correct PHP file based on the request? Should the PHP files just reside in a new, special php directory?
  3. How are POST, GET, and SESSION variables passed to/from PHP? It seems PHP sessions are stored on the server; not sure about POST and GET... PmWiki uses URL variables, so I think they are being passed somehow.
Any insights from people more familiar with Web2Py, PHP, and/or Django much appreciated!

John

mdipierro

unread,
Dec 30, 2010, 1:42:14 AM12/30/10
to web2py-users
All you need is this this (except for windows) in a model (php.py?):

from subprocess import Popen, PIPE
import sys, os, threading
def runphp(source):
PHP_BIN = '/usr/bin/php'
PHP_ARGS = ['-q']
PHP_IN_SHELL = True
php = Popen([PHP_BIN,] + PHP_ARGS, shell=PHP_IN_SHELL,
bufsize=1<<12, universal_newlines=True, ## restriction of
templates
stdin=PIPE, stdout=PIPE, #stderr=PIPE,
close_fds= True)
php.stdin.write(source)
php.stdin.close()
page = php.stdout.read()
php.stdout.close()
return page


than in web2py

def index():
return runphp(response.render('theview.html',a=1,b=2,c=3))

theview.html will first be processed as a web2py template and then as
a php template. Mind that it is slow. For every page it create a new
process.

I did not try and I may have typos but should work.


Massimo


On Dec 30, 12:03 am, John-Kim Murphy <left...@gmail.com> wrote:
> I have been thinking about how to run PHP on top of Web2Py. I'm interested
> in doing this because I want to augment an existing PHP app via Web2Py (For
> example, use the T() internationalization object; use Web2Py's auth access
> control). Also it will be easier to port a PHP application to Web2Py one
> piece at a time if the rest of the unported application can run as PHP.
>
> Something similar was done with Django<http://code.djangoproject.com/ticket/2440>: the
> PHP-based PmWiki <http://www.pmwiki.org/wiki/Main/WikiSandbox?action=edit> and
> even WordPress were integrated with Django<http://showmedo.com/videotutorials/video?name=pythonNapleonePyConTech...>.
> I've been studying the Python source code<http://code.djangoproject.com/attachment/ticket/2440/php.py>,
> and it looks like this could be used to render PHP from a Web2Py view. I'm
> trying to imagine how this would fit into Web2Py; perhaps distributed as a
> plugin:
>
>    1. The PHP code should not be aware it is running on top of Web2Py. Any
>    Web2Py template language is expanded before being sent to the PHP parser. (I
>    just watched the video, and it provides some more details. It looks like the
>    PHP files had to be modified a bit, which I was trying to avoid, if
>    possible.)
>    2. The PHP files (possibly with some {{Web2Py template code}} added) seem
>    like views, but a PHP application will not have any associated Web2Py
>    actions. Should there be a Web2Py controller that manages requests for PHP
>    content, picking the correct PHP file based on the request? Should the PHP
>    files just reside in a new, special php directory?
>    3. How are POST, GET, and SESSION variables passed to/from PHP? It seems

jeff

unread,
Dec 30, 2010, 6:56:51 AM12/30/10
to web2py-users
This is very interesting and could make me save (or waste) a lot of
time : I have to move a website from PHP to web2py. The website is
small and not really dynamic : the content is in tables and so but the
site will be extended (in web2py) and can be see as a static website
(but with ugly urls with vars). For some reasons I have to move it
"like that" to web2py quick (and dirty). I had that way in mind:
- crawl and capture the whole site (not that big and then perfectly
feasible) and put everything in a the static folder of a web2py app.
- write a simple and generic controller function (or generate one
simple controller function per page).
- write a regex script to find and replace the <a href ...> tags in
order to use URL() in them.
- tweak the route.py file in order to keep the actual urls unchanged
(BTW, I could change the urls if this is done in a good way -this is
the only cleanliness requirement, all the rest can be ugly- for google
and if that's possible for bookmarkers : any hint ?)

It can be some work. But now I read this thread about using PHP from
web2py. Maybe, that would be quickly done like that. I just don't want
to use any other webserver than web2py (apache or whatever) at this
time. The performance penalty is not an issue (the part of the site
that will remain in php is there for historical reasons and not
heavily used).

My main concerns about this way are:
- the complexity of having runphp working
- the work on the templates : I guess that I have to put the php
templates in the view folder but I don't see exactly what else I have
to do on them
- do I have to tweak routes.py ? in the same way as above ?

I would appreciate any insights about that.

mdipierro

unread,
Dec 30, 2010, 12:07:45 PM12/30/10
to web2py-users

> My main concerns about this way are:
> - the complexity of having runphp working

there is no complexity but it is reeeeally slow.

> - the work on the templates : I guess that I have to put the php
> templates in the view folder but I don't see exactly what else I have
> to do on them

Or move them in views/php and make a web2py controller php.py with one
action for each file . wiht the instructions above you will be able to
inject both web2py tags {{...}} and php tags <?...?>

> - do I have to tweak routes.py ? in the same way as above ?
It depends on the original files. Probably yes.

Why not look at this first:

http://www.web2py.com/php

jeff

unread,
Jan 8, 2011, 8:43:29 AM1/8/11
to web2py-users
I had another idea which is a simplification on my first one : an
action acting like a proxy on the php server.
I just wrote a little POC that seems to work. Here are the few lines
to put in a controller:

import urllib

def make_get_stuff(an_url):
def get_stuff():
stuff=urllib.urlopen(an_url)
return stuff.read(),stuff.info(),stuff.getcode()
return get_stuff

HEADER_TAGS_TO_COPY=("Content-Type","Date","Accept-Ranges","Content-
Length",
"Etag","Last-Modified","Server","X-Powered-By")

def proxy():
stuff_url="http://www.mysite.be/%s?%s" % (request.url[22:],
request.env.query_string)
stuff_content,stuff_info, stuff_status=cache.ram(stuff_url,
lambda: cache.disk(stuff_url,

make_get_stuff(stuff_url),time_expire=None),time_expire=40)
for header_tag in HEADER_TAGS_TO_COPY:
header_line=stuff_info.getheader(header_tag)
if header_line: response.headers[header_tag]=header_line
response.status=stuff_status
return stuff_content

And I have obviously to write some lines in routes.py like (the proxy
action is in the w.py controller of the poc app):

(r'.*:http://.*:.* /(?P<any>(?:admin/|poc/).*)',
r'/\g<any>'),
(r'.*:http://.*:.* /(?P<any>.*)',
r'/poc/w/proxy/vars=\g<any>'), # I think that's not used

That seems do the job (and it's quite faaaaaaaast ;-) ). I can even
crawl the old website and it will stand entirely in the cache, I would
then be able to shut down the php server (providing I manage the 4xx
errors myself)

Some questions about that solution:
- are there any drawbacks that I don't see ? (except that the cache
MUST be managed).
- what are the headers lines that are better to be copied from the php
response ? I guess that the only criterion is to please Google and I
have few clues about their likes and dislikes. Content-Type must be
copied, that's for sure, for the others, I don't know and for the ones
added by web2py : Set-Cookie (session.forget ?), Pragma, Cache-
Control, ... I don't know if it's better to keep them or not : I don't
want to foolish Google in a way or another.
- I could replace the cache (or add that to it) by using the db (mysql
in prod) to store of the old php site stuffs (pages, images,
ppt, ...). Any advice ?

Best wishes everybody and thx to all of you : OSS is great, web2py is
huge and that community is soooooooo cool !



On Dec 30 2010, 6:07 pm, mdipierro <mdipie...@cs.depaul.edu> wrote:
> > My main concerns about this way are:
> > - the complexity of having runphp working
>
> there is no complexity but it is reeeeally slow.
>
> > - the work on the templates : I guess that I have to put thephp
> > templates in the view folder but I don't see exactly what else I have
> > to do on them
>
> Or move them in views/phpand make a web2py controllerphp.py with one
> action for each file . wiht the instructions above you will be able to
> inject both web2py tags {{...}} andphptags <?...?>

Jonathan Lundell

unread,
Jan 8, 2011, 12:20:42 PM1/8/11
to web...@googlegroups.com
On Jan 8, 2011, at 5:43 AM, jeff wrote:
>
> And I have obviously to write some lines in routes.py like (the proxy
> action is in the w.py controller of the poc app):
>
> (r'.*:http://.*:.* /(?P<any>(?:admin/|poc/).*)',
> r'/\g<any>'),
> (r'.*:http://.*:.* /(?P<any>.*)',
> r'/poc/w/proxy/vars=\g<any>'), # I think that's not used
>
> That seems do the job (and it's quite faaaaaaaast ;-) ). I can even
> crawl the old website and it will stand entirely in the cache, I would
> then be able to shut down the php server (providing I manage the 4xx
> errors myself)

I may be reading this wrong, but you may find that your vars= line might cause problems.

If you really want a 'vars=something' construct, you need something like this:

(r'/(?P<any>.*)', r'/poc/w/proxy?vars=\g<any>')

...but that is likely to mess up some of your incoming URLs (I don't know what they look like; maybe not).

or this:

(r'/(?P<any>.*)', r'/poc/w/proxy/\g<any>')

...where you'll find the proxied path in request.args and also request.vars if there's a query string.

John-Kim Murphy

unread,
Jan 8, 2011, 8:29:23 PM1/8/11
to web...@googlegroups.com
From your original message, I was assuming you did not wish to run a PHP server at all. If running a PHP server is allowed, it is possible to run Web2Py and PHP side-by-side, in parallel:
For my original question asking about running Web2Py and PHP in serial, I added the additional requirement that  a single file could contain both Web2Py and PHP tags. In your case, the parallel method is probably better.

John-Kim

pbreit

unread,
Jan 9, 2011, 4:52:25 PM1/9/11
to web...@googlegroups.com
I'm late to the party here but my sense is that you'll be best off just moving everything over. You mentioned that it's a content site with not a lot of traffic any a moderate amount of content. Sounds to me like you would have a relatively easy time moving it over than trying to cobble together some python/php frankenstein.
Reply all
Reply to author
Forward
0 new messages