Redirect /search?query=foo to /search/foo - .htaccess

I am trying to redirect /search?query=foo to /search/foo but all my attempts have failed.
I have tried the solutions in similar questions but they have not worked. I believe this is because I am trying to rewrite the request to index.php so that the PHP framework can process it.
I know that it is not the PHP framework causing the issue as when I manually go to /search/foo it is handled correctly.
My .htaccess looks like this:
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/search$
RewriteCond %{QUERY_STRING} ^query=(.*)$
RewriteRule ^ search/%1 [R=302,NS]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [QSA,L]
I don't understand why it's not working as when I look at the logs the URL is successfully being transformed into what I'm after:
applying pattern '^' to uri 'search'
RewriteCond: input='/search' pattern='^/search$' => matched
RewriteCond: input='query=asd' pattern='^query=(.*)$' => matched
rewrite 'search' -> 'search/asd'
add per-dir prefix: search/asd -> .../app/public/search/asd
explicitly forcing redirect with http://localhost/.../app/public/search/asd

You need to get rid of the query string. Instead of:
RewriteCond %{REQUEST_URI} ^/search$
RewriteCond %{QUERY_STRING} ^query=(.*)$
RewriteRule ^ search/%1 [R=302,NS]
Try:
RewriteCond %{THE_REQUEST} \ /+search\?query=([^&\ ]+)
RewriteRule ^ search/%1? [L,R=302,NS]
The important part is the ? after the backreference, %1. This tells mod_rewrite that the new query string is just ? (i.e. nothing). Othewise the existing query string automatically gets appended to the rewritten URL/redirect.

Related

htaccess dynamic url redirect

