4

TL;DR

Does PHP 5.4 built-in webserver have any bug or restriction about relative paths? Or does it need to be properly (and additionally) configured?


When I used to programming actively I had a system working under URI routing using these lines in a .htaccess file:

RewriteEngine On

RewriteRule !\.(js|ico|gif|jpg|png|css)$ index.php [L]

The FrontController received the Request, find the proper route from given URI in a SQLITE database and the Dispatcher call the the Action Controller.

It worked very nicely with Apache. Today, several months later I decided to run my Test Application with PHP 5.4 built-in webserver.

First thing I noticed, obviously, .htaccess don't work so I used code file instead:

<?php

if( preg_match( '/\.(?:png|jpg|jpeg|gif)$/', $_SERVER["REQUEST_URI"] ) ) {
    return false;
}

include __DIR__ . '/index.php';

And started the webserver like this:

php.exe -c "php.ini" -S "localhost:8080" "path\to\testfolder\routing.php"

So far, so good. Everything my application need to bootstrap could be accomplished by modifying the include_path like this:

set_include_path(

    '.' . PATH_SEPARATOR . realpath( '../common/next' )
);

Being next the core folder of all modules inside a folder for with everything common to all applications I have. And it doesn't need any further explanation for this purpose.

None of the AutoLoader techniques I've ever saw was able to autoload themselves, so the only class manually required is my Autoloader. But after running the Test Application I received an error because my AutoLoader could not be found. o.O

I always was very suspicious about realpath() so I decided to change it with the full and absolute path of this next directory and it worked. It shouldn't be needed to do as I did, but it worked.

My autoloader was loaded and successfully registered by spl_autoload_register(). For the reference, this is the autoloading function (only the Closure, of course):

function( $classname ) {

    $classname = stream_resolve_include_path(

        str_replace( '\\', DIRECTORY_SEPARATOR, $classname ) . '.php'
    );

    if( $classname !== FALSE ) {

        include $classname;
    }
};

However, resources located whithin index.php path, like the MVC classes, could not be found. So I did something else I also should not be doing and added the working directory to the include_path. And again, manually, without rely on realpath():

set_include_path(

    '.' . PATH_SEPARATOR . 'path/to/common/next'
        . PATH_SEPARATOR . 'path/to/htdocs/testfolder/'
);

And it worked again... Almost! >.<

The most of Applications I can create with this system works quite well with my Standard Router, based on SQLITE databases. And to make things even easier this Router looks for a predefined SQLITE file within 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 exist and trigger an error if it doesn't.

And this is the specific error I'm seeing. The checking routine is 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 not changed, uses a constant value Data/Routes.sqlite, relatively to working directory.

If, again, again, I set the absolute path manually, everything (really) works, the the Request flow reached the Action Controllers successfully.

What's going on?

  • Yop.. same problem here... (using php 5.3x)... the problem is in the PHP HTTP Server... if you try this just with a HTML app you'll get the same problem... – ZEE Sep 12 '14 at 15:13
  • I noticed that if I run the batch script responsible to start the built-in webserver from within the directory where this relative path definition is, it sometimes works. Sometimes because depends on the application (phpMyAdmin didn't work). But this a terrible limitation as I can't run two different applications at once -OR- both webserver runs should listen two different ports. Worse! I would have several batch scripts, one per application while if without this bug, only one pointing to "." would be enough. –  Sep 12 '14 at 15:38
  • 1
    I'm not aware of any configuration directive to change this behavior. I still think that PHP's internal webserver misses the internal redirect. My bug report was instantly flagged as **not a bug**: https://bugs.php.net/bug.php?id=66191 – Jens A. Koch May 20 '16 at 10:11

1 Answers1

1

This a bug in PHP's built-in web server that is still not fixed, as of PHP version 5.6.30.

In short, the web server does not redirect to www.foo.com/bar/ if www.foo./bar was requested and happens to be a directory. The client being server www.foo.com/bar, assumes it is a file (because of the missing slash at the end), so all subsequent relative links will be fetched relative to www.foo.com/instead of www.foo.com/bar/.

A bug ticket was opened back in 2013 but was mistakenly set to a status of "Not a Bug".

I'm experiencing a similar issue in 2017, so I left a comment on the bug ticket.

Edit : Just noticed that @jens-a-koch opened the ticket I linked to. I was not awar of his comment on the original question.

S. Saad
  • 336
  • 2
  • 9