htaccess content negotiation not working on LiteSpeed server - .htaccess

We have code in our htaccess that presents a different web template for mobile users like
RewriteCond %{HTTP_USER_AGENT} "Mobile"
RewriteCond %{REQUEST_URI} "!_mob.php"
RewriteRule ^(.*).php$ /$1_mob.php [L,QSA]
So a file foo.php would be internally rewritten to foo_mob.php if the condition evaluates to true.
Now we have additional a 'pretty-url' directive that rewrites the descriptive category and product page names to the internal format based on query strings like
RewriteCond %{REQUEST_URI} ^/category1\.htm
RewriteRule ^.*$ /index.php?cPath=1 [L,QSA]
In combination with the above this should then display the template index_mob.php to the user on a mobile device. This has been working fine for many years with Apache server, but is not working anymore after we moved to a LiteSpeed server now. The mobile template is displayed for requests with an explicit .php extension, but not those that have gone through the rewrite to index.php first (that includes also the root / that is rewritten to index.php by default)
Any help to solve the problem would be appreciated.

If you use both above .htaccess rules in Combination while using Litespeed, The problem is the L tag being in the .htaccess twice.
[L] tag stands for Last, and has different meanings in Apache and Litespeed.
The ruleset after an [L] flag may still be processed by Apache on a subsequent iteration, but that is not true with Litespeed and most other contexts.
Additional information and Official Documentation is here.

Related

Drupal 9 multisite split .htaccess

I am working on Drupal 9 multisite and I want split the .htaccess file, one per site to create different redirect rules.
I know that it's possible to add all rules on drupal_root/.htaccess but I prefer to have one .htaccess per site.
The structure is:
drupal_root/sites/site-1/
drupal_root/sites/site-2/
drupal_root/sites/site-3/
drupal_root/sites/site-4/
and i want add .htaccess, for example in drupal_root/sites/site-1/ and another different in drupal_root/sites/site-2/
I tried adding .htaccess directly on drupal_root/sites/site-1/ but it doesn't work.
# Various rewrite rules.
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{HTTP_HOST} ^www.dev.{site-1}.com/test/?$ [OR]
RewriteCond %{HTTP_HOST} ^dev.{site-1}.com/test/?$ [NC]
RewriteRule ^(.*)$ https://www.dev.{site-1}.com/testredirect [R,L]
</IfModule>
Presumably the URLs used to access "site-1" don't actually contain /sites/site-1/? In which case the URL would need to be internally rewritten (by Apache) to this directory (or a subdirectory of) for the /sites/site-1/.htaccess file to be processed (by Apache) - but I don't believe that happens (since everything is handled by the core Drupal installation in the root - the purpose of having a "multisite" installation).
So, I don't think what you are suggesting is realistically possible I'm afraid (without more work).
Ordinarily you would need to have multiple "separate" Drupal installations to be able to have separate .htaccess files.
This would seem to be backed up by the following question on the Drupal SE site, which suggests to use the "Redirect module" to manage per site redirections.
Drupal Stack Exchange - Per site htaccess with multisite
Aside:
RewriteCond %{HTTP_HOST} ^www.dev.{site-1}.com/test/?$ [OR]
RewriteCond %{HTTP_HOST} ^dev.{site-1}.com/test/?$ [NC]
RewriteRule ^(.*)$ https://www.dev.{site-1}.com/testredirect [R,L]
This rule wouldn't do anything anyway, since the HTTP_HOST server variable contains the hostname from the request only, not the URL-path. But would you need to check the hostname if this .htaccess file is intended only to be processed when the user makes requests to "site-1"?
For example, it should be written:
RewriteCond %{HTTP_HOST} ^(www\.)?dev.{site-1}\.com.?$ [NC]
RewriteRule ^test/?$ https://www.dev.{site-1}.com/testredirect [R,L]

Surprising rewriting of URL by htaccess rule

