Hoping this isn't a duplicate, done a lot of looking and I just get more confused as I don't use .htaccess
often.
I would like to have some pretty URLs and see lots of help regarding getting information where for example index.php
is passed a parameter such as page
. So I can currently convert www.example.com/index.php?page=help
to www.example.com/help
.
Obviously I'm not clued up on this but I would like to parse a URL such as www.example.com/?page=help
.
Can't seem to find much info and adapting the original I am obviously going wrong somewhere.
Any help or pointers in the right direction would be greatly appreciated. I'm sure its probably stupidly simple.
My alterations so far which do not seem to work are:
RewriteCond %{THE_REQUEST} ^.*/?page=$1
RewriteRule ^(.*)/+page$ /$1[QSA,L]
Also recently tried QUERY_STRING
but just getting server error.
RewriteCond %{QUERY_STRING} ^page=([a-zA-Z]*)
RewriteRule ^(.*) /$1 [QSA,L]
Given up as dead to the world so thought I would ask. Hoping to ensure the request/url etc starts ?page
and wanting to make a clean URL from the page
parameter.
This is the whole/basic process...
Make sure you are linking to the "pretty/canonical" URL in your HTML source. This should be a root-relative URL starting with a slash (or absolute), in case you rewrite from different URL path depths later. For example:
<a href="/help">Help Page</a>
In .htaccess
(using mod_rewrite), internally rewrite the "pretty" URL back to the file that actually handles the request, ie. the "front-controller" (eg. index.php
, passing the page
URL parameter if you wish). For example:
DirectoryIndex index.php
RewriteEngine On
# Rewrite URL of the form "/help" to "index.php?page=help"
RewriteRule ^[^.]+$ index.php?page=$0 [L]
The RewriteRule
pattern ^[^.]+$
matches any URL-path that does not include a dot. By excluding a dot we can easily omit any request that would map to a physical file (that includes a file extension delimited by a dot).
The $0
backreference contains the entire URL-path that is matched by the RewriteRule
pattern.
The DirectoryIndex
is required when the "homepage" (root-directory) is requested, when the URL-path is otherwise empty. In this case the page
URL parameter is not passed to our script.
index.php
)In index.php
(your "front-controller" / router) we read the page
URL parameter and serve the appropriate content. For example:
<?php
$pages = [
'home' => '/content/homepage.php',
'help' => '/content/help-page.php',
'about' => '/content/about-page.php',
'404' => '/content/404.php',
];
// Default to "home" if "page" URL param is omitted or is empty
$page = empty($_GET['page']) ? 'home' : $_GET['page'];
// Default to 404 "page" if not found in the array/DB of pages
$handler = $pages[$page] ?? $pages['404'];
include($_SERVER['DOCUMENT_ROOT'].$handler);
As seen in the above script, the actual "content" is stored in the /content
subdirectory. (This could also be a location outside of the document root.) By storing these files in a separate directory they can be easily protected from direct access.
This is only strictly necessary (in order to preserve SEO) if you are changing an existing URL structure and the "old/ugly" (original) URLs have been exposed (indexed by search engines, linked to by third parties, etc.), otherwise the "old" URL (ie. /index.php?page=abc
) is accessible. This is the same whenever you change an existing URL structure.
If the site is new and you are implementing the "new/pretty" URLs from the start then this is not so important, but it does prevent users from accessing the old URLs if they were ever exposed/guessed.
The following would go before the internal rewrite and after the RewriteEngine
directive. For example:
# Redirect "old" URL of the form "/index.php?page=help" to "/help"
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{REQUEST_URI} ^/index\.php$ [OR]
RewriteCond %{QUERY_STRING} ^page=([^.&]*)
RewriteRule ^(index\.php)?$ /%1 [R=301,L]
The check against the REDIRECT_STATUS
environment variable prevents a redirect-loop by not redirecting requests that have already been rewritten by the later rewrite.
The %1
backreference contains the value of the page
URL parameter, as captured from the preceding CondPattern (RewriteCond
directive). (Note how this is different to the $n
backreference as used in the rewrite above.)
The above redirects all URL variants both with/without index.php
and with/without the page
URL parameter. For example:
/index.php?page=help
-> /help
/?page=help
-> /help
/index.php
-> /
(homepage)/?page=
-> /
(homepage)TIP: Test first with 302 (temporary) redirects to prevent potential caching issues.
The above does not handle additional URL parameters. You can use the QSA
(Query String Append) flag on the initial rewrite to append additional URL parameters on the initially requested URL. However, implementing the reverse redirect is not so trivial.
You don't need to pass the page
URL parameter in the rewrite. The entire (original) URL is available in the PHP superglobal $_SERVER['REQUEST_URI']
(which also includes the query string - if any). You can then parse this variable to extract the required part of the URL instead of relying on the page
URL parameter. This generally allows greatest flexibility, without having to modify .htaccess
later.
However, being able to pass a page
URL parameter can be "useful" if you ever want to manually rewrite (override) a URL route using .htaccess
.
Incorporate regex (wildcard pattern matching) in the "router" script so you can generate URLs with "parameters". eg. /<page>/<param1>/<param2>
like /photo/cat/large
.