Closed DanKottke closed 5 years ago
Can you give us an example of the situation that leads to both $_SERVER['SCRIPT_NAME']
equaling $_SERVER['REQUEST_URI']
?
Hey, sure, though I'm not sure in what way you mean for an example. I'll give you all I know. When I halt execution right before the return of Uri::createFromEnvironment(), I can verify that both of those server variables equal (these are dummied, but the same sort of thing I'm seeing) "/documentation/api/view", which is the route entered into, let's just say for clarity, a normal GET route in a browser to "
Apache-wise, we're using virtual hosts with mod rewrite in place to route to appropriate routing scripts. So, for instance:
RewriteCond %{REQUEST_URI} ^/documentation
RewriteRule .* /www/<stuff here>/documentation/routes/main.php [NS,L,QSA]
This file, main.php, is where the Slim\App is instantiated, configured with paths to respond to, and where run() is called on it.
Another thing I've noticed is that in version 4.x, the references to basePath have been reduced. I'm hoping this means that the concept is being phased out? One of the critical places where basePath still factors in on 4.x is in URI::createFromEnvironment() at the part relevant to this ticket:
if (stripos($requestUri, $requestScriptName) === 0) {
$basePath = $requestScriptName;
} elseif ($requestScriptDir !== '/' && stripos($requestUri, $requestScriptDir) === 0) {
$basePath = $requestScriptDir;
}
if ($basePath) {
$virtualPath = ltrim(substr($requestUri, strlen($basePath)), '/');
}
I'd like to mention that the solution that I've employed locally is actually commenting out this entire block and therefore completely gutting this basePath/virtualPath distinction.
Hi, this problem occurred when I was using php-cli server in my develop environment. When I access to /aabb.txt
, the SCRIPT_NAME
is /aabb.txt
, others are /index.php
. To fix this problem, I have to manually write a line such as $_SERVER['SCRIPT_NAME'] = '/index.php'
in my index.php file.
I was referred to the implementation in Symfony HttpFoundation, usingSCRIPT_FILENAME
and SCRIPT_NAME
in the same time is a good idea to avoid this problem.
Yes there is an open problem with the php-cli web server which they have indicated that they will not be fixing.
@DanKottke Yes we are deprecating it :)
I am still having this problem with apache2.4.27-2ubuntu3 and Slim 3.9.0.
I am using this rewrite;
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.php [QSA,L]
And all URLs are resolving to /
and not being routed where they should be.
Here is my $_SERVER
;
Array
(
[SCRIPT_URL] => /basket
[SCRIPT_URI] => http://127.0.0.1/basket
[HTTP_HOST] => 127.0.0.1
[HTTP_USER_AGENT] => Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:57.0) Gecko/20100101 Firefox/57.0
[HTTP_ACCEPT] => text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
[HTTP_ACCEPT_LANGUAGE] => en-GB,en;q=0.5
[HTTP_ACCEPT_ENCODING] => gzip, deflate
[HTTP_COOKIE] => XDEBUG_SESSION=XDEBUG_ECLIPSE
[HTTP_CONNECTION] => keep-alive
[HTTP_UPGRADE_INSECURE_REQUESTS] => 1
[HTTP_CACHE_CONTROL] => max-age=0
[PATH] => /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
[SERVER_SIGNATURE] => <address>Apache/2.4.27 (Ubuntu) Server at 127.0.0.1 Port 80</address>
[SERVER_SOFTWARE] => Apache/2.4.27 (Ubuntu)
[SERVER_NAME] => 127.0.0.1
[SERVER_ADDR] => 127.0.0.1
[SERVER_PORT] => 80
[REMOTE_ADDR] => 127.0.0.1
[DOCUMENT_ROOT] => /var/www
[REQUEST_SCHEME] => http
[CONTEXT_PREFIX] =>
[CONTEXT_DOCUMENT_ROOT] => /var/www
[SERVER_ADMIN] => webmaster@localhost
[SCRIPT_FILENAME] => /var/www/index.php
[REMOTE_PORT] => 38632
[GATEWAY_INTERFACE] => CGI/1.1
[SERVER_PROTOCOL] => HTTP/1.1
[REQUEST_METHOD] => GET
[QUERY_STRING] =>
[REQUEST_URI] => /basket
[SCRIPT_NAME] => /basket
[PHP_SELF] => /basket
[REQUEST_TIME_FLOAT] => 1513643368.615
[REQUEST_TIME] => 1513643368
)
As you can see SCRIPT_NAME
is not correct, which leads the path to be incorrect during routing. Is there a solution to this which doesn't involve manually setting SCRIPT_NAME
in my PHP? (feels like a hack)
This is still an issue out of the box with the latest Slim skeleton. This issue should really not be closed IMHO since all the instructions say to use the PHP built-in development web server and it is apparently also happening to @jackwilsdon w/Apache.
An easy but ugly workaround is to add this in index.php:
if (strpos($_SERVER['SCRIPT_FILENAME'], $_SERVER['DOCUMENT_ROOT']) === 0) {
$_SERVER['SCRIPT_NAME'] = substr($_SERVER['SCRIPT_FILENAME'], strlen(rtrim($_SERVER['DOCUMENT_ROOT'], DIRECTORY_SEPARATOR)));
}
I confirm the same bug with the latest slim version.
If this can be fixed in a B/C way I'm interested.
Also, can someone test if this is a problem for Slim 4?
I'm removing the Slim 4 label from this as it is not an issue there. URI comes from ServerRequestInterface which is determined by the PSR-7 implementation that you choose since #2529 was merged.
We could do with a reproducible project with .htaccess
file and php -S
command line.
Hunting around for the cause of this and possible workarounds, I found this long-standing bug report in Apache: https://bz.apache.org/bugzilla/show_bug.cgi?id=40102 Although dating to Apache 2.0, I believe this is the same issue I'm seeing on Apache 2.4
Based on that discussion, the key here seems to be the "context" within the Apache configuration:
<VirtualHost>
block, SCRIPT_NAME
will end up equal to REQUEST_URI
, breaking Slim's automatic base path detection.<Directory>
or <Location>
block, or in a .htaccess
file, mod-rewrite sets SCRIPT_NAME
as expected. This explains why not everyone sees this bug, because they're using a .htaccess
rather than editing <VirtualHost>
block in the main server config. It also gives a workaround, since surrounding the redirect with <Location /> ... </Location>
is enough to change the context.
An additional workaround mentioned in the Apache bug is to use the [PT]
(pass-through) flag on the RewriteRule
. This forces it to rewrite URL-to-URL rather than URL-to-filename, which seems to cause SCRIPT_NAME
to populate correctly.
All that being said, it would be nice if this could be mitigated in Slim as well.
If the detection code cannot be fixed, perhaps a setting could be added in some way to disable it, for people running into this issue. Unfortunately, \Slim\Http\Uri::createFromEnvironment
is static, and only has access to the environment collection, so I'm not sure how to do that other than putting something into the environment data.
Alternatively, we might be able to detect the broken case by comparing SCRIPT_FILENAME
and SCRIPT_NAME
: in the expected case, SCRIPT_FILENAME
is the full path on disk for the same file as SCRIPT_NAME
; in the broken case, SCRIPT_NAME
is an unrelated string from the requested URL.
if ( substr($env->get('SCRIPT_FILENAME'), -strlen($requestScriptName)) != $requestScriptName ) {
$requestScriptName = '';
$requestScriptDir = '';
}
Adding that just after the definition of $requestScriptName
in Uri::createFromEnvironment
seems to leave the feature working in the PHP built-in server, and when Apache sets SCRIPT_NAME
correctly, but disable it (and so let the router work) when SCRIPT_NAME
is bogus.
I don't have environments on hand to test it under other setups, though, like CGI, Apache+FPM, or Nginx.
Actually, combining that detection with mmelvin0's fix above might make it work for everyone:
$requestScriptFullPath = $env->get('SCRIPT_FILENAME');
if ( substr($requestScriptFullPath, -strlen($requestScriptName)) != $requestScriptName ) {
// SCRIPT_NAME appears to have been set wrong by the server
// Attempt to recover the correct value by taking everything in SCRIPT_FILENAME not also in DOCUMENT_ROOT
$documentRootNoSlash = rtrim($env->get('DOCUMENT_ROOT'), DIRECTORY_SEPARATOR);
if (strpos($requestScriptFullPath, $documentRootNoSlash) === 0) {
$requestScriptName = substr($requestScriptFullPath, strlen($documentRootNoSlash));
$requestScriptDir = dirname($requestScriptName);
}
else {
// If SCRIPT_FILENAME and DOCUMENT_ROOT don't match either, just disable the base path detection
$requestScriptName = '';
$requestScriptDir = '';
}
}
Again, though, I'm not confident how these vars will behave under other setups.
I'm closing this as the Slim 3 branch is now in maintenance mode only for security fixes.
I'm trying to incorporate Slim v 3.x and encountered a problem when $_SERVER['SCRIPT_NAME'] and $_SERVER['REQUEST_URI'] are identical (in our case, say both equal '/documentation/test/foo'). In this case, Slims Uri::createFromEnvironment() function sets the basePath property of the $uri object to '/documentation/test/foo' and the path property to '/'. When Router::dispatch() fires, it ignores the basePath and attempts to route to '/'.
I may have a naive understanding of this virtualPath and basePath distinction that Uri::createFromEnvironment() is making, but one would imagine that in a clean apache httpd.conf case, without virtual hosts or re-write rules configured, that you would encounter this situation where SCRIPT_NAME == REQUEST_URI commonly. Shouldn't Router::dispatch() incorporate the "basePath" in the uri used to dispatch the request? Something like: