htaccess redirect to a maintainance file - php

I have an htaccess in the public directory:
<IfModule mod_rewrite.c>
<IfModule mod_negotiation.c>
Options -MultiViews
</IfModule>
RewriteEngine On
RewriteBase /sub/web1/
# Redirect Trailing Slashes...
RewriteRule ^(.*)/$ /$1 [L,R=301]
# HERE I NEED SOM MAGICAL ONELINER TO REDIRECT STUFF TO MAINTENANCE.HTML
# BUT NO IDEA HOW TO WRITE IT ;(
# Handle Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
</IfModule>
and I want to add some rule inside, so when I uncomment the rule, all links that hit http://example.com/sub/web1/ or any files down that line, will be redirected to http://example.com/sub/web1/maintenance.html
I have tried to add:
DirectoryIndex maintenance.html
but this only redirects http://example.com/sub/web1/, if I have some subfolder or specific files like http://example.com/sub/web1/posts, it is useless.
Is there some oneliner that can even pull the domain name so it hasn't have to be typed absolutely? So, the example.com - or whatever domain - is not needed to type in the rule?

You can have a rule like this:
<IfModule mod_rewrite.c>
<IfModule mod_negotiation.c>
Options -MultiViews
</IfModule>
RewriteEngine On
RewriteBase /sub/web1/
# uncomment line below to route everything to maintenance.html
# RewriteRule !^maintenance\.html$ maintenance.html [L,NC]
# Redirect Trailing Slashes...
RewriteRule ^(.*)/$ /$1 [L,R=301]
# HERE I NEED SOM MAGICAL ONELINER TO REDIRECT STUFF TO MAINTENANCE.HTML
# BUT NO IDEA HOW TO WRITE IT ;(
# Handle Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
</IfModule>

Although this has already been answered and accepted, it's worth mentioning that if your maintenance page is temporary, you really should be returning the right http response, otherwise search engines might drop or re-index pages incorrectly.
At my company we use something like this:
RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}/holding/holding.html -f
RewriteCond %{DOCUMENT_ROOT}/holding/holding.enable -f
RewriteCond %{SCRIPT_FILENAME} !holding.html
RewriteRule ^.*$ /holding/holding.html [R=503,L]
ErrorDocument 503 /holding/holding.html
We create holding.html as the maintenance page, and then touch holding.enable to make the server switch to it without requiring a restart (not forgetting to rm it when we're done). The 503 return code on the rewrite rule, and the ErrorDocument 503 ensure that search engines see this a temporary outage and don't start de-listing our pages.

You can use the %{HTTP_HOST} variable to get the current domain that was used when hitting the given htaccess file - here's a handy cheat sheet of things:
askapache - cheatsheet
And some examples
askapache - examples
Although it's worth trying this out as it'll use root ^$ and rewrite that to the sub directory you want to use:
RewriteBase /
ReqwriteRule ^$ /sub/web1/

Related

Multiple Rewrite Rules for .htaccess, Redirect to www while including index.php

Specifically, I want to redirect all non-www pages to www, while also running an index.php file located in my root directory. To solve both of these problems I am using .htaccess.
I have already set up my site to run the PHP file to run in every directory. But the moment I add redirection from non-www to www it breaks.
The problem seems to be, that the multiple rewrite rules conflict with each other. Either one runs and the other does not, or the site just responds with a 500 error.
My question is, should multiple Rewrite rules be "combined" into one? Or am I just using those multiple rules wrong? (Or is it just some strange syntax thing I messed up? I have been working on this for a while haha)
Any help is very much appreciated.
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L,QSA]
# Redirect to www.
RewriteCond %{HTTP_HOST} ^example.com$
RewriteRule (.*) https://www.example.com/$1 [R=301,L]
</IfModule>
I found this works:
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L] #if not already index.php
RewriteCond %{REQUEST_FILENAME} !-f #only if NOT a FILE (directory / non-existent file)
RewriteRule . /index.php [L] #redirect to index.php
RewriteCond %{HTTP_HOST} ^example.com$
RewriteRule ^(.*) https://www.example.com/%{REQUEST_FILENAME} [R=301,L] #redirect to https://www
</IfModule>
This cannot possibly "work" as written, as there are a number of errors:
You are missing the opening <IfModule mod_rewrite.c> directive. However, this <IfModule> wrapper is not required anyway and should be removed.
Line-end comments are not supported by Apache. Specifically, the following line will result in a 500 error due to "bad flag delimiters":
RewriteCond %{REQUEST_FILENAME} !-f #only if NOT a FILE (directory / non-existent file)
(UPDATE: If you are not seeing a 500 error response here, it's possible you are on a LiteSpeed server; not Apache? On LiteSpeed, this line-end comment appears to work as intended!)
Your external redirect (at the end) that redirects to www never gets processed for anything other than requests for directories (including the root) or real files (except index.php). This redirect needs to go first, before the existing rewrites. However, see the next point...
You are incorrectly using REQUEST_FILENAME (the absolute filesystem path) in the target URL - this will result in a malformed redirect. You could use the REQUEST_URI server variable instead (full URL-path), but note that you also have a double slash issue. So, it would need to be rewritten like the following instead:
RewriteRule ^ https://www.example.com%{REQUEST_URI} [R=301,L]
Minor points:
The RewriteBase is not being used here and could be safely removed. (Unless you have other directives that use this?)
Summary
Bringing the above points together we have:
RewriteEngine On
# Redirect to https://www
RewriteCond %{HTTP_HOST} ^example\.com$
RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
# Stop here if already index.php
RewriteRule ^index\.php$ - [L]
# Only if NOT a FILE (non-existent file)
RewriteCond %{REQUEST_FILENAME} !-f
# Rewrite to index.php (in the document root)
RewriteRule . /index.php [L]
Note that this still rewrites directories to /index.php, contrary to what your comment stated.
Test first with a 302 (temporary) redirect to avoid potential caching issues.
You will need to clear your browser cache before testing.
After lots of tinkering/research, I found this works:
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L] #if not already index.php
RewriteCond %{REQUEST_FILENAME} !-f #only if NOT a FILE (directory / non-existent file)
RewriteRule . /index.php [L] #redirect to index.php
RewriteCond %{HTTP_HOST} ^example.com$
RewriteRule ^(.*) https://www.example.com/%{REQUEST_FILENAME} [R=301,L] #redirect to https://www
</IfModule>
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "*"
</IfModule>

