Apache rewrite rules for creating user friendly urls - apache

I am relatively new to rewrite and cant get the following to work. (clearly my domain is not testsite, but dont want my proper one going public as its not finished yet.)
i want to rewrite testsite/fishing/region/region.php?region=fife
to:
testsite/fishing/fife.php
then want to rewrite testsite/fishing/region/fishery/fishery.php?url=goldenloch
to
testsite/fishing/fife/goldenloch.php
I am using the following rules
RewriteRule ^fishing/([^/]*)\.php$ /fishing/region/region.php?region=$1 [L]
RewriteRule ^fishing/([^/]*)/([^/]*)\.php$ /fishing/region/fishery/fishery.php?url=$2&region=$1 [L]
each rule works on its own but when combined only the last one work. I have added the [L] flag which i believe should stop any other rewrite rules of the condition is met. however this still doesnt work.

I tried this and it seemed to work:
RewriteRule ^/fishing/([^/]*)\.php$ /fishing/region/region.php?region=$1 [R,L]
RewriteRule ^/fishing/([^/]*)/([^/]*)\.php$ /fishing/region/fishery/fishery.php?url=$2&region=$1 [R,L]
The only difference from yours (I think) is the leading / and I used redirects (R) just to see it was working. You should be able to remove the R so the user doesn't see the real url in his browser.
Just in case you're not, I would recommend using a command line tool (like curl) and not a browser to test this, just so you avoid any caching or other annoyances:
curl -vv 'http://localhost/fishing/fife/goldenloch.php'
You'll see the Location header in the server's response, that's the redirect at work. In my case, I see:
Location: http://localhost/fishing/region/region.php?region=fife
and
Location: http://localhost/fishing/region/fishery/fishery.php?url=goldenloch&region=fife

Turns out i needed to do
RewriteRule ^fishing/([^/]*)/([^/]*) fishery.php?url=$2&region=$1 [L]
RewriteRule ^fishing/([^/]*) region.php?region=$1 [L]
with the longer query first and it worked fine.

Related

Apache Baikal server RewriteRule for CardDAV short URL

I'm using Baikal CalDAV and CardDAV server to keep my contacts and calendars in sync. It works pretty well with all of my clients. For iPhone and Mac suppoer I even put /.well-known/ redirect rules in my Apache vHost file.
Contacts Sync is work on the following URL:
myurl/html/card.php/principals/(username)
I would like to make this URL shorter for other users. I thought I could do it with mod_rewrite on Apache but I couldn't make it work.
I want to rewrite
myurl/(username)
to
myurl/html/card.php/principals/(username)
It looks really simple but I mostly ended up with recursive redirects. I used following rewrite rule
RewriteRule ^(.*) /html/card.php/principals/$1
Any help would be appreciated.
Yes, it's a rewrite loop error.
(.*) matches any uri including the destination uri and rewrites it back to itself causing an infinite loop error.
To avoid this error, we need to exclude the path we are rewriting to.
RewriteCond %{REQUEST_URI} !^/html/card.php/principal/
RewriteRule (.*) /html/card.php/principal/$1
Now the rule is conditional, it will rewrite /foo to /html/card.php/principal/foo it will not rewrite /html/card.php/principal/foo to /html/card.php/principal/foo .

RewriteRule Redirects paths not working

I moved my website to a new server with a new CMS so I had to make a lot of 301 Redirects. 'Normal' 301 redirects didn't recognize the url path of my old urls so I tried to make RewriteRules, this is what it looks like now:
Options -MultiViews
RewriteEngine On
RewriteBase /
RewriteRule ^Category http://www.example.com/category [R=301,L]
RewriteRule ^Category/Subcategory http://www.example.com/category-subcategory [R=301,L]
The first RewriteRule works, but as soon as there is a second path in the old url (the second example) the redirect will point to the main cateagy and not the subcategory. So it's basically ignoring the url paths...
Try to invert your rules, or to add a $ at the end of the first one :
RewriteRule ^Category$ http://www.example.com/category [R=301,L]
RewriteRule ^Category/Subcategory http://www.example.com/category-subcategory [R=301,L]
Explanation : Category/Subcategory is also matching the first rule, and as you have use a L flag in the first one, Apache will just use this first rule and don't bother to look further.
For general purpose solution, quoting from apache rewrite guide:
Move Homedirs to Different Webserver Description:
Many webmasters have asked for a solution to the following situation:
They wanted to redirect just all homedirs on a webserver to another webserver. They usually need such things when establishing a newer webserver which will replace the old one over time.
Solution:
The solution is trivial with mod_rewrite. On the old webserver we just
redirect all /~user/anypath URLs to http://example.com/~user/anypath.
RewriteEngine on
RewriteRule ^/~(.+) http://example.com/~$1 [R,L]
In your case URL structure has changed so ôkio's suggestion would work.

How can you ignore the end of a URL using mod_rewrite?