I have the following URL
https://example.com/expert-profile?id=john-doe&locale=en
I want it to be redirected to
https://example.com/expert/john-doe
I tried the following
RewriteCond %{QUERY_STRING} ^(([^&]*&)*)id=([^&]+)&?(.*)?$
RewriteRule ^expert-profile$ https://example.com/expert/%3?%1%4 [L,R=301]
And a couple of other solutions, nothing is working here. Can someone help me to go in the right direction?
Update:
This is my current .htaccess file
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule . /index.html [L]
</IfModule>
Redirect 301 "/en/download-app" "/download-app"
Please keep your htaccess file in your root and have it in following way.
Please clear your browser cache before testing your URLs.
RewriteEngine ON
RewriteCond %{QUERY_STRING} ^id=([^&]*)&locale=(.*)$ [NC]
RewriteRule ^([^-]*)-.*/?$ $1/%1-%2 [R=301,L]
OR in case you don't have Rules to handle non-existing files/directories then use following Rules set. Please make sure either use above OR following Rules set one at a time only.
RewriteEngine ON
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{QUERY_STRING} ^id=([^&]*)&locale=(.*)$ [NC]
RewriteRule ^([^-]*)-.*/?$ $1/%1-%2 [R=301,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(?:expert)/([^-]*)-(.*)$ $1-profile?id=$1&locale=$2 [NC,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^ /index.html [L]
I have following URL
https://example.com/expert-profile?id=john-doe&locale=en
I want it to be redirected to
https://example.com/expert/john-doe
You would need to do something like the following at the top of your .htaccess file, before your existing directives (order is important):
RewriteCond %{QUERY_STRING} (?:^|&)id=([^&]+)
RewriteRule ^expert-profile$ /expert/%1 [QSD,R=301,L]
This captures the value of the id URL parameter (in the %1 backreference) regardless of where it appears in the query string and discards all other URL parameters. I'm assuming you don't specifically need to match locale=en?
Note that the regex subpattern ([^&]+) (the id value) only matches something, not nothing. If the URL parameter is empty (ie. id=&locale=en) then no redirect occurs.
The QSD flag is necessary to discard the original query string.
Test first with a 302 (temporary) redirect to avoid potential caching issues. And clear your browser cache before testing. Only use a 301 (permanent) redirect if this really is intended to be permanent.
To redirect the specific URL /expert-profile?id=<name>&locale=en to /expert/<name>, ie. the id parameter is at the start of the query string and is followed by locale=en only then you can (and should) be more specific in the condition. For example:
RewriteCond %{QUERY_STRING} ^id=([^&]+)&locale=en$
RewriteRule ^expert-profile$ /expert/%1 [QSD,R=301,L]
RewriteCond %{QUERY_STRING} ^(([^&]*&)*)id=([^&]+)&?(.*)?$
RewriteRule ^expert-profile$ https://example.com/expert/%3?%1%4 [L,R=301]
This is close (providing you placed the rule at the top of the file), however, this tries to preserve the other URL parameters, ie. locale=en and whatever else, to create another query string - which you've not stated in your requirements.
Aside: The existing answers are assuming you are wanting to internally rewrite (URL rewrite) the request in the other direction, ie. from /expert/john-doe to /expert-profile?id=john-doe&locale=en. This is probably due to how questions of this nature are notoriously miswritten and this is often the real underlying intention. However, you've made no mention of this here and a URL of the form /expert-profile is not a valid endpoint - so it wouldn't really make sense to "rewrite" the URL in that direction. (?)
If you want it rewritten, capture the name (.+) and insert it into the target $1
RewriteRule ^expert/(.+)$ /expert-profile?id=$1&locale=en [L]
And don't use flag R|redirect here, unless you really want a redirect.---
To redirect from expert-profile?id=john-doe to expert/john-doe, capture the id (.+?) from the query string and insert it in the substitution URL %1
RewriteCond &%{QUERY_STRING}& &id=(.+?)&
RewriteRule ^expert-profile$ /expert/%1 [R,L]
When everything works as it should, you may replace R with R=301 (permanent redirect).
Don't use both rules together. If you do, it will result in an endless redirect loop and finally give a "500 Internal Server Error".
Unrelated, but never test with R=301!

URL rewrite like instagram profile

I'm trying to rewrite my URLs with unique slug like Instagram or Facebook.
Example: facebook.com/joe
My URLs are like that: website.com/user.php?username=joe
I try this rule in .htaccess:
RewriteEngine On
RewriteRule ^([a-z]+)$ user.php?username=$1 [L]
But it doesn't work, it redirects on /user.php.
It works if I use this rule:
RewriteEngine On
RewriteRule ^u/([^/]*)$ /user.php?username=$1 [L]
But result is website.com/u/joe and I prefer without u.
Any idea?
Add this to your .htaccess in your web root / directory
RewriteEngine on
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ user.php?username=$1 [NC,L]
The .* in the pattern ^(.*)$ matches /anything and the parentheses help capture the anything part as a $1 variable used in the substitution URL as user.php?username=$1.
In case if you need multiple parameters you can simply add &%{QUERY_STRING} after $1 to separate and add them to the end of your query string.
for example : if you pass website.com/joe?age=31 the result will be website.com/user.php?username=joe&age=31.
Finally, the flag NC simply makes the rule non case-sensitive, so it matches /Joe or /JOE as well.

Remove parenthesis from htaccess (Helicon Ape)

I'm using Helicon Ape on a Windows Server to create htaccess files.
Originally, part of a larger set of conditions, I had this condition set to return 403 if the url contained (). However it is causing false positives in case of mailchimp tracking codes that end up getting wrapped in ()
RewriteCond %{QUERY_STRING} ^.*(\[|\]|\(|\)|<|>).* [NC,OR]
For example in the below URL
http://domain.com/page/11/page-name?ct=t(Newsletter_Tracking)
As an alternative, I was attempting to remove the parenthesis and redirect to a "cleaned version".
I tried a few different things that I found in SO but none worked.
So far the closest thing that I could get to working is this:
RewriteCond %{REQUEST_URI} [\(\)]+ [OR]
RewriteCond %{QUERY_STRING} [\(\)]+
RewriteRule ^(.*)[\(]+([^\)]*)[\)]+(.*)$ $1$2$3 [R=301,L]
The problem with the above code is that works if the () were in the URL but not the query string. It doesn't redirect and clean the querystring.
So this would work:
http://domain.com/page/11/pag(e-name)
but this wouldn't:
http://domain.com/page/11/page-name?ct=t(Newsletter_Tracking)
Your assistance is appreciated
Thank You.
You can use the following rule :
RewriteCond %{THE_REQUEST} /page/11/page-name\?ct=t\(Newsletter_Tracking\)\sHTTP [NC]
RewriteRule ^ %{REQUEST_URI}? [L,R]
If the querystring is dynamic, try:
RewriteCond %{THE_REQUEST} /page/11/page-name\?ct=.+\(.+\)\sHTTP [NC]
RewriteRule ^ %{REQUEST_URI}? [L,R]
Using #starkeen 's example, I was able to create a working solution.
This code handles the Query String separate from the URL. It cleans the URL but removes the query string.
RewriteCond %{REQUEST_URI} [\(\)]+
RewriteRule ^(.*)[\(]+([^\)]*)[\)]+(.*)$ $1$2$3 [R=301,L]
RewriteCond %{QUERY_STRING} [\(\)]+
RewriteRule ^ %{REQUEST_URI}? [R=301,L]

Error 500 on RewriteRule

