Change all request if contains a word - .htaccess

I want to change all request uri in my project if the request contains phrase "ajax". For example now I have:
http://www.address.com/ajax/getIdeas
And when the user changes language it adds /ru/ in the URL. So the link became http://www.address.com/ru/ajax/getIdeas and its not working. All I want to do, is to change via .htaccess all links which contains word ajax and ru. So if the request is http://www.address.com/ru/ajax/getIdeas it should redirect to http://www.address.com/ajax/getIdeas. How to do it?

You can use this rule in your DOCUMENT_ROOT/.htaccess file to remove 2 digit language rom start of your URLs:
RewriteEngine On
RewriteRule ^[a-z]{2}/(ajax/.*) /$1 [L,NC,R=301]

I would recommend against making rules to rewrite, or redirect, your ajax requests. Redirects will cause your POST ajax requests to stop working. Your rewrites in general will cause extra, unnecessary work to occur regardless.
In your case I would recommend fixing your scripts to not use language-specific ajax-requests where they do not cause different results. You would use an url relative to your root (/ajax/page) instead of relative to your current url (ajax/page).

Related

Rewrite rule for URL with multiple query parameters in .htaccess

I'd like to be able to dynamically change the following URL type
www.website.com/listings/?q=&rtcl_location=city-state&rtcl_category=category-type
to look like
www.website.com/city-state/category-type/
I tried using [generateit.net/mod-rewrite/](Generate It's Mod Rewrite) but the only thing it changed was removing the q=%, the new URL looks like this:
www.webiste.com/?rtcl_location=city-state&rtcl_category=category-type
This is all latin to me and I appreciate any guidance.
Thanks
I tried reading multiple answers online and translate those answers to my own htaccess but have failed thus far.
I've also tried utilizing some generators online, as mentioned above, which have not given the intended result.
Sounds pretty straight forward, actually:
RewriteEngine on
# Redirect /listings/?q=&rtcl_location=city-state&rtcl_category=category-type
RewriteCond %{QUERY_STRING} ^(?:^|&)rtcl_location=([^&]+)&rtcl_category=([^&]+)(?:&|$)
RewriteRule ^/?listings/?$ /%1/%2/ [QSD,L,R=301]
# Rewrite /city-state/category-type/
RewriteRule ^/?([^/]+)/([^/]+)/?$ /listings/?rtcl_location=$1&rtcl_category=$2 [L]
That covers both, redirecting requests to the "old" URL and internally rewriting requests to the "new" URL.
I dropped the "q" query arg, it does not have any meaning according to what you wrote.
It is a good idea to start with a R=302 temporary redirection. And to only change that to a R=301 permanent redirection once everything works as desired. That precents nasy caching issues while testing. Nevertheless you should always test using a fresh anonymous browser window or clear or disable your browsers cache.

htaccess redirect not working for long url

How do I redirect the following long link:
http://www.vbpmonitor.com/index.php?option=com_content&view=article&id=24&utm_source=MagnetMail&utm_medium=email&utm_term=asmith#panaceainc.com&utm_content=EVVWP040716&utm_campaign=White%20Paper%3A%20Optimizing%20VBM%20Quality%20Tiering%20for%20Physicians
to
http://www.vbpmonitor.com/optimizing-vbm-quality-tiering-for-physicians
Redirect 301 /index.php?option=com_content&view=article&id=24&utm_source=MagnetMail&utm_medium=email&utm_term=asmith#panaceainc.com&utm_content=EVVWP040716&utm_campaign=White%20Paper%3A%20Optimizing%20VBM%20Quality%20Tiering%20for%20Physicians http://www.vbpmonitor.com/optimizing-vbm-quality-tiering-for-physicians
As said above in the comments I suspect that you have a glitch in your logic here and that in reality you want to redirection to work the other way 'round. Redirecting from the long to the search engine friendly URL simply does not make any sense. So:
Using a Redirect rule you could try that instead:
Redirect 301 /optimizing-vbm-quality-tiering-for-physicians /index.php?option=com_content&view=article&id=24&utm_source=MagnetMail&utm_medium=email&utm_term=asmith#panaceainc.com&utm_content=EVVWP040716&utm_campaign=White%20Paper%3A%20Optimizing%20VBM%20Quality%20Tiering%20for%20Physicians
This will redirect an incoming request to the short URL to the actually existing long URL. That is the usual scenario.
If however you really want to redirect that short URL to the long version, then you cannot do that with a Redirect rule. This might for example be the case if you accidentally sent out that long URL and have a working redirection setup for the short version. Unfortunately you do not explain anything about that in your question or comments, so I can only guess here.
You'd have to use the more flexible rewriting module and use a combination of RewriteCond and RewriteRule. That allows to "cut out" specific patterns of request URLs and to "redesign" how the request should look like after the rewriting.
This would be a simple example that applies two conditions to rewriting the request for file index.php to the long URL:
RewriteEngine on
RewriteCond %{QUERY_STRING} view=article
RewriteCond %{QUERY_STRING} id=24
RewriteRule ^/?index\.php$ /optimizing-vbm-quality-tiering-for-physicians [L,R=301]
Note: this version should work both in the http servers host configuration and also in those .htaccess style files. Where you always should prefer the first option if you have access.
As said above, I can only guess here with the sparse information you provided. I picked two out of many request arguments, since those appear to be the ones best suited as distinct identifiers. But you may have to tweak things. Note that per default RewriteConds are combined by a logical AND, so they both have to resolve to something truish.
For more precise details about this stuff I would like to point you to the official documentation of those modules again. The documentation is extremely precise, well written and comes with good examples. I would always prefer the information there to snippets you find somewhere in the internet or partial answers to questions...
http://httpd.apache.org/docs/current/mod/mod_alias.html#redirect
http://httpd.apache.org/docs/current/mod/mod_rewrite.html

How can I use mod_rewrite and preserve the url's fragment (anchor part)?

I'm taking a site that used to be static html (generated by an offline tool) and converting it to PHP. I'm sending all page urls to a single PHP file which parses the url. At first I just stuck FallbackResource MyPage.php in the .htaccess file, and it worked fine... except for urls with a fragment part. Many of the old urls were like /some-page.html#part2, and in the new scheme, part2 is a whole separate page, so I can't ignore that part of the url. With FallbackResource, all that MyPage.php would ever see is /some-page.html.
Now I've read some other questions on here about the topic, such as this one, and it seemed clear that mod_rewrite should in theory be able to do the job, but I can't get it to work. Here's my most current attempt:
Options +Indexes
DirectoryIndex MyPage.php
RewriteEngine on
#RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^[^:/.?#&]+\.html#(\w+) MyPage.php#$1 [NC,NE]
RewriteRule ^[^:/.?#&]+\.(html|php) MyPage.php [NC]
This works, again, for everything except anchors. It works no better than the old FallbackResource command did. I've tried juggling various parts of this in random ways, such as looking for %23 instead of #, omitting the NE flag, passing the value in a querystring instead of as a fragment, and whatnot.
I will note that I don't want to use redirection to translate the urls -- the PHP has to perform a lookup on it.
Well, I guess the answer is that it can't be done. The fragment part is never even sent to the server as part of the HTTP request. It stays inside the browser. Which means if anyone's saved an old link, it's just gonna go to the wrong page and that's all there is to it.
But I can write javascript into the page to redirect from the client. The PHP can iterate through the known list of old anchors on a given page and emit conditions to send them to the new page.

Compress .htaccess file

I've got a htaccess file which contains over 3,000 lines mainly thanks to 301 redirects I have setup from my old ecommerce site. The file is 323kb in size and I'm worried it's going to be a burden for load times and therefore conversions.
Is there anything available that can compress (minify?) the file into a smaller size or someone offer a better idea to handle the 301 redirects?
If the redirects are simple redirects i.e. url1 to url2, no regex etc, AND you have access to httpd.conf, then you could use a RewriteMap for all the redirects and possibly have just 1 rule in your .htaccess to handle these.
From the RewriteMap documentation
The looked-up keys are cached by httpd until the mtime (modified time) of the mapfile changes, or the httpd server is restarted. This ensures better performance on maps that are called by many requests.
Can you specify some regular expressions to group / match all of these redirects? This then offers two options for doing this:
The first is to use a (hopefully smaller) set of RewriteRule statements using the [R=301] flag.
The second is to move this redirection into a redirector script where you use, say, PHP logic to decode the legacy ecommerce URI into its current format then issue a response with and 301/302 status and Location: pointing to the current URI. This would also need you to do a catch-all rewrite of the legacy ecommerce URIs to this redirector script, e.g.
RewriteRule ^(product/.*) rewriter.php?uri=$1 [QSA,L]
Without some examples, I can't give a more specific reply. Sorry.
I've had some of these cases before, most of the times you can replace the redirect statments with RewriteRules. For example, if your URL's went from:
http://shop.example.com/shop/category/product-id.html
To this:
http://shop.example.com/category/product-id.html
You can fetch it with a rewrite like this:
RewriteRule ^/shop/([a-z]+)/([0-9]+)\.html$ /$1/$2.html [L, R=301]
This will still result in a 301 redirect, so crawlers will still know it's a permanent move.

Why does this cause an infinite request loop?

Earlier today, I was helping someone with an .htaccess use case, and came up with a solution that works but can't quite figure it out myself!
He wanted to be able to:
Browse to index.php?id=3&cat=5
See the location bar read index/3/5/
Have the content served from index.php?id=3&cat=5
The last two steps are fairly typical (usually from the user entering index/3/5 in the first place), but the first step was required because he still had some old-format links in his site and, for whatever reason, couldn't change them. So he needed to support both URL formats, and have the user always end up seeing the prettified one.
After much to-ing and fro-ing, we came up with the following .htaccess file:
RewriteEngine on
# Prevents browser looping, which does seem
# to occur in some specific scenarios. Can't
# explain the mechanics of this problem in
# detail, but there we go.
RewriteCond %{ENV:REDIRECT_STATUS} 200
RewriteRule .* - [L]
# Hard-rewrite ("[R]") to "friendly" URL.
# Needs RewriteCond to match original querystring.
# Uses "?" in target to remove original querystring,
# and "%n" backrefs to move its components.
# Target must be a full path as it's a hard-rewrite.
RewriteCond %{QUERY_STRING} ^id=(\d+)&cat=(\d+)$
RewriteRule ^index\.php$ http://example.com/index/%1/%2/? [L,R]
# Soft-rewrite from "friendly" URL to "real" URL.
# Transparent to browser.
RewriteRule ^index/(\d+)/(\d+)/$ /index.php?id=$1&cat=$2
Whilst it might seem to be a somewhat strange use case ("why not just use the proper links in the first place?", you might ask), just go with it. Regardless of the original requirement, this is the scenario and it's driving me mad.
Without the first rule, the client enters into a request loop, trying to GET /index/X/Y/ repeatedly and getting 302 each time. The check on REDIRECT_STATUS makes everything run smoothly. But I would have thought that after the final rule, no more rules would be served, the client wouldn't make any more requests (note, no [R]), and everything would be gravy.
So... why would this result in a request loop when I take out the first rule?
Without being able to tinker with your setup, I can't say for sure, but I believe this problem is due to the following relatively arcane feature of mod_rewrite:
When you manipulate a URL/filename in per-directory context mod_rewrite first rewrites the filename back to its corresponding URL (which is usually impossible, but see the RewriteBase directive below for the trick to achieve this) and then initiates a new internal sub-request with the new URL. This restarts processing of the API phases.
(source: mod_rewrite technical documentation, I highly recommend reading this)
In other words, when you use a RewriteRule in an .htaccess file, it's possible that the new, rewritten URL maps to an entirely different directory on the filesystem, in which case the .htaccess file in the original directory wouldn't apply anymore. So whenever a RewriteRule in an .htaccess file matches the request, Apache has to restart processing from scratch with the modified URL. This means, among other things, that every RewriteRule gets checked again.
In your case, what happens is that you access /index/X/Y/ from the browser. The last rule in your .htaccess file triggers, rewriting that to /index.php?id=X&cat=Y, so Apache has to create a new internal subrequest with the URL /index.php?id=X&cat=Y. That matches your earlier external redirect rule, so Apache sends a 302 response back to the browser to redirect it to /index/X/Y/. But remember, the browser never saw that internal subrequest; as far as it knows, it was already on /index/X/Y/. So it looks to you as though you're being redirected from /index/X/Y/ to that same URL, triggering an infinite loop.
Besides the performance hit, this is probably one of the better reasons that you should avoid putting rewrite rules in .htaccess files when possible. If you move these rules to the main server configuration, you won't have this problem because matches on the rules won't trigger internal subrequests. If you don't have access to the main server configuration files, one way you can get around it (EDIT: or so I thought, although it doesn't seem to work - see comments) is by adding the [NS] (no subrequest) flag to your external redirect rule,
RewriteRule ^index\.php$ http://example.com/index/%1/%2/? [L,R,NS]
Once you do that, you should no longer need the first rule that checks the REDIRECT_STATUS.
The solution below worked for me.
RewriteEngine on
RewriteBase /
#rule1
#Guard condition: only if the original client request was for index.php
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /index\.php [NC]
RewriteCond %{QUERY_STRING} ^id=(\d+)&cat=(\d+)$ [NC]
RewriteRule . /index/%1/%2/? [L,R]
#rule 2
RewriteRule ^index/(\d+)/(\d+)/$ /index.php?id=$1&cat=$2 [L,NC]
Here is what I think is happening
From the steps you quoted above
Browse to index.php?id=3&cat=5
See the location bar read index/3/5/
Have the content served from index.php?id=3&cat=5
At Step 1, Rule 1 matches and redirects to location bar and fulfills Step 2.
At Step 3, Rule 2 now matches and rewrites to index.php.
The rules are rerun, for the reasons David stated, but since THE_REQUEST is immutable once set to the original request, it still contains /index/3/5 so Rule 1 does not match.
Rule 2 does not match either and the result of index.php is served.
Most other variables are mutable e.g. REQUEST_URI. Their modification during rule processing, and the incorrect expectation that the pattern matches are against the original request is a common reason for infinite loops.
Its feels quite esoteric sometimes, but I am sure there is a logical reason for its complexity :-)
EDIT
Surely there are two distinct requests
There are 2 client requests, the original one from Step1 and the one from the external redirect in step 2.
What I glossed over above is that when Rule 2 matches on the second request, it is rewritten to /index.php and causes an internal redirect. This forces the .htaccess file for / directory to be loaded again (it could easily have been another another directory with different .htaccess rules) and Re-run all the rules again.
So... why would this result in a request loop when I take out the first rule?
When the rules are re-run, the first rule now unexpectedly matches, as a result of Rule2's rewrite, and does a redirect, causing an infinite loop.
David's answer does contain most of this information and is what I meant "for the reasons David stated".
However, the main point here is that you do need the extra condition, either your condition, which stops further rule processing on internal redirects, or mine, which prevents rule 1 from matching, is necessary to prevent the infinite loop.

Resources