Forum Moderators: phranque

Message Too Old, No Replies

Apache2.2 mod rewrite not rewriting

         

eZACKe

2:47 pm on Feb 7, 2012 (gmt 0)

10+ Year Member



Not sure why this is not working. I've checked in httpd.conf and I have this line:
LoadModule rewrite_module modules/mod_rewrite.so

And when I do phpinfo(), I see mod_rewrite in the loaded modules box.

My directory structure: I'm using Apache, so there's a htdocs directory. Inside the htdocs directory I have myProject directory. This is the root of my site. Within the my Project directory I have all the files and folders that make up my site. Sitting right in this "root" myProject directory I created a .htaccess file (making sure that it doesn't have a .txt type).

Here's the contents of this file:


RewriteEngine On


RewriteBase /

RewriteRule .* index2.php


And here's index2.php (which is located right in myProject):

<?php
echo "hiiii";
class Foo {
static public function test($classname)
{
if(preg_match('/\\\\/', $classname))
{
$path = str_replace('\\', '/', $classname);
}
else
{
$path = str_replace('_', '/', $classname);
}

if (is_readable($path.".php"))
{
require_once $path .".php";
}
}
}
spl_autoload_register('\Foo::test');

\controller\Controller::run();
?>



So no matter what I do, this index2.php file should be run, right? Well it's not. I know it's not because I'm getting no echo of hiiii unless I physically go to index2.php.

What could be going wrong?

Thanks!

EDIT:
Just want to make a note that I believe the problem is that the .htaccess file is not being read at all. Here's why I think that:


RewriteEngine On


RewriteBase /
This is garbage
RewriteRule .* index2.php



This should throw a 500 internal server error, should it not? Well it doesn't. When I go to this url:
[localhost...]

I am just getting a 404 Not Found Error screen.

g1smd

4:42 pm on Feb 7, 2012 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Rewite all requests to update the pointer to point to index2.html. That now re-matches the rule pattern and is rewritten again. You have an infinite loop.

Additionally, requests for robots.txt, images, stylesheets, and javascript files are also rewritten to be handled by your index file.

You need a better pattern than (.*) in order to limit which URL requests are rewritten. You need to exclude requests for index2.html from being rewritten.

Every RewriteRule also needs the [L] flag.

eZACKe

7:04 pm on Feb 7, 2012 (gmt 0)

10+ Year Member



Thanks for you input. I changed it around a bit, added some things and what not. It's working as far as I can tell now.

Here's what I have:

RewriteEngine On
Options FollowSymLinks

RewriteCond %{REQUEST_URI} !\.(css|js|jpe?g|png|gif|swf)$ [NC]
RewriteRule ^([^/]+)/?([^/]+)?/?([^/]+)?/? index2.php?cmd=$1&action=$2&ajax=$3 [L,QSA]


Anything that looks like it could be a problem? I've seen other people talking about mod_rewrite and SEO on this website. Is that something that I could run into problems with the way I'm doing this?

Thanks for the help!

g1smd

7:35 pm on Feb 7, 2012 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



All those optional bits mean that I wouldn't be at all sure what parts of the request land in $1, $2 and $3.

You're better off having three separate rules if the URLs can have one, two or three levels of virtual folder.

By allowing an optional trailing slash you allow two URLs to be valid for every piece of content. That's a Duplicate Content issue. Redirect "with slash" to "without" and rewrite only the "without slash" requests.

As you have things now, all requests for robots.txt will need to be handled by your index file.

If you use extensionless URLs on the site, you can make the final [^/]+ sub-pattern into [^/.]+ and that then excludes all requests with an extension. In that case you can also do away with the preceding RewriteCond, as there's no need to test for any filetypes.

[edited by: g1smd at 7:39 pm (utc) on Feb 7, 2012]

eZACKe

7:37 pm on Feb 7, 2012 (gmt 0)

10+ Year Member



About all responses needed to be handled by index, that is the point. I'm creating a Front Controller framework.

eZACKe

7:40 pm on Feb 7, 2012 (gmt 0)

10+ Year Member



But as for this part:

By allowing an optional trailing slash you allow two URLs to be valid for every piece of content. That's a Duplicate Content issue. Redirect "with slash" to "without" and rewrite only the "without slash" requests.


I'm a little confused what you mean. Could you put down a small little example, that may be more clear and help me better understand what should be done.

Thanks again for your help.

g1smd

7:41 pm on Feb 7, 2012 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Yes, but you need to filter what the front controller "sees" in terms of URL requests. Requests for robots.txt, searchengine verification files, and so on, should be handled by "real" files.

Do NOT make the mistake of adding
RewriteCond {REQUEST_URI} !-f
to any of your code. That is one of the most massively inefficient ways to do things. You can do this with RegEx patterns alone.

The pattern ending /? allows requests for example.com/foo/bar/quux and for example.com/foo/bar/quux/ to both resolve to the same content. Link only to the former. Redirect all requests for the latter to the former. Rewrite only requests for the former.

Additionally, the lack of end anchoring on your pattern opens your site to malicious linking, such as example.com/foo/bar/quux/this-product-is-junk and your server will dutifully return the content for /foor/bar/quux (as yet another duplicate) and with 200 OK status.

[edited by: g1smd at 8:00 pm (utc) on Feb 7, 2012]

eZACKe

7:55 pm on Feb 7, 2012 (gmt 0)

10+ Year Member




Yes, but you need to filter what the front controller "sees" in terms of URL requests. Requests for robots.txt, searchengine verification files, and so on, should be handled by "real" files.


Oh believe me, I know. My Front Controller is alive and well, I'm just looking for the most efficient way to do my mod_rewriting.

Thanks a lot for your input. It's very helpful.

eZACKe

8:14 pm on Feb 7, 2012 (gmt 0)

10+ Year Member




RewriteEngine On
Options FollowSymLinks

RewriteCond %{REQUEST_URI} !\.(css|js|jpe?g|png|gif|swf)$ [NC]
RewriteRule ^([^/]+)$ index2.php?cmd=$1 [L,QSA]
RewriteRule ^([^/]+)/([^/]+)$ index2.php?cmd=$1&action=$2 [L,QSA]
RewriteRule ^([^/]+)/([^/]+)/([^/]+)$ index2.php?cmd=$1&action=$2&ajax=$3 [L,QSA]


I have tried this but it doesn't seem to work. Am I correctly fixing the /? problem?

g1smd

10:17 pm on Feb 7, 2012 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Leave a blank line after every RewriteRule. This is for clarity of reading.

Add the same RewriteCond before each and every rule. It applies only to the next rule each time.

If you were to use "extensionless" URLs, you could omit the RewriteCond completely and simply replace the "last" sub-pattern in each rule with ([^/.]+)$

Alternatively if you use only the .html extension in your page URLs you could build that into the RewriteRule pattern by ending them with ([^/.]+)\.html$ for the final part of each rule pattern and completely remove the RewriteCond from each rule too.

I prefer extensionless.

eZACKe

10:40 pm on Feb 7, 2012 (gmt 0)

10+ Year Member



Ok so I believe this is what we are going for, correct?:

RewriteEngine On
Options FollowSymLinks

RewriteRule ^([^/.]+)$ index2.php?cmd=$1 [L,QSA]

RewriteRule ^([^/]+)/([^/.]+)$ index2.php?cmd=$1&action=$2 [L,QSA]

RewriteRule ^([^/]+)/([^/]+)/([^/.]+)$ index2.php?cmd=$1&action=$2&ajax=$3 [L,QSA]


And that does work when I try it out, so that's great news.

Question though: When I put in say "localhost/myProject/yes/

Then that doesn't work. It doesn't work because in my rules I'm only allowing no ending slash, just as we wanted to deal with the duplicate content issue. You mentioned linking the latter (which is having a / following the last one) to the former though. How do I achieve this link?

Thanks a lot!

g1smd

10:53 pm on Feb 7, 2012 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



You're on the right track now. One and only one URL format returns the content. You now don't have a Duplicate Content problem.

The next thing to do is add more rules to your htaccess file. This one is real simple. It will say "if requested URL ends with slash, redirect request to URL without slash" and it goes before all the rewrites. It will need a preceding RewriteCond that tests THE_REQUEST to ensure only external requests with a slash are redirected.

eZACKe

11:07 pm on Feb 7, 2012 (gmt 0)

10+ Year Member




RewriteEngine On
Options FollowSymLinks

RewriteCond %{THE_REQUEST} (/) [NC]
RewriteRule /$ $1 [L,QSA]

RewriteRule ^([^/.]+)$ index.php?cmd=$1 [L,QSA]

RewriteRule ^([^/]+)/([^/.]+)$ index.php?cmd=$1&action=$2 [L,QSA]

RewriteRule ^([^/]+)/([^/]+)/([^/.]+)$ index.php?cmd=$1&action=$2&ajax=$3 [L,QSA]


I think that's close because now localhost/myProject/yes/ worked, but at the same time I don't think it's right.

The condition takes THE_REQUEST and sees if it has a slash in it (I think). If it does it hits that RewriteRule which has a RegExp for ending in slash. If so it just drops the slash (maybe?).

g1smd

12:57 am on Feb 8, 2012 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



THE_REQUEST will always contain at least two slashes as it matches the literal GET request sent by the browser.

This will be something like:
GET /somepath HTTP/1.1


Expand your RewriteCond pattern to cater for that:
%{THE_REQUEST} ^[A-Z]{3,9}\ /somestuff/ HTTP/


In your first rule, $1 is always blank because you didn't capture anything in the RewriteRule pattern. Adjust the rule pattern to suit, perhaps
^([^/]+/)*([^/.]+)/$
which is slightly different to your other patterns. Do NOT use (.*) here.

You'll need related patterns in the condition and rule because both need to evaluate true for requests that will be redirected.

eZACKe

1:25 am on Feb 8, 2012 (gmt 0)

10+ Year Member



While I see what you're saying and you're making it seem easy, I cannot get this to work it seems.

Something new is happening though, so that's progress..right?

I'm getting an internal server error now. When I look at error.log it says RewriteCond: bad flag delimiters

RewriteEngine On
Options FollowSymLinks

RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.*/ HTTP/ [NC]
RewriteRule ^([^/]+/)*([^/.]+)/$ $1$2 [R]

RewriteRule ^([^/.]+)$ index.php?cmd=$1 [L,QSA]

RewriteRule ^([^/]+)/([^/.]+)$ index.php?cmd=$1&action=$2 [L,QSA]

RewriteRule ^([^/]+)/([^/]+)/([^/.]+)$ index.php?cmd=$1&action=$2&ajax=$3 [L,QSA]

eZACKe

1:39 am on Feb 8, 2012 (gmt 0)

10+ Year Member



I am even seeing this error when my RewriteCond doesn't have flags:

RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.*/ HTTP/
RewriteRule ^([^/]+/)*([^/.]+)/$ $1$2 [R]

g1smd

1:48 am on Feb 8, 2012 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



The
^([^/]+/)*([^/.]+)/$
should have been
^(([^/]+/)*([^/.]+))/$
here.

P.S. Never use (.*) in the "middle" of a RegEx pattern. It is greedy and ambiguous.

eZACKe

1:51 am on Feb 8, 2012 (gmt 0)

10+ Year Member



Well I have that sorted out in the time from my post to your reply, but a different problem is facing me now with this modified .htaccess:

RewriteEngine On
Options FollowSymLinks

RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.*/\ HTTP/
RewriteRule ^(([^/]+/)*([^/.]+))/$ $1 [R]

RewriteRule ^([^/.]+)$ index.php?cmd=$1 [L,QSA]

RewriteRule ^([^/]+)/([^/.]+)$ index.php?cmd=$1&action=$2 [L,QSA]

RewriteRule ^([^/]+)/([^/]+)/([^/.]+)$ index.php?cmd=$1&action=$2&ajax=$3 [L,QSA]


Now when I load up a url like localhost/myProject/yes/ I get this:
Forbidden

You don't have permission to access /C:/Program Files/Apache Software Foundation/Apache2.2/htdocs/myProject/y on this server.

It's converting the entire absolute path in the RewriteRule.

lucy24

2:00 am on Feb 8, 2012 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



I'm a little uneasy about the QSA.

There should be an absolute either-or: on one side the pretty URLs that your users see (and that all links lead to); on the other side the "real" business with query strings and php page. QSA implies that there could be both. And this in turn implies that something isn't being redirected properly at some earlier stage.

RewriteRule ^(([^/]+/)*([^/.]+))/$ $1 [R]

Ouch! What's that naked [R] doing there? If it's supposed to be a redirect, call it [R=301]. Also add the [L] flag unless you are absolutely sure you know what you are doing. [R] seems as if it would imply [L], but it doesn't. This can lead to bizarre and horrible follow-ups.

Alternatively if you use only the .html extension in your page URLs you could build that into the RewriteRule pattern by ending them with ([^/.]+)\.html$ for the final part of each rule pattern and completely remove the RewriteCond from each rule too.

Heh. Reading this whole thread in one gulp, I was just wondering how long it would be before you conceded this possibility ;)