I want the following behaviour:
http://www.example.com/mysubdir -> show /mysubdir/index.htm
http://www.example.com/mysubdir/first -> show /mysubdir/redirect.php?token=first
http://www.example.com/mysubdir/first/second -> show /mysubdir/redirect.php?token=first&action=second
http://www.example.com/mysubdir/first/second/third -> show /mysubdir/redirect.php?token=first&action=second&param=third
therefore I created the following .htaccess (inside mysubdir)
RewriteEngine on
RewriteBase /mysubdir/
RewriteRule ^([^\/]+)\/([^\/]+)\/([^\/]+)\/? ./redirect.php?token=$1&action=$2&param=$3 [L]
RewriteRule ^([^\/]+)\/([^\/]+)\/? ./redirect.php?token=$1&action=$2 [L]
RewriteRule ^([^\/]+)\/? ./redirect.php?token=$1 [L]
This causes an error 500
If I remove the last line, however, the first two rules work as expected. I can't see any visible difference between these rules that should cause such an error.
You're getting 500 (internal server error) because your rules are looping infinitely due to presence of [^/]+ in your last rule that will match rewritten URI redirect.php also.
You can fix it using this modified code:
RewriteEngine on
RewriteBase /mysubdir/
# skip all files and directories from rewrite rules below
RewriteCond %{REQUEST_FILENAME} -d [OR]
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [L]
RewriteRule ^([^/]+)/([^/]+)/([^/]+)/?$ redirect.php?token=$1&action=$2&param=$3 [L,QSA]
RewriteRule ^([^/]+)/([^/]+)/?$ redirect.php?token=$1&action=$2 [L,QSA]
RewriteRule ^([^/]+)/?$ redirect.php?token=$1 [L,QSA]
Few more changes made are:
Use QSA to preserve any existing query string in URLs.
You should use anchor $ in your regex patterns.
No need to escape / in regex patterns.

htaccess 301 redirection using regular expression

This is my current .htaccess file
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteRule ^(.*)$ $1/
RewriteRule ^([^/]+)/$ index.php?p1=$1 [L]
RewriteRule ^([^/]+)/([^/]+)/$ index.php?p1=$1&p2=$2 [L]
RewriteRule ^([^/]+)/([^/]+)/([^/]+)/$ index.php?p1=$1&p2=$2&p3=$3 [L]
RewriteRule ^([^/]+)/([^/]+)/([^/]+)/([^/]+)/$ index.php?p1=$1&p2=$2&p3=$3&p4=$4 [L]
RewriteRule ^([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/$ index.php?p1=$1&p2=$2&p3=$3&p4=$4&p5=$5 [L]
Basically, it takes up to five "Friendly url folders" and assign the value to varibles and then, send those to my index.php page
IE: http://www.example.com/ford/focus/grey/
$p1 = 'ford';
$p2 = 'focus';
$p3 = 'grey';
$p3 = 'grey';
So far, so good.
Now, I need to integrate a 301 instruction (RegExp?) in that same .htaccess because initially, I had GET parameters like this :
IE: http://www.example.com/ford/focus/grey/?lang=fr
I need to get rid of all GET variables because Google sees it as duplicate content (even if I'm using the nofollow attribute on my languages links)
IE: http://i.want.to.keep/my/url/?AND_DUMP_GET_VARIABLES
http://www.example.com/ford/focus/grey/?lang=fr
http://www.example.com/ford/focus/grey/?lang=en
http://www.example.com/ford/focus/grey/?lang=sp
==> http://www.example.com/ford/focus/grey/
Logically, the instruction should be interpreted between the first and the second block but I just don't know where to start. Any hints?
THANKS!
As I understand you want to get rid of the QUERY STRING and redirect (301 Permanent Redirect) to the same URL but without QUERY STRING.
The rule below will redirect EVERY request that has query string:
RewriteCond %{QUERY_STRING} !^$
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^(.*)$ http://%{HTTP_HOST}/$1? [R=301,L]
1. The ? will do the magic -- will strip query string
2. You desperately need this line: RewriteCond %{ENV:REDIRECT_STATUS} ^$. The problem is that it may not work on your Apache setup and I cannot give you what exactly you need to make it work (it works fine on my vanilla Apache v2.2.17 on Windows).
After rewrite (internal redirect) occurred, it goes to next iteration and Apache starts matching all rules from the top again but for already rewritten URL. If we not add the above line, then mod_rewrite will apply the above rule to rewritten URL form and you will end up with all URLs get rewritten to /index.php with no parameters at all.
If the above will not work, then try the code below:
# do not do anything for already existing files and folders
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule .+ - [L]
RewriteCond %{QUERY_STRING} !^$
RewriteRule ^(.*)$ http://%{HTTP_HOST}/$1? [R=301,L]
With help of # do not do anything for already existing files and folders rule, mod_rewrite will stop rewriting after URL will be rewritten to /index.php?p1=... format.
In case the above will not work at all (better -- in addition to the above -- I would suggest adding this anyway) use <link rel="canonical" href="FULL_PROPER_RUL"/> in your page:
http://googlewebmastercentral.blogspot.com/2009/02/specify-your-canonical.html
http://www.google.com/support/webmasters/bin/answer.py?answer=139394

Resources