mod_rewrite problem with 2 virtual folders - php

i have a problem to rewrite 2 parameters that are on the same place in a URL.
i want the following URL Structure:
category (No page or letetr is set)
category/page-2 (different page from page 1)
category/e/page-2 (letter and page is set)
The problem is that my second rule is ignored. :(
Here is my code:
RewriteRule ([^/.]+)/([^/.]+)$ index.php?cat=$1&letter=$2 [L,NC]
RewriteRule ([^/.]+)/page-([^/.]+)$ index.php?cat=$1&page=$2 [L,NC]
RewriteRule ^([^/.]+)$ index.php?cat=$1 [L,NC]

Your second rule isn't being ignored. Instead, anything that matches the second rule will also match the first rule, so the first rule is processed instead (and the [L] modifier prevents further processing).
Basically, the second rule is the same as the first, but with the additional condition that the characters page- must also exist between the two captured sections. This page- portion matches the ([^/.]+) condition of the first rule, so it will be matched when the first RewriteRule is processed.
Try reversing the order of the first two rules.

Related

Same .htaccess rules doesn't work

I want to rewrite url for two pages like that:
Original:
http://example.com/team.php?PAGE=profile&LINK=jenifer
http://example.com/course.php?PAGE=view&LINK=dance
Desired:
http://example.com/jenifer
http://example.com/dance
I tried with this rules
RewriteRule ^([^/]*)$ /team.php?PAGE=profile&LINK=$1 [L]
RewriteRule ^([^/]*)$ /course.php?PAGE=view&LINK=$1 [L]
I don't know why only the first page is rewrited corectly and the second page is rewrited as the first page too.
Also, my index.php is redirected to team.php
Thank you!
mod_rewrite looks at each rule in turn, until it finds a matching one.
Take for example http://example.com/jenifer, where the request for jenifer is matched against the first rule pattern ^([^/]*)$. And look at http://example.com/dance, here again dance is matched against the first rule pattern ^([^/]*)$. The second rule is never tried, because the first one already swallows each request.
When you have a request matching the pattern ^([^/]*)$, Apache will always stop at the first RewriteRule, because this is the first matching one.
If you want to distinguish between team members and courses, you must also have different patterns to match against, as #anubhava already suggested in the comments, e.g.
RewriteRule ^team/([^/]*)$ /team.php?PAGE=profile&LINK=$1 [L]
RewriteRule ^course/([^/]*)$ /course.php?PAGE=view&LINK=$1 [L]
Now, when you get a request for http://example.com/team/jenifer or http://example.com/course/dance, Apache is able to select the proper rule because of the leading team or course in the requests.

Removing the query string and redirecting (rewrite rule and rewrite cond)

I am currently trying to set up a rewrite rule to set up an internal redirect for a more SEO-friendly url-structure.
I want to show:
/find-teacher/primary-school.php
instead of the sad looking:
/find-teacher/subject-class-choose.php?school=primary-school
After I read some posts and tutorials about the rewrite rule and rewrite cond, I came up with this:
In my choose-school.php I have as a link with the nice looking url:
<a href="https://www.example.com/find-teacher/primary-school.php">
Primary School</a>
In my .htaccess:
RewriteCond %{REQUEST_URI} ^find-teacher/primary-school.php$
RewriteRule ^find-teacher/([a-z-]+)-([0-9]+).php$ /find-teacher/subject-class-choose.php?school=$1 [NC]
Now if I got that right, the RewriteCond part checks if the following url is requested. If that is the case, then the part of ([a-z-]+)-([0-9]+) is replaced by the $1 of the substitution part (/find-teacher/subject-class-choose.php?school=$1)
Problem is that I am redirected to my error page if I click on /find-teacher/primary-school.php
You don't need both a RewriteCond and a RewriteRule here, because they are (or should be) both checking the same thing.
However, currently, there is no URL which will match both patterns. Let's break down the problem.
To check specifically for the URL /find-teacher/primary-school.php, you could just write:
RewriteRule ^find-teacher/primary-school.php$ /find-teacher/subject-class-choose.php?school=primary-school [NC]
The next step is to "capture" the "primary-school" with ( and ), and place it dynamically onto the target with $1:
RewriteRule ^find-teacher/(primary-school).php$ /find-teacher/subject-class-choose.php?school=$1 [NC]
Finally, we can make the pattern match any letters or hyphens instead of an exact string, using the regex [a-z-]+:
RewriteRule ^find-teacher/([a-z-]+).php$ /find-teacher/subject-class-choose.php?school=$1 [NC]
In the rule in your question, you've added an extra part to the regex: -([0-9]+). This matches - and then a number. To capture that number, you'd put $2 somewhere in your target:
RewriteRule ^find-teacher/([a-z-]+)-([0-9]+).php$ /find-teacher/subject-class-choose.php?school=$1&id=$2 [NC]
This would match something like /find-teacher/primary-school-123.php, and turn it into /find-teacher/subject-class-choose.php?school=primary-school&id=123.
Two final notes:
depending how your Apache configuration is set up, you may or may not need to include the leading / in your patterns, i.e. start them with ^/
I find a nice way to debug rewrite rules is to make them redirect your browser, by adding R=temp to the flags (e.g. [NC,R=temp]); that way, you don't have to rely on your PHP code to tell you what URL was requested

What does the =$1 mean in url rewriting?

I can't find any information on stackoverflow or google about the meaning of =$1. I get superficial information but nothing for beginners like me. What does it do?
If I have something like this:
www.website.com/profile.php?simon
Does the name simon correspond to the $1 variable and why 1?
This is how I understand it:
(.*) profile/profile.php?id=$1
The bold corresponds to:
www.website.com/profile.php?id=simon
Converted with rewrite it becomes:
www.website.com/profile/simon
Am I missing something here?
Edit:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteCond %{REQUEST_FILENAME}.php -d
RewriteRule ^(.*)$ /profile/index.php?id=$1
Does this change
localhost/test/index.php?philip
to:
localhost/test/profile/philip
I tried to enter the url but it failed. I understand what regex does but somehow im utterly confusing how the replacement works.
Backreference:
RewriteRule ^.*$ /?id=$1
$1 would be blank
RewriteRule ^(.*)$ /?id=$1
$1 would be whatever .* matched
RewriteRule ^(a|b|c)/(d|e|f)$ /?id=$1-$2
$1 would be either "a", "b", or "c", depending on which one matched, and $2 would be either "d", "e", or "f", depending on which one matched.
See: http://httpd.apache.org/docs/trunk/rewrite/intro.html#regex
One important thing here has to be remembered: Whenever you use parentheses in Pattern or in one of the CondPattern, back-references are internally created which can be used with the strings $N and %N (see below). These are available for creating the Substitution parameter of a RewriteRule or the TestString parameter of a RewriteCond.
Captures in the RewriteRule patterns are (counterintuitively) available to all preceding RewriteCond directives, because the RewriteRule expression is evaluated before the individual conditions.
Figure 1 shows to which locations the back-references are transferred for expansion as well as illustrating the flow of the RewriteRule, RewriteCond matching. In the next chapters, we will be exploring how to use these back-references, so do not fret if it seems a bit alien to you at first.
Does this change
localhost/test/index.php?philip to: localhost/test/profile/philip
No, It changes localhost/test/profile/philip to localhost/profile/index.php?id=philip. Assuming that the rule is in an htaccess file that is in your "profile" directory, then:
Browser types in or clicks on the link: localhost/test/profile/philip
The request is sent to localhost: /test/profile/philip
The request makes its way through apache's processing pipeline and mod_rewrite is applied to it, and the request is truncated to philip
Assuming that philip is neither a directory or file, the rule matches (.*) to it, and the string philip is captured
The rule then rewrites the request to /profile/index.php?id=philip
First, use Apache documentation rather than Google searches or Forums it's more helpful.
http://httpd.apache.org/docs/2.2/rewrite/intro.html#regex
And this
http://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewritecond
Now (.*) is a parenthesized capture group in Regex. It says to match any single character and the asterisk means to repeat it 0 or more times.
When there is only 1 capture group. The numbered back reference is $1. Additional capture groups used or added will then be $2, $3 and so on.
For this example
www.website.com/profile/simon
You would get this rewrite rule.
RewriteRule (.*) profile/profile.php?id=$1
But your back reference $1 won't be simon, it will be profile/simon because you matched all characters requested using (.*).
If you only want to match simon you need to use a partial match like this.
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteCond %{REQUEST_FILENAME}.php -d
RewriteRule ^profile/(.+)/?$ profile/profile.php?id=$1
Then your $1 will only be simon and also the rule won't match any empty strings, meaning if there is no text after /profile/ it won't process the rewrite.
Let me try to explain in layman's terms.
Let's say you would normally link to a page like this...
/listing.php?id=2146_east_fifth_street
Then you create a rewrite rule like this...
RewriteRule ^([A-Za-z0-9_-]+)$ listing.php?id=$1 [NC,L]
This part ^([A-Za-z0-9_-]+)$ says to accept any querystring parameter with uppercase letters / lowercase letters / 0-9 / underscores / hyphens
This part listing.php?id=$1 says what page will be served up to the browser. the $1 asks for the first querystring parameter and appends it to the URL like this... your-domain.com/2146_east_fifth_street
That's what you see in the URL bar instead of... your-domain.com/listing.php?id=2146_east_fifth_street
EDIT
The second part of the rewrite rule is where the "real" page is located.
If you want your url to read /profile/philip
Your rewrite rule would start with /profile/ like this...
RewriteRule ^profile/(.*)$ path/to/the/real/file/index.php?id=$1
in .htaccess $1 is a back-reference to a group, usually from a regex statement.
Each group has its own reference, so a rewrite like
RewriteRule /profile/(.*)/([0-9]) /profile/index.php/$1/$2
$1 would equal the value of (.*) that group
$2 would equal the value of ([0-9]) which can only include numbers
and so on...
It helps when id numbers and url's are dynamic. So you do not need to manually add them one by one.
Example url:
website.com/profile/idealcastle/25555
And then in php or other languages, you can pull these "url segments". Just like using a "query" parameter, ?id=simon It's much better to use proper urls for SEO purposes.

Rewriting URLs with .htaccess

I am trying to convert urls like this http://example.com/page.php?user=x&post=x into
http://example.com/blogs/user/post
This is the code I have so far, not sure if I'm missing something or have done something wrong as it haven't been successful so far.
RewriteEngine On
RewriteRule ^blogs/([a-z0-9\-]+)/([0-9]{1,11})/$ page.php?user=$1&post=$2 [L]
EDIT: After making some amendments, it returns now an error 404 error saying page.php is not found. I know for certain the file is there.
2ND EDIT: Resolved 404 issue.
The post parameter is optional as well.
user can will have a mix of A-z0-9 (no character limit)
post can only be 0-9 with and upto 11 characters in length
According to http://htaccess.madewithlove.be/, this should work:
RewriteEngine On
RewriteRule ^blogs/([a-z0-9-]+)/([0-9]+)$ /page.php?user=$1&post=$2 [L]
This transforms http://example.com/blogs/abc_123/67890 to http://example.com/page.php?user=abc_123&post=67890.
The most notable change is that you apparently can't have a leading / in the first component of the rule, but I also removed the {11} constraint on the post ID since it's unlikely that would have the intended effect.
Try
RewriteRule ^blogs/?([a-z0-9]*)?/?$ page.php?user=$1&post=$2 [NC,L]
The ? indicates that the matching is optional. Therefore for /? the slash is optional.
And for the second section after the ^blogs/?
([a-z0-9]*)?
If you remove the ? and * from the above to become like this :
RewriteRule ^blogs/?([a-z0-9])/?$ page.php?user=$1&post=$2 [NC,L]
The user will no longer become optional and must be fully matched.
Example http://blogs/John;
If you put + in place of * like below:
RewriteRule ^blogs/?([a-z0-9]+)/?$ page.php?user=$1&post=$2 [NC,L]
The user need to be matched with at least 1 character. For example : http://blogs/J
And if you put * asterisk like below:
RewriteRule ^blogs/?([a-z0-9]*)/?$ page.php?user=$1&post=$2 [NC,L]
It can match to zero length. For example : http://blogs/ . Almost like optional.
If the match failed you will get the 404 Not found error
This code provides the desired results...
RewriteRule ^blogs/([a-z0-9]+)?/?$ page.php?user=$1 [NC,L]
RewriteRule ^blogs/([a-z0-9]+)?/?([0-9]+)?/?$ page.php?user=$1&post=$2 [NC,L]
I also amended the post ID constraint as Fraxtil pointed out.

.htaccess with products (string)

i use .htaccess and i have a rule that allow me to dynamically look for product in my database.
so someone can click on a link like this one:
www.domain.com/product/modular-plastic-lunch-set.html
and see the product. Now my problem is, when i use
www.domain.com/product/Modular-Plastic-Lunch-Set.html
it does not work,
why?
here's my rules:
RewriteEngine On
RewriteRule ^product/([a-z0-9\-]+).html$ products.php?name=$1
It does not work because you don't have either A-Z or the [NC] flag.
Use of the [NC] flag causes the RewriteRule to be matched in a
case-insensitive manner. That is, it doesn't care whether letters
appear as upper-case or lower-case in the matched URI.
RewriteRule ^product/([a-z0-9\-]+).html$ php.php?name=$1 [NC,L,QSA]
or
RewriteRule ^product/([a-zA-Z0-9\-]+).html$ php.php?name=$1 [L,QSA]
I added the L:
The [L] flag causes mod_rewrite to stop processing the rule set. In
most contexts, this means that if the rule matches, no further rules
will be processed. This corresponds to the last command in Perl, or
the break command in C. Use this flag to indicate that the current
rule should be applied immediately without considering further rules.
and QSA flag:
When the replacement URI contains a query string, the default behavior
of RewriteRule is to discard the existing query string, and replace it
with the newly generated one. Using the [QSA] flag causes the query
strings to be combined.
More information about the flags at: http://httpd.apache.org/docs/2.3/rewrite/flags.html
TIP: if you are looking for products using the name, you might see delay in your query, speically if you don't have an index. You should look into this before it gets ugly.
You're only looking for lower case letters (and numbers). You need to add upper case letters.
RewriteEngine On
RewriteRule ^product/([A-Za-z0-9\-]+).html$ products.php?name=$1

Categories