Apache mod_rewrite is removing slashes and generally ignoring my rules - regex

I'm at my wit's end, Stack Overflowers. Trying to do what I thought was a simple rewrite rule to replace slashes in the URL with tilde, then add a ".html" at the end.
So my .htaccess is thus:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^/(.+)/(.+)$ $1~$2 [N]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^/([^/]+)$ $1.html [L]
Basically I'm running a repeated rule to replace all slashes with tildes one at time, then my final rule adds the ".html" -- because all our web files need to be in one folder (client request--silly, I know).
I've tested the pattern "part-one/part-two/part-three" here: http://martinmelin.se/rewrite-rule-tester/ and it only works if I chop off the initial slash and remove the rewrite conditions (which makes no sense b/c no filename I put in there should exist on that server), but that's not the case on my local server.
It should eventually read the file "part-one~part-two~part-three.html" but when I look at the Apache error log on my local machine, I get this:
File does not exist: /path/to/website/part-one
So it basically chops off the final two parts and never tries to add a ".html" -- so what on earth is going on?? Please help, mod_rewrite gurus!!

The reason why it wants you to remove the leading / is because the rewrite engine strips off the prefix (the leading slash of an URI) before it runs them through rules in an htaccess file. If you were using apache 1.3 or if the rules were in a non-per-directory context in the server or vhost config, then you'd need the leading slash in the rule's pattern:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)/(.+)$ /$1~$2 [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^([^/]+)$ /$1.html [L]
Additionally, you probably don't want the N flag, as you want rewrite to stop immediately in its current iteration. Also, a condition which first checks if the .html actually exists before you rewrite will prevent 500 internal server errors.

Related

mod_rewrite .htaccess rewrite match with or without file extension

I'm using a php script to match request links to a site. I'm currently matching on 'jcole/' and 'jcole'. However I'd like to be able to match on "jcole"(.php|.html|.htm), "jcole/", and "jcole". I'd like the match to be agnostic of whatever the file extension maybe and also not care if there are periods in the name.(for example I'd like to be able to match on "j.cole")
Currently I have my .htaccess configured like so:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*\.html)$ /loadlink.php=link=$1 [L,QSA]
RewriteRule ^(.*)/?$ /loadlink.php?link=$1 [L,QSA]
You are way better off doing all of this from within php. Regex is not going to be able to do everything you want, especially having to deal with arbitrary periods in the name. So you'd just want the second rule:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]+)/?$ /loadlink.php?link=$1 [L,QSA]
Note that rewrite conditions only apply to the immediately following RewriteRule.
This will send everything to the "link" parameters, only removing an arbitrary trailing slash if it exists. It's up to the loadlink.php script to get rid of the .php or random periods in the name.

URL rewriting with Apache .htaccess with two matches

Sorry about this question - I know this is asked a lot, but this case is a little more distinct (for me at least).
I have the following content in my current .htaccess:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]+)/?$ index.php?mode=$1 [QSA,L]
This rewrites all URLs that are from index.php and have the mode parameter to a simply URL where the mode's content becomes the main part of the URL, like this:
http://someurl.com/index.php?mode=mymode
Becomes:
http://someurl.com/mymode
This is exactly what I need. But I also need to extend this and be able to achieve the same effect with another file of mine named user.php. The case is almost the same:
http://someurl.com/user.php?action=hello
Becomes:
http://someurl.com/hello
I have no idea how to achieve the second part without conflincting with the first one.
I'm kinda stuck on this one.
Keep your rules like this:
# new rules for /user.php?action=hello
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^user/([^/]+)/?$ user.php?action=$1 [QSA,L]
# existing rule for /index.php?mode=mymode
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]+)/?$ index.php?mode=$1 [QSA,L]
PS: Also better to use absolute path in your css, js, images files rather than arelative one. Which means you have to make sure path of these files start either with http:// or a slash /.

What is the error in this .htaccess?

