htaccess RewriteRule with a variable not working - apache

This rule takes us to the error page
RewriteRule ^latest/([A-Za-z0-9]+)$ latest?auth=$1 [NC,L]
I have the following in my .htaccess file
<IfModule mod_rewrite.c>
RewriteRule ^sucuri-(.*)\.php$ - [L]
</IfModule>
# END - Allow Sucuri Services
<Files 403.shtml>
order allow,deny
allow from all
</Files>
ErrorDocument 404 /404.php
Options +FollowSymLinks
Options +MultiViews
RewriteEngine on
RewriteCond %{HTTPS} !=on
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R,L]
RewriteCond %{HTTP_HOST} !^www.xxxxx.com$ [NC]
RewriteRule ^(.*)$ https://www.xxxxx.com/$1 [L,R=301]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ ci_index.php?/$1 [L]
## Remove php extension
RewriteCond %{REQUEST_URI} !^/index.php$
RewriteRule ^([^\.]+)$ $1.php [NC,L]
RewriteRule ^latest/([A-Za-z0-9]+)$ latest?auth=$1 [NC,L]```
With the following rule
```RewriteRule ^latest/([A-Za-z0-9]+)$ latest?auth=$1 [NC,L]```
Trying to achieve the following -
```https://www.xxxxx.com/latest?auth=US-mobile-county
to
https://www.xxxxx.com/latest/US-mobile-county```

This rule takes us to the error page RewriteRule ^latest/([A-Za-z0-9]+)$ latest?auth=$1 [NC,L]
You've not stated precisely what "error page" you are referring to? Or what is expected to handle this request. This directive is not correct by itself, so it's not immediately clear what it is you are trying to do. I'm assuming the intention is to rewrite to latest.php (not latest as suggested by this rule, and mentioned later in the question) - since this would seem to be the only reason to implement such a rule (and your question is tagged php). By rewriting to latest only you are dependent on other directives appending the .php extension - and therein lies a conflict.
There are a number of issues with the directives as posted that is preventing this from working. Notably, the rules are in the wrong order and the use of MultiViews (probably in an attempt to get extensionless URLs working) is compounding matters. In fact, it doesn't look like the rule in question is actually being processed at all.
Without MultiViews, and due to the order of the directives, a request of the form /latest/something would be rewritten to /ci_index.php?/latest/something (presumably a CodeIgniter front-controller) which I would guess would result in a CI generated 404 response. However, since MultiViews has been enabled mod_negotiation first "rewrites" the request to /latest.php/something, which doesn't match any of your rules so either results in a 404 (depending on your server config) or calls latest.php but without any URL parameter, which presumably causes your script to fail?
https://www.xxxxx.com/latest/US-mobile-county
Also, note that your example URL contains hyphens (-), but the regex in your directive (ie. ^latest/([A-Za-z0-9]+)$) does not permit hyphens so it wouldn't have matched anyway.
Try the following instead, replacing everything after the ErrorDocument directive:
# Disable MultiViews
Options +FollowSymLinks -MultiViews
RewriteEngine on
# Redirect HTTP to HTTPS
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
# Redirect non-www to www
RewriteCond %{HTTP_HOST} !^www\.example\.com [NC]
RewriteRule ^ https://www.example.com%{REQUEST_URI} [R=301,L]
# Rewrite "/latest/something" to "/latest.php?auth=something"
RewriteRule ^latest/([A-Za-z0-9-]+)$ latest.php?auth=$1 [L]
# Allow extensionless PHP URLs to work
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule ^([^.]+)$ $1.php [L]
# Front-controller
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ ci_index.php?/$1 [L]
Note that I've reversed the order of the directives so that the rule in question is now first and the CI front-controller is now last. The order of the directives in .htaccess is important.
Since you had enabled MultiViews (now disabled in the above), your rule to enable PHP extensionless URLs (that you had labelled "Remove php extension") was not actually being used at all (unless you had directories or files that contained dots, other than that used to delimit the file extension).

Related

I need help placing a 301 redirect in my htaccess file of my new php site

