.htaccess url rewriting and redirect 301 - .htaccess

At the moment we have one page which shows a list of links
each link has got its own ID number
each link gets opened with the file info.php?ID=X
for example:
www.mysite.com/info.php?ID=1 shows the link "weather italy"
www.mysite.com/info.php?ID=2 shows the link "weather france"
Since we have several links for "weather italy" and "weather france" we would like to rewrite new urls (weather-italy and weather-france) in .htacces
Whith the new urls we would have the folowing structure:
www.mysite.com/weather-italy/info.php?ID=1
www.mysite.com/weather-france/info.php?ID=2
With the following code we tell the server to rewrite the urls and call the original file:
RewriteRule ^weather-italy/info.php?$ info.php [NC,L]
RewriteRule ^weather-france/info.php?$ info.php [NC,L]
This works fine.
To avoid double indexing we want to redirect 301 the old link to the new link.
We have achieved that with the following code:
RewriteCond %{THE_REQUEST} \?ID=1
RewriteRule ^info\.php$ http://www.touristinfo.fr/weather-italy/info\.php [L,R=301]
RewriteCond %{THE_REQUEST} \?ID=2
RewriteRule ^info\.php$ http://www.touristinfo.fr/weather-france/info\.php [L,R=301]
This also does the job but combined with the first part of the script is produces a never ending loop.
What is wrong with our code?
Thanks a lot for your help :)

%{THE_REQUEST} is supposed to only match if the url you want to match is an external request. Your problem is that the regex you made is not specific enough.
Let's examine what happens. You go to example.com/info.php?ID=2. The first two rules don't match, but the 4th one does. You end up with a redirect to example.com/weather-france/info.php?ID=2.
This goes through your .htaccess again. The second rule matches, and internally rewrites it to info.php?ID=2. The [L] flag doesn't make a difference here, because the url will be pulled through .htaccess until it stops changing. On the second cycle through .htaccess, the url will now match the 4th rule, even though the external request contained /weather-france/info.php?ID=2. ID=2 is in the external request too, and the internal rewrite is now info.php again.
The fix is to make %{THE_REQUEST} match enough so that the rewritten url doesn't match it anymore.
On a further note: Familiar yourself with the difference between regex and strings in RewriteRules and RewriteConds. You escaped a dot in a string, while leaving a dot in a regex unescaped. The ? is "match the previous character 0 or 1 times", not a question mark literal. The query string cannot be matched in the first argument of RewriteRule.
You'll end up with:
RewriteRule ^weather-italy/info\.php$ info.php [NC,L]
RewriteRule ^weather-france/info\.php$ info.php [NC,L]
RewriteCond %{THE_REQUEST} ^(GET|POST)\ /info\.php\?ID=1
RewriteRule ^info\.php$ http://example.com/weather-italy/info.php [L,R]
RewriteCond %{THE_REQUEST} ^(GET|POST)\ /info\.php\?ID=2
RewriteRule ^info\.php$ http://example.com/weather-france/info.php [L,R]

Related

how to replace "?" and "=" sign with "/" in URL - PHP htaccess

i am working on project, which is running XAMPP localhost and PHP MYSQLI,
my question : how i replace "?","=" signs with "/" slash. ?
like, my url is "archive?date=2017-06-02&p=4"
and i want to force it "archive/2017-08-02/4"
i found many codes on stackoverflow and some other sites, but that are not working for me.
if codes are working then, CSS files and GET method doesn't work on my project.
complete code of .htaccess is given below.
Options +FollowSymlinks
RewriteEngine on
RewriteRule ^([^=]*)=([^=]*)=(.*) /$1/$2/$3 [N]
RewriteRule ^([^=]*)=([^=]*)$ $1/$2 [L]
RewriteRule ^home index.php [NC,L]
RewriteRule ^archive archive.php [NC,L]
RewriteRule ^about about.php [NC,L]
RewriteRule ^article article.php [NC,L]
RewriteRule ^news news.php [NC,L]
RewriteRule ^video videos.php [NC,L]
RewriteRule ^video?vid=([0-9]+) videos.php?q=$1 [NC,L]
RewriteRule ^article?num=([0-9]+) article.php?num=$1 [NC,L]
RewriteRule ^editorial?num=([0-9]+) editorial.php?num=$1 [NC,L]
RewriteRule ^news?news=([0-9]+) news.php?news=$1 [NC,L]
You cannot check against the query string in a rewrite rule. You need rewrite conditions for that:
RewriteCond %{QUERY_STRING} date=([^&]+)&p=(.+)
RewriteRule ^archive/? /archive/%1/%2?
Demo here: http://htaccess.mwl.be?share=81e85c09-d505-5206-ab14-6c5059107808
If you want to actually redirect just add [R=301,L] to the end of the RewriteRule.
However, looking at the above I suspect you have your script sitting listening at /archive/index.php?data=foo&p=bar but want URLs to be like /archive/date/p, ie pretty.
This is actually a very common misconception about how htaccess URL rewrites work when you first get into them.
RewriteRules will mask or redirect URLs for you but they cannot change the underlying location a script is located at and thus the address used to pass it information.
In other words - you can mask /archive/index.php?data=foo&p=bar as /archive/date/p so that requests made to /archive/date/p resolve to /archive/index.php?data=foo&p=bar, but you cannot make it so that if you enter /archive/index.php?data=foo&p=bar as URL you have the URL change to /archive/date/p while still serving content from /archive/date/p. It has to be either or.
If this all sounds about right my advice would be as follows:
First, put your code into a different file, say /archive/script.php.
Next add the following to your htaccess:
RewriteCond %{QUERY_STRING} date=([^&]+)&p=(.+)
RewriteRule ^archive/? /archive/%1/%2? [R=301,L]
RewriteRule ^archive/([^/]+)/([^/]+) /archive/script.php?date=$1&p=$2
Note that the first two lines are the same as before, but now there is a new line that looks for the masked URL format of /archive/date/p and sends it off to the actual script, which is handled by the new RewriteRule.
The behaviour of the new rule is demoed here: http://htaccess.mwl.be?share=06751667-f16f-5c13-91eb-dd5cffdc6db3
Hope this makes sense / helps.

