Rewrite rule for one or two parameters - mod-rewrite

I have the following rewrite rule:
RewriteRule ^(.*)/(.*)$ /?page=$1&id=$2 [L,QSA]
But i want the id parameter to be optional … how do i have to write the rule?
RewriteRule ^(.*)$ /?page=$1 [L,QSA]
RewriteRule ^(.*)/(.*)$ /?page=$1&id=$2 [L,QSA]
Doesn't work.

Your own attempt looks just fine from the point of view of the rewriting itself. You claim "doesn't work" is nothing we can argue with, but it also does not really help, since it does not say anything about what that means exactly.
Assuming that in general rewriting does work for you and you only get the wrong (undesired) result I would suggest some slightly altered rule set:
RewriteEngine on
RewriteRule ^/?([^/]+)/?$ /?page=$1 [L,QSA]
RewriteRule ^/?([^/]+)/([^/]+)/?$ /?page=$1&id=$2 [L,QSA]
And a general hint: you should always prefer to place such rules inside the http servers (virtual) host configuration instead of using dynamic configuration files (.htaccess style files). Those files are notoriously error prone, hard to debug and they really slow down the server. They are only supported as a last option for situations where you do not have control over the host configuration (read: really cheap hosting service providers) or if you have an application that relies on writing its own rewrite rules (which is an obvious security nightmare).

Related

Forwarding only the root of a subdomain to a folder in the main domain (mod_rewrite)

I think I'm misunderstanding some fundamental thing here, as this is my first time using mod_rewrite.
I would like the following:
blog.example.com
blog.example.com/
blog.example.com/index.php
to redirect to:
example.com/blog
However, I would like all other cases to do nothing, e.g.
blog.example.com/foobar
blog.example.com/wp-admin
blog.example.com/wp-admin.php
This is my current .htaccess:
RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_HOST} =blog.example.com
RewriteCond %{REQUEST_URI} ^|/|index\.php$
RewriteRule ^(.*)$ http://www\.example\.com/blog [QSA,L]
I have tried many variants but each time either all requests redirect, or none redirect, so mod_rewrite is definitely doing something, just not what I want.
I have skimmed through this post for anything relevant, but I think the issue is more that I'm missing some subtle fact due to inexperience. Would someone kindly point out my error? I know we don't need yet another mod_rewrite question on SO but I'm really struggling with this one. Thanks in advance.
Try this:
RewriteEngine On
RewriteCond %{HTTP_HOST} =blog.example.com [NC]
RewriteRule ^/?(index\.php)?$ http://www.example.com/blog [QSA,R,L]
Some basic points:
The second part of the rewrite rule is not a regular expression, so periods do not need to be escaped there.
I was not familiar with the =String option for RewriteCond. Thank you for teaching me something today (I was worried when I did not see a regex there but that should be fine)! I would add [NC] here since it will help match both lowercase and uppercase versions of your domain.
None of this will work unless your virtual host includes the blog.example.com subdomain as a proper alias, and DNS is set up for that subdomain.

when to use which mod_rewrite rule for self routing?

There are several ways to write a mod_write rule for self routing. At the moment i am using this one:
RewriteCond %{REQUEST_URI} !\.(js|ico|gif|jpg|png|css)$
RewriteRule ^.*$ index.php [NC,L]
But i also could use
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*) index.php
OR
ErrorDocument 404 /index.php
There may be many more.
Are there any drawbacks for using one of these examples?
Are there any use cases where one rule makes more sense then the other?
Could you explain the difference between these rules in detail?
Thx for your time and help.
When your condition is:
RewriteCond %{REQUEST_URI} !\.(js|ico|gif|jpg|png|css)$
Then only images, icons, styles, and javascript are excluded from routing. This means you can't access static html, directories, or directory indexes. So if you just want to plop down a static html page somewhere, and serve it without it getting routed through index.php. It also means if you accidentally put an image or script or style in the wrong place, and try to access it (you would normally get a 404), it wouldn't get routed through index.php eventhough and would yield the default 404 error page.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
These conditions will exclude any URI that points to an existing resource. So if you plot an image, a script, or directory, static html, etc anywhere in your document root, you'll be able to go there without it being routed through index.php. Sometimes the condition RewriteCond %{REQUEST_FILENAME} !-s is also included, which excludes URI's that point to a symlink. This is usually what you'd see when doing routing, wordpress uses this.
ErrorDocument 404 /index.php
This does essentially the same thing as the previous conditions, except it does it outside of mod_rewrite and there's no way to impose additional conditions in the future or as needed. The downside of doing routing outside of mod_rewrite is that mod_rewrite and the core directives (ErrorDocument in this case) do processing on the URI at different times in the URI-file mapping pipeline. So if you have rules that do other things, they could get applied, and then ultimately still get routed through index.php because the 2 directives are conflicting with each other. Simply because rewrite rules are applied at one point in the pipeline doesn't mean other directives won't get applied later down in the pipeline. This is a bad way to do routing.
There's also stuff like:
RewriteCond %{REQUEST_URI} !^/index.php
RewriteRule ^.*$ index.php [L]
Which will blindly route everything. Even javascript, even images, even static html, everything. Sometimes this is what people want. Ultimately, this is going to be dependent on what you want and what your index.php script does. Is it going to handle 404's? (like what you'd want in the first routing rule), is it just going to handle non-static resources? (like what the second rule does), or is it a literal catch all and will do everything (what the rule above does)?
Also note that your rewrite flags are different between the first and second rules. Those are significant if you have other rules.
The biggest drawback to the first example (which is the one you say that you use) is that this method hard codes the files extensions (.js .ico .gif .pnd) that are excluded from being rewritten to index.php. The problem with this is that if you need to add new static content that uses a file extension that is not in your exclusion list, you must modify your rewrite rule accordingly. For example, if you were to start hosting flash content and needed to host .swf and .flv files you will need to update your existing rewritecond rule.
The middle solution is best (IMHO) because it does exactly what is says it does, namely if the requested file doesn't exist (!-f condition) OR the requested directory doesn't exist (!-d condition) then rewrite the request to index.php.

