mod_rewrite and redirect causing loop - .htaccess

I have problem when I try to redirect and rewrite together.
I have site example.com/show_table.php?table=12 (max 99 tables). I wanted nice links, so I got this .htacces rw rule:
RewriteRule ^table/([0-9]{1,2})$ show_table.php?table=$1 [L,NC]
Now are links something like example.com/table/12 - it's definitely OK. But I want all old links redirect to new format. So I use Redirect 301, I added to .htaccess this code:
RewriteCond %{REQUEST_URI} show_table.php
RewriteCond %{QUERY_STRING} ^table=([0-9]{1,2})$
RewriteRule ^show_table\.php$ http://example.com/table/%1? [L,R=301,NC]
But when I visit example.com/show_table.php?table=12, I receive just redir-loop. I don't understant - the first is rewrite, the second is redirection, there ain't no two redirections. Do You see any error?
Thanks!

Instead of checking REQUEST_URI in the condition, you need to be checking in THE_REQUEST (which contains the full original HTTP request, like GET /show_table.php HTTP/1.1). When Apache performs the rewrite, it changes REQUEST_URI, so to the rewritten value, and that sends you into a loop.
# Match show_table.php in the input request
RewriteCond %{THE_REQUEST} /show_table\.php
RewriteCond %{QUERY_STRING} ^table=([0-9]{1,2})$
# Do a full redirection to the new URL
RewriteRule ^show_table\.php$ http://example.com/table/%1? [L,R=301,NC]
# Then apply the internal rewrite as you already have working
RewriteRule ^table/([0-9]{1,2})$ show_table.php?table=$1 [L,NC]
You could get more specific in the %{THE_REQUEST} condition, but it should be sufficient and not harmful to use show_table\.php as the expression.
You'll want to read over the notes on THE_REQUEST over at Apache's RewriteCond documentation.
Note: Technically, you can capture the query string in the same RewriteCond and reduce it to just one condition. This is a little shorter:
# THE_REQUEST will include the query string so you can get it here.
RewriteCond %{THE_REQUEST} /show_table\.php\?table=([0-9]{1,2})
RewriteRule ^show_table\.php$ http://example.com/table/%1? [L,R=301,NC]

Related

add string at the end of URL using htaccess which has query string also

I want to change
domain.com/division1/index.php?members/maxmusterman.5
to
domain.com/division1/index.php?members/maxmusterman.5/#div
That is if the URL contains index.php?members, then I add /#div at the end of url. I tried this
RewriteEngine On
RewriteCond %{REQUEST_URI} index.php?
RewriteRule (.*) /%1/%{QUERY_STRING}&123 [L,QSA,R=301]
but it returns
domain.com/members/maxmusterman.5&123?members/maxmusterman.5
Note here that &123 is attached after URI before starting parameters. I researched htaccess QSA flag but I could not find a way to add a custom string at the end of the query string. How can I do that. Here I have used &123 for test purpose, actual requirement is adding /#div
To redirect
domain.com/division1/index.php?members/maxmusterman.5
to
domain.com/division1/index.php?members/maxmusterman.5/#div
.
You can use something like the following :
RewriteEngine on
RewriteCond %{QUERY_STRING} !loop=no
RewriteRule ^division1/index\.php$ %{REQUEST_URI}?%{QUERY_STRING}&loop=no#div [L,R,NE]
I added an additional perameter loop=no to the destination url to prevent infinite loop error .You can't avoid this as both your old url and the new url are identical and can cause redirect loop if you remove the RewriteCond and Query perameter.
NE (no escape ) flag is important whenever you are redirecting to a fragment otherwise mod-rewrite converts the # to its hex %23 .
solution #2
RewriteEngine on
RewriteCond %{THE_REQUEST} !.*loop=no [NC]
RewriteCond %{THE_REQUEST} /division1/index\.php\?(.+)\s [NC]
RewriteRule ^ /division1/index.php?%1&loop=no#div [NE,L,R]
Clear your browser cache before testing these redirects.

.htaccess redirect question mark with no parameters