eZACKe

2:04 am on Feb 8, 2012 (gmt 0)

10+ Year Member



Thanks lucy, I've never done this before and I'm just trying to learn good practices and attempting to get them to work. As painful as it may seem.


RewriteEngine On
Options FollowSymLinks

RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.*/\ HTTP/
RewriteRule ^(([^/]+/)*([^/.]+))/$ $1 [R=301,L]

RewriteRule ^([^/.]+)$ index.php?cmd=$1 [L,QSA]

RewriteRule ^([^/]+)/([^/.]+)$ index.php?cmd=$1&action=$2 [L,QSA]

RewriteRule ^([^/]+)/([^/]+)/([^/.]+)$ index.php?cmd=$1&action=$2&ajax=$3 [L,QSA]


So with your suggestion about the R and the L, my newest .htaccess looks like that above. Still have the Forbidden error I mentioned above though.

g1smd

2:08 am on Feb 8, 2012 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



There's multiple ways to code this, some way more efficient than others.

What you do also depends on whether you use extensionless URLs, a single extension or a mix of extensions.

It's not possible to design a single piece of code for all possibilities, nor possible to re-post code for each endless possibility and variation.

Don't use (.*) or .* in the middle of a pattern. Strip the ^ and $ off the rewriterule pattern and drop the remaining part into the rewritecond pattern in place of the .* bit.