MVC3 .net 4.0 extensionless urls and isapi_rewrite

Unfortunatly I am forced to use IIS6 for my MVC website. .net 4.0 adds functionality to mimic the stupid hack for getting extensionless urls to work in IIS6. My website is designed to take advantage url rewriting for SEO purposes. The keyword urls that the client wishes to use dictate an elaborate url rewriting scheme.
The problems with Microsofts impelmentation of the feature really comes down to url rewriting and the attempt to match a pattern. I have seen various rules that attempt to strip the dreaded eurl.axd from the url so that the patterns will match. I attempted to use these rules
RewriteRule ^(.)/eurl.axd/[a-f0-9]{32}(.)$ $1$2
or
RewriteRule (.)eurl.axd/. $1
which does work but it also introduces other problems when there are nested redirects. i.e. handling old urls to new ones, etc
what happens is the eurl.axd gets stripped and on the redirect the isapi_filter doesnt get the request which results in an IIS 404 errror.
Tinkering around with the urls, i came up with this possible solution.
RewriteRule ^generators/generator-parallel-capability/([^/])/([^/])$ /generators/htmlcontent/generator-parallel-capability/$1/$2 [NC,L]
it just grabs the eurl.axd portion and rewrites it to the executing url with it appended.
Is there a better way? I have several hundred urls that meet this pattern and it would be nice to have a single rule handle them all.
We used one generic rule on top of the config to cut the /eurl.axd234234
RewriteRule ^(.)/eurl.axd.$ $1 [NC]
this must work for everything but the root.
Using the rewrite rule RewriteRule ^(.)/eurl.axd.$ $1 [NC] results in some unplesant behavior when the url is rewritten more than one time. i.e. from an old url to the new vanity url then to the actual execution url.
Using maps, I was able to produce a pattern that works quite nicely and keeps the .htaccess file from being cluttered.
RewriteCond ${contentmap:$2} >"" [NC]
RewriteRule ([^/]*)/([^/]*)/([^/]*)/([^/]*)$ /$1/${contentmap:$2}/$2/$3/$4 [NC,L]
RewriteCond ${contentmap:$2} >"" [NC]
RewriteRule ([^/]*)/([^/]*)$ /$1/${contentmap:$2}/$2 [NC,L]
The first detects the pattern /controller/some-content/eurl.axd/1234 and rewrites it to /controller/some-controller-action/eurl.axd/1234
the second does the same thing just without the eurl junk at the end. this is for my dev machine running iis 7
Im sure there are better ways and I am certainly open to better suggestions.

mod_rewrite understanding sub-directories whilst passing $_GET value server issue?

This may well be a server config issue; or simply a blindly obvious reason I'm missing...
Pre mod_rewrite URL:
www.example.com/subfolder/index.php?userName=x
The devised mod_rewrite:
RewriteEngine on
RewriteRule ^subfolder/[^/]([\w]*)$ /subfolder/index.php?userName=$1 [L]
It is my understanding that the above should allow navigation to: www.example.com/subfolder/x. However this causes a 404 error.
Rewrites without the sub-folder work fine; it is only when adding the subfoler to the mix things fall to put.
Your advice is much appreciated.
Try this one instead (works OK for me):
RewriteEngine on
RewriteCond %{REQUEST_URI} !^/subfolder/index\.php$
RewriteRule ^subfolder/([^/]+)$ /subfolder/index.php?userName=$1 [L]
NOTE:
This rule is to be placed in .htaccess. If placed in server config / virtual host context, some small tweaking will be required.

htaccess rewrite

I would like to rewrite /anything.anyextension into /?post=anything.
eg:
/this-is-a-post.php into /?post=this-is-a-post or
/this-is-a-post.html into /?post=this-is-a-post or even
/this-is-a-post/ into /?post=this-is-a-post
I tried
RewriteRule ^([a-zA-Z0-9_-]+)(|/|\.[a-z]{3,4})$ ?$1 [L]
but it doesn't work.
Any help appreciated.
If you have access to the main server configuration, use this:
RewriteRule ^/(.+)\.\w+$ /?post=\1 [L]
If not, and you are forced to put this in a .htaccess file, you could try
RewriteRule ^(.+)\.\w+$ /?post=\1 [L]
In either case, this assumes you will only be rewriting URLs with a single path component (i.e. if you get a request like /path/anything.anyextension it might not work as you expect, the rewrite rule would need to be modified to handle that)
You need a better way to determine when to apply the rewrite rule, otherwise your page won't be able to display external JS or CSS, unless you define an exception.
SilverStripe (or the core, Sapphire) offers a good approach to this, something like:
RewriteEngine On
RewriteCond %{REQUEST_URI} !(\.css)|(\.js)|(\.swf)$ [NC]
RewriteCond %{REQUEST_URI} .+
RewriteRule ^([^\.]+) /?post=$1 [L,R=301]
This requires the URI not to be empty, not to be JS, CSS or SWF, and redirects back to your root directory:
http://localhost/this-is-a-post.php
http://localhost/?post=this-is-a-post
If you don't want a redirection, but the processing, remove the redirection rule R=301

Resources