I'm building a simple PHP router and I understand the most things except for the things in the ".htaccess" file. If I comment out the things in the ".htaccess" file, nothing changes, or I don't notice anything changing(the contents of the ".htaccess" file is from a tutorial). The ".htaccess" file contains the following things
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(. )$ index.php [QSA,L]
and this is the content from the index.php
$request = $_SERVER['REQUEST_URI'];
switch ($request) {
case '/ROUTER/index.php':
case '/ROUTER/index.php/home':
require __DIR__ . '/controller/homeController.php';
break;
case '/ROUTER/index.php/about' :
require __DIR__ . '/controller/shopController.php';
break;
default:
http_response_code(404);
require __DIR__ . '/controller/404Controller.php';
break;
}
the contents in the homeController.php etc files are just a simple echo with a text. Maybe someone can explain to me what happens in the ".htaccess" file.
CodePudding user response:
Most web servers have logic like this for determining which file to serve:
- If a file exists with a file name that matches the URL path, use that file
- If a directory exists with a name that matches the URL path:
- If a default file (usually
index.htmlorindex.php) exists in that directory, use that file - If configured to show a file listing, do so
- If a default file (usually
Otherwise the web server returns an error status.
Many web applications want to implement their own logic for what to show for each URL and implement their own routing rules. They typically use .htaccess to create a Front controller that passes nearly every request into a single central file that handles its own routing for the web application. Your .htaccess has fairly standard front controller rules that pass most URLs into index.php
Breaking it down line by line:
RewriteEngine On-- Enables mod rewrite which is an Apache module that uses rules to change which file handles which URLsRewriteBase /-- Specifies which directory the rules are relative to. This can usually be omitted because/is the default value in.htaccessin the document root. See What does RewriteBase do and how to use it?RewriteCond %{REQUEST_FILENAME} !-d-- If the requested URL is not an existing directoryRewriteCond %{REQUEST_FILENAME} !-f-- If the requested URL is not an existing fileRewriteRule ^(. )$ index.php [QSA,L]-- Handle all URLs withindex.php.- A rewrite rule has three sections:
- The pattern to match against the URL path (
^(. )$)^is starts with.one or more of any character$is ends with()parenthesis capture the matched characters as a group that is available in a variable ($1). The parenthesis in this rule could be removed because the variable is never used.
- The pattern to match against the URL path (
- The target file that handles the URLs (
index.php) - Flags that modify how the rule works (
[QSA,L])QSAis query string append to make sureindex.phphas access to anything after the?in the URLLis last so that any later rewrite rules wouldn't also get executed.
- A rewrite rule has three sections:
In effect, it uses the default web server logic for files or directories that exist, but pass all other requests to index.php.
CodePudding user response:
@StephenOstermiller's answer has done a great job of describing the .htaccess file / front-controller process, but I thought I'd address the other issue you raised...
If I comment out the things in the ".htaccess" file, nothing changes
That's because the format of the URLs you are using (eg. /ROUTER/index.php/home) completely negates the need for the .htaccess file to begin with. You are calling index.php (the "front-controller") directly in the URL itself and passing /home as additional pathname information (aka. path-info).
The .htaccess file is still processed, but the 2nd condition (RewriteCond directive), which checks that the request does not map to a physical file, fails (index.php is a physical file) so the rule is not triggered (it does nothing).
The additional path-info on the URL is available to PHP in the $_SERVER['PATH_INFO'] superglobal. So, if you are using URLs of the form /ROUTER/index.php/home then you could write your front-controller (index.php) like this instead (simplified):
// URLs of the form "/ROUTER/index.php/home"
$request = $_SERVER['PATH_INFO'];
switch ($request) {
case '':
case '/home':
:
case '/about' :
:
}
(As noted above, this is not making use of .htaccess)
On the other hand, your .htaccess file allows you to have URLs of the form /ROUTER/home (or simply /home), avoiding you having to include index.php in the URL, which is then internally rewritten to index.php (by the rule in .htaccess). You then use $_SERVER['REQUEST_URI'] (as in your original script) to access the requested URL in PHP.
For example (simplified):
// URLs of the form "/ROUTER/home"
$request = $_SERVER['REQUEST_URI'];
switch ($request) {
case '/ROUTER/':
case '/ROUTER/home':
:
case '/ROUTER/about' :
:
}
However, your existing .htaccess file is not configured correctly for this. The .htaccess file is assuming index.php is located in the document root, but your URLs suggest you have a /ROUTER subdirectory, in which index.php (the "front-controller") is located.
If your .htaccess file is in the /ROUTER subdirectory at /ROUTER/.htaccess then remove the RewriteBase directive entirely.
If, however, your .htaccess file is located in the document root then you will need to change your RewriteBase directive to read:
RewriteBase /ROUTER
(Setting RewriteBase /ROUTER in both cases will also work.)
