Trying to make a GET variable invisible in an URL but retain its usefulness using mod_write - .htaccess

Good day all,
I am trying to master the ,magic of mod_rewrite and require some advice/help.
I am trying to turn an URL from:
http://www.domainname.com/preview/about/5
To this:
http://www.domainname.com/preview/about
The issue is, I still need to retain the [id] part of the original URL to be used as a GET later on and it not be visible.
The code I have thus far:
RewriteRule ^preview\/([^/]+)\/([^/]+)\/$ /preview\/$1?id=$2 [R=301,QSA]
RewriteRule ^preview\/([^/]+)\/$ ?mode=preview&id=$2 [L,QSA]
This manages to create an URL like: http://www.domainname.com/preview/about/?id=5 and passes the ID through, I just need the ?id=5 to be invisible in the URL.
Thank you in advance anyone who has a solution for this, much appreciated.
UPDATE:
I have managed to get the following code to work as expected alas this is using static values for ID all I now need for this to be complete is to get it working off dynamic values for ID.
RewriteRule ^preview\/([^/]+)\/([^/]+)\/$ /preview\/$1 [R=301,QSA]
RewriteCond %{QUERY_STRING} !.*id=5.*$
RewriteRule ^preview\/([^/]+)\/$ ?mode=preview&id=5 [L,QSA]

You cannot get 'invisible' get parameters. The closest you'll get is setting a cookie to pass this data onwards.
RewriteRule ^preview/([^/]+)/([^/]+)[/]?$ preview/$1/ [CO=id:$2:127.0.0.1:1:/preview/$1:0:1,R]
In php you can access this cookie with $_COOKIE['id'] and the id is invisible in the url (because it isn't actually there). Documentation about the CO flag can be found here.
Edit: If you want to do it all with mod_rewrite, you can access this cookie from mod_rewrite too. As this is an internal rewrite, you can probably just use a direct path to the actual file you want to call.
RewriteCond %{HTTP_COOKIE} id=([^;]*)
RewriteRule ^preview/([^/]+)[/]?$ preview/$1?id=%1 [CO=id:-:127.0.0.1:-1:/preview/$1:0:1,END]
Edit2: I've added in a reset for the id-cookie in the second rule (expiry time T-1 minutes). This will cause the correct page to load if the user decides to go to preview/about/ again within 1 minute from going to preview/about/5 (which redirects to preview/about/ with a hidden id set to '5' to load something different).

If you are not passing the "ID" as part of the query string (e.g. ?id=5) or part of the URI (e.g. /preview/about/5) then you need to pass it in the request body, in something like a POST request. Otherwise, you can't make it "invisible", because the webserver isn't going to see it. If the webserver doesn't see it as a request, there is nothing mod_rewrite can possibly do to extract it.
Assuming you can't setup your site so that requests get POSTed (sort of like how a form is submitted) everytime someone clicks on a link, you're best bet is probably having it look like the http://www.domainname.com/preview/about/5 form, or maybe http://www.domainname.com/preview/about-5?

Related

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.

Redirect dynamic url to new dynamic URL which is also prettified in htaccess

I have a website which has dynamic URLs and they're not currently prettified. I have re-worked the site and included pretty URLs, but the real dynamic folder structure/filename has also changed.
To better explain, the current dynamic URLs look like
http://example.com/liveguide/year.php?year=2017
The new dynamic url for the same page is
http://example.com/shows/show-list.php?year=2017
I use the following:
RewriteRule ^shows/(199[5-9]|200[0-9]|20[0-1][0-7])/?$ /shows/show-list.php?year=$1 [L]
To enable the use of pretty URLS like
http://example.com/shows/2017
So what I'm trying to do is if anyone followed a link of the original dynamic URL, they'll end up on the new clean URL. So far I've just got
RewriteRule ^liveguide/year.php /shows/show-list.php [R=301,L]
Which redirects to the correct page, but you're left with the ugly URL in the address bar. How could I do it so that the new, pretty URL is in the address bar?
Ie someone visits
http://example.com/liveguide/year.php?year=2017
They end up on, and see in their address bar
http://example.com/shows/2017
You just need to match the query string, which is in a separate variable, and used in a RewriteCond, which capture to %1, %2 etc. Like this:
RewriteCond %{QUERY_STRING} ^year=(\d{4})$
RewriteRule ^liveguide/year\.php$ /shows/%1? [R=301,L]
While we are here, do you really need to only match just those exact years? Would it matter if /shows/1234 also got rewritten? Probably not, you can just return a 404 from your PHP, so a simpler rule would be ok, like the above just saying any four numbers. It will also work for future years without changing it.
RewriteRule ^shows/(\d{4})/?$ /shows/show-list.php?year=$1 [L]
The goal is usually not to match exactly what you want, and only that, but rather to ensure nothing else (other parts of the site) will be matched that shouldn't be. Simpler rules are easier to maintain and review later. Your script must already be able to handle bad data anyway, so just let it handle the detailed checking without duplicating it unnecessarily.
Hope this helps.

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]

