Why does RewriteRule only work when I change the line position? - .htaccess

I have the following lines in my .htaccess file:
RewriteCond %{QUERY_STRING} id=([0-9]+)
RewriteRule ^page/([0-9]+)/$ ?page=$1 [L]
RewriteRule ^(20\d\d)/page/([0-9]+)/$ ?yearMeasure=$1&page=$2 [L]
RewriteRule ^(20\d\d)/$ ?yearMeasure=$1 [L]
RewriteRule ^category/([A-Za-z0-9-]+)/page/([0-9]+)/$ ?category=$1&page=$2 [L]
RewriteRule ^category/([A-Za-z0-9-]+)/$ ?category=$1 [L]
RewriteRule ^(20\d\d)/([A-Za-z0-9-]+)/$ ?type=post&year=$1&title=$2 [L,QSA]
When the file is left as above, the server does not capture /page/1/. Rather, it returns a 404 error. However, when I flip the second and third lines, everything works perfectly. Why is this?
RewriteCond %{QUERY_STRING} id=([0-9]+)
RewriteRule ^(20\d\d)/page/([0-9]+)/$ ?yearMeasure=$1&page=$2 [L]
RewriteRule ^page/([0-9]+)/$ ?page=$1 [L]
RewriteRule ^(20\d\d)/$ ?yearMeasure=$1 [L]
RewriteRule ^category/([A-Za-z0-9-]+)/page/([0-9]+)/$ ?category=$1&page=$2 [L]
RewriteRule ^category/([A-Za-z0-9-]+)/$ ?category=$1 [L]
RewriteRule ^(20\d\d)/([A-Za-z0-9-]+)/$ ?type=post&year=$1&title=$2 [L,QSA]
Edit:
After a few minutes of experimenting, it seems that the line that comes directly after RewriteCond %{QUERY_STRING} id=([0-9]+) is ineffectual.
Any help is appreciated.

Any RewriteCond belongs to the RewriteRule directly following it
The RewriteCond directive defines a rule condition. One or more RewriteCond can precede a RewriteRule directive. The following rule is then only used if both the current state of the URI matches its pattern, and if these conditions are met.
1. RewriteCond ...
2. RewriteRule ...
3. RewriteCond ...
4. RewriteRule ...
5. RewriteRule ...
So in this case condition 1 belongs to rule 2, and condition 3 belongs to rule 4, and finally rule 5 has no condition at all.
This means, when you have
1. RewriteCond ...
2. RewriteRule ...
3. RewriteRule ...
and switch rules 2 and 3,
1. RewriteCond ...
3. RewriteRule ...
2. RewriteRule ...
the condition belongs to the other rule.
When you use the first set of rules and request /page/1/?id=5, it would work, because now the preceding condition "QUERY_STRING matches id=([0-9]+)" is met.

Related

.htaccess RewriteRule(s) not working

I am trying to learn how to use RewriteRule.
I have 2 'pages' (wordpress)-
domain.com/webinars/ (shows list of all webinars)
and
domain.com/webinar/ (shows specific webinar details)
I have trying to set the following conditions -
(1) domain.com/webinars/{Year}/{Month}/ will load /webinar/?year={Year}&month={Month}
(2) domain.com/webinar/ (with no /{Year}/{Month}) will load /webinars/
(3) domain.com/webinar/?year={Year}&month={Month} will redirect to /webinars/{Year}/{Month}/ and then apply condition #1
This is my attempted code
RewriteEngine On
RewriteRule ^/webinars/([0-9]+)/([A-Za-z0-9]+)/$ /webinar/?year=$1&month=$2 [NC]
RewriteRule ^/webinar/$ /webinars/
RewriteRule ^/webinar/year=(\d+)$month=([\w-]+)$ /webinars/%1/%2? [R=301,L]
Condition #1 results in a 404 page not found
Condition #2 shows /webinar/ and not /webinars/
Condition #3 stays on domain.com/webinar/?year={Year}&month={Month} and does not redirect
What am I doing wrong? Only other code in my htaccess file is the default wordpress block.
Try the following :
Options +FollowSymlinks
RewriteEngine on
RewriteRule ^webinars/([^/]+)/([^/]+) /webinar/?year=$1&month=$2 [NC]
The rest could be done the same way .
Try with below rules,
RewriteCond %{REQUEST_URI} ^/webinar$
RewriteCond %{QUERY_STRING} ^year=([^/]+)&month=([^/]+)
RewriteRule ^ http://example.com/webinars/%1/%2/? [R=302]
RewriteCond %{REQUEST_URI} ^/webinars/([^/]+)/([^/]+)/$
RewriteRule ^ webinar/?year=%1&month=%2 [L,END]
RewriteCond %{REQUEST_URI} ^/webinar/$
RewriteRule ^ webinars/ [L]
You can use this
RewriteEngine on
# if /webinar/ is requested skip the rules and serve /webinar/ directory
RewriteRule ^webinar/?$ - [L]
#redirect /webinar/?year={year}&month={month}
#To /webinar/year/month
RewriteCond %{THE_REQUEST} /webinar/\?year=([^\s&]+)&month=([^\s&]+) [NC]
RewriteRule ^.+$ /webinar/%1/%2? [L,R]
# rewrite new url to the old one
RewriteRule ^webinar/([^/]+)/([^/]+)/?$ /webinar/?year=$1&month=$2 [L,NC]