I have several URLs with question marks that need to be removed. For example, I need to redirect this URL:
http://example.net/?/services
To this URL:
http://example.net/services
I have many more like this, so I would like something that can catch everything with the question mark and properly redirect it. Many of the answers I found were trying to use QUERY_STRING as the condition for the rewrite, but without parameters this does not help. After some digging I found a RewiteCond that works, but the RewriteRule redirects to the homepage, rather than the URL without the question mark. What I have currently is this:
# Remove question mark from string
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /(index\.php)?\?([^&\ ]+)
RewriteRule ^ /%1? [L,R=301]
# Removes index.php from ExpressionEngine URLs
RewriteCond %{THE_REQUEST} ^GET.*index\.php [NC]
RewriteRule (.*?)index\.php/*(.*) /$1$2 [R=301,NE,L]
# Directs all EE web requests through the site index file
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php?/$1 [L]
The first block is the rewrite that I have so far, and the next two are for the CMS url routing. What seems to be happening is that my rewrite in the first block is not keeping the rest of the url. I have tried several combinations and can't seem to figure out how to keep the rest of the url intact.
Many of the answers I found were trying to use QUERY_STRING as the condition for the rewrite, but without parameters this does not help.
Yes, this is exactly what the first URL, with a question mark, contains. So, I'm not sure why "this does not help"? In the URL http://example.net/?/services, /services is the query string. Whether there are key/value pairs (ie. "parameters") is irrelevant.
To redirect URLs of the form http://example.net/?/services, that consist of no URL-path and only a query string, try something like:
# Remove question mark from string
RewriteCond %{QUERY_STRING} ^/(.+)
RewriteRule ^$ /%1? [R,L]
%1 is a backreference to the captured group in the last matched CondPattern (ie. (.+), which captures services). This assumes that the query string (after the ?) always starts with a slash, as in your example. (Incidentally, this is also what your front controller is doing, in reverse, so I assume it must be correct.)
The trailing ? on the substitution removes the original query string from the request.
Make sure you clear your browser cache, as any earlier/erroneous 301s will have been cached by the browser.
If this is intended to be a permanent (301) redirect then change R to R=301, but only when you are sure it's working OK.

Redirect to 'pretty-urls' doesn't work

I want to make my website to have 'pretty-urls'. Also I want to make so users which input 'ugly' urls will be redirected to 'pretty-urls'.
Simplified example:
I have page data.php?id=123. I want so it shows to users as data/123 and for whose who typed in address bar data.php?id=123 it will be redirected to data/123.
I have tried following code in .htaccess:
# redirect to pretty url
RewriteCond %{QUERY_STRING} ^id=([0-9]+)$
RewriteRule ^/?data\.php data/%1? [R=301,L]
# convert pretty url to normal
RewriteRule ^/?data/([0-9]+)$ data.php?id=$1 [L]
However it doesn't work, it goes into infinite loop as I understood.
Is what I wanted possible and how if yes?
Using %{QUERY_STRING} for your case will produce a infinite loop because the internal destination also relies on it.
However using %{THE_REQUEST} does not:
# Redirect /data.php?id=123 to /data/123
RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s/+data\.php\?id=([0-9]+) [NC]
RewriteRule ^ /data/%1? [R=302,L]
# Internally forward /data/123 to /data.php?id=123
RewriteRule ^data/([0-9]+)/?$ /data.php?id=$1 [NC,L]

301 redirect get pagination

I'm trying to 301 redirect a paginated blog list from an old site onto a new url.
I think I'm getting pretty close with the RewriteRule but I'm not quite there yet, this is what I have:
RewriteCond %{QUERY_STRING} ^page=
RewriteRule ^(blog)?$ http://www.newdomain.com/news/page/$1? [R=301,L]
Using this rule if I go to
http://www.olddomain.com/blog?page=1
I currently get redirected to
http://www.newdomain.com/news/page/blog
I would like to be sent to
http://www.newdomain.com/news/page/1
I'm sure its just something small and simple that I'm missing.
Edit
Expanding on the solution below, I've added tags/category support to the rewrite rule using $1.
RewriteCond %{QUERY_STRING} ^page=([^&]+) [NC]
RewriteRule ^blog/tag/([^/\.]+)?$ http://www.newdomain.com/news/tag/$1/page/%1? [R=301,L,NC]
Few minor mistakes in your code.
You need to capture page parameter's value from query string first
Then use that capture value using % instead of $1
No need to capture blog since you don't need it.
Change your code with:
RewriteCond %{QUERY_STRING} ^page=([^&]+) [NC]
RewriteRule ^blog/?$ http://www.newdomain.com/news/page/%1? [R=301,L,NC]

.htaccess redirect from GET variable to url string

I need to redirect
/search?keywords=somesearchterm
to
/search/somesearchterm
This seems incredibly basic but I've been pounding my head against it for an hour.
Thanks for taking the time to look at this.
You want to implement what is called a "301 Redirect" with mod_rewrite.
RewriteEngine ON
RewriteRule ^/search\?keywords=somesearchterm$ /search/somesearchterm
adding regular expressions:
RewriteEngine ON
RewriteRule ^/search\?keywords=(.+) /search/$1 [R=301,L]
R=301 means provide a 301 Header redirect so the user's URL changes in the browser, and L means don't process any more rewrite rules if this one matches.
If you want to do the reverse -- in other words, if someone goes to mysite.com/search/asearchterm and you want the URL to stay the same, but "behind the scenes" you want it to load a certain server script, do this:
RewriteEngine ON
RewriteRule ^/search/(.+) /search.php\?keywords=$1 [L]
You can not match aginst Query string in RewriteRule directive. Use %{THE_REQUEST} or %{QUERY_STRING} server variables to match the Query string :
The following rule works fine for this redirection
RewriteEngine On
RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s/search\?kewords=([^&\s]+) [NC]
RewriteRule ^ /search/%1? [NE,NC,R,L]
RewriteRule ^search/([^/]+)/?$ /search?keyword=$1 [QSA,NC,L]

Resources