How to rewrite on htaccess - .htaccess

I need to substitute the character %26 for & and %3D for = in my URL:
http://www.example.com/dir/?sort-by=title%26listing_types%3Dcars
I tried the rewrite below but it does not work
RewriteRule ^dir/?$ ?sort-by=$1&listing-types=$2 [QSA,L]
Any help will be welcome

RewriteRule ^dir/?$ ?sort-by=$1&listing-types=$2 [QSA,L]
Your backreferences $1 and $2 don't actually refer to anything so these will always be empty (resulting in empty URL parameters). However, $n backreferences refer back to the RewriteRule pattern, which does not match against the query string anyway. You would need %n type backreferences that refer back to the last matched CondPattern in a preceding RewriteCond directive.
This also looks like it should ideally be a redirect, rather than an internal rewrite? Otherwise, you run the risk of duplicate content.
http://www.example.com/dir/?sort-by=title%26listing_types%3Dcars
You can do something like the following to match the above URL and replace the appropriate characters:
RewriteCond %{QUERY_STRING} ^(sort-by=.*)%26(listing_types)%3D(.*)
RewriteRule ^(dir/)$ /$1?%1&%2=%3 [R,L]
The above would temporarily (302) redirect /dir/?sort-by=<anything1>%26listing_types%3D<anything2> to /dir/?sort-by=<anything1>&listing_types=<anything2>. Change R to R=301 if this should be permanent, but only once you have confirmed it is working OK.
$1 is a backreference to the captured group in the RewriteRule pattern (ie. "dir/") and %1, %2 and %3 are backreferences to the corresponding captured groups in the preceding CondPattern in order to reconstruct the query string.
If you specifically need this to be an internal rewrite then remove the R flag (and optionally remove the slash prefix on the substitution).
http://www.example.com/dir/?sort-by=title%26listing_types%3Dcars
As mentioned in comments, you could instead handle this entirely in your server-side code. For example, in PHP you could do something like:
<?php
$queryString = urldecode($_SERVER['QUERY_STRING']);
parse_str($queryString,$urlParams);
print_r($urlParams);
?>
Given the above request URL, this will output:
Array
(
[sort-by] => title
[listing_types] => cars
)

Related

I need a 301 redirect for .htaccess

I need a redirect from
https://example.com/shop/vip-schmuck/18-karat-gold/18-karat-gold-nasenstecker-spirale-schmetterling-kristalle/
to
https://example.com/shop/vip-schmuck/18-karat-gold/280419/18-karat-gold-nasenstecker-spirale-schmetterling-kristalle/
what means 1 is the old URL und 2 is the new one.
The only change is the "280419" in the new URL.
UPDATE:
I want to redirect all of my product URLs. ie. from example.com/shop/placeholderhere/placeholderhere/placeholderhere/ to example.com/shop/placeholderhere/placeholderhere/280419/placeholderhere/
At the top of your root .htaccess file you can do something like this:
RewriteRule ^(shop/vip-schmuck/18-karat-gold)/(18-karat-gold-nasenstecker-spirale-schmetterling-kristalle/)$ /$1/280419/$2 [R=302,L]
The $1 and $2 backreferences in the substitution string (2nd argument) contain the values captured from the parenthesised subpatterns in the preceding RewriteRule pattern. This simply saves repetition (and potential error).
This is a 302 (temporary) redirect. Only change to a 301 (permanent) redirect - if that is the intention - once you have confirmed this works as intended.
Reference:
https://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewriterule
UPDATE:
i want to redirect alll of my producs , what means old protect-example.com/shop/placeholderhere/placeholderhere/placeholderhere/ to protect-example.com/shop/placeholderhere/placeholderhere/280419/placeholderhere/
To inject the code 280419 in every URL that follows that format you can do something like this instead:
RewriteRule ^(shop/[^/]+/[^/]+)/([^/]+)/?$ /$1/280419/$2/ [R=302,L]
Where $1 contains the URL-path that matches the first subpattern (shop/[^/]+/[^/]+) and $2 matches the last path segment (excluding an optional trailing slash) as denoted by ([^/]+)/?$. The trailing slash is enforced on the target URL.

Replace part of a long URL and redirect