.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.

mod_rewrite and redirect causing loop

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]

mod_rewrite so that first-level subdirectory is a GET variable

Alright, title is REALLY sloppy.
Here's my problem: I have a news site and when you go to the main page (domain.com) it redirects you to domain.com/news/top?geography=San_Francisco after it figures out your geography.
How do I use the .htaccess so that it goes from domain.com/news/top?geography=San_Francisco domain.com/San_Francisco/news/top ?
There are some similar questions, but I have not found one similar enough in that you're editing the URL as a furtherback subdirectory.
It should also be noted that I am using the Code Igniter framework for PHP and it normally has it as domain.com/index.php/news/top?geography=San_Francisco but I did a mod_rewrite already to get rid of the index.php. The code is as follows for that:
RewriteEngine on
RewriteCond $1 !^(index\.php|images|robots\.txt)
RewriteRule ^(.*)$ /index.php/$1 [L]
Code I've tried:
RewriteRule ^([^/]+)/news/top$ /news/top?geography=$1 [L,QSA]
RewriteCond $1 !^(index\.php|images|robots\.txt)
RewriteRule ^(.*)$ /index.php/$1 [L]
Before the index.php rule that you have, try adding this:
RewriteRule ^([^/]+)/news/top$ /news/top?geography=$1 [L,QSA]
You'll need to make sure the links you generate are in the form of domain.com/San_Francisco/news/top though.
But to take care of the links in the wild that still look like the old way, you have to match against the actual request:
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /news/top\?geography=([^&]+)
RewriteRule ^news/top$ /%1/news/top? [L,R=301]
This will 301 redirect the browser if someone goes to the link domain.com/news/top?geography=San_Francisco and make it so the browser's address bar says this: domain.com/San_Francisco/news/top. At which point the browser will send another request for the second URL, and you use the rule above to change it back into the one with a query string.

How does rewrite URL and 301 redirection work together

I've got:
RewriteRule ^page/([^/\.]+)/?$ index.php?page=$1 [L]
Which points page/([^/\.]+)/? to index.php?page=$1.
When I go to page/([^/\.]+)/, I don't want to see index.php (which is achieved from the above)
For the reverse, when I go to index.php, I want to see a visible 301 redirection to page/([^/\.]+)/.
How do I do this without causing an infinite loop... or do I only rely on canonical tags?
Update:
I got it happening in one direction (new to old), but not the other (Old to new)
RewriteRule ^([^/\.]+)-yum/?$ yum/?x=$1 [L]
RewriteRule ^([^/\.]+)/([^/\.]+)-yum/?$ yum/?x=$2&y=$1 [L]
You need to do a check against the %{THE_REQUEST} variable so that you are rewriting only when the actual request is for the index.php file:
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /index\.php\?page=([^&]+)([^\ ]*)
RewriteRule ^/?index\.php$ /page/%1/?%2 [L,R=301]
So if a browser requests http://yourdomain.com/index.php?page=qwe&someother=var
It should get redirected to: http://yourdomain.com/page/qwe/?someother=var
Full solution here:
RewriteCond %{QUERY_STRING} Variable=([A-Za-z]+)$
RewriteRule OldURL/$ /NewURL/%1? [L,R=301]
RewriteRule ^NewUrl/([^/\.]+)$ MappedNewLocationFolder/?Variable=$1 [L]
1st Line: Check (the name and number of) parameters are as expected
2nd Line: Check base path of parameter(s), which is OldURL is correct and 301 to NewUrl
3rd Line: Map NewUrl to actual location where file sits (not shown in browser)
(The question mark right at the end of 2nd line strips out the variables from appending to the NewUrl)

Resources