Slim: routes with dot don't work when using PHP 5.4 embedded webserver

Created on 1 Aug 2012  路  10Comments  路  Source: slimphp/Slim

Whenever the URL includes a dot the PATH_INFO is always "/" and the correct value is located in SCRIPT_NAME... This makes Slim's routing fail.

<?php
require 'Slim/Slim.php';
$app = new Slim();
$app->get('/', function( ){
    echo "FRONT PAGE";
});
$app->get('/hello/:name', function ($name) {
    echo "Hello, $name!";
});
$app->get('/he.llo/:name', function ($name) {
    echo "HE.LLO $name!";
});
$app->run();
?>

Launch:
php -S 0.0.0.0:3000 index.php

http://localhost:3000/hello/Joe will display Hello, Joe!

http://localhost:3000/he.llo/Joe will display FRONT PAGE

http://localhost:3000/hello/Joe.Smith will display FRONT PAGE

Most helpful comment

I've been trying out Slim 3 and have also ran into this issue. Note that it only occurs when you don't prefix the URL path with the router script name: e.g. it breaks when you use /foo.bar but works fine with /index.php/foo.bar.

Minimal app to reproduce:

composer.json:

{
    "require": {
        "slim/slim": "^3.0@RC"
    }
}

index.php:

<?php

require 'vendor/autoload.php';

$app = new Slim\App();

$app->get('/', function ($request, $response) {
    echo 'ROOT';
});

$app->get('/{name}', function ($request, $response, $args) {
    echo 'NAME: ', $args['name'];
});

$app->run();

PHP invocation:

$ php -v
PHP 5.5.27 (cli) (built: Aug 22 2015 18:20:44)
Copyright (c) 1997-2015 The PHP Group
Zend Engine v2.5.0, Copyright (c) 1998-2015 Zend Technologies
$ php -S localhost:8080 index.php

Results:

| Request URI | Expected Output | Actual Output |
| --- | --- | --- |
| http://localhost:8080/ | ROOT | ROOT |
| http://localhost:8080/index.php | ROOT | ROOT |
| http://localhost:8080/foobar | NAME: foobar | NAME: foobar |
| http://localhost:8080/foo.bar | NAME: foo.bar | ROOT |
| http://localhost:8080/index.php/foobar | NAME: foobar | NAME: foobar |
| http://localhost:8080/index.php/foo.bar | NAME: foo.bar | NAME: foo.bar |

Inspecting $_SERVER in the above situations makes it pretty clear that the issue is related to the fact that for the request to /foo.bar, PHP sets $_SERVER['SCRIPT_NAME'] to /foo.bar while for all other requests it sets it to /index.php.