Using mod_rewrite, I want to look for all requested files in an assets directory, and otherwise fallback to index.php for API calls. This is my .htaccess.
RewriteEngine on
RewriteRule ^.+\.[^/]+$ assets/$1 [L]
RewriteRule .* index.php
Asset files are determined by whether the last last url segment has a file extension, which means a dot without following slashes. I already tested the regex at regexpal and it seems to work fine.
Unfortunately, all request result in a 500 Internal Server Error using these rewrite rules. I know that mod_rewrite is set up correctly, since omitting the second line works as expected.
Try these rules:
RewriteEngine on
# rewrite to assets/file if file exists in assets dir
RewriteCond %{DOCUMENT_ROOT}/assets/$1 -f
RewriteRule ^(.+?\.[^/]+)/?$ assets/$1 [L]
# otherwise rewrite to index.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule !^assets/ index.php [NC,L]
You need to add a condition to prevent the rewrite engine from looping:
RewriteEngine on
RewriteCond %{REQUEST_URI} !index\.php
RewriteRule ^.+\.[^/]+$ assets/$1 [L]
RewriteCond %{REQUEST_URI} !index\.php
RewriteRule .* index.php
The rewrite engine loops until the URI stops changing, and since .* matches index.php as well, it'll continue to loop through that rule until the internal recursion limit is reached you get a 500 error.
Additionally, you can add conditions that won't reroute existing files or directories:
RewriteEngine on
RewriteCond %{REQUEST_URI} !index\.php
RewriteRule ^.+\.[^/]+$ assets/$1 [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .* index.php

.htaccess regular expression issue

I still have no answer about this so I'm posting it here.
I want to match an url in the form of root/language/sub/.../document in a .htaccess file and then rewrite it as root/sub/.../document.php?lang=language
Im close to hit but it seems my regexp doesn't 'catch' the input url. Here it is :
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond ^[a-z]{2}.*$/%{REQUEST_FILENAME}\.php -f
RewriteRule ^([a-z]{2})/(.*)$ $2.php?lang=$1
Can someone point me out what is wrong here ? I'm no expert in regexp nor apache rewrites.
Tyvm
* EDIT *
root stands for domain ie mydomain.net
Here are a few examples :
mydomain.net/fr/contact
should be rewriten to
mydomain.net/contact.php?lang=fr
and
mydomain.net/en/articles/view
should be rewriten
mydomain.net/articles/view.php?lang=en
etc...
I believe you are looking for this configuration:
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} ^(.*/|)(en|de|fr)/(.*)$ [NC]
RewriteCond %1%3.php -f
RewriteRule ^(.*/|)(en|de|fr)/(.*)$ $1$3.php?lang=$2 [NC,QSA,L]
Explanation:
RewriteCond %{REQUEST_FILENAME} !-d
Checks if requested url is not a directory. If yes, no rewriting will be processed.
RewriteCond %{REQUEST_FILENAME} ^(.*/|)(en|de|fr)/(.*)$ [NC]
Checks if url contains /xx/ part inside, where xx is one en, de or fr. Flag [NC] allows uppercase and lowercase charactes, so for example EN or Fr will be accepted. If there is no such "language" part in the url, no rewriting will be processed.
RewriteCond %1%3.php -f
Checks if %1%3.php file exists, where %1 is (.*/|) and %3 is (.*) matches from the previous RewriteCond ^(.*/|)(en|de|fr)/(.*)$. If such php file does not exist, no rewriting will be processed.
RewriteRule ^(.*/|)(en|de|fr)/(.*)$ $1$3.php?lang=$2 [NC,QSA,L]
In the RewriteRule left condition will be matched if it came to this line, as it was already checked with RewriteCond, so now it will process rewriting to php file, adding lang part, but because there is also [QSA] flag, it will keep also other GET parameters, so lang will be added to existing parameters. Flag [L] says it is last rewriting rule that should apply and no more rewriting will be processed with this url.
Well I'm not sure what root is doing in there, have you tried
RewriteRule ^root/([a-z]{2})/(.*)$ root/$2.php?lang=$1
What's wrong is the second RewriteCond. But your question is vague. If you mean you're trying to convert
root/foo/sub/.../something.php
to
root/sub/.../something.php?lang=foo
then start fidgeting with this:
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^root/([^/]+)/sub/(.*)/%{REQUEST_FILENAME}$ root/sub/$2/%{REQUEST_FILENAME}?lang=$1

.htaccess issue, existing .php files and search.php

I'm new to playing with .htaccess for nicely formatted urls and I'm just not sure I'm doing it right.
My current .htaccess file looks like this:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^search/(.*) search.php?query=$1 [L]
RewriteRule !\.(gif|jpg|ico|css|js|txt|xml|png|swf)$ index.php
What I want is for mysite.com/home/56/page-title to go to index.php where I filter out the number and load the correct index page, which works fine.
Before that, I want to check if the url is pointing at search.php, and if so redirect to mysite.com/search/the-search-term, this also works fine.
What isn't working is if I try to visit a specific .php file say mysite.com/control_panel.php - it just takes me to index.php, but I thought that the following line stopped that from happening?
RewriteCond %{REQUEST_FILENAME} !-f
If someone could explain it to me that would be great :)
Thanks!
1. Order of rules matters
2. RewriteCond directives will only be applied to the ONE RewriteRule that follows it. If you need to apply the same conditions to multiple rules you have to write them multiple times or change the rewrite processing logic (multiple approaches available).
Try this one:
RewriteEngine On
RewriteRule ^search/(.*) search.php?query=$1 [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule !\.(gif|jpg|ico|css|js|txt|xml|png|swf)$ index.php [L]