Clean URL and php file extension removal - apache

I want to achieve two things with .htaccess:
Only show the value in the URL parameter "slug" making the URL clean
For all other php pages on my site which doesn't have the URL parameter "slug" simply remove the file extension ".php".
I have the following .htaccess code which takes care of point 1 above:
RewriteEngine On
RewriteRule ^([a-zA-Z0-9_-]+)$ somepage.php?slug=$1
RewriteRule ^([a-zA-Z0-9_-]+)/$ somepage.php?slug=$1
The question is; how do I incorporate point 2 above in the same code without breaking what is already working in point one?
I have tried simply including the following code below the above but this gives me a 404 error when I go to example.com/somepage:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^\.]+)$ $1.php [NC,L]

You need to prioritise your extensionless .php URLs, so this rule needs to go before your existing rule that rewrites the "slug".
You also need to check that the corresponding .php file exists before rewriting the request. The rule you are currently proposing blindly rewrites the request when the request does not map to a file, so this would naturally catch requests that should otherwise be rewritten to the "slug".
Try it like this instead (in the root .htaccess file):
RewriteEngine On
# Handle extensionless ".php" files
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule ^([^.]+)$ $1.php [L]
# Rewrite to "slug"
RewriteRule ^([\w-]+)/?$ somepage.php?slug=$1 [L]
I've combined your two rules that rewrite to "slug" into one, since the only difference is the trailing slash - just make it optional in the regex. The \w shorthand character class in the same as [a-zA-Z0-9_]. HOWEVER, consider canonicalising the trailing slash instead (ie. redirect to one or the other). Since by allowing an optional trailing slash (two different URLs) to serve the same content you are potentially creating a duplicate content issue.
I have tried simply including the following code below the above but this gives me a 404 error when I go to example.com/somepage
The request would have been rewritten to somepage.php?slug=somepage, so I assume it must have been somepage.php that generated the 404 response, rather than Apache?

Related

The requested URL was not found on this server .htacess

