I'm using mod_rewrite to rewrite pretty URLs to a form supported by a Spring 2.5 application.
e.g. /category/cat1?q=x => /controller?category=cat1&q=x
However from my controller I want to know the original URL the request came from (so I can generate a link if required). This approach is needed generically across all pages so it is difficult to hard code.
How can I access the original path + query string from my controller?
I have tried using $0 to include the full path but this doesn't include the query string. I can't just append the path and the query string as this would result in some parts of the path being added as parameters /category/cat1?category=cat1&q=x Note the addition of the unwanted &category=cat1 parameter, this causes the URL to no longer match that sent from the browser.
I'm hoping mod_rewrite will let me reference the full URL and encode it as a parameter so my rule could look like:
RewriteRule /category/(.+)
/controller?category=$1&_originalUrl=${escape:$0}?${escape:<original query string>}
[QSA]
Using my original example the end result passed through to my controller would be:
/controller?category=cat1&_originalUrl=%2Fcategory%2Fcat1%3Fsearch%3Dx&search=x
The important part is the value of &_originalUrl which should be %2Fcategory%2Fcat1%3Fsearch%3Dx which in its unescaped version is /category/cat1?q=x (the original request URL that was sent from the browser).
Any suggestions welcome, thanks in advance!
The query can ony be tested with RewriteCond since RewriteRule does only test the URL path. See Jonathan Feinberg’s example how to do that.
But you could also just set the QSA flag and the old query gets automatically appended to the new one:
RewriteRule ^/category/([^/]+)$ /controller?category=$1 [QSA]
Edit In response to your comment to this question: If you want to get the initial requested URI path and query, you need to extract it from the request line (THE_REQUEST variable):
RewriteCond %{THE_REQUEST} ^[A-Z]+\ ([^\s]+)
RewriteRule ^/category/([^/]+)$ /controller?category=$1&_originalUrl=%1 [QSA]
But in most languages there is an environment variable with the very same information.
You have to capture the query string in an initial, separate step.
RewriteCond %{query_string} ^q=([^&]+)
RewriteRule ^/category/(cat1)$ /controller?category=$1&q=%1
etc.
Is there a host header you can use? Sorry for being so vague, but last time I had to do this was using PHP (urgh, dont ask), and I think thats how we did it - eg REQUEST_URI (http://www.askapache.com/htaccess/mod_rewrite-variables-cheatsheet.html)
You also may be able to SET a host header in the rewrite (http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html)
eg:
ReWriteRule /category/(cat1)?q=(x) /controller?category=$1&q=$2 [E=FOO:....]
(and no, I'm so totally NOT a mod-rewrite ninja)
Related
Appreciate the help in advance because I absolutely hate mod_rewrite and can't get my head around it!
I currently have a rule in my .htaccess that converts two parameters in a query string to a pretty URL.
RewriteRule ^projects/([^/]+)/([^/]+)/?$ single-project.php?id=$1§ion=$2 [L]
For example, this converts the URL /single-project.php?id=5§ion=documents into /projects/5/documents/
What I want to do is have an additional query string (through a new rule) that would convert /projects/5/documents/?subfolder=PDFs into /projects/5/documents/PDFs/
A few caveats:
This additional query string may not always be there
This query string would only need to work if the URL is /projects/[ANY_ID]/documents/
I hope this makes sense and that you can help!
Cheers
With your shown samples, please try following rules in your .htaccess file. Please make sure to clear your browser cache before testing URLs. Have added comments inside rule file for understanding.
RewriteEngine ON
##Op's already present rules, added 1 more flag in it QSA.
RewriteRule ^projects/([^/]+)/([^/]+)/?$ single-project.php?id=$1§ion=$2 [NC,QSA,L]
##Newly added Rule to perform internal rewrite for project id here.
RewriteRule ^(projects)/([^/]+)/([^/]+)/(.*)/?$ $1/$2/$3/?subfolder=$4 [NC,QSA,L]
I have already rewritten my old "ugly" URL:
http://example.com/ppd-brands/generic/?gen_id=Mjky
to
http://example.com/ppd-brands/generic/gen_id/Mjky
using the code below
RewriteRule ^ppd-brands/generic/gen_id/([^/]*)$ /ppd-brands/generic/?gen_id=$1 [L]
and it's working.
Now my problem is how can I redirect the old "ugly" URL to the new URL when the user visits the old "ugly" URL?
RewriteRule ^ppd-brands/generic/gen_id/([^/]*)$ /ppd-brands/generic/?gen_id=$1 [L]
Just a precursor... whilst your old "ugly" URL was of the form /ppd-brands/generic/?gen_id=Mjky, you should ideally be rewriting to the actual file that handles the request, eg. index.php, instead of allowing mod_dir to issue an additional internal subrequest to the directory index - which is what I assume is happening here.
For example:
RewriteRule ^ppd-brands/generic/gen_id/([^/]*)$ /ppd-brands/generic/index.php?gen_id=$1 [L]
Now, your main question... to externally redirect from the old "ugly" URL to the new URL. In this case, you need to be careful of a redirect loop, since if we simply redirect then the above rewrite will rewrite it back again in an endless loop. You can't use a mod_alias Redirect (as the other answer suggests) for this reason. (And a mod_alias Redirect can't match the query string either - another reason.)
Aside: Since we changed the above rewrite to include index.php in the rewritten URL, which would appear to differ from the old "ugly" URL, we could perhaps get away with a simple redirect if you are on Apache 2.4 (but Apache 2.2 would result in a conflict because mod_dir would issue an internal subrequest for index.php before we can process the URL with mod_rewrite).
We need to only redirect initial requests, not requests that we have already rewritten. We can do this by checking against the REDIRECT_STATUS environment variable, which is empty on the initial request and set to "200" (as in 200 OK HTTP status) after the first successful rewrite. (Another way is to check against THE_REQUEST, instead of the dynamic/rewritable URL-path.)
For example, try the following before your existing rewrite:
# Redirect "old" to "new"
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{QUERY_STRING} ^gen_id=([^/&]*)
RewriteRule ^(ppd-brands/generic)/(?:index\.php)?$ /$1/gen_id/%1 [QSD,R=302,L]
Note that in order to match the query string we need a condition (RewriteCond directive) that checks against the QUERY_STRING server variable. The URL-path matched by the RewriteRule pattern notably excludes the query string.
The index.php in the request URL is optional, so it matches /ppd-brands/generic/?gen_id=Mjky or /ppd-brands/generic/index.php?gen_id=Mjky (if that is the actual URL).
The $1 backreference is simply to save typing/duplication. This will always contain ppd-brands/generic when the directive matches. We could have done the same with "gen_id", but that could make the susbstitution string look a bit too cryptic.
The %1 backreference (note the % prefix) is a backreference to the captured group in the last matched CondPattern (as opposed to $1 which refers to the RewriteRule pattern), ie. the value of the gen_id URL parameter.
The QSD flag (Apache 2.4+) strips the query string from the redirected URL. Otherwise gen_id=XYZ would be passed through to the target URL. If you are still on Apache 2.2 then you would need to append a ? to the end of the substitution string instead (essentially an empty query string). eg. /$1/gen_id/%1?
The "magic" is really the first condition that checks the REDIRECT_STATUS env var. As mentioned above, this ensures that we only process initial requests and not the rewritten request, thus avoiding redirect loop.
Note that this is currently a 302 (temporary) redirect. Only change to a 301 (permanent) once you have tested this works OK. 301s are cached persistently by the browser so can make testing problematic.
And just to clarify... a redirect like this should only be implemented once you have already changed all the URLs in your application. This redirect is to simply redirect search engines, backlinks and anyone who should manually type the URL (unlikely).
Redirect 301 /oldurl.htm /newurl.htm
change old and new URL according to your need. Hope it helps you
I've been trying to redirect this URL (and all its substructures):
http://example.com/archive/
to (and its corresponding substructures):
http://archive.example.com/
For example: http://example.com/archive/signature/logo.png ==> http://archive.example.com/signature/logo.png
I tried to generate an .htaccess rule using a generator and evaluating it by looking at the regex, which I can understand (I think).
The result was the following rule:
RewriteEngine On
RewriteRule http://example.com/archive/(.*) http://archive.example.com/$1 [R=301,L]
The way I see it, the server will proccess any URL that starts with http://example.com/archive/ , will capture the string that comes next and will change the whole initial portion with the subdomain structure and append the captured string.
Unfortunately, this doesn't seem to work neither on my server, nor on online testing tools such as: http://htaccess.madewithlove.be/
Is there anything I'm missing there?
Thank you!
You should be able to try it this way.
RewriteEngine On
RewriteRule ^archive/(.*)$ http://archive.example.com/$1 [R=301,L]
Note that I did not make it dynamic as you didn't specific if you will have more URL's that need to work this way as well or not.
So I'm adjusting the URLs on a site I'm working on and I'm having some trouble with a couple of variables being passed in the URL.
mylighting.com/bath-fixture-c-13.html?osCsid=u2qj8o9rvjn0p5pa7p8npuhs54
RewriteRule ^bath-fixture bath-fixture-c-13.html?id=$1
So this Rewrite works perfect as the page that comes up is mylighting.com/bath-fixture
Now unfortunately on that page there are several other items to view and I'm having some trouble with the page variable. I think I have the code correct but every time I try to go to the correct page it doesn't seem to work.
http://mylighting.com/bath-fixture-c-13.html?page=2&id=u0hnumfus6gjhjc45av36663m3
RewriteRule ^bath-fixture/([a-zA-Z0-9]+)$ bath-fixture-c-13.html?page=$1&id=$2
So I thought I had this correct but apparently not. I would like the output to be
mylighting.com/bath-fixture/2 for the second page.
Unfortunately with that code in the .htaccess, every time I input that URL it takes me to the first page of the category and not the second like it should.
It appears that you have misunderstood the format of the RewriteRule. The first one is working by accident.
RewriteCond %{QUERY_STRING} page=([0-9]+)
RewriteRule ^bath-fixture-c-13.html bath-fixture/%1 [R=301,QSA,L]
RewriteRule ^bath-fixture-c-13.html bath-fixture/ [R=301,QSA,L]
The first argument to RewriteRule is the regex to match against the requested URL. The second argument is the URL to send as a Redirect to the user, so they end up at your desired URL instead. Because you want to parse the QUERY_STRING I believe you need to use a RewriteCond. If you are doing this for SEO purposes do not forget to add the [R=301].
http://httpd.apache.org/docs/current/mod/mod_rewrite.html
If you are trying to go the other direction then you need the following.
RewriteRule ^bath-fixture/$ bath-fixture-c-13.html [QSA,L]
RewriteRule ^bath-fixture/([0-9]+) bath-fixture-c-13.html?page=$1 [QSA,L]
If you can clarify your desired inputs and outputs you will get correct answers much more quickly.
Either I am too tired to see what I am doing wrong or there is something important I am missing here.
Basically I have a simple set of rewrite rules which are used in conjunction with a central dispatcher file (index.php) to handle requests coming for HTML, CSS and JavaScript files separately and they look like this.
RewriteEngine on
RewriteRule (.+)\.html$ index.php?action=view&url=$1.html [L]
RewriteRule (.+)\.css$ index.php?action=resource&type=css&url=$1.css [L]
RewriteRule (.+)\.js$ index.php?action=resource&type=js&url=$1.js [L]
Long story cut short these rules work fine however I've been notified by the SEO agency responsible for the site that there is an error in one of the URLs which needs to be permanently redirected (301) to the correct link. Since its just one URL that requires redirecting I have chosen to use Redirect instead of URL rewriting and added the following rule.
Redirect 301 /page1.html /page2.html
This works well too except for the fact that after the remote redirection is done for page1.html I get the query part (?action=view&url=page2.html) displayed in browsers address bar. I perfectly understand that the HTMl rewriting rule simply added the query string part after it was done with the URL but what would I need to do to get rid of the query part after a remote 301 redirection is performed.
Just to add I tried the URL rewrite method too but it seems that whatever I do the L flag is simply ignored and the HTML rewrite rule is still executed.
RewriteRule ^page1\.html$ page2.html [L,R=301]
That's a rewrite redirect and should cut off the query string. Put it before your other 3 rules, otherwise it will be ignored.
I don't know how much the solution may change with the web-server and the web-server version, but what worked for me was "When you want to erase an existing query string, end the substitution string with just a question mark".
See "Modifying the Query String" at http://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewriterule (Apache v2.4)
So,
RewriteRule ^page1\.html$ page2.html? [L,R=3xx]
The R flag is needed for the new URI to be showed and not the original with the query string. But even without the R flag, the query string will not be passed.