PHP .htaccess -> pretty url (in reverse) - php

I know how to make URL's rewrite, for example:
www.example.com/index.php?id=1&cat=3 to www.example.com/1/3/ (or whatever). I know that.
What I don't know is how on earth to change my whole links in all pages to link to pretty URL's. All my site's links are old fashion (<a href="index.php?id=1&cat=2">) and there are many.
I`m asking if someone has an idea or know how to automaticaly redirect to that pretty url if the user click on index.php?id=1. (Almost like this site Stackoverflow if you change title in the url).
So my presumtions are...
Use .htaccess to read the index.php?id=1&cat=2 to rewrite index/1/3 that itself interprets again (strange)
a php file to do the redirects that htaccess rewrites back to original...
Conclusion: change <a href="index.php?id=1&....."> automaticaly to index/1/2
SOLVED
Options +FollowSymLinks
RewriteEngine On
RewriteBase /
##################################
# This turns index.php?id=1&cat=2 into index/1/2 and then back 'transparent' into index.php?id=1&cat=2 if you have old fashioned
# links in your site and don't want to change them :)
# Avoid mod_rewrite infinite loops
# This is critical if you want to use this code
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://localhost/index/%1/%2/? [L,R]
# Soft-rewrite from "friendly" URL to "real" URL.
# Transparent to browser.
# Won't re-trigger the above rewrite, though I'm
# not really sure why! The order of the rules
# doesn't seem to make a difference.
RewriteRule ^index/(\d+)/(\d+)/$ index.php?id=$1&cat=$2 [L]

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
Of course, ideally, you'd just fix your links, and then you'd only require the soft-rewrite. :)
Tested with Apache/2.2.3. I think I made up the terms "hard-rewrite" and "soft-rewrite".

Why not just change your index.php file to do it? You could theoretically do a little more error checking that way, allowing for the variables to be in any order and still get routed to the correct end location.
<?php
// Permanent redirection
header("HTTP/1.1 301 Moved Permanently");
header("Location: http://www.example.com/{$_GET['id']}/{$_GET['cat']}");
I didn't do any error checking here, but wanted to give a base example.
On second thought I guess this is adding in functionality to the index.php file which you then want to use for your application itself, so perhaps it would end up confusing the functionality in the code.

Related

Removing .php Extension from Specific URL

I've tried searching but can't find a solution that works.
I'd like to remove the .php extension and add a trailing slash from a specific URL (about.php).
For instance...
www.example.com/about.php should redirect to www.example.com/about/
and
www.example.com/about should redirect to www.example.com/about/
I've tried various RewriteRules in .htaccess but none of them worked the way I needed them to.
The following adds the trailing slash, and I can access the page without the extention... but the .php version still shows up.
RewriteEngine On
RewriteBase /
RewriteRule ^about/$ about.php [END,QSA,NC]
Does anyone have any idea how to get this working?
To externally redirect /about.php (and /about - no trailing slash) to /about/ (for the benefit of search engines and external third parties that may have indexed/linked to the old URL) you would need to add something like the following before your existing rewrite:
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^about(\.php)?$ /about/ [R=302,L]
The condition that checks against the REDIRECT_STATUS environment variable is to ensure we only redirect direct requests and not already rewritten requests by the later rewrite. REDIRECT_STATUS is empty on the initial request and gets set to the HTTP status (ie. "200" on success) after the first rewrite.
The RewriteRule pattern matches both /about and /about.php and redirects to /about/.
Note that this is a 302 (temporary) redirect. Only change it to a 301 (permanent) - if that is the intention - once you have confirmed it works OK. This is to avoid caching issues (301s are cached persistently by the browser). Likewise, if you have previously experimented with 301s then you will need to make sure the browser is cleared before testing.
UPDATE#1: If I wanted to do this to multiple pages
If you have just two pages (as in your example/comment) then you can combine both rules into one (rather than duplicating the rule block). For example:
RewriteEngine On
RewriteBase /
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^(about|contact)(\.php)?$ /$1/ [R=302,L]
RewriteRule ^(about|contact)/$ $1.php [END,QSA,NC]
The $1 backreference will hold either "about" or "contact" from the capturing group in the RewriteRule pattern.
UPDATE#2: ... I'm starting to add a lot of pages and I'm afraid the list will get out of control. Is there a better way to handle tons of pages... like 50+?
If all your pages are files in the document root then you could generalise the regex and essentially rewrite everything. For example:
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^([\w-]+)(\.php)?$ /$1/ [R=302,L]
RewriteRule ^([\w-]+)/$ $1.php [END,QSA,NC]
This is no longer "specific", as it redirects/rewrites any URL that simply "looks like" a valid request.
\w is the shorthand character class for any word character (ie. a-z, A-Z, 0-9 and _), to this we add the hyphen. So your URLs/filenames can only consist of those characters.
The above will match /about/, /contact/, /something-else/ and /foo_BAR_123/, etc. But it won't match /foo.jpg, /foo/about/ or /foo.bar/, etc.
If required, you could first check that the file exists before rewriting to it (or redirecting), but that is relatively expensive and probably not required here.
You can use index.php instead.
index page does not show up on browser address.
You can create http://www.example.com/about/index.php and on the browser, it will show as:
http://www.example.com/about/
If you need to redirect from http://www.example.com/about.php I can recommend use header http-equiv:
< meta http-equiv="refresh" content="0; URL='http://www.example.com/about/'" />

.htaccess redirect only if GET parameter exists

I have a client with an old website without 'pretty' URLs. So currently it looks like this:
http://www.domain.com/?w=42&a=5&b=3
The parameter values are numbers only.
Now they want to move the old site to a subdomain and main (www) domain would be home to a new website (WP with SEO friendly URLs).
Now what I would like to do is redirect all requests that come to the /?w=<num> (and ONLY those) to sub.domain.com/?w=<num>, so that existing links (mostly from Google) get redirected to the subdomain page, while the new page works serving new content thorough pretty URLs.
I tried this:
# This works, but redirects the entire www.domain.com
# to sub.domain.com no mather what
RewriteCond %{HTTP_HOST} ^www\.domain\.com$ [NC]
RewriteRule ^(.*)$ http://sub.domain.com/$1 [R=301,L]
# But this DOESN'T work
RewriteRule ^/?w(.*) http://sub.domain.com/?w$1 [R=301,L]
# Also tried to redirect 'by hand', but DIDN'T work either
Redirect 301 /?w=42 http://sub.domain.com/?w=42
What am I doing wrong? I searched high and low but always end up with this kind of suggestions. Or maybe I'm just searching for wrong keywords ...
Thank you!
You can't match against the query string inside a rewrite rule or a redirect directive. You need to match against the %{QUERY_STRING} variable. Try:
RewriteCond %{QUERY_STRING} (^|&)w=[0-9]+(&|$)
RewriteRule ^(.*)$ http://sub.domain.com/$1 [L,R=301]
Note that the query string gets automatically appended to the end of the rule's destination.
Just for documentation: If you want to redirect one directory (path) only if there is a URL parameter present, from one path to another, while maintaining the URL parameter, you can use this in your htaccess file:
# /programs/?id=1 to new path /loadprog/?id=1
RewriteCond %{REQUEST_URI} ^/programs/
RewriteCond %{QUERY_STRING} id=
RewriteRule ^programs\/$ /loadprog/$1 [R=301,L]
I am sure this will help others since I stumbled over the question above trying to find this answer.

Rewrite Url (URL Routing) in .htaccess

My directories are like:
http://www.mydomain.com/macbook-computer
http://www.mydomain.com/sony-computer
http://www.mydomain.com/lenovo-computer
I want to make that, if a user type computers/macbook-computer like:
http://www.mydomain.com/computers/macbook-computer
I want to display page which is : http://www.mydomain.com/macbook-computer.
My restrictions are:
1. User must type /computers (segment 1)
2. String coming from computers/ must end with "computer". (segment 2)
How can I make this achieve in my .htaccess file?
You may try this:
Options +FollowSymlinks
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} ^/computers/([^-]+)-computer/? [NC]
RewriteRule .* %1-computer? [R=301,L]
Redirects permanently
http://www.mydomain.com/computers/anyname-computer with or without trailing slash.
To:
http://www.mydomain.com/anyname-computer
Strings computers and computer are assumed to be fixed, while anything is assumed to be variable.
The incoming URL structure has to be kept for the rule-set to work: First folder /computers followed by /anyname-computer.
For silent mapping, remove R=301 from [R=301,L]
You need a rewrite rule in your .htaccess file, and a little regular expression magic. Something like this should do the trick
RewriteRule ^computers/macbook-computer$ http://www.mydomain.com/macbook-computer
Here's a nice online tool for checking rewrite rules
http://htaccess.madewithlove.be/

PATH_INFO stops working after internal redirect?

I have been at this for 45 minutes with no luck. I've found similar questions, but none that fully address my situation/problem.
I am trying to do a rewrite that does 2 things: 1) makes clean URL's (removes index.php) 2) hides a directory (my app is at web_root/dir, but I want it appear at domain.com/) 3) leaves $_SERVER('PATH_INFO') unchanged
So, for example. I want:
www.mydomain.com/some/path
to internally rewrite to:
www.mydomain.com/dir/index.php/some/path
This is what I have so far:
RewriteBase /dir/
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^/dir.*$
# if I change the [L] to an [R], it all works
# but it obviously "dirties" my desired clean URL
RewriteRule ^(.*)$ /dir/index.php/$1 [L]
# not sure why I need this
RewriteRule ^/?$ /dir/
I should at: there is a proxy at my institution, but I don't think its causing the problem.
Using PHP 5.3 and FastCGI
What's the secret to keep PATH_INFO working with an internal redirect?
Hmmm! Trailing path stuff.
So this path info is being lost in the rewrites?
Have you tried doing the www.mydomain.com/some/path -> www.mydomain.com/dir/index.php/some/path rewrite not in the per-directory context, but earlier in the server's URL handling, like VirtualHost?
I'm thinking that doing it on URL's cannot lose the path info because it is not know at that time which part is physical path and which is trailing junk. Not util the URL is mapped to a file. If you produce the
Heck, how about a simple Alias? Aliases are often used to map abstract URL locations to concrete places in the filesystem for applications. I have a whole bunch of them; here is one:
Alias /cgit/txr /cgit/cgit.cgi/txr
When people access www.kylheku.com/cgit/txr it redirects internally to www.kylheku.com/cgit/cgit.cgi/txr. That URL will work too, but the former one is nicer, because it doesn't have three repetitions of the string cgi.
Needless to say, the alias doesn't lose any trailing stuff from the URL.

PHP all GET parameters with mod_rewrite

I am designing my application. And I should make the next things. All GET parameters (?var=value) with help of mod_rewrite should be transform to the /var/value. How can I do this? I have only 1 .php file (index.php), because I am usign the FrontController pattern. Can you help me with this mod_rewrite rules?Sorry for my english. Thank you in advance.
I do something like this on sites that use 'seo-friendly' URLs.
In .htaccess:
Options +FollowSymLinks
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .* /index.php [L]
Then on index.php:
if ($_SERVER['REQUEST_URI']=="/home") {
include ("home.php");
}
The .htaccess rule tells it to load index.php if the file or directory asked for was not found. Then you just parse the request URI to decide what index.php should do.
The following code in your .htaccess will rewrite your URL from eg. /api?other=parameters&added=true to /?api=true&other=parameters&added=true
RewriteRule ^api/ /index.php?api=true&%{QUERY_STRING} [L]
.htaccess
RewriteEngine On
# generic: ?var=value
# you can retrieve /something by looking at $_GET['something']
RewriteRule ^(.+)$ /?var=$1
# but depending on your current links, you might
# need to map everything out. Examples:
# /users/1
# to: ?p=users&userId=1
RewriteRule ^users/([0-9]+)$ /?p=users&userId=$1
# /articles/123/asc
# to: ?p=articles&show=123&sort=asc
RewriteRule ^articles/([0-9]+)/(asc|desc)$ /?p=articles&show=$1&sort=$2
# you can add /? at the end to make a trailing slash work as well:
# /something or /something/
# to: ?var=something
RewriteRule ^(.+)/?$ /?var=$1
The first part is the URL that is received. The second part the rewritten URL which you can read out using $_GET. Everything between ( and ) is seen as a variable. The first will be $1, the second $2. That way you can determine exactly where the variables should go in the rewritten URL, and thereby know how to retrieve them.
You can keep it very general and allow "everything" by using (.+). This simply means: one or more (the +) of any character (the .). Or be more specific and e.g. only allow digits: [0-9]+ (one or more characters in the range 0 through 9). You can find a lot more information on regular expressions on http://www.regular-expressions.info/. And this is a good site to test them: http://gskinner.com/RegExr/.
AFAIK mod_rewrite doesn't deal with parameters after the question mark — regexp end-of-line for rewrite rules matches the end of path before the '?'. So, you're pretty much limited to passing the parameters through, or dropping them altogether upon rewriting.

Categories