Do make sure the redirecting RewriteRule has the domain name in the rule target as well as [R=301,L] flags.

You might need an extra
RewriteCond %{REQUEST_URI} !-d
condition on this to ensure that requests for real folders are not redirected.

[edited by: g1smd at 2:33 am (utc) on Feb 8, 2012]

eZACKe

2:13 am on Feb 8, 2012 (gmt 0)

10+ Year Member




Do make sure the redirecting RewriteRule has the domain name in the rule target as well as [R=301,L] flags.


Was this directed at my problem? If so, what exactly do you mean by this?

eZACKe

2:20 am on Feb 8, 2012 (gmt 0)

10+ Year Member




You might need an extra RewriteCond %{REQUEST_URI} !-d condition on this to ensure that requests for real folders are not redirected.



RewriteEngine On
Options FollowSymLinks

RewriteCond %{REQUEST_URI} !-d
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.*/\ HTTP/
RewriteRule ^(([^/]+/)*([^/.]+))/$ $1 [R=301,L]

RewriteRule ^([^/.]+)$ index.php?cmd=$1 [L,QSA]

RewriteRule ^([^/]+)/([^/.]+)$ index.php?cmd=$1&action=$2 [L,QSA]

RewriteRule ^([^/]+)/([^/]+)/([^/.]+)$ index.php?cmd=$1&action=$2&ajax=$3 [L,QSA]


