# Apache handler with Multiple PHP versions

- Thread: https://externals.io/message/30795
- Original archive: https://news-web.php.net/php.internals/30795
- Started by Tijnema on 2007-07-11T22:43:49+00:00
- Messages: 15
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · RFCs at https://externals.io/rfc.md · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #30795 — Tijnema — 2007-07-11T22:43:49+00:00

URL: https://externals.io/message/30795#30795

Hello developers,

The thread about dropping support for PHP4 gave me a new idea, having
multiple PHP versions to be loaded by the Apache2handler SAPI.

The idea:
I was thinking about something like the shebang(#!) line used in
bash/perl/python and even PHP scripts. But this time not for the
program to be executed, but for which PHP version to load. This could
be used like this:
<?php // PHP4 ?>
for PHP4, and so it could be
<?php // PHP5 ?> or <?php // PHP6 ?>
for resp. PHP5 or PHP6.
This way can scripts define which PHP version they require, as it is a
normal comment line, other PHP version can simply ignore the line.

The implementation:
The Apache2handler SAPI should be loaded first, and read the very
first line of the PHP script to determine if a version is specified
there. If not, the handler needs to load its default PHP version. If
it is specified, it should try to load that version, and if it
couldn't find or load that version, fall back to the default version
and issue a warning.

What needs to change:
Currently, PHP is one big module for Apache, which will load a full
PHP version at once. For this, we require a very small handler, that
will use dlopen() to load the appropriate version and continue with
the execution of the PHP script.
Some kind of mini parser is also required to read the very first line
of a PHP script, because that needs to be done before any PHP version
is loaded. And maybe also a parser for the php.ini file, as php.ini
needs an extra option for the default PHP version to be loaded, and
one or more settings for configuring the different PHP versions and
their path to the library.

Some extra ideas, not sure if they need to be implemented:
* Support for sub versions of PHP, like this:
<?php // PHP4.3 ?>
<?php // PHP5.2.1 ?>
* Support for multiple possible PHP versions, like this:
<?php // PHP4 || PHP5 ?>
Where the first one is the preferred one, which can also be combined
with the first one of course, like this:
<?php // PHP5.2.1 || PHP5.2.0 || PHP 4.3 ?>
* Support for <, > and && signs in the version, like this:
<?php // PHP > 5.2 && PHP < 5.3 ?>
So that any PHP version between 5.2 and 5.3 fits, but that 5.2 is the
preferred one, if 5.3 should be the preferred one, it should be
written like this:
<?php // PHP < 5.3 && PHP > 5.2 ?>
* Support for this in other handlers, like FastCGI, ISAPI, etc.


It seems to be the perfect solution for shared hosting providers to
me, as it will allow the user to select which PHP version he wants to
use, and shared hosts can just install all three versions of PHP and
use the one they need for their admin panels etc. (One of the reasons
against upgrading to PHP5), and users can use another version.
I don't know too much about PHP core, and nearly nothing about the
apache2handler, so if it's not possible, please excuse me for wasting
your time.
But, if it is possible, I will definitely go deeper inside the core
and SAPI code to get it working.

Now, the reason I'm sending this to the list is that I need to know if
*) it is possible?
*) it is not yet done
*) it is wanted
*) it will have any negative effect on something?

I'd like to hear all your comments and objections on this, and of
course, if you have any question, feel free to ask.

Regards,

Tijnema

---

## #30797 — Jani Taskinen — 2007-07-11T23:08:13+00:00

URL: https://externals.io/message/30795#30797 · In reply to: #30795

A lot easier (and works already) is to install PHP as CGI/FastCGI
(one version or all of them, one can be module of course) and define the 
required PHP version by the file suffix..

--Jani

