URL rewrite checks for static files then rewrites to index.php - .htaccess

OK, I'm pants at rewrite rules in .htaccess files!
My desired scenario is (using the URL http://doma.in/ as an example):
First check to see if an index.html file exists in the /public sub-dir; if it does, serve it
If it did not; serve (rewrite to) index.php
To expand on my example, say we requested the URL http://doma.in/js/foobar.js:
First check to see if an foobar.js file exists in the /public/js sub-dir; if it does, serve it
If it did not; serve (rewrite to) index.php?controller=js%2Ffoobar.js
That would cover static files but I also need URLs like http://doma.in/foo:
First check to see if an foo file exists in the /public sub-dir; if it does, serve it
If it did not; serve (rewrite to) index.php?controller=foo
And a URL http://doma.in/foo/bar:
We can assume the file foo/bar does not exists in the /public sub-dir as files can't be named like that.
So serve (rewrite to) index.php?controller=foo&action=bar
I'm sure if this complicated (for me) bit is covered then I can work query-strings into the occasion too; so http://doma.in/foo/bar/foo/bar would serve index.php?controller=foo&action=bar&querystring=foo%2Fbar.
I'd also like to make sure that a trailing slash is handled the same as if a trailing slash was omitted, for example: http://doma.in/foo/bar/foo/bar and http://doma.in/foo/bar/foo/bar/
I'll handle 404s from within my app as if the file did not exist, it would redirect to index.php which does exist - I'm happy with this unless you've a better solution :)
I really hope all this makes sense as I've been looking to find a solution to this scenario all day now and this is all I have:
Options +FollowSymLinks
RewriteEngine on
RewriteBase /
#RewriteBase /prompt-v3/
#RewriteCond %{REQUEST_URI} ^/prompt-v3/(.*)$
RewriteCond $1 !^public
RewriteRule ^(.*)$ public/$1 [R]
The commented-out lines deal with a sub-dir when on a remote host. So far I can redirect to the /public sub-dir if the file exists there and that's about it.
Thank you everyone for your help!

Options +FollowSymLinks
RewriteEngine on
RewriteBase /
#RewriteBase /sub-dir/
#RewriteCond %{REQUEST_URI} ^/sub-dir/(.*)$
RewriteRule ^index.html$ $1 [L,R=301]
RewriteCond $1 !^public
RewriteCond $1 !^lib
RewriteRule ^(.*)$ public/$1 [L]
RewriteCond $1 ^public/$
RewriteCond %{REQUEST_FILENAME}/index.html !-f
RewriteRule ^(.*)$ lib/bootstrap.php [L]
RewriteCond $1 !^public/$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond $1 ^public/(.*)$
RewriteRule ^(.*)$ lib/bootstrap.php?path=%1 [L]
This will look for an index.html file in the public directory and if it does not exist rewrite the URL to lib/bootstrap.php. it in fact checks for any request as a static file in the public directory first and deals with canonicalisation too.

Put this .htaccess in your document root
<ifModule mod_rewrite.c>
RewriteEngine on
# For /js/foobar.js (/js/*)
RewriteRule ^js/(.*)$ /public/js/$1 [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^public/(.*)$ index.php?controller=$1 [NC,L]
# For foo/bar (/*/*?*)
RewriteRule ^(.*)/(.*)$ /public/$1/$2 [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^public/(.*)/(.*)$ index.php?controller=$1&action=$2&querystring=%{QUERY_STRING} [NC,L]
</IfModule>

Related

Redirect to subfolder with same name on localhost

I have a webproject saved in a "base" folder of the domain "example.com" which contains a main.php and several subfolders. The second part of the code below redirects all requests (except main.php itself and page404.php) to this main.php and hands over the originally requested URL in the variable "path".
In addition there is a first part which redirects all requests of pages of the baseurl to a subfolder "folder1". So in the end the request of
www.example.com/somepage.php
will lead to
example.com/main.php?path=www.example.com/folder1/somepage.php
(Requests to other subfolders shall only be redirected to the main.php. So www.example.com/somefolder/somepage.php will lead to example.com/main.php?path=www.example.com/somefolder/somepage.php - without adding "folder1".)
The code below actually does what I want:
ErrorDocument 404 /page404.php
Options -Indexes
DirectoryIndex index.php
<IfModule mod_rewrite.c>
RewriteEngine on
#first part: redirect to folder1/
RewriteCond %{HTTP_HOST} ^(www.)?example.com$
RewriteCond %{REQUEST_URI} !^/*
RewriteCond %{REQUEST_URI} !^page404*
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ folder1/$1
RewriteCond %{HTTP_HOST} ^(www.)?example.com$
RewriteRule ^(/)?$ index.php
#second part: redirect to main.php
RewriteCond %{REQUEST_FILENAME} (.*)\.php [NC]
RewriteCond %{REQUEST_URI} !main\.php
RewriteCond %{REQUEST_URI} !page404\.php
RewriteRule ^([^?]*)$ /main.php?path=$1 [NC,L,QSA]
</IfModule>
But I have two questions:
Side question: I have the feeling that actually redirecting to "folder1" is way to complicated (even though it works) when I only want to add the "folder1" to the path variable in case a file of the base folder is called. Can you show me a better way to archieve this?
Main question: I have the same project on a localhost where the main folder is named "folder1" which contains the folder "folder1". So there the request of htttp://localhost/folder1/somepage.php shall lead to htttp://localhost/folder1/main.php?path=htttp://localhost/folder1/folder1/somepage.php (I replaced "http" by "htttp" to avoid automatic link recognition of SO) - How do I have to change the code above to have it working in the "localhost/folder1" scenario?
This stuff can be simplified:
ErrorDocument 404 /page404.php
Options -Indexes
DirectoryIndex index.php
RewriteEngine on
# ignore main.php, page404.php OR any files/directory for any rules below
RewriteCond %{REQUEST_URI} ^/(main|page404)\.php
RewriteRule ^ - [L]
#first part: /folder1/path
RewriteRule ^([^/]+?\.php)$ main.php?path=folder1/$1 [L,QSA]
#second part: rewrite to main.php
RewriteRule ^(.+?\.php)$ main.php?path=$1 [L,QSA]

How to make RewriteRule work only if URL contains specific string?

I need to add RewriteRule which works only if there is a certain string in the URL, otherwise I need to load the content from another folder. If the URL contains the string test, I need to send it to index.php as a parameter, else the content should be loaded from the directory folder.
For example: The root folder of the project is new_project. If the URL is http://localhost/new_project/test/something/, then I need to send test/something/ to index.php as parameter. Else if the URL is something like http://localhost/new_project/something/, then I need to load the content from directory/something folder.
Following is the .htaccess file I've written so far:
Options +FollowSymLinks
RewriteEngine on
# Force Trailing Slash
RewriteCond %{REQUEST_URI} /+[^\.]+$
RewriteRule ^(.+[^/])$ %{REQUEST_URI}/ [R=301,L]
# Send request via index.php (again, not if its a real file or folder)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?/$1 [L]
# Serve other requests from the directory/ folder
RewriteRule ^(.*)$ directory/$1 [L]
What needs to be changed in the above .htaccess file so that the occurrence of test string in the URL passes the string after the string test along with the string test to index.php and if the URL doesn't contain the string test then loads the content from the directory folder?
You can test for the test/ inside the RewriteRule itself. Place the more specific rewrite rule before the "catch-all" directory/ rewrite rule.
Options +FollowSymLinks
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} /+[^\.]+$
RewriteRule ^(.+[^/])$ %{REQUEST_URI}/ [R=301,L]
# All requests starting with `test/` go to index (without the `test` part).
RewriteRule ^test/(.*)$ index.php?/$1 [L] # Not sure how GET parameters starting with `?/` behave.
# All others go to directory. Assuming not a valid file or dir.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ directory/$1 [L]

htaccess to redirect all files to index.php apart from a specific subdirectory

I have a site in which all requests should go to index.php, apart from those in a specific subdirectory, which should go to subdirectory/index.php.
I would like the directory path to be translated to a query string for use in the subdirectory index page.
I really have very little idea about htaccess files and I'm sure this question has been answered a hundred times, but I can't work out what to search for to get an answer.
So - this is what I would like to happen under these conditions...
RULE 1
www.example.com/anything_or_nothing <goes to> /index.php
www.example.com/anything/anything_else <goes to> /index.php
RULE 2
www.example.com/subdirectory/ <goes to> /subdirectory/index.php
RULE 3
www.example.com/subdirectory/some_other_directory/ <goes to> /subdirectory/index.php?a=some_other_directory
This is what I have currently. It doesn't work - At least, RULE 1 does work, RULE 2 works (though I think this is only because the physical /subdirectory exists and the index.php is served as a default.) RULE 3 doesn't work.
Options All -Indexes
RewriteEngine On
RewriteBase /
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !^/?timeline/
#RULE 1
RewriteRule ^.*$ ./index.php
#RULE 2
RewriteRule ^/sub.*$ /sub/index.php
#RULE 3
RewriteRule ^/sub/([^/\.]+)/?$ /sub/index.php?a=$1 [L,NC]
I have been unable to get a .htaccess file working in the subdirectory, so I'd like the rules all to be in the root .htaccess file.
I have cobbled this .htaccess together from other sites, so I do apologise for my level of ignorance, but I'm just not sure where to go...
Thank you in advance.
ADDITIONAL INFO>>>>>>>>
Other things I have tried.
This
RewriteRule ^/sub/([^/\.]+)/?$ /sub/index.php?a=$1 [L,NC]
RewriteRule ^/sub.*$ /sub/index.php
RewriteRule ^.*$ ./index.php
Stops all rules from working.
This:
RewriteRule ^.*$ ./index.php
RewriteRule ^/sub/([^/\.]+)/?$ /sub/index.php?a=$1 [L,NC]
RewriteRule ^/sub.*$ /sub/index.php
Seems to behave as the original example.
As you answered yourself the second rule is unecessary.
# Don't rewrite if file already exists to prevent rewriting images, scripts etc
RewriteCond %{REQUEST_FILENAME} -d
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule .* - [L]
# Rewrite sub/anything to sub/index.php?a=anything
RewriteRule ^sub/([^/]+)$ sub/index.php?a=$1 [L,NC]
# Fallback all unknown requests to index.php
RewriteRule .* index.php [L,NC]
A note of warning: this approach will completely hide all natural 404 errors as you're rewriting non-existing files to index.php.

htaccess rewrite / remove parent dir

there's been similar posts about this but I can't quite seem to find what I need.
I want my .htacess to rewrite "up one level".
The Url would be somethign like
http://www.site.com/variable_dir/
or
http://www.site.com/variable_dir/sub_dir
I need that to basically rewrite the request to
http://www.site.com/
or
http://www.site.com/sub_dir
I DO want the URL to still show the original
http://www.site.com/variable_dir/
or
http://www.site.com/variable_dir/sub_dir
I currently have
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php [L]
This redirects to where I want, but this changes the URL to
http://www.site.com/
or
http://www.site.com/sub_dir
which I don't want.
I know it's simple but I just can't seem to get there.
The rule below woule rewrite http://www.site.com/variable_dir/ to http://www.site.com/ and http://www.site.com/variable_dir/sub_dir to http://www.site.com/sub_dir
RewriteEngine on
RewriteBase /
#for a request to /variable_dir
RewriteCond %{REQUEST_URI} ^/variable_dir/(.+)$
#rewrite it to directory without variable_dir
RewriteRule . /%1 [L]
Edit:
If the directory is not literally variable_dir, the rule above will not work. However, if you have a short list of directories, you could enumerate them as below.
RewriteEngine on
RewriteBase /
#only apply if this directory does not exist
RewriteCond %{REQUEST_FILENAME} !-d
#for any direcory enumerated here
RewriteCond %{REQUEST_URI} ^/(variable_dir|dir2|dir3|etc)/(.+)$
#rewrite it to directory without variable_dir
RewriteRule . /%2 [L]
If not, then ideally the directories would all have something in common so you could limit what the rule affects. If you want a completely variable dir, nothing in common, I don't recommend it, but you can try
RewriteEngine on
RewriteBase /
#only apply if this directory does not exist
RewriteCond %{REQUEST_FILENAME} !-d
#skip any top level directory
RewriteCond %{REQUEST_URI} ^/[^/]+/(.+)$
#rewrite it to directory without variable_dir
RewriteRule . /%1 [L]
Edit:
Finally if the trailing slash is optional, as in the example in your comment, change the RewriteCond and rule above to be
#skip any top level directory, optional trailing slash
RewriteCond %{REQUEST_URI} ^/[^/]+(/(.+))?$
#rewrite it to directory without variable_dir
RewriteRule . /%2 [L]

Logical AND in htaccess modrewrite?

This is my htaccess file
RewriteBase /
RewriteCond %{HTTP_HOST} ^example.com [NC]
RewriteRule ^(.*)$ http://www.example.com/$1 [L,R=301]
RewriteCond %{REQUEST_URI} !^/chat/
RewriteCond %{REQUEST_URI} !^/m/
RewriteCond %{REQUEST_URI} !^/__admin/
RewriteCond %{REQUEST_URI} !^/gzip_headers.php
RewriteCond %{REQUEST_URI} !^/phpfreechat/
RewriteCond %{REQUEST_URI} !^/_temp/
RewriteRule ^.+\.php$ index.php [L]
RewriteRule ^.*\.css gzip_headers.php [L]
RewriteRule ^.*\.js gzip_headers.php [L]
RewriteRule ^classifieds/ /index.php [L]
RewriteCond %{REQUEST_URI} !^/movies/.
RewriteRule ^movies/ /index.php [L]
RewriteCond %{REQUEST_URI} !^/games/.
RewriteRule ^games/ /index.php [L]
RewriteRule ^jntu/ /index.php [L]
RewriteRule ^news/ /index.php [L]
My idea behind this basically is,
forward everything to public_html/index.php (except some directories)
forward all js and css to gzip file, ( i am doing this basically because im not jsut gzipping them but also compressing in tha phpfile)
the problem is when I load images from subdirectories the are redirected to index.php as well, so just creating conditions for those directories and storing images in them like RewriteCond %{REQUEST_URI} !^/games/.
I would like to make it simple to do stuff like this
forward everything to index.php (except some conditions on top)
forward css and js to gzip file
load images and flash and some other mime types straight away only if they exists. (jpg|gif|png|swf|flv|mp4|3gp|mp3|zip|rar|exe)
Something like logical AND REQUEST_URI and -f flag I guess
Try these rules:
RewriteCond %{HTTP_HOST} =example.com [NC]
RewriteRule ^ http://www.example.com%{REQUEST_URI} [L,R=301]
RewriteRule .*\.(js|css)$ gzip_headers.php [L]
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule .+\.(jpg|gif|png|swf|flv|mp4|3gp|mp3|zip|rar|exe)$ - [L]
RewriteCond %{REQUEST_URI} !^/(gzip_headers|index)\.php$
RewriteCond %{REQUEST_URI} !^/(chat|m|__admin|phpfreechat|_temp)/
RewriteRule ^.+\.php$ index.php [L]
I'm not sure why your images are being redirected if your rule only redirects URIs ending with '.php'. That should exclude all other file extensions from the rule.
I'm also not sure what you mean by needing 'logical and'. When you have a number of RewriteCond lines before a RewriteRule those conditions are ANDed together and the rule is only applied if they all are true.
You can't use modrewrite to check for the existance of files and say "if the file exists, don't apply any rules, just serve up the file".
I think the best solution would be to either use a single top-level directory called 'static' or 'images' where you put all your files and exclude it from the rules, or have a wider-matching rule.
So for example you could make 'static' or 'images' a special directory name and exclude any url that contains .*/images/.* from the rules. Then /something/images/image.jpg and /something/else/images/image.jpg would both be excluded and the file would be served up.
Another hacky way would be to serve the files up from PHP. So in PHP you would translate $_SERVER['REQUEST_URI'] into a filename and see if it exists. If it does, you can write the file contents to the PHP output stream, although this won't be as efficient as leaving it up to Apache, and actually I really would not recommend it.
But like I said before, if your rule is only matching files that end with .php then your images should not be getting redirected. I would figure out why this is happening first. There is a way to turn on debug logging for mod_rewrite but you'll have to Google that.

Resources