mod_rewrite directory heirarchy, rules specific to rewritten URLs? - apache

I have directories and subdirectories similar to below:
Each file and folder here is preceded by localhost/dir/
/common/style.css
/common/js.js
/common/top.php
/common/bottom.php
/images/items/1.png
/images/items/2.png
/images/items/3.png
/index.php
/items.php
/specificitem.php
On every page in the default directory, everything in the common folder is included (each page includes top.php and bottom.php, top.php includes js.js and style.css). specificitem.php relies on $_GET to grab data to populate that page, and is directed to from items.php.
In my .htaccess file, I rewrite the URLs for specificitem.php like the below:
RewriteEngine on
RewriteBase /dir/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule items/john specificitem.php?id=1 [NC,L]
RewriteRule items/jane specificitem.php?id=2 [NC,L]
RewriteRule items/jill specificitem.php?id=3 [NC,L]
...
When directing to these pages, no links work, styling and Javascript are broken/not loaded. Links are in the form ./somelink.php, and when on one of the item pages (eg. localhost/dir/items/john), ./somelink.php tries to direct to localhost/dir/items/somelink.php when this page doesn't exist. Stylesheets and Javascript are also attempted to be found at localhost/dir/items/common/ when likewise this doesn't exist. Changing the links to /somelink.php instead tries to go to /localhost/somelink.php when this doesn't exist.
What have I done wrong in my .htaccess file, or what is missing such that I can apply link rules to rewritten links only? My links, extra files, images are loaded properly for any page without a rewritten URL.

First have your rules like this:
RewriteEngine on
RewriteBase /dir/
# skip all files and directories from rewrite rules below
RewriteCond %{REQUEST_FILENAME} -d [OR]
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [L]
RewriteRule ^items/john/?$ specificitem.php?id=1 [NC,L,QSA]
RewriteRule ^items/jane/?$ specificitem.php?id=2 [NC,L,QSA]
RewriteRule ^items/jill/?$ specificitem.php?id=3 [NC,L,QSA]
Then to fix links/css/js/images paths you need to add this just below <head> tag of your page's HTML:
<base href="/dir/" />
so that every relative URL is resolved from that base URL and not from the current page's URL.

Related

How can I make my site load example.html when somebody visits example.com/example

I have a file in my public_html folder called example.html.
When somebody visits example.com/example.html, they get a 404 response.
How can I make Apache serve example.html instead?
I have a bunch of files like that, so I'd prefer to create some kind of general rule instead of redirecting them all individually.
#Turning RewriteEngine On
RewriteEngine on
#Making sure a directory or file does not exist under that name
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
#RewriteRule {WHAT THE USER SEES} {WHAT IS CALLED}
RewriteRule ^example$ example.html
With this, loading example.com/example would show whatever example.html loads.
If you have a bunch of HTML files that you want to load in that format, use this:
RewriteRule ^(.*)$ $1.html
You can put whatever regex you want in the first argument.

htaccess - Redirect to subfolder without changing browser URL

I've a domain that contains a subfolder with the web app structure. I added a .htaccess on my root domain to point the public folder on my subfolder web app. It works fine, but when I type www.example.com the browser URL changes to www.example.com/subfolder/public, but I would like that it doesn't change.
This is my .htaccess:
RewriteEngine On
RewriteRule ^.*$ subfolder/public [NC,L]
EDIT
This first .htaccess is used to redirect on subfolder/public, where there is an other .htaccess that makes all the works.
Here the code of the second .htaccess located on www.example.com/subfolder/public/:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]
Sorry, just realised what is happening. It has nothing to do with the second .htaccess file in the subdirectory, as mentioned in comments.
RewriteRule ^.*$ subfolder/public [NC,L]
Since public is a physical directory on the file system, you need to include a trailing slash when internally rewriting to that directory. Otherwise, mod_dir is going to try to "fix" the URL by appending a slash - that is where the external redirect is coming from. (mod_dir implicitly triggers an external redirect from subfolder/public to subfolder/public/.)
So, try the following instead in your root .htaccess file:
RewriteRule .* subfolder/public/ [L]
The important thing is the trailing slash. The anchors (^ and $) on the RewriteRule pattern are not required, since you are matching everything. And the NC flag is also not required for the same reason.
As always, make sure the browser cache is clear before testing.
UPDATE#1: The single directive above rewrites everything, including static resources, to the directory subfolder/public/ which then relies on the second .htaccess file in the subdirectory to correctly route the request. In order to allow static resources to be rewritten correctly (represented in the HTML as root-relative URL-paths, of the form "/js/myjs.js") then you will need additional directives in order to rewrite these.
For example, to specifically rewrite all .js and .css files to the real location in /subfolder/public/...
# Rewrite static resources
RewriteRule (.+\.(?:js|css))$ subfolder/public/$1 [L]
# Rewrite everything else to the "public" directory
RewriteRule .* subfolder/public/ [L]
UPDATE#2: To make the above more general, and to rewrite any static resource (images, PDFs, .txt, etc...) we can check for the existence of the file before rewriting, something like:
# Rewrite static resources
RewriteCond %{DOCUMENT_ROOT}/subfolder/public/$1 -f
RewriteRule (.+) subfolder/public/$1 [L]
# Rewrite everything else to the "public" directory
RewriteRule .* subfolder/public/ [L]
This will mean that if any .css does not exist it will be passed through to subfolder/public/.

Change root directory in .htaccess

