htaccess rewrite stopped working properly - .htaccess

I have the following code block in my .htaccess file:
RewriteEngine on
RewriteCond %{REQUEST_URI} !^(.*)2021layout(.*)$
[other directories to omit, like assets and admin]
RewriteRule ^(.*) RESThandler.php
Basically I want certain directories to be processed normally, like 2021layout, while others use the REST handler. In the 2021layout directory, the member area is in the directory 2021layout/myaccount, and all css/js files are in 2021layout/assets/[whatever directory]. Both the assets and myaccount directories have permissions 0755.
On Friday, everything was working fine. Today, having changed nothing, pages in the 2021layout directory are working, and css and js files loaded by those pages are fine, but pages in the 2021layout/myaccount directory are trying to use the REST handler and getting redirected to my 404 page.
I have tried renaming both the 2021layout and myaccount directories, which didn't work. I have tried adding !^(.*)2021layout/myaccount(.*)$ as a RewriteCond, and that didn't work.
Why would this one specific directory suddenly stop obeying my htaccess instructions? Can I fix this?
Again, to reiterate: I didn't change anything to make this happen. It worked one day, and the next day it didn't, seemingly on its own.
EDIT: I have gotten the directory to work again by renaming the newly-created file settings.php to mysettings.php. So apparently the mere existence of settings.php within the directory was preventing it from loading correctly. Does anyone have any insight into this?

You may try this rule with THE_REQUEST:
RewriteCond %{THE_REQUEST} !\s/2021layout/ [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ RESThandler.php [L]
THE_REQUEST variable represents original request received by Apache from your browser and it doesn't get overwritten after execution of other rewrite directives. Example value of this variable is GET /index.php?id=123 HTTP/1.1
Make sure to clear your browser cache before testing this change.
So apparently the mere existence of settings.php within the directory was preventing it from loading correctly. Does anyone have any insight into this
I am guessing that you have option MultiViews turned on in your Apache config. To turn it off use this directive at top of your .htaccess:
Option -MultiViews
Option MultiViews (see http://httpd.apache.org/docs/2.4/content-negotiation.html) is used by Apache's content negotiation module that runs before mod_rewrite and makes Apache server match extensions of files. So if /file is the URL then Apache will serve /file.html.

Related

Proper .htaccess settings for Next.js SSG catch all routes

I've build a website, using Next.js and SSG - Static Site Generation.
I'm serving the website on an Apache server and, therefore, because of this answer, I'm using the following .htaccess configuration:
# Disable directory indexes and MultiViews
Options -Indexes -MultiViews
# Prevent mod_dir appending a slash to directory requests
DirectorySlash Off
# Rewrite /foo to /foo.html if it exists
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}.html -f
RewriteRule !\.\w{2,4}$ %{REQUEST_URI}.html [L]
# Otherwise, rewrite /foo to /foo/index.html if it exists
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}/index.html -f
RewriteRule !\.\w{2,4}$ %{REQUEST_URI}/index.html [L]
# Handling 404
ErrorDocument 404 /my-custom-404.html
And it's been working perfectly.
But recently, there was a need for an admin page, the usual CRUD. I've developed it without SSG in mind (because there were actually no need for it), created my own custom router and used Next.js's catch all routes to handle all content of this admin page, which I called dashboard.
So, on my built website, I have a whole bunch of page.html files, and a /dashboard/[[...dashboard]].html file, which is the CRUD itself (all subpages and contents are imported dynamically) - and, therefore, every single link starting with /dashboard will be handled via that file.
So, the problem is: navigating through the links on the website and into the dashboard, everything works perfectly. But if I try to directly access any link within /dashboard (including itself, and subroutes: /dashboard/users, for instance), it simply does not work. With the provided .htaccess configuration, it goes straight to 404.
I've tried a few different configurations added to .htaccess, but none have worked so far (either it still goes straight to 404, or the browser shows the error ERR_TOO_MANY_REDIRECTS):
RewriteCond %{DOCUMENT_ROOT}/dashboard/$1
RewriteRule (.*) /dashboard/[[...dashboard]].html [L]
This one almost worked... but the dashboard itself does not do anything (no subpages are ever rendered):
RewriteCond %{REQUEST_URI} .*dashboard*.
RewriteRule (.*) /dashboard/[[...dashboard]].html [L]
Important note: this whole thing works perfectly on the local dev server.
If anyone has any tip on how I can sort this thing out, I would really appreciate it!
I've managed to solve it, at least on an acceptable level.
As I mentioned on the question, this was almost working (no sub page was ever rendered, but at least the browser was correctly redirecting to the dashboard):
RewriteCond %{REQUEST_URI} .*dashboard*.
RewriteRule (.*) /dashboard/[[...dashboard]].html [L]
No page was ever rendered, because I was using Next.js's withRouter/useRouter to inform my custom router of the current route (via router.asPath), and when the above rule as met, router.asPath was set to dashboard/[[...dashboard]].html.
So, I wrote a small test to redirect any access with that asPath to my entrypoint. Basically:
if(router.asPath.contains('[[...dashboard]]')
router.push('/dashboard')
But, another problem arouse...
The first problem was solved: trying to access any dashboard routes directly was working, but navigating through the website (links) was not. After an arduous and long process of trial and error, I found out that my previous .htaccess rule was preventing my client-side code to request my [[...dashboard]].html file.
RewriteCond %{REQUEST_URI} .*dashboard*.
RewriteCond %{REQUEST_URI} !(\[\[\.\.\.dashboard\]\])
RewriteRule (.*) /dashboard/[[...dashboard]].html?p=$1 [L]
Basically:
If my request URI contains 'dashboard'
AND if that same request does not contain [[...dashboard]]
THEN I rewrite it to the dashboard file
Hope this might help someone someday!

removed .html extensions with htaccess now index.html give 403 error

After entering the code below, my home page gives a 403 error. The rest of the site works perfectly. All instances of .html were removed.
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^\.]+)$ $1.html [NC,L]
Any advice?
Thank you!
example.com leads ti the 403 error. If I write example.com/index it works fine.
Something else must have changed for this to result in a 403 error. The code you posted won't actually do anything when you request example.com/ - the same as if that code didn't exist at all. (UPDATE: However, this assumes your .htaccess file is located in the document - it appears this is not the case - see below.)
However, what will trigger a 403 in such cases is when "formatted directory listings" are disabled and the directory index document cannot be found (or has been disabled).
So, try setting the appropriate directory index at the top of your .htaccess file:
DirectoryIndex index.html
It is the DirectoryIndex that serves the appropriate file when requesting your "home page", not your directives in .htaccess.
UPDATE:
It [.htaccess] is located in my root directory. Would it be better to put it in the public_html folder?
Yes, the code you posted should go in the /public_html directory (ie. your document root). If these directives are in a .htaccess file above the document root then the RewriteRule pattern will match the URL-path public_html/ and rewrite the URL to public_html/.html which is possibly where your 403 error is coming from ("dot" files are usually hidden/protected OS files and you may also have a directive in your server config blocking access. However, this behaviour may also be dependent on other factors in the server config/OS). However, with that code in the document root then a request for example.com/ (your home page) won't be processed by these directives (which is good) - mod_dir should then serve the index.html file in this instance.
However, you don't want to process "directories" anyway (public_html is obviously a "directory", not a file). Which is what's happening above. eg. .html shouldn't be appended to public_html/ to begin with (or example.com/path/to/directory/ or any other directory). This can be avoided by adding an additional condition to your rule block to avoid directories (as well as files). For example:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^.]+)$ $1.html [L]
Simply adding that additional RewriteCond directive might be enough and still allow you to keep your .htaccess file above the document root. (However, you may still need to move the .htaccess file as well, as described above.)
Also, the NC flag is not required here and literal dots don't need to be escaped when used inside a character class.
You could also extend this code to first check the existence of the file (with a .html extension) before rewriting, although this may be unnecessary in your case. For example:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^([^.]+)$ $1.html [L]
This requires an additional "file check" which may be an unnecessary overhead.