Tijnema kirjoitti:
> Hello developers,
> 
> The thread about dropping support for PHP4 gave me a new idea, having
> multiple PHP versions to be loaded by the Apache2handler SAPI.
> 
> The idea:
> I was thinking about something like the shebang(#!) line used in
> bash/perl/python and even PHP scripts. But this time not for the
> program to be executed, but for which PHP version to load. This could
> be used like this:
> <?php // PHP4 ?>
> for PHP4, and so it could be
> <?php // PHP5 ?> or <?php // PHP6 ?>
> for resp. PHP5 or PHP6.
> This way can scripts define which PHP version they require, as it is a
> normal comment line, other PHP version can simply ignore the line.
> 
> The implementation:
> The Apache2handler SAPI should be loaded first, and read the very
> first line of the PHP script to determine if a version is specified
> there. If not, the handler needs to load its default PHP version. If
> it is specified, it should try to load that version, and if it
> couldn't find or load that version, fall back to the default version
> and issue a warning.
> 
> What needs to change:
> Currently, PHP is one big module for Apache, which will load a full
> PHP version at once. For this, we require a very small handler, that
> will use dlopen() to load the appropriate version and continue with
> the execution of the PHP script.
> Some kind of mini parser is also required to read the very first line
> of a PHP script, because that needs to be done before any PHP version
> is loaded. And maybe also a parser for the php.ini file, as php.ini
> needs an extra option for the default PHP version to be loaded, and
> one or more settings for configuring the different PHP versions and
> their path to the library.
> 
> Some extra ideas, not sure if they need to be implemented:
> * Support for sub versions of PHP, like this:
> <?php // PHP4.3 ?>
> <?php // PHP5.2.1 ?>
> * Support for multiple possible PHP versions, like this:
> <?php // PHP4 || PHP5 ?>
> Where the first one is the preferred one, which can also be combined
> with the first one of course, like this:
> <?php // PHP5.2.1 || PHP5.2.0 || PHP 4.3 ?>
> * Support for <, > and && signs in the version, like this:
> <?php // PHP > 5.2 && PHP < 5.3 ?>
> So that any PHP version between 5.2 and 5.3 fits, but that 5.2 is the
> preferred one, if 5.3 should be the preferred one, it should be
> written like this:
> <?php // PHP < 5.3 && PHP > 5.2 ?>
> * Support for this in other handlers, like FastCGI, ISAPI, etc.
> 
> 
> It seems to be the perfect solution for shared hosting providers to
> me, as it will allow the user to select which PHP version he wants to
> use, and shared hosts can just install all three versions of PHP and
> use the one they need for their admin panels etc. (One of the reasons
> against upgrading to PHP5), and users can use another version.
> I don't know too much about PHP core, and nearly nothing about the
> apache2handler, so if it's not possible, please excuse me for wasting
> your time.
> But, if it is possible, I will definitely go deeper inside the core
> and SAPI code to get it working.
> 
> Now, the reason I'm sending this to the list is that I need to know if
> *) it is possible?
> *) it is not yet done
> *) it is wanted
> *) it will have any negative effect on something?
> 
> I'd like to hear all your comments and objections on this, and of
> course, if you have any question, feel free to ask.
> 
> Regards,
> 
> Tijnema

---

## #30798 — Tijnema — 2007-07-11T23:13:33+00:00

URL: https://externals.io/message/30795#30798 · In reply to: #30797

> A lot easier (and works already) is to install PHP as CGI/FastCGI
> (one version or all of them, one can be module of course) and define the
> required PHP version by the file suffix..
>
> --Jani

Hello Jani:

I know this is possible, and I believe it is possible in Apache too
with some kind of hack?
But this still doesn't solve a lot of problems, but will generate a
lot more with portable code. Take a bulletin board for example, there
are a lot of files inside a board, and when you want to install that
on your host that has PHP5 for files with .php5, you need to rename a
hell lot of files to .php5, AND change code inside the .php5 files to
point to the renamed files.

Regards,

Tijnema
>
> Tijnema kirjoitti:
> > […]
>


-- 
Vote for PHP Color Coding in Gmail! -> http://gpcc.tijnema.info

---

## #30800 — Guilherme Blanco — 2007-07-12T00:13:32+00:00

URL: https://externals.io/message/30795#30800 · In reply to: #30798

Hi Tijnema,

I think here is something that might interest you:

http://www.phpclasses.org/browse/package/3472.html


Regards,