I have a php website and my current .htaccess file is as follows:
<IfModule mod_rewrite.c>
#Options +FollowSymlinks
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php?page=$1 [NC,L,QSA]
Options -Indexes
</IfModule>
Now I want to do a 301 redirect on a URL. From example.com/folder/old-url-london.htm to example.com/new-url-london/
The problem is everytime I try something I get:
www.example.com/new-url-london/?page=folder/old-url-london.htm
Now I can't change this line (RewriteRule ^(.*)$ /index.php?page=$1 [NC,L,QSA]) as it is essential to the working of the website.
Any ideas?
I tried the following:
Redirect 301 /folder/old-url-london.htm example.com/new-url-london/
as well as
RewriteRule ^folder/old-url-london.htm$ /new-url-london/ [R=301,L]
Sounds like you are perhaps putting the rule in the wrong place. Or used the Redirect directive. And/or are perhaps now seeing a cached response.
You need to use mod_rewrite RewriteRule to avoid conflicts with the existing rewrite AND the rule needs to be at the top of the file, before the existing rewrite and ideally after the RewriteEngine directive.
For example:
Options +FollowSymlinks -Indexes
RewriteEngine On
RewriteRule ^folder/old-url-london\.htm$ /new-url-london/ [R=301,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) index.php?page=$1 [QSA,L]
You will need to clear your browser cache before testing, since any erroneous 301 (permanent) redirects will have been cached by the browser. Test first with 302 (temporary) redirects for this reason.
Don't forget to backslash-escape literal dots in the regex.
I tidied up a few other bits:
<IfModule> wrapper is not required.
Combined Options at the top and re-enabled FollowSymLinks (since it is required by mod_rewrite)
RewriteBase is not required in the directives you've posted.
Removed spurious spacing.
NC flag not required on the rewrite since the pattern .* already matches everything.
The anchors on the pattern ^(.*)$ are not required since regex is greedy by default.

Chaining multiple required rewrites in .htaccess

I have at present 2 rewrites that are supposed to occur on any given url,
The first redirects any url matching the pattern %DOMAIN%/mcc-* to show.php?id=mcc-*
The second redirects any url without the .php extension to the page as if it had one.
The first rewrite gets called and works, but the second does not.
I have tried swapping the places of the rewrites, but the result is the same, the 'Add Extension' rewrite is never called, even on pages that don't redirect to show.php
ErrorDocument 404 /error/404.php
Options All -Indexes -MultiViews
RewriteEngine On
# Silent Redirect from any url ending with mcc-* to show.php?id=mcc-*
# This works as intended.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(mcc-[\d]+)/?$ show.php?id=$1 [QSA,NC]
# Allow urls to not include the .php extension
# This is not not being called.
RewriteBase /
RewriteCond %{REQUEST_URI}/$1.php -f [NC]
RewriteRule ^(.+?)/?$ $1.php [L]
Is there someway to get both of these conditionals to run, or at the very least run the second if the first doesn't match?
With your shown samples please try following .htaccess rules file. Please make sure to clear your browser cache before testing your URLs.
ErrorDocument 404 /error/404.php
Options All -Indexes -MultiViews
RewriteEngine ON
# Allow urls to not include the .php extension
# This is not not being called.
RewriteBase /
RewriteCond %{DOCUMENT_ROOT}/$1.php -f [NC]
RewriteRule ^(.+?)/?$ $1.php [L]
# Silent Redirect from any url ending with mcc-* to show.php?id=mcc-*
# This works as intended.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(mcc-[\d]+)/?$ show.php?id=$1 [QSA,NC]

.htaccess RewriteRule with existing file and folder

My web structure looks like this:
public_html/
/images/
/user/
/userimage1.jpg
/userimage2.jpg
/userimage3.jpg
/icons/
/index.php
/user.php
...
I have 2 domains: example.com and images.example.com and I want to use a .htaccess RewriteRule that the images.example.com subdomain leads to the /images/-folder but also to use URLs without the file extension.
My .htaccess looks like this:
<IfModule mod_rewrite.c>
Options +FollowSymLinks +MultiViews
RewriteEngine on
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
RewriteCond %{HTTP_HOST} ^images\.example\.com$ [NC]
RewriteCond %{REQUEST_URI} !^/images/
RewriteRule ^(.*)$ /images/$1 [NC,L]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-d
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}\.php -f
RewriteRule ^(.*)$ $1.php [L]
</IfModule>
Now, https://example.com/user/ works fine, but when I try to open https://images.example.com/user/userimage1.jpg it says that %{REQUEST_URI} is /images/redirect:/images/user.php/userimage1.jpg
Unfortunately, both, the domain and the subdomain have to be installed with public_html as the root folder.
How do I have to adept my .htaccess file so that both URLs, https://example.com/user/ and https://images.example.com/user/userimage1.jpg work fine?
You have a conflict with MultiViews (which you've enabled at the top). The fact that "https://example.com/user/ works fine" (with a trailing slash) is because of MultiViews, not because of your mod_rewrite directives. (The mod_rewrite directives as written would only "work" with /user - no trailing slash.)
When you request https://images.example.com/user/userimage1.jpg, MultiViews triggers an internal subrequest for /user.php/userimage1.jpg (/user.php with additional path-info /userimage1.jpg), but mod_rewrite has also tried to rewrite the request (an internal "redirect") - hence the seemingly malformed rewrite.
Generally, you need to avoid using MultiViews with mod_rewrite rewrites - a common cause of conflict.
Try the following instead:
Options +FollowSymLinks -MultiViews
RewriteEngine on
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
# Rewrite images subdomain
RewriteCond %{HTTP_HOST} ^images\.example\.com$ [NC]
RewriteCond %{REQUEST_URI} !^/images/
RewriteRule ^(.*)$ /images/$1 [L]
# Append .php file extensions
RewriteCond %{DOCUMENT_ROOT}/$1 !-d
RewriteCond %{DOCUMENT_ROOT}/$1\.php -f
RewriteRule ^(.*)/$ $1.php [L]
Note that I've included the trailing slash in the RewriteRule pattern and taken this out of the capturing subpattern - this is assuming that the trailing slash is mandatory on your URLs (as in your example).
You don't need the <IfModule> wrapper unless mod_rewrite really is optional? (It's not.)

