Running Slim 4 in a subdirectory
If you want to run Slim 4 in a subdirectory of your website, then you have a few things you need to do. Let’s consider the situation:
- Your main website is in the directory /var/www/html and is accessed at https://example.com/.
- You want your new Slim 4 app to be in the directory /var/www/html/myapp and to be accessed at https://example.com/myapp.
- Your Slim 4 index.php file is stored in /var/www/html/myapp.
There are two things you need to sort out: the web server and the Slim app. Let’s start with the web server.
The web server (Apache)
I’m going to cover Apache here as that’s the one I know. Somewhere in your virtual host definition file (a .conf file within /etc/apache2/sites-available on Ubuntu) you have DocumentRoot /var/www/html. You should also have a <Directory "/var/www/html"> section. Ensure that there is AllowOverride All within that Directory section so that Apache will read .htaccess files.
Create a .htaccess file in /var/www/html/myapp with the following contents:
RewriteEngine On
RewriteBase /myapp
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.php [QSA,L]
The key thing here is the RewriteBase directive which must be set to the URL segments where your index.php is. In our case, our Slim 4 app’s index.php is at https://example.com/myapp/index.php, so the RewriteBase is /myapp/. If our index.php was at https://example.com/foo/bar/index.php, then we would set RewriteBase /foo/bar/.
Now that we’ve told Apache where to rewrite from, we need to tell Slim 4 too.
Slim 4 config
In our Slim 4 application, we need to set the base path so that the router can match the URL from the browser with the path set in the route registration methods ($app->get(), $app->post()). This is done with the setBasePath() method.
In your index.php, add:
$app->setBasePath('/myapp');
Note that you do not include the trailing / as that’s the first character in the route registration method’s path (.e.g $app->get('/contact', ...)).
Everything will now work, but if you don’t want to hard code the base path in setBasePath(), then you can use this function:
$app->setBasePath((function () {
$scriptDir = str_replace('\\', '/', dirname($_SERVER['SCRIPT_NAME']));
$uri = (string) parse_url('http://a' . $_SERVER['REQUEST_URI'] ?? '', PHP_URL_PATH);
if (stripos($uri, $_SERVER['SCRIPT_NAME']) === 0) {
return $_SERVER['SCRIPT_NAME'];
}
if ($scriptDir !== '/' && stripos($uri, $scriptDir) === 0) {
return $scriptDir;
}
return '';
})());
In this case, we define an anonymous function and call it. The code in this anonymous function is based on how Slim 3 determined the base path. It works well when it works, but if you have a more esoteric requirement, then it won’t work. With Slim 3, it was complicated to handle those situations, which is why in Slim 4 it’s an explicit setBasePath() call where you have full control.
All done
There you have it. This is another case where Slim 4 has removed some magic as that magic didn’t work in all situations. The same solution can be used for any web server and will allow you to run your Slim 4 application in subdirectory should you need to.
Update Slim’s website now has documentation on this too.
This works great if index.php is located at '/var/www/html/myapp/index.php', but I cannot get the directory index to work if I want to deploy index.php in a 'public' sub directory, thus in '/var/www/html/myapp/public/index.php'.
I have set 'RewriteBase' to '/myapp/public' and all the defined routes are working fine, except the '/' route (the index route).
It would be helpful if you could also document a way to solve this problem.
Just remove this line, it will start working,
RewriteCond %{REQUEST_FILENAME} !-d
This will not work if you are not going to add .htaccess to /var/www/html, I am experiencing this right now, but the problem with adding an .htaccess to the root directory is it will make the current website unusable, do you happen to have a remedy for this?
Thank you! Very Helpful for me!! save my life now hahahah
Hi.
Thank you so much for this help!!!
I've got a demo app at /var/www/html/slim/t1.
It seems to work with this standard root .htaccess:
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [QSA,L]
And this one in /slim/t1/public:
RewriteEngine on
RewriteBase /slim/t1
RewriteRule ^$ public/ [L]
RewriteRule (.*) public/$1 [L]
Just starting! Will need to check other routes. Thanks!
Done all these but not sure how to get access to apache .conf on remote host
I tried to run it locally on MAMP (macos)
What should I do?
I have a /public folder with inside the index.php file
Copied the repository from here: http://github.com/akrabat/slim4-starte