Is there a way to redirect the URL as follows:
URL is generated based on a filtering system so it is like this
https://example.com/product-category-no-slash-generated-part-is-autoadded-here
Due to the massive product number, it is impossible for me to change all generated URL-s but I need to change, for example, only no-slash part to something-else, so redirect does this:
Old URL:
https://example.com/product-category-no-slash-generated-part-is-autoadded-here
New URL:
https://example.com/product-category-something-else-generated-part-is-autoadded-here
I hope I managed to explain the problem.
I tried to use stuff like RewriteRule ^/no-slash/(.*)$ /something-else/$1 [L] but I think this does not work for what I need.
To replace no-slash with something-else in the URL-path that only consists of a single path-segment then you can do something like the following using mod-rewrite, near the top of the root .htaccess file.
RewriteEngine On
# Replace "no-slash" in URL-path with "something-else"
RewriteRule ^([\w-]+)no-slash([\w-]+)$ /$1something-else$2 [R=302,L]
This assumes the URL-path can only consist of the characters 0-9, a-z, A-Z, _ (underscore) and - (hyphen).
The $1 and $2 backreferences contain the matched URl-path before and after the string to replace repsectively.
I tried to use stuff like RewriteRule ^/no-slash/(.*)$ /something-else/$1 [L]
In this you are matching slashes in the URL-path - which do not occur in your example. You are also not allowing for anything before the string you want to replace (eg. product-catgeory-).
In a .htaccess context, the URL-path matched by the RewriteRule pattern does not start with a slash. S, a pattern like ^/no-slash will never match.
UPDATE:
another example. example.com/demo-tools-for-construction-work So word TOOLS in URL must be replaced with EQUIPMENT-AND-TOOLS.
(I'm assuming this should all be lowercase.)
A problem with your second example (in comments) is that tools also exists in the target URL, so this would naturally result in an endless redirect loop.
To prevent this "loop" you would need to exclude the URL you are redirecting to. eg. You could exclude URLs that already contain equipment-and-tools.
For example:
# Replace "tools" in URL-path with "equipment-and-tools"
# - except if it already contains "equipment-and-tools"
RewriteCond %{REQUEST_URI} !equipment-and-tools
RewriteRule ^([\w-]+)tools([\w-]+)$ /$1equipment-and-tools$2 [R=302,L]
The ! prefix on the CondPattern (2nd argument to the RewriteCond directive) negates the expression. So, in this case it is successful when equipment-and-tools is not contained in the requested URL.

How to rewrite URL GET parameters

I have a URL
https://example.com/cart?prdid=223
I want to redirect it to
https://example.com/cart/223
using .htaccess
i've tried to use
RewriteEngine on
RewriteCond %{QUERY_STRING} (?:^|&)prdid=(.*)$
RewriteRule ^cart/(.*)$ /cart/$1?prdid=%1 [L,R]
But it does not work.
Rewrite rules have the pattern to match first, then the result you want.
The pattern you need to match is the current URL, which just ends "/cart", with no extra slash or word on the end of it, so instead of cart/(.*)$ you just want cart$
Then the result you want has the ID directly in the URL, not in the query string, and there's nothing for $1 to refer to, only %1 from the RewriteCond line. So instead of /cart/$1?prdid=%1 you just want /cart/%1
Once you've fixed that, the browser will redirect to the new URL. To actually make that URL work, you'll probably need a second rule, without the R flag, to tell Apache what to do when it sees the "pretty" URL. That one will have cart/(.*)$ as the pattern to match, but no condition on the query string, and $1 in the result part, not %1

htaccess RewriteRule with literal question marks (not query string)

I need to be able to match question marks because there was a translated text encoding mistake, and part of the URL ended up hardcoded with question marks in them. Here's a URL example that I need to rewrite:
https://example.com/Documentation/Product????/index.html
Here is my current rewrite rule. It works when the characters following "Product" are not question marks, but when they are, the rule doesn't apply.
RewriteRule "^Documentation/Product[^/]+/(.*)$" "https://s3.amazonaws.com/company-documentation/Help/Product/$1" [L,NC]
How would I make sure that question marks are considered to be characters too in this rule? I can't expect that only question marks and not the original non-English characters will be in the URL, so I want the rule above to match both question marks and any other character.
I found this topic which seems relevant, but the flags don't help, and the answer doesn't explain how to overcome the problem mentioned in the "Aside".
https://webmasters.stackexchange.com/questions/107259/url-path-with-encoded-question-mark-results-in-incorrect-redirect-when-copied-to
https://example.com/Documentation/Product????/index.html
You say it's "not a query string", but actually that is exactly what it is. And that is why you can't match it with the RewriteRule pattern. The above URL is split as follows:
URL-path: /Documentation/Product (matched by the RewriteRule pattern)
Query string: ???/index.html (note 3 ? - the first one starts the query string)
To match the query string you'll need an additional RewriteCond directive that checks against the QUERY_STRING server variable.
For example, to match the above URL, you would need to do something like:
RewriteCond %{QUERY_STRING} ^\?*/index\.html
RewriteRule ^Documentation/Product$ https://s3.amazonaws.com/company-documentation/Help/Product/index.html [NC,R,L]
This matches any number of erroneous ? at the start of the query string.
I've added the R (redirect) flag. Your directive (without the R flag) would trigger an external redirect anyway (because you specifying an absolute URL in the substitution), but it is far better to be explicit here. This is also a temporary (302) redirect. If this should be permanent (301) then change it to R=301, but only once you have confirmed that it's working OK (301s are cached hard by the browser so can make testing problematic).
UPDATE:
...so I want the rule above to match both question marks and any other character.
Only if there are question marks in the URL will there be a query string, so I think it is advisable to keep these two rules separate.
If there could be any erroneous characters at the start of the query string and if you want to capture the end part of the URL (like you are doing in your original directive, eg. index.html) then you can modify the above to read:
RewriteCond %{QUERY_STRING} /(.*)$
RewriteRule ^Documentation/Product$ https://s3.amazonaws.com/company-documentation/Help/Product/%1 [NC,R,L]
Note the %1 (as opposed to $1) backreference in the substitution string. This is a backreference to the captured group in the last matched CondPattern (ie. /(.*)$).
You can follow this with your existing directive (but remember to include the R flag) for more "normal" URLs that don't contain a ? (ie. query string).
NB: Surrounding the arguments in double quotes are entirely optional in this example. They are only required if you have unescaped spaces in the pattern or substitution arguments.
In summary
# Redirect URLs of the form:
# "/Documentation/Product?<anything#1>/<anything#2>"
RewriteCond %{QUERY_STRING} /(.*)$
RewriteRule ^Documentation/Product$ https://s3.amazonaws.com/company-documentation/Help/Product/%1 [NC,R,L]
# Redirect URL-paths of the form (no query string):
# "/Documentation/Product<something>/<anything>"
RewriteRule ^Documentation/Product[^/]+/(.*) https://s3.amazonaws.com/company-documentation/Help/Product/$1 [NC,R,L]

Why does my RewriteRule not work when there is a `?` in the URL

I am learning how to write regular expressions for .htaccess redirects.
So far I've managed to figure out everything I needed, except for a couple of regular expressions which don't behave as I expected. I am testing my regular expressions using a desktop application, and they work fine there, but not in the .htaccess file.
FYI: The RewriteBase is set to /site/
This is the incoming URL:
/site/view-by-tag/politics/?el_mcal_month=3&el_mcal_year=2009
I want to grab "politics" and redirect to /site/tags/politics/
Here is what I used:
RewriteRule ^view-by-tag/([a-zA-Z\-]+)/([a-zA-Z0-9\-\/\.\_\=\?\&]+) /tags/$1/ [R=301,L]
I added the capture of all the characters after politics because I am having the issue that when there is a ? in the URL the redirect does not work, and I can't figure out why. In the URL given above, if I remove the ? it works fine, but if the ? is in there, nothing happens. Is there a reason for this?
The same thing happens when I try to capture 307 from /site/?option=com_content&view=article&id=307&catid=89&Itemid=55
I used this regular expression, article&id=([0-9]+) /?p=$1 [R=301,L] but again, when there is a ? in the URL it stops the redirect for doing anything.
What is the reason for that?
The .htaccess file in question is on a Wordpress blog (3.4.1)
The point that you've missed is that the rewrite engine splits the URI into two parts: the REQUEST_URI and the QUERY_STRING. The query string part isn't used in the rule match string so there is no point in constructing rule regexp patterns to look for it.
You can probe and pick out parameters from the query string by using rewrite conditions and condition regexps to set %N variables.
By default the query string is appended to the output substitution string unless you have a ?someparam in it -- in which case it is ignored unless you used the [QSA] (query string append) parameter.
The way that you'd pick up the id in /site/?option=com_content&view=article&id=307&catid=89&Itemid=55 is to use something like:
RewriteCond %{QUERY_STRING} \bid=(\d+)
Before the rule and this would set %1 to 307. Read the rewrite documentation for more general discussion of how to do this.
The query string is must be processed separately in a RewriteCond if you need to manipulate it, and should not be matched inside the RewriteRule Instead, just match the request not including the query string, and use QSA to append the query string onto the redirect:
RewriteRule ^view-by-tag/([A-Za-z-]+)/?$ /tags/$1/ [R=301,L,QSA]
# OR, if you don't want the rest of the query string appended, put a `?` onto
# the redirect to replace it with nothing
RewriteRule ^view-by-tag/([A-Za-z-]+)/?$ /tags/$1/? [R=301,L]
Actually, the QSA may not be needed in a R redirect - I think that the default behavior is to pass the query string with the redirect.
If you need to capture 307 from the query string, do it in a RewriteCond and capture in %1:
# Capture the id in %1
RewriteCond %{QUERY_STRING} id=([\d]+)
# Redirect everything to /, pass %1 into p
RewriteRule . /?p=%1 [LR=301,L]

Resources