Overriding it by setting $_SERVER['SCRIPT_NAME'] to /index.php at the top of index.php fixes the problem, but this seems like something that Slim should correct itself (note that Symfony/Silex doesn't have this issue).

All 10 comments

Will investigate. For now, use an alternative character (e.g. underscore, pipe, or dash)

I don't think this is a Slim issue but rather a PHP dev webserver issue.

If you access http://127.0.0.1/he.llo/df
$_SERVER['REQUEST_URI'] = "/he.llo/df"
$_SERVER['SCRIPT_NAME'] = "/he.llo/df"

Where as if you access http://127.0.0.1/hello/df
$_SERVER['REQUEST_URI'] = "/hello/df"
$_SERVER['SCRIPT_NAME'] = "/index.php"

That smells of server issue not Slim. Slim will then see this as a url rewrite happening and $env['PATH_INFO'] = substr_replace($_SERVER['REQUEST_URI'], '', 0, strlen($env['SCRIPT_NAME'])); will proceed to set PATH_INFO to \

Not to mention if you have a route of $app->get('/he.llo/:name', function ($name) {} that will also match /heAllo/brian as the period is a wilcard in a regular expression so I'd say its generally not a great idea anyway.

I've tested this here and Slim appears to work fine for me with the built-in 5.4 web server. Granted, you don't have .htaccess so you have to include "/index.php" in your request URLs. But it seems to work just fine here with periods in the URL. I'm using the develop branch. Which branch are you using?

Also, you may want to do a print_r($_SERVER) to see if the request URLs are getting malformed before they hit the web server. As is, I can't duplicate. Closing this out. Please open a thread at http://help.slimframework.com/ and I'll continue to help you out there.

I've been trying out Slim 3 and have also ran into this issue. Note that it only occurs when you don't prefix the URL path with the router script name: e.g. it breaks when you use /foo.bar but works fine with /index.php/foo.bar.

Minimal app to reproduce:

composer.json:

{
    "require": {
        "slim/slim": "^3.0@RC"
    }
}

index.php:

<?php

require 'vendor/autoload.php';

$app = new Slim\App();

$app->get('/', function ($request, $response) {
    echo 'ROOT';
});

$app->get('/{name}', function ($request, $response, $args) {
    echo 'NAME: ', $args['name'];
});

$app->run();

PHP invocation:

$ php -v
PHP 5.5.27 (cli) (built: Aug 22 2015 18:20:44)
Copyright (c) 1997-2015 The PHP Group
Zend Engine v2.5.0, Copyright (c) 1998-2015 Zend Technologies
$ php -S localhost:8080 index.php

Results:

| Request URI | Expected Output | Actual Output |
| --- | --- | --- |
| http://localhost:8080/ | ROOT | ROOT |
| http://localhost:8080/index.php | ROOT | ROOT |
| http://localhost:8080/foobar | NAME: foobar | NAME: foobar |
| http://localhost:8080/foo.bar | NAME: foo.bar | ROOT |
| http://localhost:8080/index.php/foobar | NAME: foobar | NAME: foobar |
| http://localhost:8080/index.php/foo.bar | NAME: foo.bar | NAME: foo.bar |

Inspecting $_SERVER in the above situations makes it pretty clear that the issue is related to the fact that for the request to /foo.bar, PHP sets $_SERVER['SCRIPT_NAME'] to /foo.bar while for all other requests it sets it to /index.php.

Overriding it by setting $_SERVER['SCRIPT_NAME'] to /index.php at the top of index.php fixes the problem, but this seems like something that Slim should correct itself (note that Symfony/Silex doesn't have this issue).

It is probably related to PHP bug 61286. Built-in server will consider request as a static file request if there is a dot in the SCRIPT_NAME.

@tuupola Yeah, I did notice that bug report, and that appears to be the root cause. Unfortunately, it doesn't look like they're going to change it (marked Wont Fix).

On a related note, I noticed that Slim's ServerRequest factory implementation differs from Zend Diactoros in how it determines the path from the environment. Slim splits the base path and only returns the path info in Uri::getPath(), while Diactoros returns the full request URI including the base path.

@codeguy What do you think? Can you duplicate it with the code above?

I'm struggling with this now and I've just thrown my hands up. I really can't believe that bug is "won't fix", but then I'm frustrated right now and perhaps not thinking it through clearly.

Overriding it by setting $_SERVER['SCRIPT_NAME'] to /index.php at the top of index.php fixes the problem ...

@chriseskow Yes, it does solve the problem of the built in webserver not matching the route, but using that solution causes the server to stop serving static files. Totally bizarre, totally frustrating, and I wish core would just fix the problem already.

/rant

@jeremykendall: I believe this can be worked around reasonably cleanly by adding a routing script to the PHP web server call and returning false for static assets. See how I have done so here, and ping me if you want more info.

Adding the following line in my public/index.php worked for me (PHP 7.2.1):

if (PHP_SAPI == 'cli-server') {
    $_SERVER['SCRIPT_NAME'] = '/index.php';
}

I had tried (started with):
PHP if (PHP_SAPI == 'cli-server') { $_SERVER['SCRIPT_NAME'] = '/index.php'; $_SERVER['PATH_INFO'] = $_SERVER['REQUEST_URI']; $_SERVER['PHP_SELF'] = $_SERVER['SCRIPT_NAME'] . ($_SERVER['REQUEST_URI'] === '/' ? '' : $_SERVER['REQUEST_URI']); }
But neither PATH_INFO nor PHP_SELF are used by Slim, so forcing SCRIPT_NAME is enough.

Other workaround which worked (but it's application might not always be possible/desired):
Instead of requesting:
http://localhost:3000/hello/Joe.Smith
request:
http://localhost:3000/index.php/hello/Joe.Smith

Had same problem. Thanks for your info all! I will leave my workaround.

router.php

<?php
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
if (file_exists($_SERVER['DOCUMENT_ROOT'] . $path)) {
    return false;
} else {
    $_SERVER['SCRIPT_NAME'] = '/index.php';
    require $_SERVER['DOCUMENT_ROOT'] . '/index.php';
}

Launch cli-server: php -S localhost:8004 -t public_html application/tools/cli-server/router.php

Was this page helpful?
0 / 5 - 0 ratings

Related issues

l0gicgate picture l0gicgate  路  28Comments

derekjones picture derekjones  路  19Comments

akrabat picture akrabat  路  22Comments

Paratron picture Paratron  路  24Comments

alexweissman picture alexweissman  路  38Comments