[HowTo] PHP4/PHP5 as CGI - patched (English HowTo)

  • Thread starter Thread starter server4downs
  • Start date Start date
S

server4downs

Guest
Hey guys,

there you go, this is the long expected, ultimate, most awesome (etc) HowTo ;)

Hinweis: Bitte klicken Sie hier um die deutsche Version zu sehen.

Purpose of this HowTo is:
- To have PHP4 and PHP5 run in parallel
- To not abandon PHP's open_basedir, even though running it with CGI or using Apache's mass-hosting module (mod_vhost_alias)

Prerequisite:
- Linux-Webserver
- Apache 1.xx or 2.xx
- good knowlegde of linux (basic linux skills are required!)
- 20 minutes of your (spare) time
- 20 litres of beer (optional)

Let's start with a lil story of how it came to this HowTo:
Every experienced serveradministrator is familiar with the following problem: you are running PHP4 (in most cases as Apache module) and at the same time you wanna use PHP5. Since it is not possible having 2 PHP versions running as Apache modules you need to think of some sort of a patch (or whatever you want to name it). You already might have asked Google...
Basically there are 3 solutions offered by Google search:
1. Run the 2.nd PHP version as CGI
2. Install a 2.nd instance of Apache (complicated and in most cases not very useful [dumb solution])
3. only run one version at a time (doesn't solve our problem at all [screw this solution])
So let's take a look at #1:
First you might think "yes awesome, that's the most wicked solution". After a couple of hours you then realize that it actually isn't as perfect as you first thought. (Hint: reading the next few lines could save you some time)
The problems connected to the CGI edition of PHP:
1) open_basedir (very important security feature of PHP) is not available through Apache config files anymore.
2) right now I cant think of any other problems (except for the reduction of speed, which is not solvable)
First issue can be solved the following ways:
a) using suPHP or fastCGI
b) this HowTo (way better, since it works very well with a large amount of vhosts or mod_vhost_alias)
I only offer a HowTo for b) at the moment. If you are still interested: keep on reading ;)
We are now going to edit the source of PHP! (it's pretty easy... ;))
This workaround should work just fine. I have tested it several times on different servers and systems.
You don't need to be a C-Programmer for editing the source ;)
So, I better shut up now and start the step by step HowTo:

1. Get the PHP sources:
e.g.:
Code:
 wget http://de3.php.net/get/php-5.0.5.tar.gz/from/this/mirror
2. unzip/untar:
Code:
 tar xfz php-5.0.5.tar.gz
3. cd into dir:
Code:
 cd php-5.0.5
3. execute configure
e.g.:
Code:
 ./configure --prefix=/usr/share/php5 --datadir=/usr/share/php5 --bindir=/usr/bin/php5 --libdir=/usr/share/php5 --with-config-file-path=/etc/php5 --with-exec-dir=/usr/lib/php5/bin --enable-memory-limit [B]--enable-force-cgi-redirect[/B] --enable-track-vars [B]--with-mysql=/usr[/B] --without-pear --enable-session --without-sqlite --enable-exif
Note:
--enable-force-cgi-redirect is needed by CGI version. Don't use apxs/apxs2!
--with-mysql=/usr MySQL needs to be included in PHP5 (if you dont want to have MySQL support.. just leave it out;))
5. hit ENTER!
6. Wait (be patient). Configure is being executed. This may take some time. Any errors? >> Ask Google! Most of the time configure complains about missing header files. In order to solve this problem you need to install them (devel-packages).
7. (optional) The first 0,5l of beer can be drunk. Depending on your server (speed) you can think about drinking another 0,5l afterwards ;)
8. Configure has now successfully finished configuring your PHP source. Congratulations ;)
9. Now comes the good part! We are going to patch PHP now:
a) Open the file /php-5.0.5/main/fopen_wrappers.c with your favorite editor (e.g. with vi)​
b) Search for line
Code:
[COLOR=Indigo][COLOR=Black]PHPAPI int php_check_open_basedir_ex(const char *path, int warn TSRMLS_DC)[/COLOR][/COLOR]
This is the function we are about to modify!​
c) Let's point our cursor to the following section:
Code:
[COLOR=Indigo][COLOR=Black]if (PG(open_basedir) && *PG(open_basedir)) {[/INDENT][/INDENT]
[INDENT][INDENT]                char *pathbuf;[/INDENT][/INDENT]
[INDENT][INDENT]                char *ptr;[/INDENT][/INDENT]
[INDENT][INDENT]                char *end;[/COLOR][/COLOR]
d) Now comes the tricky part... we insert the following code:
Code:
   /*faked base_dir */[/INDENT][/INDENT]