.htaccess RewriteRule not redirecting from real folder

I'm still a bit fuzzy on the working of .htaccess, and I've looked around but I can't find anything to help this specific issue.
EDIT: I realize there are other questions that seem like they cover this issue, but I checked some and they didn't seem to offer any help I could understand, and I didn't want to hijack them with my own issues.
This is what I have:
Options +FollowSymLinks
#RewriteBase /
RewriteEngine on
RewriteRule /mp3/(.*) http://old.domain.com/mp3/$1 [R=301,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]*)$ /index.php?p=$1 [L]
As you can see from the last line, the string typed after the server name is actually a URL parameter and depending on that parameter, different content is pulled from the database and that page is displayed on the site.
The problem I'm having is that the client has a content page called "podcast", so they would go to site.com/podcast which should quietly redirect to site.com/index.php?=podcast and load the content for that page. Unfortunately, the client also has a real site.com/podcast/ folder on their server. Because of this, the rewrite is ignored and the browser attempts to load that folder. It either shows a file listing or a forbidden error if I disable the listing.
After some research (I'm still new to htaccess), I learned that the two lines prior disable the rewrite if the path points to an actual file or folder. Unfortunately, commenting out the one with !-d doesn't seem to have any effect, and commenting out both gives me a server error.
Admittedly, part of the problem here was lack of foresight. URL rewrites should have been planned before everything else was put together, but it wasn't until the site was basically completed that I was notified that the client wants "Friendly URLs" that don't include the ?p= part. Regardless, perhaps there is a way to fix this.
Is there some .htaccess trickery I can use that will force the rewrite even if the URL entered points to a folder (not a specific file) that actually exists? As stated before, removing the !-d doesn't seem to help, although I'm not sure why. Perhaps I misunderstand its purpose.
Thank you for any help, and please be lenient with me if I overlooked something obvious. This is an issue presenting itself on the client's live site right now so I feel a little rushed in solving it. Thanks again.
OH YEAH, and the solution can't be specific to /podcast. The way the client's site is set up, when they want to create a new subpage for the site, a new name is saved for that content based on their title for the page and it is possible (unlikely, but still possible) that another page can be created with a name that matches an existing folder on the server.
Here is a note from mod_rewrite documentation:
By default, mod_rewrite will ignore URLs that map to a directory on
disk but lack a trailing slash, in the expectation that the mod_dir
module will issue the client with a redirect to the canonical URL with
a trailing slash.
This explains why mod_rewrite ignores the URL /podcast. I would suggest that you rename physical directories so that do do not (accidentally) match article names.
Another option would be to disable the DirectorySlash setting. This will prevent Apache from redirecting /podcast to /podcast/.
DirectorySlash Off
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^/]*)$ /index.php?p=$1 [L]
Be warned that disabling this setting has side effects. Read through the documentation first.
Change the following line of code:
RewriteRule ^([^/]*)$ /index.php?p=$1 [L]
to
RewriteRule ^(podcast([^?]*)) index.php?p=$1 [L,NC]

