htaccess time-conditional rule isn't working properly - .htaccess

We're trying to set up a proof of concept for a/b testing using htaccess on a homepage based on this gist: https://gist.github.com/iconifyit/c8d715d62b6e3960696ac1c9cbd231c5
We've modified the code to target the homepage only & it half works, meaning that it will only use the first condition & ignores the second. I'm not 100% on my htaccess rules & I've gone over this for the past couple days to figure out what is going wrong but I feel like I'm shooting at a target in the dark.
# ############################### #
# A/B TESTING (START) #
# ############################### #
# (1) Check if our cookie is already set.
# If so, redirect to the previously-viewed page.
RewriteCond %{HTTP_COOKIE} ab_test_vers=([^;]+)
RewriteRule ^/$ HTTPS://example.com/%1/$1 [cookie=ab_test_vers_match:true:example.com,L]
# (2) If no cookie is set (new visitor)
# AND the current time is on the first half of the minute
# Rewrite to /test-option-a AND set our cookie
RewriteCond %{HTTP_COOKIE} !ab_test_vers=([^;]+)
RewriteCond %{TIME_SEC} <30
RewriteRule ^/$ /even/$1 [cookie=ab_test_vers:even:example.com,L]
RedirectMatch 302 ^/$ HTTPS://example.com/welcome/
# (3) If no cookie is set (new visitor)
# AND the current time is on the second half of the minute
# Rewrite to /test-option-a AND set our cookie
RewriteCond %{HTTP_COOKIE} !ab_test_vers=([^;]+)
RewriteCond %{TIME_SEC} >29
RewriteRule ^/$ /odd/$1 [cookie=ab_test_vers:odd:example.com,L]
RedirectMatch 302 ^/$ HTTPS://example.com/about/
# ############################### #
# A/B TESTING (END) #
# ############################### #
What should be happening is that based on the time that a visitor hits the homepage of said site, they're automatically redirected to one of the two pages, in this case the pages being used for proof of concept are /welcome & /about. What's actually happening is that they're only being redirected to /welcome & the second rule is being ignored completely.

Related

Redirect parameter to its parent post url

i have several set of error URL with parameter that i need to redirect to the parent post URL
http://www.mysite.co/post1.html?amp=1
http://www.mysite.co/post1.html?amp=0
http://www.mysite.co/post1.html?utm_source=xxxxx
so what im trying to achieve http://www.mysite.co/post1.html?amp=1 (status 404 ) should redirect to http://www.mysite.co/post1.html (200 ok)
i tried to add htaccess code but it always gave me 500 errors, can someone help me with the proper htaccess code
Htacess
# BEGIN WordPress
# The directives (lines) between "BEGIN WordPress" and "END
<IfModule mod_rewrite.c>
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]
</IfModule>
# END WordPress
current permalinks are set to
/%postname%.html
Parameter in url ?amp, ?utm_source are added by third party service/plugins which resulted 404 error
Try the following at the top of the .htaccess file, before the # BEGIN WordPress section:
RewriteCond %{QUERY_STRING} ^(amp=[01]|utm_source=[^&]+)$
RewriteRule ^[\w-]\.html$ /$0 [QSD,R=301,L]
This matches any URL-path that ends in .html. Only the specific query strings as mentioned in the question are matched. ie. amp=0 or amp=1 or utm_source=<something>. It will not redirect amp=2 or utm_source= or utm_source=<something>&foo=1 etc.
The QSD flag (Apache 2.4) discards the original query string.
Test first with 302 (temporary) redirects to avoid potential caching issues.
UPDATE:
#REDIRECTION UTM CLEAR
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{QUERY_STRING} "utm" [NC]
RewriteRule (.*) /$1? [R=301,L,QSD]
<IfModule mod_rewrite.c>
which one you thing serves better?
What do you mean by "better"?
As written, this code is strictly invalid (and contains superfluous directives). But (when corrected) this code arguably matches too much (and does not handle the amp URL parameter at all). It matches utm anywhere in the query string which could potentially create conflicts with existing code. It also matches any URL-path, so is potentially checking 1000s of requests that don't need checking. eg. It would match /image.jpg?nutmeg=5 and /?scoutmaster=1 - which clearly have nothing to do with utm tracking parameters (which all start utm_).
The code I posted above matches precisely the criteria you've stated in the question. And thus avoids potential conflicts. So, from that perspective, the code I posted above is "better".
However, to match amp or any URL parameter that simply starts utm_ and only whole URL parameters that might occur anywhere in the query string then use something like the following instead:
RewriteCond %{QUERY_STRING} (?:^|&)(amp|utm_\w+)=
RewriteRule ^[\w-]\.html$ /$0 [QSD,R=301,L]
This matches URLs of the form /%postname%.html - your permalink structure. It does not match /image.jpg etc.
You do not need to repeat the RewriteEngine directive. The RewriteBase directive is entirely superfluous. You should not wrap these directives in a <IfModule> container.
Note that if you have any legitimate URL parameters mixed in then they will also be removed.
This matches the following:
/<postname>.html?amp=<anything>
/<postname>.html?utm_source=<anything>
/<postname>.html?utm_campaign=<anything>&bar=1
/<postname>.html?foo=1&utm_<something>=<anything>
etc.
But does not match:
/<postname>.html?wamp=<anything>
/<postname>.html?nutmeg_source=<anything>
/image.jpg?utm_source=<anything>
etc.

