.htaccess | Rewrites with pages - regex

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.

Related

.htaccess and regex: trying to convert parts of my url with mod_rewrite doesn't work as expected

I'm a bit stuck trying to figure out .htaccess and mod_rewrite properly.
I know that 90% of the problem is my terrible regex skill, 10% is due to apache (or my knowledge around its mod_rewrite best practices).
We have a web service that will soon be replaced by a new one, similar in functionality but different in terms of urls, params and other things.
What needs to happen for our users (most of them can't perform this update on their end, so we have to do it on our side; we also don't build the tool directly nor have access to the source code and we agreed with the vendor that these redirects will not be done on this new web service.
What I need apache to do, with mod_rewrite is to be able to replace parameters in the querystring one by one, based on a mapping I provide
Then it should replace certain separators; ultimately, it should replace the HTTP_REFERER as well and redirect with 301.
Here's the code I have so far:
RewriteEngine On
RewriteBase /
RewriteRule ^(.*/)?\.svn/ - [F,L] ErrorDocument 403 "Access Forbidden"
# One group of RewriteCond/RewriteRule per parameter
RewriteCond %{QUERY_STRING} ^([^&]*(?:&.*)?)?param=([^&]*(?:&.*)?)$ [NC]
RewriteRule ^ %{REQUEST_URI}?%1param_changed=%2 [N,NE]
RewriteCond %{QUERY_STRING} ^([^&]*(?:&.*)?)?another_param=([^&]*(?:&.*)?)$ [NC]
RewriteRule ^ %{REQUEST_URI}?%1another_param_modified=%2 [N,NE]
...
# This is meant to replace all | with , within the url
RewriteRule ^(.*)|(.*)$ $1,$2 [N]
# This is the one that should finalise the url replace
RewriteCond %{REQUEST_URI} ^http://this.old.url/api/1/access/activity.(xml|csv)([^&]*(?:&.*)?))$ [NC]
RewriteRule ^ https://the.new.one/api/activities/?format=1&%2$ [R=301,NE,L]
This is the result I'm expecting from an example call:
input:
http://this.old.url/api/1/access/activity.xml?reporting-org=GB-GOV-1|GB-1&recipient-country=BD&stream=True
output:
https://the.new.one/api/activities/?reporting_organisation=GB-GOV-1,GB-1&recipient_country_id=BD&format=xml
I'm trying it with the htaccess tester found here and these are the issues I am still facing:
rewrite of parameters works fine, but each parameter's modified version does not get propagated to the next RewriteCond/RewriteRule group
I can't have that | matched (it gets converted in %7C in the url, but regardless, I can't have it match).
The resulting url, at the end is:
https://the.new.one/api/activities/?format=1&%2$ which leads me to think that the regex I specify in the associated RewriteCond is wrong and doesn't match, so this works partially as a side effect (it's basically replacing the whole url I think) but I need it to get that .xml/csv format and the query string afterwards. I can't seem to be able to fix that regex to work as I need it to.
I know there's a lot in this post, so thanks In advance to whoever can help me sort out the 3 issues I'm still facing

Rewrite Portion of URL Only

I am trying to rewrite a URL so that this-area-profile- will change to area-profile-, with everything after "profile-" matching what was in the original URL:
http://example.com/a-directory/this-area-profile-everything-after-profile-
http://example.com/a-directory/area-profile-everything-after-profile-
The below is my latest of numerous attempts, based on what I have read here and on other websites:
RewriteRule ^a-directory/area-profile-(.+)$ /a-directory/this-area-profile-$1 [R=301,L]
The other answers talk about changing or removing a directory, but I want to rename a portion of the URL.
I know my english is bad, but I understand the opposite from your explanation:
RewriteRule ^a-directory/this-area-profile-(.+)$ /a-directory/area-profile-$1 [R=301,L]

Url rewriting - Querystring parsing