> 
> > […]
>
> Hello Jani:
>
> I know this is possible, and I believe it is possible in Apache too
> with some kind of hack?
> But this still doesn't solve a lot of problems, but will generate a
> lot more with portable code. Take a bulletin board for example, there
> are a lot of files inside a board, and when you want to install that
> on your host that has PHP5 for files with .php5, you need to rename a
> hell lot of files to .php5, AND change code inside the .php5 files to
> point to the renamed files.
>
> Regards,
>
> Tijnema
> > […]
>
>
> --
> Vote for PHP Color Coding in Gmail! -> http://gpcc.tijnema.info
>
> --
> 
> 
>
>


-- 
Guilherme Blanco - Web Developer
CBC - Certified Bindows Consultant
Cell Phone: +55 (16) 9166-6902
MSN: guilhermeblanco@hotmail.com
URL: http://blog.bisna.com
São Carlos - SP/Brazil

---

## #30801 — johannes@schlueters.de — 2007-07-12T00:15:38+00:00

URL: https://externals.io/message/30795#30801 · In reply to: #30798

Hi


> 
> I know this is possible, and I believe it is possible in Apache too
> with some kind of hack?
> But this still doesn't solve a lot of problems, but will generate a
> lot more with portable code. Take a bulletin board for example, there
> are a lot of files inside a board, and when you want to install that
> on your host that has PHP5 for files with .php5, you need to rename a
> hell lot of files to .php5, AND change code inside the .php5 files to
> point to the renamed files.

Then setup a VirtualHost or use an .htaccess file or something like that
where you bind the .php extension to the relevant Handler...

johannes

---

## #30802 — Richard Lynch — 2007-07-12T00:25:32+00:00

URL: https://externals.io/message/30795#30802 · In reply to: #30798

> 
> > […]
>
> Hello Jani:
>
> I know this is possible, and I believe it is possible in Apache too
> with some kind of hack?
> But this still doesn't solve a lot of problems, but will generate a
> lot more with portable code. Take a bulletin board for example, there
> are a lot of files inside a board, and when you want to install that
> on your host that has PHP5 for files with .php5, you need to rename a
> hell lot of files to .php5, AND change code inside the .php5 files to
> point to the renamed files.

No, you add a <Directory> config in httpd.conf or add to .htaccess a
line like
<Files ~.php>
  ForceType whatever/gets/you/to/php-5
</Files>

Other problems:

Getting 2 PHP modules to co-exist without tromping on each others'
symbols is, I think, the show-stopper...

It was possible to have PHP3 and PHP4 both as modules, I think, but
that was an anomoly?

You also would have to re-think what happens when a version is
requested that isn't installed at all...

You currently have it just run in the default version, I think, but is
that really useful?  If the code really NEEDS PHP 5, and the server
doesn't have 5, only 4, running the code that needs 5 is probably not
the right action...

-- 
Some people have a "gift" link here.
Know what I want?
I want you to buy a CD from some indie artist.
http://cdbaby.com/browse/from/lynch
Yeah, I get a buck. So?

---

## #30843 — Tijnema — 2007-07-12T09:38:44+00:00

URL: https://externals.io/message/30795#30843 · In reply to: #30802

Hello Richard,


> 
> > […]
>
> No, you add a <Directory> config in httpd.conf or add to .htaccess a
> line like
> <Files ~.php>
>  ForceType whatever/gets/you/to/php-5
> </Files>

1) Did you ever see a shared host that has multiple versions
configured like this?
2) This will end up to be confusing for the end user, as they will
need to create the .htaccess file (as most users don't have write
rights for httpd.conf)

>
> Other problems:
>
> Getting 2 PHP modules to co-exist without tromping on each others'
> symbols is, I think, the show-stopper...

Both modules are different files, and only one will be dynamically
loaded by dlopen(), that works fine right? or do I forget something?

>
> It was possible to have PHP3 and PHP4 both as modules, I think, but
> that was an anomoly?
That was nice :)
>
> You also would have to re-think what happens when a version is
> requested that isn't installed at all...
>
> You currently have it just run in the default version, I think, but is
> that really useful?  If the code really NEEDS PHP 5, and the server
> doesn't have 5, only 4, running the code that needs 5 is probably not
> the right action...

I did, I think it should generate an error message,
 `E_RECOVERABLE_ERROR` maybe? And then the default PHP version should
just give the code a try, just like it does when it is installed on a
host that has the wrong PHP version installed.