Make files not accessible via URL

How can I redirect via .htaccess file, that only the index.html can be accessed via URL.
I already got this:
RewriteEngine on
RewriteBase /
Options +FollowSymlinks
RewriteRule ^/?login/?$ /php/login.php [NC,R=301,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.html [L,QSA]
It works fine if somebody types in for example "www.mypage.com/skd/lasnd"
but if somebody types in a file which exists on the webserver, e.g. "www.mypage.com/php/login.php", he will be redirected to that page. How to forbid that?
To be more exact: my JavaScript & PHP scripts should be still allowed to access to every file on my webserver.
These lines:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
are conditions "if REQUEST_FILENAME is NOT a file, if REQUEST_FILENAME is not a directory" and if both are met then RewriteRule is taking place. This is usually to allow "friendly urls" to work and at the same time to not rewrite any images, css etc. You can block access to files with many ways, but you have to take care to not block too much (like said images etc). The simplest approach would be to put your files in subdirectory and add another .htaccess file in that directory with line
Deny From All
This will make httpd reny any request to whatever is in that directory and subdirectories (unless another .htaccess overwrite these rules) while your scripts will be able to access them without a problem.
I strongly recommend do read mod_rewrite docs
EDIT
There's no "my javascript" and "their javascript". There's request and that's all you can tell for sure. You cannot tell which access yours and which is not. "i only want to deny request via typing in the browser adress line" - you can't tell that either. You theoretically could check REFERER, and if there's none set then assume it's direct hit, but REFERER comes from browser so it can be faked as well. And I personally block all REFERERS by default, so all my requests are w/o any REFERER even these not direct. You could try cookies, but again - these can be be grabbed by script and sent back too. The only real option is to Deny from all to these files and "tunel" them thru some sort of script (i.e. PHP) that would do i.e. file() on target file only if user authenticated himself previously using login and password. Any other attempts are broken from the start.
try the following
RewriteRule /.* http://www.new-domain.com/index.html

.htaccess rewrite rule for /

I have a website where if I go to the URL http://mysite.com/community it shows page not found. But, the URL http://mysite.com/community/ correctly displays the page. How can I set up a rewrite for that "/" after community?
This is my present .htaccess:
Options +FollowSymLinks
Options +Indexes
RewriteEngine On
RewriteRule ^admin$ Admin/index.php?qstr=$1 [L]
RewriteRule ^(.*)/$ index.php?qstr=$1 [L]
These were the ones tried by me, but failed
First,
RewriteRule ^(.*)/community $1/community/ [L]
second,
RewriteRule /community /community/ [L]
All with different combinations of with and without [L].
From the Apache URL Rewrite Guide:
Trailing Slash Problem
Description:
Every webmaster can sing a song about the problem of the trailing slash on URLs referencing directories. If they are missing, the server dumps an error, because if you say /~quux/foo instead of /~quux/foo/ then the server searches for a file named foo. And because this file is a directory it complains. Actually it tries to fix it itself in most of the cases, but sometimes this mechanism need to be emulated by you. For instance after you have done a lot of complicated URL rewritings to CGI scripts etc.
Solution:
The solution to this subtle problem is to let the server add the trailing slash automatically. To do this correctly we have to use an external redirect, so the browser correctly requests subsequent images etc. If we only did a internal rewrite, this would only work for the directory page, but would go wrong when any images are included into this page with relative URLs, because the browser would request an in-lined object. For instance, a request for image.gif in /~quux/foo/index.html would become /~quux/image.gif without the external redirect!
So, to do this trick we write:
RewriteEngine on
RewriteBase /~quux/
RewriteRule ^foo$ foo/ [R]
The crazy and lazy can even do the following in the top-level .htaccess file of their homedir. But notice that this creates some processing overhead.
RewriteEngine on
RewriteBase /~quux/
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^(.+[^/])$ $1/ [R]
Well, after trying out all the above solutions as well as some of my own, I finally solved this. I'm definitely sure that this is NOT a complete solution but it sure solved it for the time being.
Solution: Just created an empty directory named "community" in the root folder. That's it!
But I'm still on the lookout for the actual solution to this.

Resources