vlucas / bulletphp

A resource-oriented micro PHP framework
http://bulletphp.com
BSD 3-Clause "New" or "Revised" License
416 stars 50 forks source link

Path "/" not working in subfolder #73

Closed jvdh closed 6 years ago

jvdh commented 8 years ago

My project is in http://localhost/bullet

Path("/") gives me a 404 other paths work as expected

When I move my project to root (http://localhost) the "/" path works.

I'm on windows 10, apache 2.4,10, PHP 5.4

vlucas commented 8 years ago

Bullet can work in a subdirectory. What path are you giving Bullet in the initial $app->run() method in your index.php file?

jvdh commented 8 years ago

I'm using the Installation Guide example, so I'm passing $app->run(new Bullet\Request());

alanondra commented 8 years ago

I used this to define the "base" for the project, so if it were on www.website.com/bullet/ it would get bullet/ (it would also detect just / if that were the case):

define('WEB_ROOT',trim(dirname($_SERVER['PHP_SELF']),'/').'/');

I then inserted this in parallel to the index route:

$app->path(WEB_ROOT,function(Request $request) {
    return $this->run($request->method(),'index');
});
vlucas commented 8 years ago

@AlanOndra that's a decent approach, but instead of modifying your paths, you just need to run bullet with the proper URL. For some reason, it doesn't know it's in a subdirectory, and that's why the paths are not matching. I would do this:

$requestPath = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$app->run($request->method(), $requestPath);

You might also see what Bullet thinks is the request URL so you can fix it:

var_dump($request->url());
vlucas commented 8 years ago

@jvdh Bullet by default uses the whole path in the REQUEST_URI, so it's trying to match /bullet to / and returning a 404 with no match. You essentially just need to remove the bullet from the beginning of the path, and then match the rest of it.

There are some good solutions for doing this in this thread: http://stackoverflow.com/questions/1252693/using-str-replace-so-that-it-only-acts-on-the-first-match

Code-wise, it will look like this:

function str_replace_first($search, $replace, $subject) {
    $pos = strpos($subject, $search);
    if ($pos !== false) {
        $subject = substr_replace($subject, $replace, $pos, strlen($search));
    }
    return $subject;
}

$requestPath = str_replace_first(__DIR__, '', $request->url());
$app->run($request->method(), $requestPath);
twocore commented 8 years ago

I had the same problem. I modified the uri() function in the Request.php as follows:

    public function uri()
    {
        $script = $this->server('SCRIPT_NAME');
        $rquuri = $this->server('REQUEST_URI');

        if (strpos($rquuri, $script) !== false) {
            $phypath = $script;
        } else {
            $phypath = str_replace('\\', '', dirname($script));
        }

        $script = rtrim($phypath, '/');
        $pathinfo = $phypath;

        if (substr($rquuri, 0, strlen($phypath)) == $phypath) {
            $pathinfo = substr($rquuri, strlen($phypath));
        }

        //return $this->server('REQUEST_URI');
        return $pathinfo;
    }
alanondra commented 8 years ago

@vlucas - Thanks, didn't know about that. Do you think you'll start writing a more detailed API description in the wiki here?

netom commented 6 years ago

@alanondra's approach is good one, and there are several others: @vlucas gave a great example, one could even create a Request object manually, or even subclass the Request to handle more complicated cases.

I think Bullet works exactly as intended and documented, I'm going to close this issue.