Regards,

Tijnema

---

## #30844 — Tijnema — 2007-07-12T09:45:20+00:00

URL: https://externals.io/message/30795#30844 · In reply to: #30800

> Hi Tijnema,
>
> I think here is something that might interest you:
>
> http://www.phpclasses.org/browse/package/3472.html
>
>
> Regards,

Hello Guilherme,

This comes quite close to my idea, except that this does only
uncomment specfic sections that are for specific versions. This means
that as a coder, you still need to write all of those bypasses for
specific versions.

Regards,

Tijnema
>
> 
> > […]
>
>
> --
> Guilherme Blanco - Web Developer
> CBC - Certified Bindows Consultant
> Cell Phone: +55 (16) 9166-6902
> MSN: guilhermeblanco@hotmail.com
> URL: http://blog.bisna.com
> São Carlos - SP/Brazil

---

## #30846 — Derick Rethans — 2007-07-12T09:50:12+00:00

URL: https://externals.io/message/30795#30846 · In reply to: #30843

> 
>
> > […]
> 
> Both modules are different files, and only one will be dynamically
> loaded by dlopen(), that works fine right? or do I forget something?

You forget that the symbol names in both shared objects are still the 
same. If you have that you get *major* issues when running the code. So 
no, it does not work fine.

Derick

-- 
Derick Rethans
http://derickrethans.nl | http://ez.no | http://xdebug.org

---

## #30912 — Stanislav Malyshev — 2007-07-14T07:13:58+00:00

URL: https://externals.io/message/30795#30912 · In reply to: #30795

> The Apache2handler SAPI should be loaded first, and read the very
> first line of the PHP script to determine if a version is specified
> there. If not, the handler needs to load its default PHP version. If
> it is specified, it should try to load that version, and if it
> couldn't find or load that version, fall back to the default version
> and issue a warning.

This means the engines would have to init/shutdown on each request, 
which makes it as bad as CGI. Why not just go FastCGI? You can use 
extensions like .php4 and .php5.
-- 
Stanislav Malyshev, Zend Software Architect
stas@zend.com   http://www.zend.com/
(408)253-8829   MSN: stas@zend.com

---

## #30929 — Tijnema — 2007-07-14T15:13:03+00:00

URL: https://externals.io/message/30795#30929 · In reply to: #30912

> > […]
>
> This means the engines would have to init/shutdown on each request,
> which makes it as bad as CGI.
Is that really a big problem?
And isn't that what Apache currently does?
As I said before, I don't know a lot about PHP core/ Apache2handler
SAPI, But I expected Apache to load PHP on each request.
And what if I just load and init all PHP versions at once with
different handles? (See example code at the bottom of this message)

> Why not just go FastCGI? You can use
> extensions like .php4 and .php5.
> --
> Stanislav Malyshev, Zend Software Architect

It's not just for my personal server, I just load different PHP
versions by updating a symlink (libphp.so -->libphp4.so, libphp5.so or
libphp5-2-1.so), and restarting Apache.
I talked to my webmaster of my Shared host, and he said:
"I don't see a reason to use FastCGI with different extensions, this
will probably lead to problems with unexperienced users on this
server. If your idea shows no security issues, performance issues or
difficult configuration settings, we will use it to support more
versions of PHP."

So, that confirms what I was thinking, but other webmasters might
think different about it.

Tijnema

The code for loading and starting up different PHP versions at once:
--------------------php4.c--------------------
int *parse_php_code(char *file)
{
	return 4;
}

int php_startup()
{
	return 1;
}
--------------------/php4.c--------------------
--------------------php5.c--------------------
int *parse_php_code(char *file)
{
	return 5;
}

int php_startup()
{
	return 1;
}
--------------------/php5.c--------------------
--------------------php6.c--------------------
int *parse_php_code(char *file)
{
	return 6;
}

int php_startup()
{
	return 1;
}
--------------------/php6.c--------------------
--------------------loader.c--------------------
#include <stdio.h>
#include <dlfcn.h>

