Mod Rewrite Map file not returning correct results - apache

Im using the following code in the mod rewrite. I have a search parameter variable that I set before and use in the rewrite condition against a map file. The Condition requires the map file to return a result but then I use the same mapfile in the rewrite rule and it returns and empty string.
RewriteCond ${root301:%{ENV:SEARCHURL2}|NOT-FOUND} !(^$|NOT-FOUND) [NC]
RewriteRule ^(.*)$ /Page1?search2=${root301:%{ENV:SEARCHURL2}} [QSA,NE,R=301,L]
so for example http://mysite/root1 is suppose to go to http://mysite/page1?search2=results but it ends up just going to http://mysite/page1?search2= with no search parameters. if the map condition wasn't satisfied the rewrite wouldn't happen at all? Im using compiled map files and I see the dictionary being compiled correctly.

I realized the issue I had was that I actually had 2 similiar redirects one was looking for a url without the trailing forward slash but when I duplicated the first one I forgot to add the trailing forward slash to the redirect rule like below. thus the search conditions weren't identical so of course it didn't work
RewriteCond ${root301:%{ENV:SEARCHURL2}/|NOT-FOUND} !(^$|NOT-FOUND) [NC]
RewriteRule ^(.*)$ /Page1?search2=${root301:%{ENV:SEARCHURL2}} [QSA,NE,R=301,L]

Related

htaccess RewriteRule : Problem to omit all after 1st argument

Goal: Want to rewrite all URLs of type
https://www.example.com/page/1234/?/blog/foo/bar/
to
https://www.example.com/page/1234/
In .htaccess I tried many variations along the line
RewriteEngine On
RewriteBase /
RewriteRule ^page/(\d+)/(.*)$ /page/$1 [R=301,L]
Using an .htaccess tester I see that at least the matching pattern is valid.
I would expect that the rewrite would not include anything after $1, but it does, and show the complete original URL.
What am I missing?
https://www.mypage.com/page/1234/?/blog/foo/bar/
Everything after the first ? is the query string part of the URL. By default, Apache passes the query string unaltered from the request to the target URL (unless you create a new query string yourself on the RewriteRule substitution). This explains why you are seeing the same query string on the target URL, without seemingly doing anything with it.
Incidentally, the RewriteRule pattern only matches against the URL-path only - this notably excludes the query string. To match the query string in mod_rewrite you need an additional condition that checks the QUERY_STRING server variable.
On Apache 2.4+ you can use the QSD (Query String Discard) flag to remove the query string from the target URL. Or, specify an empty query string on the substitution - by including a trailing ? (the ? itself does not appear on the resulting URL).
For example (on Apache 2.4):
RewriteCond %{QUERY_STRING} .
RewriteRule ^page/(\d+)/ /page/$1/ [QSD,R=301,L]
The RewriteCond directive checks for the presence of a query string, which is necessary to prevent a redirect loop.
The trailing (.*)$ on the RewriteRule pattern was superfluous.
You had omitted the trailing slash on the end of the substitution (that is present on the example URL). This would have also prevented a redirect loop, but as mentioned, this is not as per your example. (Alternatively, you could include the slash in the captured backreference.)
If you are still on Apache 2.2 then you would need to include a trailing ? instead of the QSD flag. For example:
RewriteRule ^page/(\d+)/ /page/$1/? [R=301,L]
You will need to clear your browser cache before testing, as 301 (permanent) redirects are cached persistently by the browser. For this reason, it is often easier to first test with 302 (temporary) redirects.

Remove Query String from the end of the URL after passing through Rewrite Map

I have a list of several hundred URL redirects/rewrites inside of a rewrite map. Most of the URL's contain query strings that match a specific entry in the rewrite map. I found this question on how to pass the query string into the rewrite map. I got this working fine but the problem now is that the existing query string is appended to the end of the rewritten URL. For example:
Expected Rewrite:
/subdir/dir.cfm?categoryID=123 -> https://example.com/subdir/endurl
Actual Rewrite:
https://example.com/subdir/endurl?categoryID=123
Expected Rewrite
/subdir/dir.cfm?videoID=3422424-131FDDFD-234 -> https://example.com/subdir/awesome/stuff
Actual Rewrite:
https://example.com/subdir/awesome/stuff?videoID=3422424-131FDDFD-234
This is the rewrite rules I have:
RewriteEngine on
RewriteMap redirects dbm=sdbm:C:\Apache24\conf\redirects.sdbm
RewriteCond ${redirects:$1} !=""
RewriteRule ^(.*\.(cfm|cfml)) ${redirects:$1?%{QUERY_STRING}} [NC,R=301,L]
How can I remove the query string appended to the URL after the rewrite?
EDIT
I was able to actually get this working using this:
RewriteMap redirects dbm=sdbm:C:\Apache24\conf\redirects.sdbm
RewriteCond ${redirects:$1} !=""
RewriteRule ^(.*\.(cfm|cfml)) ${redirects:$1?%{QUERY_STRING}} [NC,C]
RewriteRule (.*) $1? [L,R=301]
However I am not sure if someone knows of a better way to accomplish what I am doing? I am thinking this might break if I ever have to redirect to a URL that contains a query string to another url that contains a query string.
In Apache version 2.4.0 and later, you can use [QSD] flag (Query String Discard):
RewriteRule ^(.*\.(cfm|cfml)) ${redirects:$1?%{QUERY_STRING}} [QSD,NC]
In Apache version 2.2, there is no [QSD] flag, but if the replacement URI contains a query string, the default behavior of RewriteRule is to discard the existing query string, so by just adding a ? to your rewrite URI, you will get the same effect:
RewriteRule ^(.*\.(cfm|cfml)) ${redirects:$1?%{QUERY_STRING}}? [NC]
(your newly added rewrite rule actually uses this feature)