I have a problem with changing the root directory in .htaccess.
My folder structure looks like this.
What I want to achieve is, when I visit this page:
/comparty/about/
The page I will see is this page:
/comparty/pages/about/
I have already tried to search on Google, but the code I found did not work, though I tried to change it:
RewriteEngine On
RewriteBase /comparty/
RewriteRule ^(.*)$ pages/$1 [L]
I don't want it to redirect, I want to keep the same URL. Also I've had a big problem with Apache caching the .htaccess file, so I haven't been able to test many things.
Thanks in advance.
EDIT
I found a way to rewrite the URL from /comparty/pages/about/ to /comparty/about/ - this is the code:
RewriteEngine On
RewriteBase /comparty/
RewriteRule ^about/(.*)$ pages/$1 [L]
This only works on the about page, though. What would I have to do, to make it dynamic and work with every page?
You need to use a dynmic pattern :
RewriteEngine On
RewriteBase /comparty/
#if the request is not for an existent dir
RewriteCond %{REQUEST_FILENAME} !-d
#and the request is not for an existent file
RewriteCond %{REQUEST_FILENAME} !-f
#rewrite the request to "/pages/request"
RewriteRule ^(.*)$ pages/$1 [L]
RewriteConditions above are important to avoid rewriting your existent files and directories to the /pages subfolder. Without those conditionrt the Rule will rewrite all requests including the destination path /pages and this may result in rewrite loop error.

.htaccess excluding directory issue

I have a website consisting of a single index.html file. I have several menus, and need to go 3 levels deep, so I want a php-like structure as such: index.html?main=$1&secondary=$2&tertiary=&3. This has to be reduced to www.example.com/$1/$2/$3. Overall pretty simple I would think, using following rules for in .htaccess:
RewriteRule ^([A-Za-z0-9-]+)/([A-Za-z0-9-]+)/([A-Za-z0-9-]+)?$ index.html?main=$1&secondary=$2&tertiary=$3
RewriteRule ^([A-Za-z0-9-]+)/([A-Za-z0-9-]+)?$ index.html?main=$1&secondary=$2
RewriteRule ^([A-Za-z0-9-]+)?$ index.html?main=$1
Now, I also have several folders in my root folder that shouldn't be affected, otherwise my include's wont work. Looking at this answer I've already tried exluding these folders using RewriteRule ^(bower_components|photos)($|/) - [L] before the other rules, but it didn't work. I've also tried this answer, making a .htaccess with contens RewriteEngine Off and putting it in my folders, also without success. So obviously I'm doing something wrong somewhere. To show my folder layout, here's a quick snapshot of it:
Here's my current .htaccess file:
Options +FollowSymLinks
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule .* - [L]
RewriteRule ^([A-Za-z0-9-]+)/([A-Za-z0-9-]+)/([A-Za-z0-9-]+)?$ index.html?main=$1&secondary=$2&tertiary=$3
RewriteRule ^([A-Za-z0-9-]+)/([A-Za-z0-9-]+)?$ index.html?main=$1&secondary=$2
RewriteRule ^([A-Za-z0-9-]+)?$ index.html?main=$1
Now, if I go to http://localhost/myProject/activities, so 1 level deep as the index.html file is located in myProject, it does work and all includes are included correctly. However, when going to http://localhost/myProject/activities/test, I get to the basic index.html page, but my includes point to http://localhost/myProject/activities/bower_components/platform/platform.js, so the activities is too much.
Keep your rules like this:
Options +FollowSymLinks
RewriteEngine On
RewriteBase /myProject/
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule .* - [L]
RewriteRule ^([A-Za-z0-9-]+)/([A-Za-z0-9-]+)/([A-Za-z0-9-]+)/?$ index.html?main=$1&secondary=$2&tertiary=$3 [L,QSA]
RewriteRule ^([A-Za-z0-9-]+)/([A-Za-z0-9-]+)/?$ index.html?main=$1&secondary=$2 [L,QSA]
RewriteRule ^([A-Za-z0-9-]+)/?$ index.html?main=$1 [L,QSA]
Then for css/js/image inclusion just use absolute path in your css, js, images files rather than a relative one. Which means you have to make sure path of these files start either with http:// or a slash /.
You can also try adding this in your page's HTML header: <base href="/myProject/" /> so that every relative URL is resolved from that URL and not the current URL.

Apache Mod_Rewrite Seems to be Causing Javascript Reloads

I'm setting up URL rewrite rules for an application I'm developing so that I can use nice clean URLs. I want the URLs to look like http://app.com/page/agency/ and to be equivalent to http://app.com/index.php?p=page&agency=agency. The agency selector is optional, so I want the URLs to redirect, even if the agency is not present. I have created the following mod_rewrite rules for this purpose:
RewriteRule ^/?([a-z]+)/$ /index.php?p=$1 [PT]
RewriteRule ^/?([a-z]+)/([a-z]+)/$ /index.php?p=$1&agency=$2 [PT]
This is working fine for redirecting the pages. However, it seems to me that my javascript files are being re-loaded with each page, as if the browser thinks that it's in a different directory and needs to re-load the JS files. The JS files are linked using a hard-coded URL, such as http://app.com/scripts/dostuff.js.
Is it possible that the browser is reloading the javascript files each time? If so, have I done something wrong?
Try this code:
RewriteEngine On
# skip rewrite rules below it is a valid file or a valid directory
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
# write single path
RewriteRule ^([a-z]+)/?$ /index.php?p=$1 [L,QSA]
# write 2 paths
RewriteRule ^([a-z]+)/([a-z]+)/?$ /index.php?p=$1&agency=$2 [L,QSA]