int main(int argc, char *argv[])
{
	void *handle4, *handle5, *handle6;
	char *error;

	int *(*parse_code4)(char *);
	int *(*startup4);

	int *(*parse_code5)(char *);
	int *(*startup5);

	int *(*parse_code6)(char *);
	int *(*startup6);

	FILE * fp;
	char *ver;
	char *buffer;

	if(argc != 2) {
		fprintf(stderr, "Syntax: %s <php file>\n", argv[0]);
		exit(1);
	}

	handle4 = dlopen("./libphp4.so", RTLD_LAZY);
	handle5 = dlopen("./libphp5.so", RTLD_LAZY);
	handle6 = dlopen("./libphp6.so", RTLD_LAZY);

	if(!handle4) {
		fprintf(stderr, "%s\n", dlerror());
		exit(1);
	}
	if(!handle5) {
		fprintf(stderr, "%s\n", dlerror());
		exit(1);
	}
	if(!handle6) {
		fprintf(stderr, "%s\n", dlerror());
		exit(1);
	}

	startup4 = dlsym(handle4, "php_startup");
	if((error = dlerror()) != NULL) {
		fprintf (stderr, "PHP%d: %s\n", 4, error);
		exit(1);
	}

	startup5 = dlsym(handle5, "php_startup");
	if((error = dlerror()) != NULL) {
		fprintf (stderr, "PHP%d: %s\n", 5, error);
		exit(1);
	}

	startup6 = dlsym(handle6, "php_startup");
	if((error = dlerror()) != NULL) {
		fprintf (stderr, "PHP%d: %s\n", 6, error);
		exit(1);
	}

	if(!(*startup4)) {
		fprintf(stderr, "Failed to startup PHP %d\n", 4);
		exit(1);
	}

	if(!(*startup5)) {
		fprintf(stderr, "Failed to startup PHP %d\n", 5);
		exit(1);
	}

	if(!(*startup6)) {
		fprintf(stderr, "Failed to startup PHP %d\n", 6);
		exit(1);
	}

	parse_code4 = dlsym(handle4, "parse_php_code");
	if((error = dlerror()) != NULL) {
		fprintf (stderr, "PHP%d: %s\n", 4, error);
		exit(1);
	}

	parse_code5 = dlsym(handle5, "parse_php_code");
	if((error = dlerror()) != NULL) {
		fprintf (stderr, "PHP%d: %s\n", 5, error);
		exit(1);
	}

	parse_code6 = dlsym(handle6, "parse_php_code");
	if((error = dlerror()) != NULL) {
		fprintf (stderr, "PHP%d: %s\n", 6, error);
		exit(1);
	}
	
	fp = fopen(argv[1], "r");
	if(fp == NULL) {
		fprintf (stderr, "Error opening php file %s\n", argv[1]);
		exit(1);
	}
	buffer = (char *) malloc(13);
	ver = (char *) malloc(2);
	fread(buffer,1,12,fp);
	if(strcmp(buffer,"<?php //PHP ") == 0) {
		fread(ver,1,1,fp);
	} else {
		ver = "6";
	}

	if(strcmp(ver,"4") == 0) {
		printf("%d\n",(*parse_code4)(argv[0]));
	} else if(strcmp(ver,"5") == 0) {
		printf("%d\n",(*parse_code5)(argv[0]));
	} else if(strcmp(ver,"6") == 0) {
		printf("%d\n",(*parse_code6)(argv[0]));
	} else {
		printf("%d\n",(*parse_code5)(argv[0]));
	}

	dlclose(handle4);
	dlclose(handle5);
	dlclose(handle6);
	return 0;
}
--------------------/loader.c--------------------

Test files used:
--------------------test4.php--------------------
<?php //PHP 4 ?>
--------------------/test4.php--------------------
--------------------test5.php--------------------
<?php //PHP 5 ?>
--------------------/test5.php--------------------
--------------------test6.php--------------------
<?php //PHP 6 ?>
--------------------/test6.php--------------------

Compiled with:
gcc -shared -fPIC php4.c -o libphp4.so
gcc -shared -fPIC php5.c -o libphp5.so
gcc -shared -fPIC php6.c -o libphp6.so
gcc -rdynamic -o loader loader.c -ldl

Test results:
./loader ./test4.php (Outputs 4)
./loader ./test5.php (Outputs 5)
./loader ./test6.php (Outputs 6)