htaccess rewrite url with a parameter that equals 0

I would like to change
detail.php?cid=$category&ccid=$category2&cccid=$category3&fid=$id&ftitle=$titleseo
to
detail/$category/$category2/$category3/$id/$titleseo
But in case one of the parameters equals 0, the parameter should not be visible.
So in case $category=0, the url should become:
detail/$category2/$category3/$id/$titleseo
In case $category2=0, the url should become:
detail/$category/$category3/$id/$titleseo
Is this possible with a rewrite rule in htaccess and if yes how should this look like?
You could use this considering /$category/$category2/$category3/ have given names /$id/$titleseo are fixed :
RewriteEngine On
RewriteBase /
RewriteRule ^detail/(\$category)?/?(\$category2)?/?(\$category3)?/?(\$id)/(\$titleseo)$ - [E=PASS:cid=$1&ccid=$2&cccid=$3&fid=$4&ftitle=$5]
RewriteCond %{ENV:PASS} (.*)(&)[a-z]+=&(.*)$|[a-z]+=&(.*)$
RewriteRule ^ details.php?%1%2%3%4 [L]
RewriteCond %{QUERY_STRING} (.*)(&)[a-z]+=&(.*)$|[a-z]+=&(.*)$
RewriteRule ^ details.php?%1%2%3%4 [L]
RewriteCond %{ENV:PASS} ^(.+)$
RewriteRule ^ details.php?%1 [L]
In general use this :
RewriteEngine On
RewriteBase /
RewriteRule ^detail/([^/]+)?/?([^/]+)?/?([^/]+)?/?(\$id)/(\$titleseo)$ - [E=PASS:cid=$1&ccid=$2&cccid=$3&fid=$4&ftitle=$5]
RewriteCond %{ENV:PASS} (.*)(&)[a-z]+=&(.*)$|[a-z]+=&(.*)$
RewriteRule ^ details.php?%1%2%3%4 [L]
RewriteCond %{QUERY_STRING} (.*)(&)[a-z]+=&(.*)$|[a-z]+=&(.*)$
RewriteRule ^ details.php?%1%2%3%4 [L]
RewriteCond %{ENV:PASS} ^(.+)$
RewriteRule ^ details.php?%1 [L]
The rules above , first make and environment by capturing any request start with details and ended with /$id/$titleseo then check that ENV values to see which one has/hasn't a value and finally redirect it accordingly.
Both rules work in case of three levels of categories if you need more you could edit the rules like this :
Add this ([^/]+)?/? after RewriteRule ^detail/ then [E=PASS:cid=$1&ccid=$2&cccid=$3&ccccid=$4&fid=$5&ftitle=$6] at the end , you could compare to see the difrenec between this and previous one to get a criteria , and finally add %5 to /details.php?%1%2%3%4 [L] like this /details.php?%1%2%3%4%5 [L] and so on .
Did not get the code from Mohammed to work so far, but used
RewriteRule ^detail/?([0-9a-zA-Z]+)?/?([0-9a-zA-Z]+)?/?([0-9a-zA-Z]+)?/([0-9a-zA-Z]+)/([0-9a-zA-Z]+) detail.php?cid=$1&ccid=$2&cccid=$3&fid=$4&&ftitle=$5

Htaccess if url starts with

