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

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.

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 pretty URLs to ugly ones

So, I'm trying to make my URL's a bit more pretty and sharable. I have a website with some items that users can currently access with example.com/?i=itemName. However, I'd like users to be able to write example.com/itemName instead.
This means I'd have to do some redirection with htaccess. I want to redirect all URL's to example.com itself, but keep the URL the same. To clarify, an example:
User types example.com/niceItem. The server shows the content of example.com, but keeps the URL as example.com/niceItem (alternatively, it can change the URL to example.com/?i=niceItem, then I can simply read the URL with javascript and change it back to example.com/niceItem in the adress bar).
So far, this is the best I could do:
RewriteRule ^/([^\/]+)$ /index.php?i=$1 [NC,L]
The idea is to capture the requests that don't have slashes after the first one (like example.com/niceItem), and then read the file at example.com/index.php?i=niceItem. The problem is, when I load a page like example.com/niceItem, the page displays what the value of i is with php; it should be niceItem, as the link is supposed to be example.com/?i=niceItem, but the value of i is actually the string index.php. Not quite what I wanted. Also, I'd expect the following to work
RewriteRule ^/([^\/]+)$ /?i=$1 [NC,L]
but this actually causes an internal server error.
So, the question is, why do those not work, and how would I be able to achieve what I'm trying to achieve?
PS. Actually, this website I'm talking about is a subdomain of example.com. So, I have sub.example.com which maps to example.com/sub/, and I need the URL's to be prettyfied like sub.example.com/itemName or example.com/sub/itemName. As I mentioned, the format of the URL isn't that big of a deal as long as the itemName part is in there. I'll be able to read the URL with javascript and change it to whatever I want once the page has loaded.
Use RewriteCond
If i is the only query argument that will be passed then
RewriteCond "%{QUERY_STRING}" "(\?i=)(.*)$"
RewriteRule "(.*)/?$" "$1/%2"
If you need to extract i only but keep other query args
RewriteCond "%{QUERY_STRING}" "(.*(?:^|&))i=([^&]*)&?(.*)&?$"
RewriteRule "(.*)/?$" "$1/%2?%1%3"
Most every framework provides this sort functionality. It is best not to reinvent the wheel when possible. This is a fragile setup, and it will probably cause you headaches in the future.

Change all request if contains a word

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

Renaming and redirecting pages fails in htaccess

I am sorry to ask this question, because the answer seemingly is so easy. However, after three hours of trial and error I am without a clue.
I have several pages on a website using parameters in the url. I would like to change that, to a more regular url. Example:
domain.com/pag.php?id=1-awesome-page should become domain.com/awesome-page
So far so good, but so far I have three problems.
1. The old page still is accessible, Google will index it as duplicated content. When I try to redirect it, I am getting infinite loop errors.
2. For whatever reason, sometimes SOME images (straight from the content) get stripped off on the newly named page. I tried playing with a base-url and renaming the images and urls, but nothing so far.
3. Also the redirect doesn't care if i'd enter id=1-awesome-page or id=2-worthless-page. It all redirects to the first one.
Among the things i've tried.
RewriteCond %{QUERY_STRING} id=1-awesome-page
RewriteRule ^pag\.php$ /awesome-page? [L,R=301]
RewriteRule ^awesome-page?$ pag\.php?id=1 [NC]
What you want to do cannot really be done with mod_rewrite, unless you want to make a rule for every page, which will probably slow your site down quite a lot. This is, because you can't summon the 1 in 1-awesome-page out of thin air, and your pag.php page doesn't seem to be able to load the page only based on it's seo name. If you need to use that number, you need to have that number somewhere in your url.
As for your questions:
The error you mention cannot be reproduced with the current iteration of your .htaccess. You likely had an infinite loop previously, and since you use R=301 to test, the browser will cache this redirect and only request the second resource afterwards when you request the first resource. You should test with [R,L] and only change to [R=301,L] when everything works as expected. Not doing so will cause weird behaviour, and behaviour you do not expect with your .htaccess.
When you have an url a and an url b, and want to redirect a to b, and want to internally rewrite b to a, you need to make sure that any given time not both rules can be matched. You can either use the %{THE_REQUEST} trick or use the END flag. Both are outlined in this answer.
If you have a problem with resources on a page not loading after making a fancy url, you likely used relative url's. This question outlines the possibilities on how to resolve this. You can either make the url's absolute or relative to the root of your site, or use <base href="/">.
The following would work for /pag.php?id=123-news-page and /news/123/news-page.
RewriteCond %{THE_REQUEST} pag\.php\?.*id=([^-]+)-([^&\s]+)
RewriteRule ^pag\.php$ /news/%1/%2? [L,R]
RewriteRule ^news/([^/]+)/([^/]+)/?$ pag.php?id=$1-$2 [L]

mod_rewrite so a specific directory is removed/hidden from the URL, but still displays the content

I'd like to create a rewrite in .htaccess for my site so that when a user asks for URL A, the content comes from URL B, but the user still sees the URL as being URL A.
So, for example, let's say I have content at mydomain.com/projects/project-example. I want users to be able to ask for mydomain.com/project-example, still see that URL in their address bar, but the browser should display the content from mydomain.com/projects/project-example.
I've looked through several .htaccess rewrite tips and FAQs, but unfortunately none of them seemed to present a solution for exactly what I've described above. Not everything on my domain will be coming from the /projects/ directory, so I'd imagine the rewrite should check to see if the page exists first so it's not appending /projects/ to every url. I'm really stumped.
If a rewrite is not exactly what I need, or if there is a simple solution for this problem, I'd love to hear it.
This tutorial should have everything that you need, including addressing exactly what you are asking: http://httpd.apache.org/docs/2.0/misc/rewriteguide.html . It may just be a matter of terminology.
So, for example, let's say I have content at mydomain.com/projects/project-example. I want users to be able to ask for mydomain.com/project-example, still see that URL in their address bar, but the browser should display the content from mydomain.com/projects/project-example.
With something like:
RewriteRule ^project-example$ /projects/project-example [L]
When someone requests http://mydomain.com/project-example and the URI /project-example gets rewritten internally to /projects/project-example. Note that when this is in an .htaccess file, the URI /project-example gets the leading slash removed when matching.
If you have a directory of stuff, you can use regular expressions and back-references, for example you want any request for http://mydomain.com/stuff/ to map to /internal/stuff/:
RewriteRule ^stuff/(.*)$ /internal/stuff/$1 [L]
So requests for http://mydomain.com/stuff/file1.html, http://mydomain.com/stuff/image1.png, etc. get rewritten to /internal/stuff/file1.html, /internal/stuff/image1.png, etc.

Resources