I am new to URL rewriting and getting a bit frustrated. I'm using Helicon on the server and have gotten most URLs to re-write correctly.
(I had to remove the '//'s to allow me to submit the questions, but the urls are the standard http:// version)
My last task is to get these:
http://example.com/Object/?page=1
http://example.com/Object/?page=1&pagesize=10
http://example.com/Object/?page=1&pagesize=10&backcolor=red
to
http://example.com/default.aspx?resource=Object&page=1
http://example.com/default.aspx?resource=Object&page=1&pagesize=10
http://example.com/default.aspx?resource=Object&page=1&pagesize=10#backcolor=red
Preferably I'd like one rule to handle all 3 possibilities, but if I need to make 3 rules, one for each, and add a [L] or something at the end that would be ok too. I just can't get the querystring parsing right.
Here is an existing rule I have that works to give you an idea of what I've been doing:
RewriteRule ^/([a-zA-Z0-9]+)(/([a-zA-Z0-9]+)(/([a-zA-Z0-9]+))?)?/?($|\?) /default.aspx?resource=$1&id=$3&option=$5 [L]
It's for a separate example, but the syntax shows what I'm doing.
Does this work for you?
RewriteRule ^\/([^/]*)\/\?(.*)$ /default.aspx?resource=$1&$2 [L]
[Update]
Try this:
RewriteRule ^([^/]*(?=\/)|[^?]*(?=\?)|.*)($|[^\?]*\?(.*)) /default.aspx?resource=$1&$3 [L]

.htaccess RewriteRule for multiple pages

I've done RewriteRule for index page in my website.
Here is the code below:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^([a-zA-Z0-9+\-\(\)]+)/?$ /index.php?origin=$1
RewriteRule ^([a-zA-Z0-9+\-\(\)]+)/([a-zA-Z0-9+\-]+)/?$ /index.php?origin=$1&gender=$2
RewriteRule ^([a-zA-Z0-9+\-\(\)]+)/([a-zA-Z0-9+\-]+)/([a-zA-Z0-9+\-]+)/?$ /index.php?origin=$1&gender=$2&type=$3
RewriteRule ^([a-zA-Z0-9+\-\(\)]+)/([a-zA-Z0-9+\-]+)/([a-zA-Z0-9+\-]+)/([a-zA-Z0-9+\-]+)/?$ /index.php?origin=$1&gender=$2&type=$3&page=$4
</IfModule>
and the url is looks like
http://babynames.agurchand.com/scottish/male/pythagorean
It's a single page website, so everything is working fine so far.
Then i wanted to add one more page on my website and i have added too. file name is 'namemeaning.php'.
I've added the below code in addition of the htaccess pasted, at the bottom. But It doesn't seem to be working.
RewriteRule ^/namemeaning/([a-zA-Z0-9+\-\(\)]+)/?$ /namemeaning/namemeaning.php?name=$1
I've tried with the below url, but I'm still being referred to the index page only.
http://babynames.agurchand.com/namemeaning/abasi
Can anyone give me a solution for this please!
You're being forwarded to the index page because your regular expression for the index page fits your request. You're being sent to index.php?origin=namemeaning&gender=abasi
http://babynames.agurchand.com/namemeaning/abasi
'namemeaning' fits the rule ([a-zA-Z0-9+\-\(\)]+)
'abasi' fits the rule ([a-zA-Z0-9+\-]+)
A simple fix would be adding the line
RewriteRule ^/namemeaning/([a-zA-Z0-9+\-\(\)]+)/?$ /namemeaning/namemeaning.php?name=$1
above the line
RewriteRule ^([a-zA-Z0-9+\-\(\)]+)/?$ /index.php?origin=$1
You should remember to always place the most specific RewriteRule(s) above those that are more general.
For more information about regular expressions, I can advice you this website.
The rewruite rules are checked sequentially from top to bottom, and all rules matched are applied in that order. Double check that none of your rules match before the desired one.
Good Tool for that purpose is http://www.regextester.com/

Is there a better way to do this regex?

I finally figured out a good/easy way to make clean URLs with regex on my site in this format below, however it will require a very large .htaccess file, I know from the post on here that it is supposed to not be to bad on performance to use mod_rewrite but I have never really seen it used where the way I am, with a seperate entry for almost every page of my site.
Below is an example of an entry, there is 2 entries for 1 page, the first entry re-writes
http://www.example.com/users/online/friends/
to
http://www.example.com/index.php?p=users.online.friends
It works great but if the user is not on the first page then there is another thing added to the URL for paging and I had to write another entry to rewrite when this happens, is this the correct way or should these be combined somehow?
RewriteRule ^users/online/friends/*$ ./index.php?p=users.online.friends&s=8
RewriteRule ^users/online/friends/(\d+)/*$ ./index.php?p=users.online.friends&s=8&page=$1
The second one would do this
http://www.example.com/users/online/friends/22/
to
http://www.example.com/index.php?p=users.online.friends&page=22
It depends what you think is more readable, but here's how you could do it with a single rule:
RewriteRule ^users/online/friends(/(\d+))?/*$ ./index.php?p=users.online.friends&s=8&page=$2
(Edited to be more faithful to treatment of trailing slash in original question. Was: RewriteRule ^users/online/friends/((\d+)/*)?$ ./index.php?p=users.online.friends&s=8&page=$2)
Here I've just put "(...)?" around the final part of the url to make it an optional match, and changed the backreference to $2.
Of course, this actually rewrites http://www.domain.com/users/online/friends/ as:
http://www.domain.com/index.php?p=users.online.friends&page=
So your PHP code would have to check whether the page parameter is non-empty.
Yes, that's fine. I guess they could be combined into a single rule but there's not really any need.
You might consider leaving page as part of the URL so instead of:
http://www.domain.com/users/online/friends/22/
just have:
http://www.domain.com/users/online/friends?page=22
and then have one rule something like:
RewriteRule ^users/online/friends/?$ ./index.php?p=users.online.friends&s=8 [L,QSA]
to append the query string
Edit: There are a couple of ways of reducing the number of rewrite rules you have.
Firstly, use wildcards in the search terms, like:
RewriteRule ^users/(\w+)/(\w+)$ /index.php?p=users.$1.$2 [L,QSA]
will reduce quite a number of rules.
Secondly, if you're passing everything through /index.php just consider delegating all requests there:
RewriteRule ^(users/*)$ /index.php/$1 [L,QSA]
That rule uses a third technique: instead of passing the path information via a query string parameter, pass it via the extra path info. That can be accessed via $_SERVER['PATH_INFO'].
That being said, lots of rules isn't necessarily bad. At least it's explicit about all your actions. The thing you have to watch out for is creating a maintenance nightmare however.
# Initial step
RewriteCond %{QUERY_STRING} !(?:^|&)p=
RewriteRule ^([^/]+)/(.+) /$2?p=$1 [QSA]
# Subsequent steps
RewriteCond %{QUERY_STRING} ((?:[^&]*&)*?)p=([^&]*)(.*)
RewriteRule ^([^/]+)/(.+) /$2?%1p=%2.$1%3
# Last step with page number
RewriteRule ^(\d+)/?$ /index.php?page=$1 [QSA,L]
# Last step without page number
RewriteCond %{QUERY_STRING} (?:((?:[^&]*&)*?)p=([^&]*))?(.*)
RewriteRule ^([^/]+)/?$ /index.php?%1p=%2.$1%3 [L]
This would rewrite the URL in several steps:
http://www.domain.com/users/online/friends/22/
http://www.domain.com/online/friends/22/?p=users
http://www.domain.com/friends/22/?p=users.online
http://www.domain.com/22/?p=users.online.friends
http://www.domain.com/index.php?p=users.online.friends&page=22
An easier method would be the following, but would require you to change your scripts:
RewriteRule ^(.*?)(?:/(\d+))?/?$ /index.php?p=$1&page=$2 [QSA,L]
It would do everything in one step, with a little difference:
http://www.domain.com/users/online/friends/22/
http://www.domain.com/index.php?p=users/online/friends&page=22
Adding the s=8 query argument would require more work:
Creating a text-file with the menu numbers for each page.
Adding a RewriteMap directive.
Changing the second-last rule to use the same RewriteCond as the last rule has.
Adding &s=%{menumap:%2|0} to the last two rules.