[INDENT][INDENT][/INDENT][/INDENT]
[INDENT][INDENT]                char awesome[MAXPATHLEN];[/INDENT][/INDENT]
[INDENT][INDENT]                char pathstuff[MAXPATHLEN];[/INDENT][/INDENT]
[INDENT][INDENT]                int counter = 0;[/INDENT][/INDENT]
[INDENT][INDENT]                strlcpy(awesome, "", sizeof(awesome));[/INDENT][/INDENT]
[INDENT][INDENT]                strlcpy(pathstuff, SG(request_info).path_translated, sizeof(pathstuff));[/INDENT][/INDENT]
[INDENT][INDENT]                int i;[/INDENT][/INDENT]
[INDENT][INDENT]                for(i = 0; pathstuff[i]; i++)[/INDENT][/INDENT]
[INDENT][INDENT]                    {[/INDENT][/INDENT]
[INDENT][INDENT]                    if(pathstuff[i] == '/')[/INDENT][/INDENT]
[INDENT][INDENT]                    counter++;[/INDENT][/INDENT]
[INDENT][INDENT]                    if(counter == [COLOR=Red][B]6[/B][/COLOR])[/INDENT][/INDENT]
[INDENT][INDENT]                        {[/INDENT][/INDENT]
[INDENT][INDENT]                        pathstuff[i+1] = 0;[/INDENT][/INDENT]
[INDENT][INDENT]                        strlcpy(awesome, pathstuff, sizeof(awesome));[/INDENT][/INDENT]
[INDENT][INDENT]                        break;[/INDENT][/INDENT]
[INDENT][INDENT]                        }[/INDENT][/INDENT]
[INDENT][INDENT]                    }[/INDENT][/INDENT]
[INDENT][INDENT][/INDENT][/INDENT]
[INDENT][INDENT]                strlcat(awesome, ":/other/base/dirs/dude/:/tmp/", sizeof(awesome));[/INDENT][/INDENT]
[INDENT][INDENT][/INDENT][/INDENT]
[INDENT][INDENT]                /* end! */
Explanation of the code (please read carefully!):
The patch is based on the following thinking:
Every webhoster should have a certain structure (directory tree).
e.g.:
Doc_Root: /home/www/hostedstuff/users/username/
Please note that /username is replaced by a username or something.
Our faked basedir checks the scriptpath of every php file which is executed and determines the Doc_Root this way.
The scriptpath is searched for "/". In this case (example) the loop runs through it 6x and saves the result into a string (our Doc_Root).
Example:
Username: sweetheart​
This user now runs the script fools.php in dir /donuts.​
Script-Path: /home/www/hostedstuff/users/sweetheart/donuts/fools.php
The scriptpath is now going to be analyzed by our patch. The patch will lock the user into the following doc_root:​
/home/www/hostedstuff/users/sweetheart/
Optionally you can add several static open_basedirs (seperated by ":"), otherwise comment it out.​
d) Now we need to modify the call of the following function:​
Code:
   pathbuf = estrdup(PG(open_basedir));
is replaced by:​
Code:
   pathbuf = estrdup(awesome);
e) save the file (no explanation needed I guess ;))​
f) exit the editor.​
g) successfully patched! Congratulations. It took you only 5minutes to patch the open_basedir... but never forget: this would never have been possible without having a person like me who spent about 5months finding/creating such a solution. Please keep this in mind and don't laugh at my bad C-Programming.​
h) (optional) drink another beer ;)
10. make:
Code:
 make
11. Waiting... (open another beer and chuck it)
12. No errors? Awesome!
Code:
 make install
13. Wait. Files are being installed.
14. PHP installation is done
15. Now we need to include the CGI stuff into Apache
16. Insert the following into a vhost file or httpd.conf or something:
Code:
 <Directory "/usr/bin/php5">
AllowOverride None
Options +ExecCGI +FollowSymLinks
Order allow,deny
Allow from all
</Directory>
ScriptAlias /php5rocks /usr/bin/php5
Action php5-cgi /php5rocks/php
AddType php5-cgi .php5
17. It is recommended to use suexec!
But this is off topic and I don't offer a HowTo on how to configure suexec (haha, what a wordplay!).
Nevertheless: this link could be helpful:
18. Every *.php5 file is now parsed by our PHP5 CGI version!
19. Finally done!
20. You made it!
21. Chuck the rest of your beers!

Epilogue:
This HowTo is also usable for PHP4!
As I already mentioned: I spent MONTHS building this patch... if you found it helpful, feel free to donate some money to CwCity.de (paypal).
Please note: I do not offer any free support neither on MSN nor on ICQ!
If you have questions/comments/anything else: feel free to reply to this Thread!

This HowTo comes with NO WARRANTY!

Copyright © 2005 by server4downs & CwCity.de

Last Update: 14th of November 2005 (9:45pm)
 
Last edited by a moderator:
Back
Top