I am trying to rewrite URL like:
example.com/speciality_details.php?id=23&name=ent
TO
example.com/specialities/23/ent
But I am getting this error:
Not Found
The requested URL was not found on this server.
Additionally, a 404 Not Found error was encountered while trying to use an ErrorDocument to handle the request.
This is my .htaccess file
RewriteEngine on
RewriteRule ^doctor/([0-9]+)/([^/.]+)$ doctor_details.php?id=$1&name=$2 [NC,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^/specialities/([0-9]+)/([^/.]+)$ speciality_details.php?id=$1&name=$2 [NC,L]
The first RewriteRule working but the second one is not working
Please help me to know what the problem is. How should I rewrite the code?
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^/specialities/([0-9]+)/([^/.]+)$ speciality_details.php?id=$1&name=$2 [NC,L]
Just as in the first rule (which is "working"), you should not be matching a slash prefix on the URL-path. And the preceding condition (RewriteCond directive) is superfluous, since a URL of the form /specialities/23/ent could not possibly match a physical file (could it?).
In .htaccess, the URL-path matched by the RewriteRule pattern does not start with a slash since the directory-prefix (that always ends with a slash) has already been removed.
So, the rule should look like the following instead (and no RewriteCond directive):
RewriteRule ^specialities/([0-9]+)/([^/.]+)$ speciality_details.php?id=$1&name=$2 [NC,L]
This would match a URL of the form example.com/specialities/23/ent, as per your example. And assumes the file being rewritten to is speciality_details.php in the document root.
The NC (nocase) flag should also be superfluous, unless you are expecting mixed case versions of sPeCiAlItIeS? But if you are then that is better resolved with a redirect since the rewrite would potentially result in a duplicate content (SEO) issue.
Make sure you clear your browser cache before testing.
Although, from your earlier question edits it looks like you had already tried this without the slash prefix, but at the time you had /speciality/23/ent, not /specialities/23/ent as the example request URL - which would obviously not match.

Editing .htaccess file to modify URL

I'm trying to modify my .htaccess file to modify my URL and have tried many methods but cannot achieve exactly what I want. For example I have this URL:
http://mywebsite.com/FOLDER/index.php?id=5
Now I want it to look like:
http://mywebsite.com/FOLDER/5
or
http://mywebsite.com/FOLDER/ID/5
My .htaccess contains the following code:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^index/([0-9]+)/([0-9a-zA-Z_-]+) index.php?id=$1 [NC]
I cannot figure out what's wrong. Thanks.
You can use:
RewriteEngine on
# external redirect from actual URL to pretty one
RewriteCond %{THE_REQUEST} \s/+FOLDER/index\.php\?id=(\d+) [NC]
RewriteRule ^ /FOLDER/%1? [R=301,L,NE]
# internal forward from pretty URL to actual one
RewriteRule ^FOLDER/(\d+)/?$ FOLDER/index.php?id=$1 [L,QSA,NC]
The first argument of RewriteRule is what the incoming url without domain and without preceding paths (more on that later) is going to be matched against. This url is, in your case, http://mywebsite.com/FOLDER/5. Assuming that your .htaccess file is in your DocumentRoot, the regex will match against FOLDER/5.
You are currently trying to match FOLDER/5 with ^index/([0-9]+)/([0-9a-zA-Z_-]+), which is not going to work. A better regex would be ^(.*)/([0-9]+)$ or ^(.*)/ID/([0-9]+)$. You can then rewrite to $1/index.php?id=$2. I would recommend using the [L] flag to stop rewriting for this round to avoid common problems with multiple rules matching while you do not expect them to.
Besides this, make sure that your .htaccess files are being read (e.g. by checking that if you enter garbage, you get a 500 internal server error), that mod_rewrite is enabled, that you are allowed to override FileInfo. You also may need to turn AcceptPathInfo off.

.htaccess mod_rewrite linking to wrong page

I have in my .htaccess the following code:
RewriteEngine On
RewriteRule ^/?([^/\.]+)/?$ $1.php [L]
RewriteRule ^/?([^/\.]+).php$ $1/ [R,L]
RewriteRule ^/?([^/\.]+)/?$ $1.php [L] is working fine. What this is doing is taking a url like http://www.example.com/whatever and making it read the page as http://www.example.com/whatever.php.
However, what I'd like to be able to do is take a url like http://www.example.com/whatever.php and automatically send it to http://www.example.com/whatever, hence the second line of the code. However, this isn't working. What its doing now, is as soon as it comes across a link ending in .php, the url becomes http://localhost/C:/Sites/page/whatever/, and pulling a 403: Forbidden page.
All I want to know is what I can to so that http://www.example.com/whatever.php will be read as http://www.example.com/whatever, and that if http://www.example.com/whatever.php is entered into the URL bar, it will automatically redirect to http://www.example.com/whatever.
Does that make any sense?
EDIT
Ok, so it appears I wasn't all too clear.. basically, I want /whatever/ to read as whatever.php while the URL still stays as /whatever/, right? However, if the URL was /whatever.php, I want it to actually redirect the users URL to /whatever/, and then once again read it as whatever.php. Is this possible?
If you're rules are inside an .htaccess file, you can omit the leading slash when you match against a URI:
RewriteRule ^([^/\.]+)/?$ /$1.php [L]
Also note that a leading slash is included in the target (/$1.php), this makes sure /whatever/ gets rewritten to /whatever.php. When you redirect, if you are missing this leading slash, apache prepends the document root to it. Thus /whatever.php gets redirected to the document root C:/Sites/page/whatever/. Even if you include the leading slash, this will never work because you're going to cause a redirect loop:
Enter "http://www.example.com/whatever.php" in your address bar
apache redirects you to "http://www.example.com/whatever/"
apache gets the URI whatever/ and applies the first rule and the URI gets rewritten to /whatever.php
The URI gets put through the rewrite engine again
the URI /whatever.php matches the second rule and redirects the browser to "http://www.example.com/whatever/"
repeat steps 3-5
You need to add a condition that the actual request is for /whatever.php:
RewriteCond %{THE_REQUEST} ^(GET|POST|HEAD)\ /([^/\.]+)\.php
RewriteRule ^ /%2/ [R,L]
So altogether, you'll have:
RewriteEngine On
RewriteRule ^([^/\.]+)/?$ /$1.php [L]
RewriteCond %{THE_REQUEST} ^(GET|POST|HEAD)\ /([^/\.]+)\.php
RewriteRule ^ /%2/ [R,L]
You're making a relative path substitution in a per-directory context (.htaccess is a per-directory context). This requires RewriteBase. Per-directory rewrites are done in a later stage of processing, when URLs have been mapped to paths. But the rewrite must produce a URL, which is processed again. I think without the RewriteBase to supply the URL prefix, you end up with a filesystem prefix instead of the URL. That may be why you're getting the C:/Sites thing. Try RewriteBase. But after a correct RewriteBase to specify the correct URL prefix to be tacked in front to the relative rewritten part, I'm afraid you will have the rewrite loop, because you're rewriting whatever.php to whatever; and whatever to whatever.php.
Reference: http://httpd.apache.org/docs/current/rewrite/tech.html

How to prevent mod_rewrite from rewriting URLs more than once?

I want to use mod_rewrite to rewrite a few human-friendly URLs to arbitrary files in a folder called php (which is inside the web root, since mod_rewrite apparently won't let you rewrite to files outside the web root).
/ --> /php/home.php
/about --> /php/about_page.php
/contact --> /php/contact.php
Here are my rewrite rules:
Options +FollowSymlinks
RewriteEngine On
RewriteRule ^$ php/home.php [L]
RewriteRule ^about$ php/about_page.php [L]
RewriteRule ^contact$ php/contact.php [L]
However, I also want to prevent users from accessing files in this php directory directly. If a user enters any URL beginning with /php, I want them to get a 404 page.
I tried adding this extra rule at the end:
RewriteRule ^php php/404.php [L]
...(where 404.php is a file that outputs 404 headers and a "Not found" message.)
But when I access / or /about or /contact, I always get redirected to the 404. It seems the final RewriteRule is applied even to the internally rewritten URLs (as they now all start with /php).
I thought the [L] flag (on the first three RewriteRules) was supposed to prevent further rules from being applied? Am I doing something wrong? (Or is there a smarter way to do what I'm trying to do?)
[L] flag should be used only in the last rule,
L - Last Rule - Stops the rewriting process here and don’t apply any more rewriting rules & because of that you are facing issues.
I had similar problem. I have a content management system written in PHP and based on Model-View-Control paradigm. The most base part is the mod_rewrite. I've successfully prevent access to PHP files globally. The trick has name THE_REQUEST.
What's the problem?
Rewriting modul rewrites the URI. If the URI matches a rule, it is rewritten and other rules are applied on the new, rewritted URI. But! If the matched rule ends with [L], the engine doesn't terminate in fact, but starts again. Then the new URI doesn't more match the rule ending with [L], continues and matches the last one. Result? The programmer stars saying bad words at the unexpected 404 error page. However computer does, what you say and doesn't do, what you want. I had this in my .htaccess file:
RewriteEngine On
RewriteBase /
RewriteRule ^plugins/.* pluginLoader.php [L]
RewriteCond %{REQUEST_URI} \.php$
RewriteRule .* index.php [L]
That's wrong. Even the URIs beginning with plugins/ are rewritten to index.php.
Solution
You need to apply the rule if and only if the original - not rewritten - URI matches the rule. Regrettably the mod_rewrite does not provide any variable containing the original URI, but it provides some THE_REQUEST variable, which contains the first line of HTTP request header. This variable is invariant. It doesn't change while rewrite engine is working.
...
RewriteCond %{THE_REQUEST} \s.*\.php\s
RewriteRule \.php$ index.php [L]
The regular expression is different. It is not applied on the URI only, but on entire first line of the header, that means on something like GET /script.php HTTP/1.1. But the critical rule is this time applied only if the user is explicitly requesting some PHP-script directly. The rewritten URI is not used.

Apache mod_rewrite redirect, keep sub-directory name

I'm wondering if this is possible.
I have a single page site in which I'd like to incorporate a trailing slash with a file name that anchors to a section on that site. I'm trying to avoid using hash or hash-bangs.
For example; www.example.com/recent
Right now, I'm removing any trailing slash, but I get a 404 with /recent because it's expecting a file.
RewriteRule ^(.*)/$ /$1 [R=301,L]
Is it possible to redirect to www.example.com, but still maintain the /recent without the server thinking it's a file so I can read it client-side (php/js)? More so that I can keep using the back and forward buttons.
Thanks for any help!
TBH it is not 100% clear for me what you want. As I understand you want URL www.example.com/recent to be rewritten (internal redirect, when URL remains unchanged in browser) to www.example.com/index.php?page=recent (or something like that).
DirectorySlash Off
Options +FollowSymLinks -MultiViews
RewriteEngine On
RewriteBase /
# remove trailing slash if present
RewriteRule ^(.*)/$ /$1 [R=301,L]
# do not do anything for already existing files
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule .+ - [L]
# rewrite all non-existing resources to index.php
RewriteRule ^(.+)$ /index.php?page=$1 [L,QSA]
With the above rules (that need to be placed in .htaccess in website root folder) this can be achieved. Request for www.example.com/recent will be rewritten to www.example.com/index.php?page=recent so your single-page server side script knows which URL was requested. The same will be with any other non-existing resource e.g. www.example.com/hello/pink/kitten => www.example.com/index.php?page=hello/pink/kitten.
It may not be necessary to pass originally requested URI as a page parameter as you should be able to access it in PHP via $_SERVER['REQUEST_URI'] anyway.
If I misunderstood you and this is not what you want then you have to clarify your question (update it with more details, make it sound clear).