missing directories don't trigger Error Document Handling htaccess

Basically, I've got the following .htaccess file:
Options -Indexes
ErrorDocument 400 /index.php?error=400
ErrorDocument 401 /index.php?error=400
ErrorDocument 403 /index.php?error=400
ErrorDocument 404 /index.php?error=400
ErrorDocument 500 /index.php?error=400
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
#Enable sites without extentions
options +MultiViews
<IfModule mod_rewrite.c>
Options +FollowSymlinks
# Adaptive-Images -----------------------------------------------------------------------------------
# Add any directories you wish to omit from the Adaptive-Images process on a new line, as follows:
# RewriteCond %{REQUEST_URI} !ignore-this-directory
# RewriteCond %{REQUEST_URI} !and-ignore-this-directory-too
#RewriteCond %{REQUEST_URI} !img
# don't apply the AI behaviour to images inside AI's cache folder:
#RewriteCond %{REQUEST_URI} !ai-cache
# Send any GIF, JPG, or PNG request that IS NOT stored inside one of the above directories
# to adaptive-images.php so we can select appropriately sized versions
# RewriteRule \.(?:jpe?g|gif|png)$ adaptive-images.php
# END Adaptive-Images -------------------------------------------------------------------------------
# SEO Friendly Redirect Rules -----------------------------------------------------------------------
RewriteRule ^(admin)/?$ admin/ [L,NC]
RewriteRule ^([A-Za-z0-9-]+)/?$ /index.php?title=$1 [L]
RewriteRule ^([A-Za-z0-9_]+)/([A-Za-z0-9_]*)/?$ index.php?title=$1&ch=$2 [L]
RewriteRule /$ index.php [END]
As of right now, the rules and conditions all work great except for one thing. If I navigate to say: "example.com/nonexistingfolder" , it is using this rule to process:
RewriteRule ^([A-Za-z0-9-]+)/?$ /index.php?title=$1 [L]
Which brings up a php error because the argument passed is invalid. Which is to be expected, because it doesn't exist. But if I no navigate to: "example.com/nonexistingfolder/index.php" , I'm correctly greeted with my 404 page defined at the top. (don't worry about the slashes, in the original these are permalinks)
ErrorDocument 404 /index.php?error=400
I don't know too much outside of what I've learned today about .htaccess and mod_rewrite. Is there some other way I should be going about this? Or am I missing other statements?
I've tried adding the following lines to my .htaccess with no progress:
RewriteCond %{REQUEST_FILENAME} -f
RewriteCond %{REQUEST_FILENAME} -d
Either these don't help in my case (and I thought the second would for sure), or I am still doing something wrong.
I expected the code to be rather straightforward, however this has left me scratching my head for a couple of hours. Thanks for taking the time to read and ponder this with me! Have a good one.
EDIT: I added these three lines of code:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .? /index.php?error=400 [L]
Which works when I navigate to something that doesn't exist. Yet, it interrupts the other RewriteRule I have set: RewriteRule ^([A-Za-z0-9-]+)/?$ /index.php?title=$1 [L]
So now I am for sure at a loss at what to do.
To further exemplify:
Say I navigate to "website.com/nonexistingfolder". Which now because I added the three lines above, shows the 404 page correctly. However, because of the single RewriteRule above, if I navigate to: "website.com/indexquery" it will also show the 404. How can I tell my .htaccess to differentiate between the two?

Symfony 4 htaccess

Ok, i fixed all the problem, configured the server on localhost, but i want to hide the /public directory and want to display the content in the root folder of my document for example /forum/ and for logging /forum/login instead of going to forum/public/login. Here is the htaccess file but it dont work, because it gives No routes for GET /forum/.
RewriteEngine On
RewriteBase /forum/
RewriteCond %{THE_REQUEST} /public/([^\s?]*) [NC]
RewriteRule ^ %1 [L,NE,R=302]
RewriteRule ^((?!public/).*)$ public/$1 [L,NC]
What im doing wrong ?
Actually sometimes we may need to add .htaccess file
We can use this code as .htaccess file. I have checked this on Ubuntu VPS and also on Cpanel.
<IfModule mod_rewrite.c>
Options -MultiViews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [QSA,L]
</IfModule>
<IfModule !mod_rewrite.c>
<IfModule mod_alias.c>
RedirectMatch 302 ^/$ /index.php/
</IfModule>
</IfModule>
My root .htaccess looks like this, I think you can put it onto your symfony root folder.
# Removes index.php from ExpressionEngine URLs
RewriteEngine on
# RewriteCond %{REQUEST_URI} !^/public/
RewriteRule ^(.*) /public/$1 [L]
Then my .htaccess inside the public/ folder:
# Determine the RewriteBase automatically and set it as environment variable.
# If you are using Apache aliases to do mass virtual hosting or installed the
# project in a subdirectory, the base path will be prepended to allow proper
# resolution of the index.php file and to redirect to the correct URI. It will
# work in environments without path prefix as well, providing a safe, one-size
# fits all solution. But as you do not need it in this case, you can comment
# the following 2 lines to eliminate the overhead.
RewriteCond %{REQUEST_URI}::$0 ^(/.+)/(.*)::\2$
RewriteRule .* - [E=BASE:%1]
# Sets the HTTP_AUTHORIZATION header removed by Apache
RewriteCond %{HTTP:Authorization} .+
RewriteRule ^ - [E=HTTP_AUTHORIZATION:%0]
# Redirect to URI without front controller to prevent duplicate content
# (with and without `/index.php`). Only do this redirect on the initial
# rewrite by Apache and not on subsequent cycles. Otherwise we would get an
# endless redirect loop (request -> rewrite to front controller ->
# redirect -> request -> ...).
# So in case you get a "too many redirects" error or you always get redirected
# to the start page because your Apache does not expose the REDIRECT_STATUS
# environment variable, you have 2 choices:
# - disable this feature by commenting the following 2 lines or
# - use Apache >= 2.3.9 and replace all L flags by END flags and remove the
# following RewriteCond (best solution)
RewriteCond %{ENV:REDIRECT_STATUS} =""
RewriteRule ^index\.php(?:/(.*)|$) %{ENV:BASE}/$1 [R=301,L]
# If the requested filename exists, simply serve it.
# We only want to let Apache serve files and not directories.
# Rewrite all other queries to the front controller.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ %{ENV:BASE}/index.php [L]

How can I rewrite URL's of a certain directory?

Ok, vague question title, I know. Wasn't sure how to summarize this in one line. I have two applications in my CodeIgniter installation: frontend and admin. There are two front controllers for each that set to the correct application folder. Currently, I use index.php/home for the home page of the frontend and admin.php/home for the home page of the admin panel.
I finally got around to removing index.php from the URL of the frontend. For the admin cp, I would like to use example.com/admin instead of example.com/admin.php. So I basically need to rewrite any uri that has admin as the first segment to admin.php. I figured that adding RewriteRule ^admin/(.*)$ admin.php/$1 to my htaccess would do the trick, but apparently it doesn't... Not completely anyway. I get 404 Page Not Found for every single page in my admin cp. What am I doing wrong?
# Deny OR Allow Folder Indexes.
# Since we disable access to PHP files you
# can leave this on without worries.
# OR better yet, create a .htaccess file in
# the dir you want to allow browsing and
# set it to +Indexes
Options -Indexes
Options +FollowSymLinks
# Set the default file for indexes
DirectoryIndex index.php
<IfModule mod_rewrite.c>
# mod_rewrite rules
RewriteEngine on
# The RewriteBase of the system (if you are using this sytem in a sub-folder).
# RewriteBase /CodeIgniter_1.6.3/
# This will make the site only accessible without the "www."
# (which will keep the subdomain-sensive config file happy)
# If you want the site to be accessed WITH the "www."
# comment-out the following two lines.
# RewriteCond %{HTTP_HOST} ^www\.example\.com$ [NC]
# RewriteRule ^(.*)$ http://example.com/$1 [L,R=301]
# If a controler can't be found - then issue a 404 error from PHP
# Error messages (via the "error" plugin)
# ErrorDocument 403 /index.php/403/
# ErrorDocument 404 /index.php/404/
# ErrorDocument 500 /index.php/500/
# Deny any people (or bots) from the following sites: (to stop spam comments)
# RewriteCond %{HTTP_REFERER} nienschanz\.ru [NC,OR]
# RewriteCond %{HTTP_REFERER} porn\.com
# RewriteRule .* - [F]
# Note: if you are having trouble from a certain URL just
# add it above to forbide all visitors from that site.
# You can also uncomment this if you know the IP:
# Deny from 192.168.1.1
# If the file is NOT the index.php file
RewriteCond %{REQUEST_FILENAME} !index.php
# Hide all PHP files so none can be accessed by HTTP
RewriteRule (.*)\.php$ index.php/$1
# If the file/dir is NOT real go to index
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [QSA,L]
RewriteRule ^admin/(.*)$ admin.php/$1
</IfModule>
# If Mod_ewrite is NOT installed go to index.php
<IfModule !mod_rewrite.c>
ErrorDocument 404 index.php
</IfModule>
You need to add your rule before you index.php routing rule. It's because ^(.*)$ is matching admin/whatever, so your admin rule will never get executed. You should also add -Multiviews to your options so it looks like this:
Options +FollowSymLinks -Multiviews
Then right under RewriteEngine On, add your rule:
RewriteRule ^admin/(.*)$ admin.php/$1 [L]

apache not serving static content correctly

I have been working on my own mvc framework to further my web app learning, but am having trouble serving static resources. I am trying to have a single entry point into the application, aka a front controller, so in my project / I have an .htaccess file that redirects all requests to the app/ folder where another .htaccess passes the request uri to index.php (in app/) who delegates the request to the appropriate controllers.
However, when I try to serve up static content, such as javascripts or cascading style sheets, I still get redirected through app/index.php. I am also getting "favicon.ico does not exist in /var/www" errors in /var/log/apache2/errors.log (maybe because of symlink to ~/www?). I do not expect to because of the following .htaccess file in the root directory of my project root:
<IfModule mod_rewrite.c>
Options -Indexes +FollowSymLinks
RewriteEngine On
RewriteBase /
# ----------------------------------------------------------------------
# Suppress the "www." at the beginning of URLs
# ----------------------------------------------------------------------
# The same content should never be available under two different URLs - especially not with and
# without "www." at the beginning, since this can cause SEO problems (duplicate content).
# That's why you should choose one of the alternatives and redirect the other one.
RewriteCond %{HTTPS} !=on
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L]
#----------------------------------------------------------------------
# Route static resources to respective files
#----------------------------------------------------------------------
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond public/$0 -f
RewriteRule ^.+\.(jpg|gif|png|ico|css|js)$ /public/$0 [L]
#----------------------------------------------------------------------
# Redirect all other requests to the app folder
#----------------------------------------------------------------------
RewriteRule ^$ app/ [L]
RewriteRule (.*) app/$1 [L]
</IfModule>
and here is the .htaccess in my app/ folder:
<IfModule mod_rewrite.c>
RewriteEngine On
# ensure request is not path to filename or directory
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# redirect all requests to index.php?url=PATHNAME
RewriteRule ^(.*)$ index.php?url=$1 [QSA,L]
</IfModule>
Why can't I serve static content correctly? This would make sense to me if I wasn't trying to sent all static requests to public/, which is where my css, jpg, png, js, etc files reside. But I have a RewriteCond rule in there to send the requests for such files to the public dir... Confusing?
Assuming, from what I understood, that your project structure is the following:
/
/.htaccess
/app/.htaccess
/app/index.php
/public/static.js (for example)
Here is what I come up with, hoping it'll solve your problem:
the .htaccess in the root folder:
<IfModule mod_rewrite.c>
Options -Indexes +FollowSymLinks
RewriteEngine On
RewriteBase /
RewriteCond %{HTTPS} !=on
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L]
RewriteRule ^public/.+\.(jpg|gif|png|ico|css|js)$ - [L]
RewriteRule ^(.*)$ app/$1 [L]
</IfModule>
And the .htaccess in the app folder is unchanged.
Every request starting with public and being a file with the listed extensions won't be redirected which is done with the dash character.
The last rule allows to redirect a request to the app/index.php file.
I think the resulting behaviour is the expected one:
static files in the public directory are not redirected,
files with another extension in the public directory will be
redirected to app/index.php (maybe for some error treatment),
requests not starting with public will be redirected to
app/index.php.

Categories