Welcome to a quick tutorial on how to create a pretty URL system with PHP and htaccess. Showing the actual file name of scripts in the URL is ugly, and it is a security risk. If you are looking to create clean, human-friendly URLs, it actually isn’t that difficult to achieve – Read on for an example!
TABLE OF CONTENTS
DOWNLOAD & NOTES
Firstly, here is the download link to the example code as promised.
EXAMPLE CODE DOWNLOAD
Just click on “download zip” or do a git clone. I have released it under the MIT license, so feel free to build on top of it or use it in your own project.
SORRY FOR THE ADS...
But someone has to pay the bills, and sponsors are paying for it. I insist on not turning Code Boxx into a "paid scripts" business, and I don't "block people with Adblock". Every little bit of support helps.
Buy Me A Coffee Code Boxx eBooks
PRETTY URL WITH HTACCESS & PHP
Let us now get started with creating a pretty URL system with Apache Web Server and PHP.
TUTORIAL VIDEO
REQUIREMENT) ENABLE URL REWRITE IN APACHE
# Make sure that mod rewrite is enabled
LoadModule rewrite_module modules/mod_rewrite.so
# Make sure that AllowOverride is enabled
<Directory "D:/YOUR-HTTP-FOLDER">
AllowOverride All
</Directory>
Before we get into the code, please make sure that the URL rewrite module is enabled with overriding allowed.
STEP 1) HTACCESS – REDIRECT EVERYTHING TO INDEX.PHP
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
First, create a .htaccess
file in your project folder. That’s right, for you guys who have used WordPress before, look no further – This is exactly what WordPress does. What these mean in plain English:
- Rewrite engine on, redirect everything to
index.php
. - Don’t redirect HTTP authentication requests.
- Also, leave the existing files and folders alone.
The whole idea here is to use PHP to load the requested page (or even fetch contents from the database).
STEP 2) PHP PAGE LOAD HANDLER
<?php
// (A) SETTINGS
define("URL_BASE", "/");
define("PATH_PAGES", __DIR__ . DIRECTORY_SEPARATOR . "pages" . DIRECTORY_SEPARATOR);
// (B) PARSE URL PATH INTO AN ARRAY
// e.g. http://site.com > [""]
// e.g. http://site.com/foo > ["foo"]
// e.g. http://site.com/foo/bar > ["foo", "bar"]
$path = parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH);
if (substr($path, 0, strlen(URL_BASE)) == URL_BASE) {
$path = substr($path, strlen(URL_BASE));
}
$path = explode("/", rtrim($path, "/\\"));
// (C) LOAD REQUESTED PAGE ACCORDINGLY
// (C1) URL PATH TO PHYSICAL FILE
// e.g. http://site.com > index.html
// e.g. http://site.com/foo > foo.html
// e.g. http://site.com/foo/bar > foo-bar.html
if (count($path)==1) {
$file = $path[0]=="" ? "index.html" : $path[0] . ".html";
} else {
$file = implode("-", $path) . ".html";
}
// (C2) LOAD PHYSICAL FILE
if (file_exists(PATH_PAGES . $file)) { require PATH_PAGES . $file; }
else {
http_response_code(404);
require PATH_PAGES . "404.html";
}
Not going to explain this line-by-line, but this script essentially “maps the URL path to the physical file”. For example:
http://site.com
will loadpages/index.html
.http://site.com/foo
will loadpages/foo.html
.http://site.com/foo/bar
will loadpages/foo-bar.html
.- If the “mapping fails”, show a 404 page.
STEP 3) HTML PAGES
With the foundations all in place, all that’s left is to create a “pages” folder and add some pages inside.
3A) HOME PAGE
<h1>HOME PAGE</h1>
<p>The dummy home page.</p>
3B) ABOUT PAGE
<h1>ABOUT PAGE</h1>
<p>The dummy about page.</p>
3C) 404 PAGE
<h1>PAGE NOT FOUND</h1>
<p>Opps. Page might have been abducted by aliens.</p>
EXTRA) PROTECTING THE PAGES FOLDER
Deny from all
Users can still manually access the pages from the URL, for example, http://site.com/pages/about.html
. So a small extra here, create a .htaccess
file in the pages
folder to deny public access.
P.S. PHP is still able to read and access the pages folder.
EXTRAS
That’s it for the pretty URL system, and here are some extras that you may find useful.
MANY OTHER WAYS TO LOAD PAGES
The above is but a simple example of how page load can be handled in PHP. There are endless ways to do it, and here are a few more ideas:
- Instead of a flat HTML page, create your own template system –
require PATH_PAGES . "HTML-TOP.PHP";
require PATH_PAGES . "REQUESTED-PAGE.PHP";
require PATH_PAGES . "HTML-BOTTOM.PHP";
- Load content from the database
require PATH_PAGES . "HTML-TOP.PHP";
SELECT `content` FROM `pages` WHERE `url`="REQUESTED"...
require PATH_PAGES . "HTML-BOTTOM.PHP;
- For you guys who are working on an eCommerce project, the path can be used to serve as the category or pagination. For example,
http://site.com/pastas/3
.$path[0]
is the category, and$path[1]
is the page number. - You can even use the pretty URL for an access check. For example,
http://site.com/admin/page
–if ($path[0]=="admin" && $_SESSION["user"]["level"]!=["admin"]) { NO PERMISSION }
So yes, feel free to change it however you see fit in your project.
HOW ABOUT OTHER WEB SERVERS?
If you are using IIS or NGINX – It is possible to achieve this as well. Just enable URL rewrite and “translate” the above .htaccess
for your web server.
LINKS & REFERENCES
- HTACCESS Guide
- URL Parts in PHP – Code Boxx
THE END
Thank you for reading, and we have come to the end of this guide. I hope it has helped you to create a better website, and if you have anything to add to this guide, please feel free to comment below. Good luck and happy coding!
Hi,
Building my site according to it Facebook scarper allerts: Bad Response Code
URL returned a bad HTTP response code. Guess no scarper can scarp my pages as GoogleAdwords allso does not see the code I pasted on my contact page (guess it just se 404). Allthough the site runs nice in browsers.
Any advice?
Attila
Try –
1) Add meta robots https://developers.google.com/search/docs/crawling-indexing/robots-meta-tag
2) See what FB is complaining about – https://developers.facebook.com/tools/debug/
3) Firewall and anti-spam allow bots
Otherwise – Sorry, I cannot give free consultations for personal projects and private websites. Good luck!
https://code-boxx.com/faq/#help “Help on a deeper level”, “Cannot be answered in a single paragraph”
Hello, thank you for sharing this. When i try to replicate this, I can not get it to work correctly. It loads the 404 page correctly if the url is mainfolder/ but does not load any of the other pages, instead i get: “The requested URL was not found on this server.” from apache. Any idea of what i might have done wrong?
(Also, when i echo the file in step 3 after $file= $folder.$file; I get: “C:\xampp\htdocs\mainfolder\pages\mainfolder.php” for the URL mainfolder/)
See “If not deployed in the base path” in quick notes above.
Ah, thank you!
Hi again and thank you for taking the time. I have by now come over the initial obstacles and even think I could be basically done if it wasn’t for the internal linking to css, js, img folders … which seems to be thoroughly upset be the redirect. So I added, e.g., RewriteCond %{REQUEST_URI} !^/css … no help. Perhaps, if you are willing to do this, you could take a (paid) look at the project =URL REMOVED=
Read step 2 carefully – The
.htaccess
file already excludes existing files and folders, it does not redirect CSS/JS/HTML/IMAGE/VIDEO/WHATEVER files. The problem lies somewhere else. Thanks for the possible job offer, but I don’t think most people will find it… “cost-effective” to hire a senior web developer. Good luck!https://code-boxx.com/faq/#hire
hi there — thx for the tutorial, but … well, my php skills are limited, I am able to understand the php handler code in a step-by-step fashion but I fail to understand the bigger view. E.g. I managed to open the about page by hard-coding in the handler, but when I change its name to about.php it stops working and I have no clue why. How on earth would I implement the handler into some sort of page navigation with parameters, relative paths to images folder etc. … thx for inspiration…
Read
index.php
section B carefully, the answer is right there.* Section A splits the URL path segments into an array –
$path = explode("/", rtrim(URL PATH, "/"))
* Section B is how we deal with
$path
. This example simply combines them to load an HTML file$file = implode($path, "-") . ".html";
* We can change the entire Section B to modify the system behavior. For example,
if ($path[0]=="admin") { CHECK IF USER IS ADMIN BEFORE LOADING PAGE }