How to redirect from non-www to www in joomla site whith ssl

I Have a joomla 2.5 & virtuemart 2 eshop.
In www.mysite.com all works perfect !
My site redirect from http to https only in checkout area and back in other areas of site (with a Plug-in SSL Redirection).
The problem is if you insert in site with http:/mysite.com in checkout redirect to https://mysite.com/checkout and browser block the page (error: ssl_error_bad_cert_domain)
and say the certificate is only for www.mysite.com !!
How can fix this problem. If i use .htaccess
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^(.*)$ http://www.%{HTTP_HOST}/$1 [R=301,L]
i thin have problem in ssl area beacause in RewriteRume have http:// ?
The .htaccess inside have
##
# #package Joomla
# #copyright Copyright (C) 2005 - 2014 Open Source Matters. All rights reserved.
# #license GNU General Public License version 2 or later; see LICENSE.txt
##
##
# READ THIS COMPLETELY IF YOU CHOOSE TO USE THIS FILE!
#
# The line just below this section: 'Options +FollowSymLinks' may cause problems
# with some server configurations. It is required for use of mod_rewrite, but may already
# be set by your server administrator in a way that dissallows changing it in
# your .htaccess file. If using it causes your server to error out, comment it out (add # to
# beginning of line), reload your site in your browser and test your sef url's. If they work,
# it has been set by your server administrator and you do not need it set here.
##
## Can be commented out if causes errors, see notes above.
Options +FollowSymLinks
## Mod_rewrite in use.
RewriteEngine On
## Begin - Rewrite rules to block out some common exploits.
# If you experience problems on your site block out the operations listed below
# This attempts to block the most common type of exploit `attempts` to Joomla!
#
# Block out any script trying to base64_encode data within the URL.
RewriteCond %{QUERY_STRING} base64_encode[^(]*\([^)]*\) [OR]
# Block out any script that includes a <script> tag in URL.
RewriteCond %{QUERY_STRING} (<|%3C)([^s]*s)+cript.*(>|%3E) [NC,OR]
# Block out any script trying to set a PHP GLOBALS variable via URL.
RewriteCond %{QUERY_STRING} GLOBALS(=|\[|\%[0-9A-Z]{0,2}) [OR]
# Block out any script trying to modify a _REQUEST variable via URL.
RewriteCond %{QUERY_STRING} _REQUEST(=|\[|\%[0-9A-Z]{0,2})
# Return 403 Forbidden header and show the content of the root homepage
RewriteRule .* index.php [F]
#
## End - Rewrite rules to block out some common exploits.
## Begin - Custom redirects
#
# If you need to redirect some pages, or set a canonical non-www to
# www redirect (or vice versa), place that code here. Ensure those
# redirects use the correct RewriteRule syntax and the [R=301,L] flags.
#
## End - Custom redirects
##
# Uncomment following line if your webserver's URL
# is not directly related to physical file paths.
# Update Your Joomla! Directory (just / for root).
##
# RewriteBase /
## Begin - Joomla! core SEF Section.
#
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
#
# If the requested path and file is not /index.php and the request
# has not already been internally rewritten to the index.php script
RewriteCond %{REQUEST_URI} !^/index\.php
# and the request is for something within the component folder,
# or for the site root, or for an extensionless URL, or the
# requested URL ends with one of the listed extensions
RewriteCond %{REQUEST_URI} /component/|(/[^.]*|\.(php|html?|feed|pdf|vcf|raw))$ [NC]
# and the requested path and file doesn't directly match a physical file
RewriteCond %{REQUEST_FILENAME} !-f
# and the requested path and file doesn't directly match a physical folder
RewriteCond %{REQUEST_FILENAME} !-d
# internally rewrite the request to the index.php script
RewriteRule .* index.php [L]
#
## End - Joomla! core SEF Section.
Try add this lines in .htaccess:
RewriteCond %{HTTPS_HOST} ^mysite\.com$ [NC]
RewriteRule ^(.*)$ https://www.mysite.com/$1 [R=301,L]
If the browser is complaining, because the certificate is only for www.mysite.com but you want it to use with mysite.com, then the browser is probably right. What you can do is:
not redirect to https://mysite.com, but to https://www.mysite.com
or get yourself a certificate for mysite.com (which might include www.mysite.com too)

.htaccess: Redirect all requests to a subdirectory except if an exact directory exists

Any request to www.example.com/* must be redirected to www.example.com/blog/*
If no www. prefix, add it.
Importantly, if there exists any directory matching the request URI, don't redirect.
Example:
(www.)example.com/<request> -> www.example.com/blog/<request> except <request> === <dirname>
Following the above 3 conditions, how do I code a .htaccess? Please help!
Thx ;-)
This should do what you wanted. I also added in a "don't redirect if this file exists", since I wasn't sure what was in your existing directories. You can try removing it by taking out the second RewriteCond if you don't want it, but I think it's probably necessary to some extent.
RewriteEngine On
# Check if the requested path is not a real file or a
# real directory
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
# If the current request doesn't start with "blog", and
# it's not a real file or directory based on the above
# conditions, add "blog" to the front of the request, and
# mark an environment variable that indicates we'll need
# to redirect
RewriteRule !^blog blog%{REQUEST_URI} [E=CHANGED:TRUE]
# Check if the host doesn't start with "www.", or if we've
# marked the change variable above, since in either of those
# cases we need to perform a redirection (We do it this way,
# since we'll at most send one redirect back to the client,
# instead of the potential two we might send if we didn't
# combine the checks)
RewriteCond %{HTTP_HOST} !^www\. [OR]
RewriteCond %{ENV:CHANGED} =TRUE
# Capture the non-"www." part of the host, regardless of
# whether or not the "www." is there
RewriteCond %{HTTP_HOST} ^(www\.)?(.*)$
# Redirect anything to the corrected URL, using the
# backreference from the above condition, and the entirety of
# the requested path (possibly modified by the above RewriteRule)
RewriteRule ^.*$ http://www.%2/$0 [R=301,L]

How do I get the [L] flag of RewriteRule (.htaccess) really working?

To newcomers: While trying to comprehensively describe my problem and phrase my questions I produced huge ammount of text. If you don't want to read the whole thing, my observations about (read "proof of") [L] flag not working the misconception, from which it all sprung, is located in Additional observations section. Why I misunderstood apparent behaviour is described in my Answer as well as solution to given problem.
Setup
I have following code in my .htaccess file:
# disallow directory indexing
Options -Indexes
# turn mod_rewrite on
Options +FollowSymlinks
RewriteEngine on
# allow access to robots file
RewriteRule ^robots.txt$ robots.txt [NC,L]
# mangle core request handler address
RewriteRule ^core/(\?.+)?$ core/handleCoreRequest.php$1 [NC,L]
# mangle web file adresses (move them to application root folder)
# application root folder serves as application GUI address
RewriteRule ^$ web/index.html [L]
# allow access to images
RewriteRule ^(images/.+\.(ico|png|bmp|jpg|gif))$ web/$1 [NC,L]
# allow access to stylesheets
RewriteRule ^(css/.+\.css)$ web/$1 [NC,L]
# allow access to javascript
RewriteRule ^(js/.+\.js)$ web/$1 [NC,L]
# allow access to library scripts, styles and images
RewriteRule ^(lib/js/.+\.js)$ web/$1 [NC,L]
RewriteRule ^(lib/css/.+\.css)$ web/$1 [NC,L]
RewriteRule ^(lib/(.+/)?images/.+\.(ico|png|bmp|jpg|gif))$ web/$1 [NC,L]
# redirect all other requests to application address
# RewriteRule ^(.*)$ /foo/ [R]
My web application (and its .htaccess file) is located in foo subfolder of DOCUMENT_ROOT (accessed from browser as http://localhost/foo/). It has PHP core part located in foo/core and JavaScript GUI part located in foo/web. As can be seen from the code above, I want to allow access only to single core script that handles all requests from GUI and to 'safe' web files and redirect all other requests to base application address (last commented directive).
Problem
Behaviour
It works until I try the last part by uncommenting the last redirecting directive. If I comment some more lines, the appropriate page parts stop working, etc.
However, when I uncomment last line, which should be performed only when matching of all previous rules fails (at least that's what I understand), page goes into redirection cycle (Firefox throws error page with something like "This page isn't redirecting properly"), because it's redirecting to http://localhost/foo/ again and again and again, forever.
Questions
What I don't understand is this processing of this rule:
RewriteRule ^$ web/index.html [L],
specifically the [L] flag. The flag apparently doesn't work for me. When the last line is commented, it correctly redirects, but when I uncomment it, it is always processed, even though rewriting should stop on [L] flag. Anyone got any ideas?
Also, on a sidenote, I'd be thrilled to know why my following attempt at fixing it doesn't work either:
RewriteEngine on
RewriteRule ^core/(\?.+)?$ core/handleCoreRequest.php$1 [NC,L]
RewriteRule ^(.*)$ web/$1 [L]
RewriteRule ^.*$ /foo/ [L]
This actually doesn't work at all. Even if I remove the last line, it still doesn't redirect anything correctly. How does the redirecting work in the first example, if it doesn't work in the second?
It would also be of great benefit to me, if anybody knew any way to actually debug these directives. I spend hours on this without even the slightest clue what could possibly be wrong.
Additional observations
After trying the advice given by bbadour (not that I haven't tried it before, but now that I had a second opinion, I gave it another shot) and it didn't work, I've come up with the following observation. By rewriting last line to this:
RewriteRule ^(.*)$ /foo/?uri=$1 [R,L]
or this
RewriteRule ^(.*)$ /foo/?uri=%{REQUEST_URI} [R,L]
and using Firebug's Net panel, I found out more evidence, that the [L] flag is clearly not working as expected in the previously mentioned RewriteRule ^$ web/index.html [L] rule (let's call it THE RULE from now on). In first case I get [...]uri=web/index.html, in second case [...]uri=/foo/web/index.html. That means that THE RULE gets executed (rewrites ^$ to web/index.html), but the rewriting doesn't stop there. Any more ideas, please?
After hours of searching and testing, I finally found the real problem and solution. Hopefully this will help somebody else too, when they come across the same problem.
Cause of observed behavior
.htaccess file is processed after every redirect (even without [R] flag),
which means that after the RewriteRule ^$ web/index.html [L] is processed, mod_rewrite correctly stops rewriting, goes to the end of the file, redirects correctly to /foo/web/index.html, and then the server starts processing .htaccess file for the new location, which is the same file. Now only the last rewrite rule matches and redirects back to /foo/ (this time with [R], so the redirect can be observed in browser) ... and the .htaccess file is processed again, and again, and again...
Once more for clarity: Because only the hard redirects can be observed, it seems like the [L] flag is ignored, but it is not so. Instead, the .htaccess is processed two times redirecting back and forth between /foo/ and /foo/web/index.html.
Solution
Disallow direct access to subfolder
To virtually move subdirectory to application root directory, additional complex conditional rewrites must be used. Variable THE_REQUEST is useful for distinguishing between hard and soft redirects:
RewriteCond %{THE_REQUEST} ^GET\ /foo/web/
RewriteRule ^web/(.*) /foo/$1 [L,R]
For this rewrite rule to be matched, two conditions must apply. First, on second line, the "local URI" must start with web/ (which corresponds with absolute web URI /foo/web/). Second, on first line, the real request URI must start with /foo/web/ too. Together this means, that the rule only matches when the file inside the web/ subfolder is requested directly from the browser, in which case we want to do a hard redirect.
Redirect to allowed content from root to subfolder (soft)
RewriteCond $1 !^web/
RewriteCond $1 ^(.+\.(html|css|js|ico|png|bmp|jpg|gif))?$
RewriteRule ^(.*)$ web/$1 [L,NC]
We want to redirect to allowed content only if we haven't done it already, hence the first condition. Second condition specifies mask for allowed content. Anything matching this mask will be softly redirected, possibly returning 404 error if the content doesn't exist.
Hide all content not in subfolder or not allowed
RewriteRule !^web/ /foo/ [L,R]
This will do a hard redirect to application root for all URIs not beginning with web/ (and remember, only requests that can begin with web/ at this point are internal redirects for allowed content.
Real example
My code shown in my "question" after using solution tips mentioned above gradually transformed into the following:
# disallow directory indexing
Options -Indexes
# turn mod_rewrite on
Options +FollowSymlinks
RewriteEngine on
# allow access to robots file
RewriteRule ^robots.txt$ - [NC,L]
# mangle core request handler address
# disallow direct access to core request handler
RewriteCond %{THE_REQUEST} !^(GET|POST)\ /asm/core/handleCoreRequest.php
RewriteRule ^core/handleCoreRequest.php$ - [L]
# allow access to request handler under alias
RewriteRule ^core/$ core/handleCoreRequest.php [NC,QSA,L]
# mangle GUI files adressing (move to application root folder)
# disallow direct access to GUI subfolder
RewriteCond %{THE_REQUEST} ^GET\ /foo/web/
RewriteRule ^web/(.*) /foo/$1 [L,R]
# allow access only to correct filetypes in appropriate locations
RewriteCond $1 ^$ [OR]
RewriteCond $1 ^(images/.+\.(ico|png|bmp|jpg|gif))$ [OR]
RewriteCond $1 ^(css/.+\.css)$ [OR]
RewriteCond $1 ^(js/.+\.js)$ [OR]
RewriteCond $1 ^(lib/js/.+\.js)$ [OR]
RewriteCond $1 ^(lib/css/.+\.css)$ [OR]
RewriteCond $1 ^(lib/(.+/)?images/.+\.(ico|png|bmp|jpg|gif))$
RewriteRule ^(.*)$ web/$1 [L,NC]
# hide all files not in GUI subfolder that are not whitelisted above
RewriteRule !^web/ /foo/ [L,R]
What I don't like about this approach is that the application root folder must be hardcoded in .htaccess file (as far as I know), so the file must be generated on application install, not simply copied.
To debug, try simplifying your regex, and the url you ask for (a part of the full url you wanna match), and see if it's working, now step by step, add more bits to the regex adn the testing url, till you find where things are stopping to work properly.
Try using:
RewriteRule ^(.*)$ /foo/ [R,L]
If it still loops, put a RewriteCond in front of it to skip the rule if it is already /foo/

Sitewide 301 Redirect with a subset of different redirects

I am trying to make a sitewide 301 redirect for a site with around 400 pages but also have a subset of about 10 individual pages that don't follow the sitewide redirect and should point somewhere else.
Any ideas how to format such redirect rules so the sitewide redirect doesnt conflict with the subset pages redirect?
I am starting with the sitewide redirect rule as:
Options +FollowSymLinks
RewriteEngine on
RewriteRule (.*) http://www.name.com/$1 [R=301,L]
The rewrite rules are parsed in the order they are written, so the order you list them also defines the priority.
Given that, you should first match the request URI with the 10 individual pages and return the redirection accordingly, and then define the sitewide redirection.
If the 10 individual pages have a single target URL, the match rule may be one, otherwise you should do a single redirection per each request URI.
Take care to use the [L] flag for the first redirections, to tell the server to exit the routine if the rule is matched, and I would also suggest to add the line
RewriteBase /
which is pivotal for some Apache versions, in which the omission of this line may cause a http bad conf error.
Options +FollowSymLinks
#switch on the rewrite engine:
RewriteEngine On
RewriteBase /
#rules for the individual redirections:
RewriteRule http://example.com/myUrl-1 http://www.example.org/new-1 [R=301,L]
RewriteRule http://example.com/myUrl-4 http://www.example.org/new-2 [R=301,L]
RewriteRule http://example.com/myUrl-3 http://www.example.org/new-3 [R=301,L]
#...and so on
#sitewide redirection rule:
RewriteRule (.*) http://www.example.org/$1 [R=301]

Resources