---

## #30930 — Rasmus Lerdorf — 2007-07-14T16:09:59+00:00

URL: https://externals.io/message/30795#30930 · In reply to: #30929

Tijnema wrote:
> 
> > […]
> Is that really a big problem?

If you care at all about performance, yes.

> And isn't that what Apache currently does?

No, of course not.  The whole point of the Apache module version of PHP
is to keep PHP in memory across requests and only call the MINIT and
MSHUTDOWN hooks on server startup and shutdown.

Not to sound too elitist here, and this is directed just at you
personally, but if you are going to post to the internals list, you
should have some notion of how PHP works internally.  We don't mind
people who don't work on the code posting here occasionally, but please
keep in mind that it is our primary means of communicating amongst the
people working on the code and lately it has gotten a bit hard to pick
out the useful stuff from the chatter.

-Rasmus

---

## #30932 — Rasmus Lerdorf — 2007-07-14T16:12:21+00:00

URL: https://externals.io/message/30795#30932 · In reply to: #30930

Rasmus Lerdorf wrote:
> Not to sound too elitist here, and this is directed just at you

Argh!  That should of course have been, "this isn't directed just at you..."

-Rasmus

---

## #30943 — Tijnema — 2007-07-15T01:01:17+00:00

URL: https://externals.io/message/30795#30943 · In reply to: #30930

> Tijnema wrote:
> > […]
>
> If you care at all about performance, yes.

Well, I do, because if I don't, it won't be accepted anywhere.

>
> > […]
>
> No, of course not.  The whole point of the Apache module version of PHP
> is to keep PHP in memory across requests and only call the MINIT and
> MSHUTDOWN hooks on server startup and shutdown.

Thank you for your very short manual on Apache Module. So, the only
way I can implement this (without the performance hit), is by loading
all PHP version at once at startup of apache, which will increase
startup time, but that shouldn't be a problem. A more worrysome thing
is the memory usage, I don't think that in the code is described how
much memory it takes to load and startup PHP, can you give an
estimate?

>
> Not to sound too elitist here, and this is directed just at you
> personally, but if you are going to post to the internals list, you
> should have some notion of how PHP works internally.  We don't mind
> people who don't work on the code posting here occasionally, but please
> keep in mind that it is our primary means of communicating amongst the
> people working on the code and lately it has gotten a bit hard to pick
> out the useful stuff from the chatter.
>
> -Rasmus
>

Thank you for clarifying the intention of this list, as I had another
intention of it. So, I'll start studying (docs of) the code soon. I
think it would be the best to actually work with the core too, so I
think I'll just start to implement this idea while learning how
everything works.

Tijnema

---

## #31016 — Arnold Daniels — 2007-07-17T20:09:28+00:00

URL: https://externals.io/message/30795#31016 · In reply to: #30943

Hi,

Sorry for this late reaction, but I was away for a few days.

We (as ISP) have solved this by running multiple instanced of
Apache. This way you can switch the IP in DNS to switch between PHP
versions. You only need 1 install of Apache and do not need to copy/move
any files while switching. As hosting company you can't really ask your
clients to change their scripts anyway. This way they can simply choose
the PHP version in the control panel.

I have written a short howto about this a while ago:
http://blog.adaniels.nl/?p=13, (showing how well my blog is read). I
have fine-tuned the method since than, this was more a test setup, so if
you want to know more, please let me know.

Best regards,
Arnold

Tijnema wrote:
> 
> > […]
>
> Well, I do, because if I don't, it won't be accepted anywhere.
>
> > […]
>
> Thank you for your very short manual on Apache Module. So, the only
> way I can implement this (without the performance hit), is by loading
> all PHP version at once at startup of apache, which will increase
> startup time, but that shouldn't be a problem. A more worrysome thing
> is the memory usage, I don't think that in the code is described how
> much memory it takes to load and startup PHP, can you give an
> estimate?
>
> > […]
>
> Thank you for clarifying the intention of this list, as I had another
> intention of it. So, I'll start studying (docs of) the code soon. I
> think it would be the best to actually work with the core too, so I
> think I'll just start to implement this idea while learning how
> everything works.
>
> Tijnema