GET parameter becomes the page name after rewrite

I have an url that looks like:
/platforms.php?platform_id=xxx
where xxx is a number
I'm rewriting the URL inside the php application. So, for example the above url would look like:
/xbox/ or /playstation/
Now in .htaccess I have:
RewriteRule ^([^/]+)/$ platforms.php?platform_id=$1 [L,QSA]
However when I go to a platform page the GET url becomes /xbox/ or /playstation/ , instead of xxx.
Any pointers would be appreciated.
Update:
Hi, the link is not relevant to my question. I've tried to reformulate what I am after for in the example bellow with better details.
Thanks for the answer and sorry for the bad explanation.
Yep, when I said GET url I was referring to $_GET["platform_id"] .
Basically I have an URL called
www.example.com/platforms.php?platform_id=1
In the above example $_GET['platform_id'] = 1.
In the actual php aplication I have a function (let's call it make_link ), with which I make the above URL output like:
www.example.com/xbox/ (since 1 is the id of the xbox platform)
Now in httaccess I also need a rewrite rule that will make accessing the URL work.
So I have :
RewriteRule ^([^/]+)/$ platforms.php?platform_id=$1 [L,QSA]
This does make the rewrite work in the terms that I can access
www.example.com/xbox/
However on the newly accessed page, if I get $_GET['platform_id'], the value for it is xbox/ .
Thanks,
In a RewriteRule, $1 is a variable backreferencing the first regular expression (in your case: ([^/]+)).
So, whatever text forms that part of your URL is what will be stored in $1.
If you wanted to use the consoles' IDs, you'd have to make these IDs part of your URLs. If you don't want that, but if you want your pretty URLs to reflect the names of the consoles, you'll have to rewrite the query part of platforms.php?platform_id=$1 in your .htaccess file.
Instead of querying for IDs (?platform_id=$1), you'll have to query for the consoles' names, e.g. ?platform_name=$1.
Edit:
In your PHP file, you'd then use $_GET['platform_name']

URL Rewriting based on form input

I'm creating a frontpage for my website with a single form and input text, Google-style. It's working fine, however, I want to generate a pretty URL based on the input. Let's say, my input is called "id", and using the GET method of form, and the action defined to "/go/", on submission, the URL will be:
site.com/go/?id=whateverIType
and I want to change it to
site.com/go/whateverIType
I was thinking on Mod Rewrite, but if the user put something in the URL, like:
site.com/go/?dontwant=this&id=whateverIType&somemore=trash
I want to ignore the other variables but "id", and rewrite the rule.
What's the better way of get this done? Thanks in advance!
PS: I'm using CodeIgniter, maybe there's something I can use for it as well. I already have a controller for "go".
I'm not familiar with CodeIgniter, but you can try the following RewriteRule
RewriteEngine on
RewriteCond %{REQUEST_URI} ^\/go\/
RewriteCond %{QUERY_STRING} id=([^&]*)
RewriteRule (.*) /go/%1? [L,R]
The %1 references the regex group from the previous RewriteCond, and the trailing ? will strip the querystring from the redirected URL.
Hope this helps.
Mod_rewrite supports conditions and rules with RegEx, so you could have a rule that matched the ?id=XXXX, that would extract it from the URL (keeping the other parameters), and rewrote the URL accordingly.
However... I don't think you want to do this, because if you rewrite the URL to be /go/Some+Search+Query, you won't be able to pick it up with say, PHP, without parsing the URL out manually.
It's really tough to have custom, SEO-friendly URLs with user input, but it is technically possible. You're better off leaving in the ?id=XXX part, and instead, using mod_rewrite in the opposite approach... take all URLs that match the pattern /go/My+Search+Terms and translate that back into something like ?id=My+Search+Terms, that way you'll be able to easily parse out the value using the URL's GET parameters. This isn't an uncommon practice - Google actually still uses URL parameters for user input (example URL: http://www.google.com/search?q=test).
Just keep in mind that mod_rewrite rewrites the URL before anything else (even PHP), so anything you do to the URL you need to handle. Think of mod_rewrite as a regular expression-based, global "Find and Replace" for URLs, every time a page is called on the server. For example, if you remove the query string, you need to make sure your website/application/whatever accounts for that.
In application/config/routes.php
$route['go/(:any)'] = "go/index/$1";
Where go is your controller and index is the index action.
http://codeigniter.com/user_guide/general/routing.html
You can use something like this in your .htaccess if you aren't already:
RewriteEngine on
RewriteCond $1 !^(index\.php|images|css|js|robots\.txt)
RewriteRule ^(.*)$ /index.php/$1 [L]

Resources