htaccess rewrite not working for multiple files in main directory - apache

The title does not fully describe the issue, but I have rewrite rules setup to go to three different files which exist in the main directory: api.php, admin.php, and index.php
Here is my .htaccess
RewriteEngine on
RewriteCond $1 ^(api)
RewriteRule ^(.*)$ /api.php/$1 [L]
RewriteCond $1 ^(admin)
RewriteRule ^(.*)$ /admin.php/$1 [L]
RewriteCond $1 !^(index\.php|admin\.php|api\.php|admin|api|_|robots\.txt)
RewriteRule ^(.*)$ /index.php/$1 [L]
For /admin and /api I get a 500 Internal Server Error. I am not sure why that happens, yet if I put those php files within a folder like /_ and edit the .htaccess to match it then it rewrites without an error. Am I limited on the number of main directory file redirects I can do? Or did I am I missing something?
My main goal is:
Redirect all /api requests to /api.php/whatever/is/after/here
Redirect all /admin requests to /admin.php/whatever/is/after/here
Redirect all other requests apart from the exceptions to /index.php/whatever/is/here

Try with:
RewriteEngine on
# skip all files and directories from rewrite rules below
RewriteCond %{REQUEST_FILENAME} -d [OR]
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [L]
RewriteRule ^(api.*)$ /api.php/$1 [L]
RewriteRule ^(admin.*)$ /admin.php/$1 [L]
RewriteCond $1 !^(index\.php|admin\.php|api\.php|admin|api|_|robots\.txt)
RewriteRule ^(.*)$ /index.php/$1 [L]

