Regex for htaccess to match pattern unless directory exists - regex

I'm using regex in a htaccess file to catch /[username] and re-direct this to a username page, for example, mywebsite.com/john will forward to mywebsite.com/username?u=john. This works, but I now want to exclude anything that matches a directory which exists. So, if someone goes to mywebsite.com/sign-up, this is EXCLUDED for the re-direction, because that directory (/sign-up) exists. Is that possible, and is it normal practice? Thank you.
Edit: Ideally I don't want to have to exclude every existing directory manually. I'd like it to be automatic for all existing directories.

Use a rewrite condition before it. !-f means not an existing file, !-d means not an existing directory.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([a-z]+)$ username?u=$1 [L]

Related

.htaccess rewriterule "loop"

I currently have this line in my .htaccess file making URLs "pretty" for pages.
RewriteRule ^([A-Za-z0-9-]+)/$ /directory/?type=page&title=$1 [L]
However, I sometimes have sub-pages (/page/sub-page/sub-page/), yet this line only supports one level (/page/).
How can I alter this code to support sub-pages (any amount) and make the title variable something like:
&title=page/sub-page/sub-page
/ being the seperator.
I know that this will definitely be a huge help:
RewriteRule loop in .htaccess not working
However, due to my lack of knowledge with regex and mod-rewrite, I don't know how to make it properly work with what I already have.
Try this:
AllowEncodedSlashes On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^([/a-z0-9-]+)/?$ /directory/?type=page&title=$1 [NC,B,L]
Don't worry about A-Z because of the NC flag.
After doing some regex research, and doing some testing, it seems like this is the answer to my problem:
RewriteRule ^(([a-zA-Z0-9-]+)/(([a-zA-Z0-9-]+)\/?)+)$ /directory/?type=page&title=$1 [L]
I altered my previous code and allowed support for multiple sub-directories. Then I placed it into a capture group and placed that data into the title variable.

How to force mod_rewrite to skip real files