I've zeroed my problem and I've specific question.
With only the following code in the .httaccess why index2.php gets called if I type in my URL as www.mysite.com/url2 ?
RewriteEngine On
RewriteCond %{REQUEST_URI} (.html|.htm|.feed|.pdf|.raw)$ [NC]
RewriteRule (.*) index2.php [L]
I've also tested it at http://www.regextester.com and should not replace it with index2.php:
In the end I want this rule to skip any URL starting with /url2 or /url2/*.
EDIT: I've made screen recording of this problem: http://screenr.com/BBBN
You have this in your .htaccess:
RewriteEngine On
RewriteCond %{REQUEST_URI} (.html|.htm|.feed|.pdf|.raw)$ [NC]
RewriteRule (.*) index2.php [L]
What it does? it rewrites anything that ends with html, htm, feed , pdf , raw to index2.php. So, if you are getting results as your URL is ends with those extensions, then there are two possible answers:
There is another rewrite rule in an .htaccess in upper directories (or in server config files) that causes the URL to be rewritten.
Your URL actually ends with those extensions. have in mind, what you enter in your address bar, will be edited and rewritten. For example, if you enter www.mysite.com/url2 in your address bar and that file doesn't exist on server, your server will try to load the proper error document. So, if your error document is /404.html, it will be rewritten to index2.php at the end.
Update:
I think it's the case. create a file named 404.php in your document root. Inside your main .htaccess (in your document root), put this:
ErrorDocument 404 /404.php
delete all other ErrorDocument directives.
inside 404.php , put this:
<?php
echo 'From 404.php file';
?>
Logic behind it:
When you have a weird behavior in mod_rewrite, the best solution in my experience is using rewrite log. to enable rewrite log put this in your virtualhost or other server config directives you may choose:
RewriteLogLevel 9
RewriteLog "logs/RewriteLog.log"
be careful: the code above will enable rewrite log and start logging at highest level possible (logging everything). It will decrease your server speed and the log file will become huge very quickly. Do this only on your dev server.
Explanation: When you try to access www.mysite.com/url2, Apache gives your URL to rewrite module. Rewrite module checks if any of RewriteRules applies to your URL. Because you have one rule and it doesn't apply to your URL, it tries to load the normal file. But this file does not exit. So, Apache will do the next step which is showing the proper error message. When you set a custom error file, Apache will run the test against the new address. For example if error document is /404.html, Apache checks whether your rule applies to /404.html or not. Since it does, it will rewrite it.
The point to remember is apache will do this every time there is change in URL, whether the change is made by rewrite module or not!
The rule you list should work as you expect if this is the only rule. Fact is that theory is fun, but apparently it doesn't work as expected. Please note that . will match ANY CHARACTER. If you want to match the full stop/period character, you'll need to escape it. That's why I use \.(html|htm|feed|pdf|raw)$ instead of (.html|.htm|.feed|.pdf|.raw)$ below.
You can add another RewriteCond that simply doesn't match if the url starts with /url2, like below. This might not be a viable solution if there are lots of urls that shouldn't be matched.
RewriteCond %{REQUEST_URI} !^/url2
RewriteCond %{REQUEST_URI} \.(html|htm|feed|pdf|raw)$ [NC]
RewriteRule (.*) index2.php [L]
To get a better understanding of what is happening you can alter the rule to something like this. Now simply enter the urls you dont want to be matched in the url bar and inspect the url bar after the redirect happens. In the url-parameter you now see what url actually triggered this rule to match. This screencast shows you a similar version working with a sneaky rewriterule that is working away on the url.
#A way of finding out what is -actually- matched
RewriteCond %{REQUEST_URI} \.(html|htm|feed|pdf|raw)$ [NC]
RewriteCond %{REQUEST_URI} !/foo
RewriteRule (.*) /foo?url=$1 [R,L]
You can decide to match the %{THE_REQUEST} variable instead. This will always contain the request itself. If something else is rewriting the url, this variable doesn't change, meaning you can use this to overwrite any changes. Make sure the url won't be matching itself. You would get something like below. An example screencast can be found here.
#If it doesn't end on .html/htm/feed etc, this one won't match
RewriteCond %{THE_REQUEST} ^(GET|POST)\ /.*\.(html|htm|feed|pdf|raw)\ HTTP [NC]
RewriteCond %{REQUEST_URI} !^/index2\.php$
RewriteRule (.*) /index2.php [L]

htacces - need to fix broken links coming from other sites to mine

I am having an issue where Google Webmaster Tools is reporting a ton of 404 links to my site which are coming from ask.com.
I have tried to get ask.com to fix their side but of course they are not, so now I am stuck with over 11k of bad links to my site which I am suspecting is effecting my ranks right now.
Anyways I have a possible way to 301 them, but not sure how to do it with .htaccess.
Here is the bad link pointing to my site
http://www.freescrabbledictionary.com/sentence-examples/fere-film/feverous/about.php
It should be
http://www.freescrabbledictionary.com/sentence-examples/fere-film/feverous/
Besides the about.php there are other variations of endings as well, I basically need to be able to remove the ending.
Problem is that the URL after /sentence-examples/ can change. The beginning is always:
http://www.freescrabbledictionary.com/sentence-examples/
So basically:
http://www.freescrabbledictionary.com/sentence-examples/<-keep but can change->/<-keep but can change->/<-remove this->
This .htaccess should be placed on the folder before sentence-examples:
RewriteEngine on
# Redirect /sentence-examples/anything/anything/remove to /sentence-examples/anything/anything/
RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s/+(sentence-examples/[^/]+/[^/]+)/.* [NC]
RewriteRule ^ /%1/? [R=302,PT,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]+)/(.*)$ /sentence-examples/examplesentence.php?havethis=$1&word=$2 [L]
Change 302 to 301 once you confirm it's working as expected.
If you have a CMS installed you might need a different rule to work along with it without conflicting.
Keep in mind that if you had previously tried different redirects using 301 aka permanent redirect its recommended that you use a different browser to test this rule to avoid the caching.
This is possibly quick and dirty but I've done a simple test on localhost and here just to make sure it works.
RewriteEngine On
RewriteRule ^sentence-examples/(.*)/(.*)/(.*)\.php http://www.freescrabbledictionary.com/sentence-examples/$1/$2/ [R=301,L]
You can see that I've added wildcard groups (.*) to the RewriteRule so that we can pick up the elements of the URL that we need to aid in proper redirection i.e. $1 and $2. You can also use the third one ($3) to get which destinations are being targeted alot for your SEO needs.
NB: The rule above assumes that that the redirected URL will always be from a .php target and to ensure that you can redirect regardless of whatever comes after the 3rd URL segment replace the RewriteRule with this
RewriteRule ^sentence-examples/(.*)/(.*)/(.*)$ http://www.freescrabbledictionary.com/sentence-examples/$1/$2/ [R=301,L]

Redirect Desktop Internal Pages to Correct Mobile Internal Pages with Htaccess

I have built a Mobile site in a sub-domain.
I have successfully implemented the redirect 302 from:
www.domain.com to m.domain.com in htaccess.
What I'm looking to achieve now it to redirect users from:
www.domain.com/internal-page/ > 302 > m.domain.com/internal-page.html
Notice that URL name for desktop and mobile is not the same.
The code I'm using looks like this:
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
# Mobile Redirect
# Verify Desktop Version Parameter
RewriteCond %{QUERY_STRING} (^|&)ViewFullSite=true(&|$)
# Set cookie and expiration
RewriteRule ^ - [CO=mredir:0:www.domain.com:60]
# Prevent looping
RewriteCond %{HTTP_HOST} !^m.domain.com$
# Define Mobile agents
RewriteCond %{HTTP_ACCEPT} "text\/vnd\.wap\.wml|application\/vnd\.wap\.xhtml\+xml" [NC,OR]
RewriteCond %{HTTP_USER_AGENT} "sony|symbian|nokia|samsung|mobile|windows ce|epoc|opera" [NC,OR]
RewriteCond %{HTTP_USER_AGENT} "mini|nitro|j2me|midp-|cldc-|netfront|mot|up\.browser|up\.link|audiovox"[NC,OR]
RewriteCond %{HTTP_USER_AGENT} "blackberry|ericsson,|panasonic|philips|sanyo|sharp|sie-"[NC,OR]
RewriteCond %{HTTP_USER_AGENT} "portalmmm|blazer|avantgo|danger|palm|series60|palmsource|pocketpc"[NC,OR]
RewriteCond %{HTTP_USER_AGENT} "smartphone|rover|ipaq|au-mic,|alcatel|ericy|vodafone\/|wap1\.|wap2\.|iPhone|android"[NC]
# Verify if not already in Mobile site
RewriteCond %{HTTP_HOST} !^m\.
# We need to read and write at the same time to set cookie
RewriteCond %{QUERY_STRING} !(^|&)ViewFullSite=true(&|$)
# Verify that we previously haven't set the cookie
RewriteCond %{HTTP_COOKIE} !^.*mredir=0.*$ [NC]
# Now redirect the users to the Mobile Homepage
RewriteRule ^$ http://m.domain.com [R]
RewriteRule $/internal-page/ http://m.domain.com/internal-page.html [R,L]
At the end, you have two RewriteRule lines which I believe should be changed to:
RewriteRule ^\/?$ http://m.domain.com [R=302]
RewriteRule ^\/?(.*)\/?$ http://m.domain.com/$1.html [R=302,L]
The ^\/?(.*)\/?$ means give me a string that starts at the beginning (^) and gives me all characters ((.*)) until the end ($) without the trailing/beginning (/) if there is one (?).
The http://m.domain.com/$1.html means that if the address is http://www.domain.com/internal-page/ then it becomes http://m.domain.com/internal-page.html.
The [R=302,L] should mean a 302 redirect (R=302) and the last rewrite (L), so no other rewrites can occur on our URL.
EDIT:
I believe that in the case of your RewriteRules the first one was redirecting to http://m.domain.com in the event that the URL was just the domain, but if there was anything else then the second rewrite was failing because it was not actually literally /internal-page/ and you needed a regex variable to put into the new URL.
EDIT (2):
To redirect to each mobile page from a specific desktop page:
RewriteRule ^\/foo\/?$ http://m.domain.com/bar.html [R=302]
RewriteRule ^\/hello\/?$ http://m.domain.com/world.html [R=302]
The (/?) means that a / is optional in that position and the (^) denotes beginning and ($) denotes ending in this case (the ^ can also be used to indicated something like [^\.] which means anything except a period).
Just put how ever many of those that you need in a row to do the redirecting and that should do the trick. To make sure there are no misconceptions, the first line would mean that http://www.domain.com/foo/ would become http://m.domain.com/bar.html and because the trailing slash is made optional http://www.domain.com/foo (notice the trailing forward slash is absent) would also redirect to http://m.domain.com/bar.html.
You can play with the syntax a bit to customize it, but hopefully I've pointed you in the right direction. If you need anything else, let me know, I'll do my best to assist.
I don't want to sound like a broken record or anything, but I feel that I could not, in good conscience, end this edit without pointing out that modifying the mobile site would be a much better way to do this. If it is not possible or you feel that a few static redirects are not a big deal versus modifying some pages, then I totally understand, but here are a few things for you to think about:
If the mobile site and desktop site are in separate folders then the exact same name scheme can be used for both making the Rewrites simpler and meaning that as new pages/content are added you will not need more Rewrite statements (making more rewrites means you have to create the new pages and then you have to create the redirects. that's extra work and more files which require your attention.)
If the mobile site is actually hosted from the same directory as the desktop site, then changing the files for one or the other so it becomes something like /desktop-foo/ or /d-foo/ then it is very easy to make the rewrite (redirect) go to something like /m-foo.html. You could forego modifying the desktop pages and make /foo/ become /m-foo.html and make all your mobile versions begin with an 'm'.
The third option that comes to mind is the most difficult and time consuming, depending on the content of the site, but it is a pretty cool one and ultimately would make the site the easiest to work on (after the initial work, of course). It is quite possible to use the same page for desktop, mobile, tablet, etc without the use of mod_rewrite or separate pages. Things like media queries in your CSS would allow you to change the look of the page depending on what the client is viewing it from. I came across a tutorial on the subject earlier which used media queries and the max-width of the screen to determine how the page should look. This would require a good bit of work now, but could save some hassle down the road as well as being an interesting learning experience if you are up to the challenge.
Again, sorry that this veered off topic at the end there, but I got the impression from your original question and your responses that you might find the alternatives interesting if you haven't already considered and dismissed them and that even if the alternatives do not interest you that you aren't going to be like some people and respond with, "Hey, $*%& you, buddy! I asked for Rewrites not all that other garbage!" I hope you take it as nothing more than what it is intended to be...helpful.

mod_rewrites .htaccess not working with godaddy hosting (linux)

On my site www.sqcp.com in testing on another linux server, all worked as it should. However since moving it to godaddy, the mod_rewrites haven't been working, therefore none of the other pages have been accessible. Even if I create a blank directory/folder in the what it's trying to tidy the url to it then works for that page (obviously isn't a fix).
So any help would be great here my .htaccess file.
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ / [L,R=301]
RewriteRule (.*)/{2,}$ /$1/ [L,R=301]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{THE_REQUEST} ^GET\ /[^?\s]+\.php
RewriteRule (.*)\.php$ /$1/ [L,R=301]
RewriteRule ^(.*)/(\d{4}\-\d{2}\-\d{2}\-[a-zA-Z0-9\-_]+)$ $1?s=$2 [L]
RewriteRule ^(.*/)?staff.php/([a-zA-Z0-9\-_]+) $1staff.php?s=$2 [L]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule (.*)/$ $1.php [L]
RewriteCond %{REQUEST_FILENAME}/index.php !-f
RewriteRule (.*)/$ $1 [L]
</IfModule>
Godaddy run a perfectly good shared hosting service, addressing a large market sector -- users who want an active site (that is with some scripting) but without the cost or complexity of paying for or having the expertise to administer their own Linux VM. This isn't a GoDaddy problem. Its yours.
So first get to understand the environment that you are running under by running a phpinfo script, and make sure it creates the variables that you use. As far as I can see on your example:
Rules 1-3 are 301 redirections to enforce some request naming convention.
Rule 1 redirects /index.php to /
Rule 2 collapses trailing multiple / to a single /
Rule 3 rewrites GET requests for *.php to *.php/
Rules 4-6 map public URIs to internal ones
Rule 4 rewrites /*/yyyy-mm-dd-word to *?s=yyyy-mm-dd-word (note no QSA)
Rule 5 seems to be attempting to rewrite /*/staff.php/word to /*/staff.php?s=word but the syntax is wrong for this.
Rule 6 replaces any trailing / by .php on redirection
Rule 7 strips any trailing '/' unless the uri is a directory with an index.php (I assume that you are assuming a DirectoryIndex index.php (is this the case for GoDaddy?)
This is all hopelessly confused. Are you hiding or exposing the .php extension? Because Rule 3,5 and 6 are inconsistent. And rule 5 would seem more logical as
RewriteRule ^(.*?)/staff.php/([a-zA-Z0-9\-_]+) $1/staff.php?s=$2 [L]
Go back to the drawing board and work out what you are trying to do with your htaccess rules; what you want your public URI grammar to be; how your scripts are laid out; what redirects you want to pass back to the client browser and which you want Apache to handle as internal rewrites and what extra conditions are needed to prevent looping and misfiring. Make sure this makes sense and then debug them by building up your .htaccess file one rule at a time and using test requests to exercise each rule in turn to validate what its doing.
Trying adding the following at the start of your htaccess file. I had the same problem getting rewrites to work on GoDaddy which worked everywhere else:
Options -Multiviews

Resources