So I am no hero when it comes to htaccess. So forgive me if I have the complete wrong code below.
Here are the example links (behind each link a number to which I shall refrer bellow to which htaccess part they should be linking to):
website.com/home/ #1
website.com/home/page2/ #1
website.com/projects/ #1 or #2 (doesnt matter since the first GET will be page in both cases)
website.com/projects/staticpage/ #1
website.com/projects/filter1/ #2
website.com/projects/filter1/filter2/ #2
The current code I am using is (part 1):
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} !^/projects/$
RewriteRule ^([-A-Za-z0-9-_]+)/?$ index.php?page=$1 [L,QSA]
RewriteRule ^/?([-A-Za-z0-9-_]+)/([-A-Za-z0-9-_]+)/?$ index.php?page=$1&sub=$2 [L,QSA]
RewriteRule ^/?([-A-Za-z0-9-_]+)/([-A-Za-z0-9-_]+)/([-A-Za-z0-9-_]+)/?$ index.php?page=$1&sub=$2&sub-sub=$3 [L,QSA]
The other bit of the htaccess (part 2):
RewriteEngine On
RewriteBase /
RewriteRule ^([-A-Za-z0-9-_+]+)/?$ index.php?secondpart=$1 [L,QSA]
RewriteRule ^/?([-A-Za-z0-9-_+]+)/([-A-Za-z0-9-_+]+)/?$ index.php?secondpart=$1&filter[]=$2 [L,QSA]
RewriteRule ^/?([-A-Za-z0-9-_+]+)/([-A-Za-z0-9-_+]+)/([-A-Za-z0-9-_+]+)/?$ index.php?secondpart=$1&filter[]=$2&filter[]=$3 [L,QSA]
The filters are dynamic so it is not possible to get them to exclude.
I get it to skip the first part when the url is equal to: website.com/projects/ but,
when I change the url to: website.com/projects/filter1/ I can't get it to grab the second part.
If you could help me fix this thank you very much.
You can do something like this:
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-d [OR]
RewriteCond %{REQUEST_URI} ^/pagesearch/(staticpage1|staticpage2)/
RewriteRule ^ - [L]
RewriteRule ^([\w-]+)/?$ index.php?page=$1 [L,QSA]
RewriteRule ^([\w-]+)/([\w-]+)/?$ index.php?page=$1&sub=$2 [L,QSA]

Is it possible to have nested ReWrite Conditions in htaccess?

I have the following situation where I want to have nested ReWrite Conditions, and I have come across a situation where I am not able to see a proper documentation for the same.
RewriteCond %{REQUEST_URI} ^(robots.txt|favicon|ico)$ [NC]
RewriteRule . - [S=3]
# Nested ReWrite Condition
RewriteCond %{HTTP_HOST} ^www
RewriteRule .* http://%{SERVER_NAME}%{REQUEST_URI} [R=301,L]
RewriteRule .* http://%{SERVER_NAME}%{REQUEST_URI_1} [R=301,L]
RewriteRule .* http://%{SERVER_NAME}%{REQUEST_URI_2} [R=301,L] # and so on
Therefore, the question comes up that whether the number of skip rules will comprise of the nested ReWrite Conditions, that is, in this case, should the number of skipped rewrite rules be 4 or 5(if including the rewrite condition).
RewriteCond %{REQUEST_URI} ^(robots.txt|favicon|ico)$ [NC]
RewriteCond %{HTTP_HOST} !^www
RewriteRule .* - [S=3]
# the following rules are run only if the first 2 conditions don't match
RewriteRule .* http://%{SERVER_NAME}%{REQUEST_URI} [R=301,L]
RewriteRule .* http://%{SERVER_NAME}%{REQUEST_URI_1} [R=301,L]
RewriteRule .* http://%{SERVER_NAME}%{REQUEST_URI_2} [R=301,L]
notice the ! negation in the 2nd cond
documentation:
This technique is useful because a RewriteCond only applies to the
RewriteRule immediately following it. Thus, if you want to make a
RewriteCond apply to several RewriteRules, one possible technique is
to negate those conditions and add a RewriteRule with a [Skip] flag.
Okay as you only have posted an example, I show you an example how it works. It's with comments, but if you still don't find it speaking enough, there is a lot more explanation available here.
# Does the file exist?
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# Create an if-then-else construct by skipping 3 lines if we meant to
# go to the "else" stanza.
RewriteRule .? - [S=3]
# IF the file exists, then:
RewriteRule (.*\.gif) images.php?$1
RewriteRule (.*\.html) docs.php?$1
# Skip past the "else" stanza.
RewriteRule .? - [S=1]
# ELSE...
Rewri
This should solve your issue. If not, please update your example in the question so it's clear what you're missing.
And yes, it skips Rules and not Conditions.

.htaccess Rewrite all

I have the following rules in .htaccess. Unfortunately, it does not work due to the last rule (everything else works fine). Why?
Options -Indexes
RewriteEngine On
RewriteRule ^(cdn) - [L]
RewriteRule ^admin/(.*)$ backend_0.0.1/index.php/$1 [QSA,L]
RewriteRule ^css/(.*)$ frontend_0.0.1/css.php/$1 [NC,QSA,E=no-gzip:1,L]
RewriteRule ^js/(.*)$ frontend_0.0.1/js.php/$1 [NC,QSA,E=no-gzip:1,L]
RewriteRule ^(.*)$ frontend_0.0.1/index.php/$1 [QSA,L]
If I replace the last line by:
RewriteRule ^(.*)$ frontend_0.0.1/index.php?q=$1 [QSA,L]
Then it suddenly starts to work but previous rules are skipped and only this last rule is applied. But I need rules to stop rewriting once the first one mathches.
You need to exclude the destinations you are redirecting to:
RewriteCond $1 !^(backend_0\.0\.1|frontend_0\.0\.1)/
RewriteRule ^(.*)$ frontend_0.0.1/index.php/$1 [QSA,L]

Resources