MultiViews is *too* tolerant of bad URLs

When I enable MultiViews, if I visit bad URLs, the my page (index.php) is still reached, when I want the user to get a 404 error instead. I'm trying to figure out how to fix this without creating rules in my .htaccess.
For example, "www.mydomain.com/index/blah/blah", visits index.php, but I want it to fail due to the extraneous trailing garbage URL components. Similarly for "/contact/blah/awuihda/hiu", which shows the content of contact.php, should give a 404 error, because "/blah/awuihda/hiu" doesn't exist.
If I disable MultiViews it works fine, but then I can't abbreviate the URL as much as I want to (for example, can't type "/contact" to bring up "contact.php").
You could just use the following so the .php extension is not required, which is the usual approach:
RewriteEngine on
# Remove .php if it's present with a 301 redirect
RewriteRule ^(.+)\.php$ $1 [R=301,L]
# If a request doesn't exist as a directory, file or symlink
# and it does exist with .php appended, rewrite to that
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.+)$ $1.php [L]
I know it's adding a rule to .htaccess but it's a one off that works for everything and also means you're not hitting potential duplicate content allowing the same thing to be served with or without .php (or indeed with anything at all trailing after it as in your examples). Hope it's useful.
It could go in main server config but would need altering.
I found a solution which works for me.
Options -Indexes SymLinksIfOwnerMatch -MultiViews
RewriteEngine On
RewriteBase /
RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s([^.]+)\.php [NC]
RewriteRule ^ %1 [R=301,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^([^\.]+)$ $1.php [NC,L]
Source: link

.htaccess eg.php?id=3 to eg/id/3

Problem:
I know there are alot of examples like the title on the web, but non of them work properly for me. How do I get my .htaccess to rewrite AND redirect ALL pages like /eg.php?id=3 to /eg/id/3 and /eg.php to /eg
My current .htaccess
ErrorDocument 404 /404.php
<Files .htaccess>
order allow,deny
deny from all
</Files>
RewriteEngine On
EDIT (WORKS)
RewriteEngine On
RewriteRule ^/?([^/]+)/id/([0-9]+)$ $1.php?id=$2 [L,QSA]
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^(.*)$ http://%1%{REQUEST_URI} [R=301,QSA,NC,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^\.]+)$ $1.php [NC,L]
ErrorDocument 404 /404.php
<Files .htaccess>
order allow,deny
deny from all
</Files>
Fixes StyleSheet errors:
<head><base href="http://website.com/"></head>
I'd say that should do what you ask for:
RewriteEngine on
RewriteRule ^/?eg/id/([0-9]+)$ eg.php?id=$1 [L,QSA]
RewriteRule ^/?eg/?$ eg.php [L,QSA]
Obviously the interpretation of .htaccess style files has to be enabled and the rewriting module has to be loaded for this to work.
This is a more general version as asked in the comments below:
RewriteEngine on
RewriteRule ^/?([^/]+)/id/([0-9]+)$ $1.php?id=$2 [L,QSA]
RewriteRule ^/?([^/]+)/?$ $1.php [L,QSA]
This further version should redirect requests still carrying a .php ending to their new versions:
RewriteEngine on
RewriteCond %{QUERY_STRING} (.*)(?:^|&)id=([^&]*)((?:&|$).*)
RewriteRule ^/?([^/]+)\.php$ $1/id/%2 [L,R=301,QSA]
RewriteRule ^/?([^/]+)\.php$ $1 [L,R=301,QSA]
RewriteRule ^/?([^/]+)/id/([0-9]+)$ $1.php?id=$2 [L,QSA]
RewriteRule ^/?([^/]+)/?$ $1.php [L,QSA]
And a general hint: you should always prefer to place such rules inside the http servers host configuration instead of using .htaccess style files. Those files are notoriously error prone, hard to debug and they really slow down the server. They are only provided as a last option for situations where you do not have control over the host configuration (read: really cheap hosting service providers) or if you have an application that relies on writing its own rewrite rules (which is an obvious security nightmare).