PHP built-in web server and relative paths
TL; DR
Does PHP 5.4 built-in web server have any bugs or restrictions regarding relative paths? Or should it be configured properly (and optional)?
When I was actively programming, I had a system working under URI routing using these lines in the .htaccess file :
RewriteEngine On
RewriteRule !\.(js|ico|gif|jpg|png|css)$ index.php [L]
FrontController received a request, find the correct route from the given URI in the SQLITE database and the dispatcher will call the action controller.
It worked great with Apache. Today, a few months later, I decided to run a test application with PHP 5.4 built-in web server.
The first thing I noticed is obviously .htaccess doesn't work, so I used the code file instead:
<?php
if( preg_match( '/\.(?:png|jpg|jpeg|gif)$/', $_SERVER["REQUEST_URI"] ) ) {
return false;
}
include __DIR__ . '/index.php';
And started the web server like this:
php.exe -c "php.ini" -S "localhost:8080" "path\to\testfolder\routing.php"
So far so good. All I need to download can be accomplished by modifying the include_path like this:
set_include_path(
'.' . PATH_SEPARATOR . realpath( '../common/next' )
);
Being next is the main folder of all modules inside a folder with everything that is common to all applications that I have. And no further explanation is required for this.
None of the AutoLoader methods I've ever seen have been able to self-load, so the only class that is manually required is my autoloader. But after running the test application, I got an error because my autoloader was not found. oo
I've always been very suspicious of realpath (), so I decided to change it with the full and absolute path in this next directory and it worked. It doesn't have to be done the way I do, but it worked.
My autoloader has been loaded and registered successfully with spl_autoload_register (). For reference, this is the autoload function (only closing of course):
function( $classname ) {
$classname = stream_resolve_include_path(
str_replace( '\\', DIRECTORY_SEPARATOR, $classname ) . '.php'
);
if( $classname !== FALSE ) {
include $classname;
}
};
However, resources located in the index.php path, like the MVC classes, cannot be found. So I did something else that I shouldn't do either, and added the working directory to the include_path. Again, manually, without relying on realpath ():
set_include_path(
'.' . PATH_SEPARATOR . 'path/to/common/next'
. PATH_SEPARATOR . 'path/to/htdocs/testfolder/'
);
And it worked again ... Almost !. > & L;
Most of the applications I can build with this system work fine with my standard SQLITE database router. And to simplify this route, this router looks for a predefined SQLITE file in the working directory.
Of course, I also provide a way to change this default entry just in case, and because of this, I check if this file exists and throws an error if it doesn't.
And this is the specific error that I see. The verification procedure looks like this:
if( ! file_exists( $this -> options -> dbPath ) ) {
throw RouterException::connectionFailure(
'Routes Database File %s doesn\'t exist in Data Directory',
array( $this -> options -> dbPath )
);
}
The dbPath entry , if unchanged , uses the constant Data / Routes.sqlite value , relative to the working directory.
If you manually set the absolute path again again, everything (really) works, the request flow has successfully reached the Action Controllers.
What's happening?
This bug is on PHP built-in web server which is still not fixed as of PHP 5.6.30.
In short, the webserver does not redirect to www.foo.com/bar/
if the request www.foo./bar
was requested and is a directory. The client being the server www.foo.com/bar
assumes it is a file (due to the lack of a trailing slash), so all subsequent relative references will be selected relative www.foo.com/
instead of www.foo.com/bar/
.
In 2013, a ticket was opened with an error , but the status was set to "Not error" by mistake.
I'm experiencing a similar issue in 2017, so I left a comment on the bit.
Edit: Just noticed that @ jens-a-koch opened the ticket I contacted. I was not familiar with his comment on the original question.