simple 301 redirect with variable not working, why?

Here's what I got so far. The first part works but not the redirect itself.
What do I need to do to make it work?
RewriteEngine On
RewriteRule ^([^/\.]+)/?$ page.php?name=$1 [L]
RewriteRule ^page.php?name=([^/\.]+)/?$ /$1 [R=301,L]
Also if I have multiple of these rules do I leave the [L] only on the last one?
Besides the first rule overriding the second one, your second rule also won't work because you're trying to match the query string in a RewriteRule. Try something like this instead:
RewriteEngine On
RewriteBase /
RewriteCond %{QUERY_STRING} ^name=([^/.&]+)/?$
RewriteCond %{ENV:REDIRECT_LOOP} !1
RewriteRule ^page\.php$ /%1? [NS,R=301,L]
RewriteRule ^([^/.]+)/?$ page.php?name=$1 [NS,QSA,E=LOOP:1]
(I included the QSA flag so that an URL like /foobar?foo=bar will be rewritten to /page.php?name=foobar&foo=bar instead of just /page.php?name=foobar. If you don't want that, leave it out.)
Note: The second RewriteCond is there to keep the first rule from matching again after the second one has matched. The problem is that, in .htaccess context, mod_rewrite acts more or less as if all rules had the PT flag, causing the ruleset to be rerun from the start after every rewrite, even internal ones. Or, to quote the documentation:
"If you are using RewriteRule in either .htaccess files or in <Directory> sections, it is important to have some understanding of how the rules are processed. The simplified form of this is that once the rules have been processed, the rewritten request is handed back to the URL parsing engine to do what it may with it. It is possible that as the rewritten request is handled, the .htaccess file or <Directory> section may be encountered again, and thus the ruleset may be run again from the start. Most commonly this will happen if one of the rules causes a redirect - either internal or external - causing the request process to start over."
The workaround I'm using is to set a custom environment variable with E=LOOP:1 when the internal rewrite triggers, and check for it before doing the external rewrite. Note that, when the request processing restarts after the internal rewrite, Apache prepends REDIRECT_ to the names of all environment variables set during the previous pass, so even though the variable we set is named just LOOP, the one we need to check for is REDIRECT_LOOP.

Conditional rewrite in the regex, not with RewriteCond

I wrote a regex for a rewrite rule that includes a negative lookahead to replace the rewriteCond line, because WordPress only accepts two values: pattern -> substitution.
It should find findme.html _here, regardless of where it's requested to be:
mydomain.com/_here/findme.html
e.g.
(Sorry, I can't modify the swf which will request findme.html in the wrong places)
So, given findme.html could be requested to be in, e.g.:
mydomain.com/findme.html
mydomain.com/directory/findme.html
mydomain.com/directory/findme.html?someparam=3
The rewrite should make them all
mydomain.com/_here/findme.html
So, I made a rewrite rule that Wordpress will accept me as follow
Options +FollowSymlinks
RewriteEngine On
RewriteRule ^.*(?!_here)/*findme\.html$ /_here/findme.html [R=301,L]
So it only matches URLs which doesn't contain "_here" in it, to prevent extra rewriting or a loop.
The problem is IT DOES loop.
What did I miss?
It looks to me like you want to move the .* that is before (?!_here) to after it because (?!_here) is a negative lookahead, so it check that the text _here does not come after it. What your regular expression is actually checking is whether your url starts with some character sequence that is not followed by _here, and _here is a character sequence not followed by _here. Then your rule becomes
RewriteRule ^(?!_here).*/*findme\.html$ /_here/findme.html [R=301,L]
Also, it looks like your pattern will exclude paths with subdirectories such as
mydomain.com/directory/subdirectory/findme.html
If you also want to include those, the pattern should be
RewriteRule ^(?!_here)(.*/)*findme\.html$ /_here/findme.html [R=301,L]

rewrite url using htaccess

How can I change url in this way using htaccess:
http://example.com/page.php?go=something.php
should be redirected to:
http://example.com/something
If the get parameter name is different than 'go' leave as it is...
This should do:
# Assuming that "RewriteEngine On" has already been called
RewriteCond %{QUERY_STRING} ^(.*&)?go=([a-z]+)\.php(&.*)?$
RewriteRule page.php %2?
What happens here? First, RewriteCond matches a query string that contains the go=something.php, where "something" is captured by ([a-z]+). Then the RewriteRule uses the second capture group's contents from RewriteCond, containing "something.php". The question mark at the end gets rid of the original query string.
Note: if you want to preserve the rest of the query string excluding go=... parameter, things get a bit more complicated.
See the docs in http://httpd.apache.org/docs/2.2/mod/mod_rewrite.html for more info.
something like this (google around for the correct syntax)
RewriteEngine On
RewriteBase /
RewriteRule ^page.php?go=login.php /login [L]