I'd like to structure my website like this:
domain.com/person/edit/1
domain.com/person/edit/2
domain.com/person/edit/3
etc.
I have a page to which all these requests should go:
domain.com/person/edit.html
The JavaScript will look at the trailing part of the url when the page is loaded so I want the server to internally ignore it.
I've got this rewrite rule:
RewriteRule ^person/view/(.*)$ person/view.html [L]
I'm sure that I'm missing something obvious but when I visit one of the pages above I get this 404 message:
The requested URL /person/view.html/1 was not found on this server.
As far as I understood it the [L] means that if this rule applies Apache should stop rewriting and serve up the alternate page. Instead it seems to be applying the rule at the earliest possible moment and then appending the rest of the unmatched url to the re-written one.
How do I get these re-writes to work properly?
"As far as I understood it the [L] means that if this rule applies Apache should stop rewriting and serve up the alternate page."
Well .. [L] flag tells Apache to stop checking other rules .. and rewrite goes to next iteration .. where it again checks against all rules again (that is how it works).
Try these "recipe" (put it somewhere on top of your .htaccess):
Options +FollowSymLinks -MultiViews
# activate rewrite engine
RewriteEngine On
# Do not do anything for already existing files
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule .+ - [L]
Another idea to try -- add DPI flag to your [L]: [L,DPI]
If Options will not help, then rewrite rule should. But it all depends on your Apache's configuration. If the above does not work -- please post your whole .htaccess (update your question).

Apache URL Rewriting,

I am trying to get URL rewriting to work on my website. Here is the contents of my .htaccess:
RewriteEngine On
RewriteRule ^blog/?$ index.php?page=blog [L]
RewriteRule ^about/?$ index.php?page=about [L]
RewriteRule ^portfolio/?$ index.php?page=portfolio [L]
#RewriteRule ^.*$ index.php?page=blog [L]
Now the 3 uncommented rewrite rules work perfectly, if I try http://www.mysite.com/blog/, I get redirected to http://www.mysite.com/index.php?page=blog, the same for "about" and "portfolio". However, if I mistype blog, say I try http://www.mysite.com/bloh/, then obviously I get a 404 error. The last rule, the commented one, was to help prevent that. Any URL should get redirected to the blog, but of course this rule is still parsed even if we have successfully used a previous one, so I used the "last" flag ([L]). If I uncomment my last rule, anything, including blog, about, and portfolio, redirect to blog. Shouldn't the "last" flag stop the execution as soon as it finds a matching rule?
Thanks.
Yes, the Last flag means it won't apply any of the rules following this rule in this request.
After rewriting the URL, it makes an internal request using the new rewritten URL which would match your last RewriteRule and thus your redirects go into an infinite loop.
Use the RewriteCond directive to limit rewriting to URLs that don't start with index.php, and you should be fine.
You could add a condition like:
RewriteCond %{REQUEST_URI} !^index\.php
I'll also mention that using RewriteRule ^.*$ is a good way to break all of your media requests (css, js, images) as well. You might want to add some conditions like:
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
To make sure you're not trying to rewrite actual files or directories that exist on your server. Otherwise they'll be unreachable unless index.php serves those too!
From apache's mod_rewrite docs
'last|L' (last rule)
Stop the rewriting process here and don't apply any more rewrite
rules. This corresponds to the Perl
last command or the break command in
C. Use this flag to prevent the
currently rewritten URL from being
rewritten further by following rules.
Remember, however, that if the
RewriteRule generates an internal
redirect (which frequently occurs when
rewriting in a per-directory context),
this will reinject the request and
will cause processing to be repeated
starting from the first RewriteRule.
You could use
ErrorDocument 404 /index.php?page=blog
but you should be aware of the fact that it doesn't return 404 error code, but a redirect one and I don't know if that is such a good practice.
After you [L]eave processing for the request, the whole processing runs again for the new (rewritten) URL. You could get out of that loop by using this before your other rules:
RewriteRule ^index.php - [L]
which means "for index.php, don't rewrite and leave processing."

Why would mod_rewrite rewrite twice?

I only recently found out about URL rewriting, so I've still got a lot to learn.
While following the Easy Mod Rewrite tutorial, the results of one of their examples is really confusing me.
RewriteBase /
RewriteRule (.*) index.php?page=$1 [QSA,L]
Rewrites /home as /index.php?page=index.php&page=home.
I thought the duplicates might have had been caused by something in my host's configs, but a clean install of XAMPP does the same.
So, does anyone know why this seems to parse twice?
And, to me this seems like, if it's going to do this, it would be an infinite loop -- why does it stop at 2 cycles?
From Example 1 on this page, which is part of the tutorial linked in your question:
Assume you are using a CMS system that rewrites requests for everything to a single index.php script.
RewriteRule ^(.*)$ index.php?PAGE=$1 [L,QSA]
Yet every time you run that, regardless of which file you request, the PAGE variable always contains "index.php".
Why? You will end up doing two rewrites. Firstly, you request test.php. This gets rewritten to index.php?PAGE=test.php. A second request is now made for index.php?PAGE=test.php. This still matches your rewrite pattern, and in turn gets rewritten to index.php?PAGE=index.php.
One solution would be to add a RewriteCond that checks if the file is already "index.php". A better solution that also allows you to keep images and CSS files in the same directory is to use a RewriteCond that checks if the file exists, using -f.
1the link is to the Internet Archive, since the tutorial website appears to be offline
From the Apache Module mod_rewrite documentation:
'last|L' (last rule)
[…] if the RewriteRule generates an internal redirect […] this will reinject the request and will cause processing to be repeated starting from the first RewriteRule.
To prevent this you could either use an additional RewriteCond directive:
RewriteCond %{REQUEST_URI} !^/index\.php$
RewriteRule (.*) index.php?page=$1 [QSA,L]
Or you alter the pattern to not match index.php and use the REQUEST_URI variable, either in the redirect or later in PHP ($_SERVER['REQUEST_URI']).
RewriteRule !^index\.php$ index.php?page=%{REQUEST_URI} [QSA,L]