No luck, still
Forbidden

You don't have permission to access /C:/Program Files/Apache Software Foundation/Apache2.2/htdocs/myProject/y on this server.

on localhost/myProject/yes/

g1smd

2:34 am on Feb 8, 2012 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month




Don't use (.*) or .* in the middle of a pattern. Strip the ^ and $ off the rewriterule pattern and drop the remaining part into the rewritecond pattern in place of the .* bit.

Do make sure the redirecting RewriteRule has the domain name in the rule target as well as [R=301,L] flags.

eZACKe

2:43 am on Feb 8, 2012 (gmt 0)

10+ Year Member




RewriteEngine On
Options FollowSymLinks

RewriteCond %{REQUEST_URI} !-d
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /(([^/]+/)*([^/.]+))/\ HTTP/
RewriteRule ^(myProject/([^/]+/)*([^/.]+))/$ $1 [R=301,L]

RewriteRule ^([^/.]+)$ index.php?cmd=$1 [L,QSA]

RewriteRule ^([^/]+)/([^/.]+)$ index.php?cmd=$1&action=$2 [L,QSA]

RewriteRule ^([^/]+)/([^/]+)/([^/.]+)$ index.php?cmd=$1&action=$2&ajax=$3 [L,QSA]



I'm pretty sure this is what you're implying.

But still have the exact same problem:

Forbidden

You don't have permission to access /C:/Program Files/Apache Software Foundation/Apache2.2/htdocs/myProject/y on this server.

eZACKe

2:48 am on Feb 8, 2012 (gmt 0)

10+ Year Member



Actually no, I was wrong. With the code I posted in the above post it's just not finding a file:

Not Found

The requested URL /myProject/y/ was not found on this server. Which means it's not even hitting the RewriteCond now.

lucy24