I have an application that routes all requests through index.php.
Here's my setup:
I access the application at http://www.example.com/sample/
On the filesystem, the application sits in /home/chris/www/sample/
The web-accessible directory of the application lives at /home/chris/www/sample/app/web.
The DocumentRoot is set to /home/chris/www
/home/chris/www/sample/.htaccess is configured as follows:
RewriteEngine on
RewriteCond %{REQUEST_URI} ^/sample/(.+)$
RewriteCond %{DOCUMENT_ROOT}/sample/app/web/%1 -f
RewriteRule ^/sample/(.*)$ %{DOCUMENT_ROOT}/sample/app/web/%1 [L]
RewriteRule ^(.+)$ index.php?ws_page=$1 [L,NC,QSA]
I've tried multiple configurations, but haven't figured out why I keep getting 404's on calls to "real" files.
Sample 404:
`http://www.example.com/sample/_css/960/reset.css`
(which I want to have rewritten to /home/chris/www/sample/app/web/_css/960/reset.css)
EDIT
I have already tried
RewriteCond %{REQUEST_URI} !-f
RewriteCond %{REQUEST_URI} !-d
RewriteCond %{REQUEST_URI} !-l
and they did not work, because the %{REQUEST_URI} prefix does not match the filesystem prefix of these files.
EDIT 2
To clarify, I want requests of the form
`http://www.example.com/sample/foo/bar`
to be rewritten to the filesystem object /home/chris/www/sample/app/web/foo/bar, but only if that filesystem object exists.
One of the biggest bear-pits in reading the mod_rewrite documentation in the difference in behaviour in a system (that this the main and vhost configs that apache reads on start-up and those directive processes in a per-directory context. See the Per-directory Rewrites subsection of the RewriteRule documentation for further details.
When using the rewrite engine in .htaccess files the per-directory prefix (which always is the same for a specific directory) is automatically removed for the RewriteRule pattern matching and automatically added after any relative (not starting with a slash or protocol name) substitution encounters the end of a rule set. See the RewriteBase directive for more information regarding what prefix will be added back to relative substitions.
and later
The removed prefix always ends with a slash, meaning the matching occurs against a string which never has a leading slash. Therefore, a Pattern with ^/ never matches in per-directory context. What you've done is to code around this.
Incidentally, this is why it is always safer to specify a RewriteBase, as the engine gets this wrong without this.
BTW, this second quote can be wrong because the prefix add-back occurs at the then of the rule set execution, and if you have a successful rule which is to a different relative branch (that is the target starts with a /) but without the [L] flag set, then the engine falls through to any subsequent rules with a leading / set. Most confusing, so my general advice is never rely on fall-through rules. Always force an immediate internal or external redirect on a successful substitution in a per-directory context as the engine has this and a couple of other bugs in this fall-through processing.
Have your code like this:
Options +FollowSymLinks -MultiViews
# Turn mod_rewrite on
RewriteEngine On
RewriteBase /sample
RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s/+sample/(.+)\s [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond /home/chris/www/sample/app/web/%1 -f [NC]
RewriteRule ^ /sample/app/web/%1 [L]
# If the request is not for a valid file
RewriteCond %{REQUEST_FILENAME} !-f
# If the request is not for a valid symlink
RewriteCond %{REQUEST_FILENAME} !-l
# If the request is not for a valid directory
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)$ index.php?page=$1 [L,QSA]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
These two rules will skip files (-f) and directories (-d) which actually exist.
Mad bonus points to whomever can explain to me why my the EOS anchor ($) was to blame for the RewriteRule not working.
I wound up with this:
RewriteEngine on
RewriteCond %{REQUEST_URI} ^/sample/(.+)
RewriteCond %{DOCUMENT_ROOT}/sample/app/web/%1 -f
RewriteRule ^(.*)$ app/web/$1 [L,NC,QSA]
RewriteCond %{REQUEST_URI} !(^/sample/app/web)
RewriteRule ^(.+)$ index.php?ws_page=$1 [L,NC,QSA]
Many thanks to all who helped me diagnose this weirdness.

Rewrite URL, regex help

I am using the following Rewrite URL:
RewriteRule /([^/?.]+) /somedir/somefile.aspx\?Name=$1 [NC,L]
which works great for my use, but I need to restrict it to only act on text that does not contain a filename... for example, if I use the url www.somedomain.com/SomeName it works fine, but it also fires if I use www.somedomain.com/TestPage.aspx
So I am not sure if I need an additional Rewtire rule, or if the current one can be modified to disallow any text with an extension, for example.
Any help with this regular expression would be greatly appreciated.
try adding this before the rewrite rule:
RewriteCond %{REQUEST_FILENAME} !-f
this condition check if the file requested exists and returns true if it doesn't (as it's negated with a !).
if you need not to fire the rule also for the directories, then add also this line:
RewriteCond %{REQUEST_FILENAME} !-d

htaccess regex help

Hi
I need some help (the solution and the explanation please)
In my application there is a php page called page.php which gets a parameter page by GET and delivers content accordingly.
What I want is:
Make this page the entry point, catch all and redirect it to page.php.
Use the URI as the page parameter value. (domain.com/string will become domain.com/page.php?page=string)
When I used ^(.*)$ page.php?page=$! it was working, except it also manipulated every resource that was called (js, css, images, etc..)
Thanks
You need to add RewriteCond statements to avoid any existing files.
RewriteEngine on
RewriteBase /
# Allow files that exists to bypass rewrites
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ page.php?page=$1 [L,QSA]

.htaccess rewrite rule preventing infinite loop

I have a directory named dollars that contains a file index.php. I would like for the url http://localhost/dollars/foo to translate to dollars/index.php?dollars=foo. This is the .htaccess file that I currently have in the dollars directorty:
Options +FollowSymLinks
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !^index\.php
RewriteRule ^(.+)$ index.php?dollars=$1 [L]
The idea being that any request other than a request to index.php should use the RewriteRule.
However, this does not work.
I've been looking for a while trying to figure out how to create the redirect I want, but I don't even know if I'm on the right track. Regex were never my thing. Thanks for any help!
A often-used solution for rewrites is to just check that the path being requested doesn't point to an actual file/directory, and rewrite it if it doesn't - since the rewritten URL will then point to an actual file, no loop occurs.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
Amber's answer should get things working for you, but I wanted to address what was going wrong in your specific case. You had the right idea, but %{REQUEST_FILENAME} actually ends up being a fully qualified path here, so your regular expression should check for index.php at the end, not the beginning.
Consequently, you should find that this will work more like you expect:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !index\.php$
RewriteRule ^(.+)$ index.php?dollars=$1
Swapping out the RewriteConds for those that Amber mentioned would be less problematic if you added other things to that directory, though, so I'd recommend using that in place of this anyway.