I found that I simply had to be more specific in my regex match. Previously I was matching anything that started with "admin" or "api" (eg. admins-at-the-new-school) which actually I was unaware of and would cause problems in the future anyways. I changed my regex and now it only matches if it's the end of a line, a pound sign, slash, or question mark. (based on testing)
Here is my final code:
RewriteEngine on
RewriteRule ^(api(?=$|[/?#]).*)$ /api.php/$1 [L]
RewriteRule ^(admin(?=$|[/?#]).*)$ /admin.php/$1 [L]
RewriteCond $1 !^(index\.php|admin\.php|api\.php|_|robots\.txt)
RewriteRule ^(.*)$ /index.php/$1 [L]
I appreciate Croises answer, and it did help give me an idea of what might be going wrong that his solution would work. However, this is what I was looking for as I did not want to open up access to files and directories simply because they existed.

Related

Complex(?) htaccess rewriting / redirecting

It seems every few weeks I have to ask more .htaccess rewriting/redirecting questions. Every time I think I understand it, another wrench gets thrown into my project that shows that I don't.
EDIT: My original question wasn't very clear so the following is an attempt to be more concise.
As it stands, all of the .html files live in the root directory. eg: http://example.com/about.html
There aren't any sub-directories with the exception of normal ones like img, css, etc.
For tracking purposes, if someone types in http://example.com/random/ where "random" can be any string of characters, I'd want them to see the index.html file, without modifying the url. The directory "random" doesn't actually exist on the server at all.
The same goes for other pages like about.html. If someone types in http://example.com/random/about.html I'd want them to see the about.html page.
At the same time, I'd like http://example.com/random/about or http://example.com/about (missing file extension) to also show the about page.
However, if someone typed in a page that doesn't exist, I'd like for it to use the ErrorDocument
Example: I don't have a file named "pickups.html" so the following would all be 404s:
http://example.com/pickups.html
http://example.com/pickups
http://example.com/random/pickups.html
http://example.com/random/pickups
It would be nice if the end redirect/rewrite did have the file extension stripped off (because it looks nicer).
My thoughts are that any request ending with a / would just serve up the index.html file that exists at the site root. So that leaves the files.
My thought process is:
strip the file extension off of the request
check if that file with an extension exists at site root
if yes, display that page.
if no, 404.
My initial code (had help on it) was this:
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.+)/(.*)$ /$2 [R=301,L]
I understand that in that code I'm grabbing everything after the last slash and serving it from the document root. Unfortunately, it doesn't account for files that do not exist.
Starting with existing files, they will be passed through unchanged. This also prevents rewrite loops.
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [L]
Next are existing files, requested as part of an optional, virtual subdirectory
RewriteCond %{DOCUMENT_ROOT}/$2 -f
RewriteRule ^(.+/)?(.+)$ /$2 [L]
RewriteCond %{DOCUMENT_ROOT}/$2.html -f
RewriteRule ^(.+/)?(.+)$ /$2.html [L]
This splits the request into an optional prefix (.+/)? and the file part. If this file part exists, maybe with an appended .html, you're done.
Next comes anything with a trailing slash, just rewrite to index.html
RewriteRule /$ /index.html [L]
Anything else will be requests for non-existing files, which yield a 404 status code.
In order to remove an optional .html extension and remove an optional trailing slash / for existing files, we must insert two rules at the beginning
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{DOCUMENT_ROOT}/$2.html -f
RewriteRule ^(.+/)?(.+?)\.html/?$ /$1$2 [R,L]
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{DOCUMENT_ROOT}/$2.html -f
RewriteRule ^(.+/)?(.+?)/$ /$1$2 [R,L]
These rules are similar to the other rules, except they do a redirect R|redirect instead of a rewrite, and have an additional condition to prevent a rewrite loop.
Putting everything together gives
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{DOCUMENT_ROOT}/$2.html -f
RewriteRule ^(.+/)?(.+?)\.html/?$ /$1$2 [R,L]
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{DOCUMENT_ROOT}/$2.html -f
RewriteRule ^(.+/)?(.+?)/$ /$1$2 [R,L]
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [L]
RewriteCond %{DOCUMENT_ROOT}/$2 -f
RewriteRule ^(.+/)?(.+)$ /$2 [L]
RewriteCond %{DOCUMENT_ROOT}/$2.html -f
RewriteRule ^(.+/)?(.+)$ /$2.html [L]
RewriteRule /$ /index.html [L]

.htaccess Rewrite Within Directory - Hide PHP extension and force trailing slash

I'm trying to hide the .php extension from my files as well as force a trailing slash on the resulting URLs.
Example: A request to /about.php would become /about/ and requests to /about would go to /about/.
The following rewrite code worked perfectly when I was in the root of my hostdomain:
RewriteEngine On
RewriteRule ^(.*)/$ /$1.php [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteRule ^(.*)$ http://edit.mydomain.org/$1/ [R=301,L]
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /(.*)\.php\ HTTP/ [NC]
RewriteRule .+ http://edit.mydomain.org/%1 [R=301,QSA]
However, I need to move my files into a directory of this host name. Adding a directory name to the rules and having the .htaccess in the directory itself didn't work at all and seems to cause a endless redirect.
I looked around StackOverflow and other websites and tried numerous examples and ended up with many different errors with the most common being:
Everything is an endless redirect.
Everything except the directory home page is a 500 Error.
about.php redirects to /about but there's no redirect to /about/ and /about/ displays a 500 Error.
Everything working, but the home page (of the directory) index.php when accessed without a filename goes into an endless redirect.
Things redirect to edit.mydomain.org/home/username/public_html/mydomain.org/edit/pagename.php which obviously doesn't exist.
Thanks for any help! I really need to keep these files in a directory although the .htaccess could go into the host name root if its needed.
The directory for this would be edit.mydomain.org/dave/
Save this as a .htaccess and put it in the 'dave' directory
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !\..+$
RewriteCond %{REQUEST_URI} !/$
RewriteRule ^(.*)$ http://edit.mydomain.org/dave/$1/ [R=301,L]
RewriteRule ^(.*)/$ $1.php [L]
This works for me
RewriteBase /
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.html -f
RewriteRule ^(.*)$ $1.html

.htaccess rewrite to default language folder?

I have my site broken down into several folders by language:
/
/en/
index.php
about-us.php
faq.php
...
/fr/
index.php
about-us.php
faq.php
...
...
etc.
I'd like to have a rewrite rule that automatically rewrites to the en folder if somebody tried to enter mydomain.com/about-us.php.
FYI, I also already have a rewrite rule in place that removes the extension, so really I want to make sure that mydomain.com/about-us rewrites to mydomain.com/en/about-us. Here's my existing rewrite rule that does this:
# allows for extension-agnostic urls
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.*)$ $1.php
That make sense? Anyone help me out here?
EDIT:
#Gumbo -
Here's what my .htaccess file looks like (this is all that's in it):
RewriteEngine On
# defaults to the english site
RewriteRule !^[a-z]{2}/ /en%{REQUEST_URI} [L,R=301]
# allows for extension-agnostic urls
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.*)$ $1.php
This file is in the root of my website (not in a language folder). I've reloaded my webserver, just to be on the safe side, and I still get this error message when I try to go to mydomain.com/about-us:
Not Found
The requested URL /about-us was not found on this server.
... where mydomain.com/en/about-us works just fine.
Any other thoughts?
Put this rule before your rule:
RewriteRule !^(fr|en)/ /en%{REQUEST_URI} [L,R=301]
Or more general:
RewriteRule !^[a-z]{2}/ /en%{REQUEST_URI} [L,R=301]

Exclude a directory from being redirected in .htaccess

OK, so we were working in the wrong directory, meh!
We have a .htaccess file that is setup to redirect some files to a PHP script. Now we are adding some hard files which we want to bypass this redirect. So far this does not seem to be working and we are stumped.
Below is our initial .htaccess file contents after starting the engine which is working for another app already:
RewriteCond $1 !^(index\.php|robots\.txt|favicon\.ico)
RewriteRule ^(.*)$ /index.php/$1 [L]
We are trying to load files now from /directory/ So we have tried adding each of these to the RewriteCond section:
RewriteCond %{REQUEST_URI} !directory
RewriteCond $1 !^(index\.php|i/|robots\.txt|favicon\.ico|directory)
Neither seems to be working. Any ideas on how to get this to load?
Examples:
Should redirect
http://example.com/thisredirects/
Should not redirect
http://example.com/directory
http://example.com/directory/
http://example.com/directory/index.php
etc.
have you tried making a second .htaccess file in the /directory dir and doing a NoRewrite in it?
Try this:
Wont redirect
RewriteRule directory/.* - [L]
Redirects
RewriteRule ^$ thisredirects/ [L]
RewriteRule (.*) thisredirects/$1 [L]
It seems you want to redirect anything that isn't actually an existing file in your docroot to your index.php. This little bit of rewrite should handle that:
RewriteCond %{REQUEST_FILENAME} -s [OR] # file with size
RewriteCond %{REQUEST_FILENAME} -l [OR] # file is a link
RewriteCond %{REQUEST_FILENAME} -d # file is a directory
RewriteRule ^.*$ - [NC,L] # don't rewrite [last rule]
RewriteRule ^(.*)$ /index.php/$1 [NC,L] # everything else gets sent to index.php
The [OR] operator may be what you are looking for on the RewriteCond as well.
Also if you just want to whitelist the /directory portion you could put a Rule before your redirects that is marked [L] for "last rule"
RewriteRule ^/directory.*$ - [NC,L]

Multiple RewriteConds and RewriteRule Stacked Together

I have this apache rewrite rule:
RewriteEngine on
RewriteBase /
RewriteCond %{HTTP_HOST} mycompany.com
RewriteRule ^$ http://mycompany.com/login [L]
# we check if the .html version is here (caching)
RewriteRule ^$ index.html [QSA]
RewriteRule ^([^.]+)$ $1.html [QSA]
RewriteCond %{REQUEST_FILENAME} !-f
# no, so we redirect to our front web controller
RewriteRule ^(.*)$ index.php [QSA,L]
The only thing I can make sense of is if it's mycompany.com, then the script will redirect to http://mycompany.com/login. If not, then ...
I can't figure out already.
Any idea what does the above script say?
Something quite interesting, not easy to understand.
A google search on the comment texts inside the code gave interesting results: http://www.google.com/search?q=%22%23+we+check+if+the+.html+version+is+here+%28caching%29%22
Edit: if we look at the last lines and knowing that Symfony uses caching (it creates local files with .html extension in the same directories as the URL shows 'em) I can try to explain the lines here
If the requested url is something like http://yoursite.com/blabla/ we try to open an index.html file in that directory. If the file is not there, another cycle of rewriting will happen and the last Cond will be hit (where the file does not exist)
RewriteRule ^$ index.html [QSA]
If something more is in the url, like http://yoursite.com/blabla/blblbl, try to find a file blblbl.html
RewriteRule ^([^.]+)$ $1.html [QSA]
This is the collector of all urls that did not match any of the previous rules or the cached file did not exist:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [QSA,L]