4:37 am on Feb 8, 2012 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



I got lost somewhere along the line. Are you doing all this on your real, "live" site, or on a pseudo-server at home?

You keep forgetting to add the full protocol and domain name to the rewrite:

RewriteRule ^(myProject/([^/]+/)*([^/.]+))/$ http://www.example.com/$1 [R=301,L]

But first: Simple test to see if .htaccess is being recognized and mod_rewrite is working:

RewriteRule foobar\.html http://www.example.com/rewrittenurl.html [R=301,L]

For "foobar.html" insert anything that doesn't really exist on your site. Same for "rewrittenurl.html". They just have to be different from each other.

Request foobar.html. If things are working, you will wind up on the 404 page, but your browser's address bar will say rewrittenurl.html. If it says foobar.html, we go back to the beginning. If it says or does something else entirely...

eZACKe

4:50 am on Feb 8, 2012 (gmt 0)

10+ Year Member



I'm doing this all at home. For every request it's all through localhost. My web root is in a directory which is in htdocs in my Apache Server called myProject.


You keep forgetting to add the full protocol and domain name to the rewrite:

RewriteRule ^(myProject/([^/]+/)*([^/.]+))/$ http://www.example.com/$1 [R=301,L]


Ok well I've now got it like this:

RewriteEngine On
Options FollowSymLinks

RewriteCond %{REQUEST_URI} !-d
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /(([^/]+/)*([^/.]+))/\ HTTP/
RewriteRule ^(myProject/([^/]+/)*([^/.]+))/$ http://localhost/$1 [R=301,L]

RewriteRule ^([^/.]+)$ index.php?cmd=$1 [L,QSA]

RewriteRule ^([^/]+)/([^/.]+)$ index.php?cmd=$1&action=$2 [L,QSA]

RewriteRule ^([^/]+)/([^/]+)/([^/.]+)$ index.php?cmd=$1&action=$2&ajax=$3 [L,QSA]


And I know mod_rewrite is working because all of the 3 RewriteRules underneath the one with the condition attached to it work just fine.

As for my newest .htaccess edition:


RewriteEngine On
Options FollowSymLinks

RewriteCond %{REQUEST_URI} !-d
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /(([^/]+/)*([^/.]+))/\ HTTP/
RewriteRule ^(applelearning/([^/]+/)*([^/.]+))/$ http://localhost/$1 [R=301,L]

RewriteRule ^([^/.]+)$ index.php?cmd=$1 [L,QSA]

RewriteRule ^([^/]+)/([^/.]+)$ index.php?cmd=$1&action=$2 [L,QSA]

RewriteRule ^([^/]+)/([^/]+)/([^/.]+)$ index.php?cmd=$1&action=$2&ajax=$3 [L,QSA]


It is just giving me the message
Not Found

The requested URL /myProject/y/ was not found on this server.

So now it looks like it's not redirecting here.

Why is this happening?

eZACKe

5:06 am on Feb 8, 2012 (gmt 0)

10+ Year Member



I think I just got it!

Tried switching it up just a bit. Let me know if anything is wrong with this approach, because now it is doing what I've been trying to accomplish:


RewriteEngine On
Options FollowSymLinks

RewriteCond %{REQUEST_URI} !-d
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /(([^/]+/)*([^/.]+))/\ HTTP/
RewriteRule ^(([^/]+/)*([^/.]+))/$ http://localhost/myProject/$1 [R=301,L]


RewriteRule ^([^/.]+)$ index.php?cmd=$1 [L,QSA]

RewriteRule ^([^/]+)/([^/.]+)$ index.php?cmd=$1&action=$2 [L,QSA]

RewriteRule ^([^/]+)/([^/]+)/([^/.]+)$ index.php?cmd=$1&action=$2&ajax=$3 [L,QSA]


Notice didn't put myProject in the RegExp, just in the redirect part.

lucy24

5:31 am on Feb 8, 2012 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



D'oh! /myProject/ is either part of the host, or part of the URL, but it can't be both. That is, of course it can be-- you're perfectly welcome to have a directory called www.example.com/myProject/myProject/myProject/myProject/myProject/filename.php if you're feeling masochistic-- but that's not what you're doing here.

So if you redirect to /index.php you will wind up at either localhost/myProject/index.php or localhost/index.php but not both.

localhost? Really? Mine insists on localhost:8080. Plain "localhost" is what the text editor's HTML preview says when I'm not going through MAMP.
This 34 message thread spans 2 pages: 34