Apache .htaccess Rewrite Query String with slashes - apache

I am trying to figure out Apache's Mod Rewrite and so far it's not working. Here is what I am trying to do.
I have an index.php in the root directory of my site that is a template for all pages. I want to be able to organize my files in directories and the query string will have slashes.
So...
http://www.example.com/page.html
should be...
http://www.example.com/index.php?url=page
and...
http://www.example.com/directory/page.html
should be...
http://www.example.com/index.php?url=directory/page
I've got that working but I want to be able to go n directories deep...
http://www.example.com/directory1/directory2/page.html
should be...
http://www.example.com/index.php?url=directory1/directory2/page
I know I could just put a bunch of rewrites for however many directories I deep I want to go, but is there a single line RewriteRule that will put anything after the first / will be considered a query string?
This is what I have so far...
RewriteEngine on
RewriteRule ^([a-z-]+)\.html$ index.php?url=$1
RewriteRule ^faculty/([a-z-]+)\.html$ index.php?url=faculty/$1
Behind the scenes, PHP is including the file that is in the location that the url is specified.

This is bad idea to include file which name was passed from user. At least implement very STRONG validation, otherwise prepare to be hacked.
If you still want to use this -- here is the rule:
RewriteRule ^(.+)\.html$ index.php?url=$1 [QSA,L]

this should redirect anything with a ending .html to index.php?url=anything
www.example.com => index.php?url=
www.example.com/test1/test2 => index.php?url=test1/test2
RewriteRule ^([a-z-]+)\.html$ index.php?url=$1 [L,NC]

Related

Mod rewrite redirect every subdirectory to the same file

I have a website with a products.html file. Now, inside this file, I will have some Javascript code that checks the url to show the correct products/categories. This are some examples of the urls:
example.com/products
example.com/products/
example.com/products/shoes
example.com/products/shoes/
example.com/products/shoes/adidas
example.com/products/shoes/adidas/
example.com/products/shoes/adidas/adidas-predator-20.3
example.com/products/shoes/adidas/adidas-predator-20.3/
So basically, I want that everytime someone goes to the any of the above urls, I want to get the file products.html, I'll manage the rest with JS.
Also I want to be able to test this on my local machine. In this case, my URLs will be:
localhost/websites/myWebsite/products
localhost/websites/myWebsite/products/
localhost/websites/myWebsite/products/shoes
localhost/websites/myWebsite/products/shoes/
localhost/websites/myWebsite/products/shoes/adidas
localhost/websites/myWebsite/products/shoes/adidas/
localhost/websites/myWebsite/products/shoes/adidas/adidas-predator-20.3
localhost/websites/myWebsite/products/shoes/adidas/adidas-predator-20.3/
So I think we would need two htaccess files right?
You may use this single rule that will work on localhost and on production host as well:
RewriteEngine On
RewriteRule (?:^|/)products(?:/|$) products.html [L,NC]
With your shown samples could you please try following, you should place .htaccess file on same level where folder products is present. Also place the products.html in same level too.
RewriteEngine ON
RewriteCond %{REQUEST_URI} ^/(?:products)/?((?:shoes)/?((?:adidas)/?((?:adidas-predator-20\.3)/?)?)?)?$ [NC]
RewriteRule ^(.*)$ products.html [L]
If these are the only rules you will have then change L to END as an additional note here.

mod_rewrite: hide real urls but keep available as different files

Possible this question has already been answered but I didn't find any answer after hours of searching.
I need to put the site under "maintenance mode" and redirect/rewrite all requests to site_down.html, but at the same time I need the site to be available if I enter the address like files are in a subfolder.
ex:
if I type http://example.com/login.php I need site_down.html to be displayed.
but if I specify http://example.com/test/login.php I need real login.php do be displayed.
I need this to be done with rewrite, so copying everything to another directory isn't a solution.
I tried a couple dozens of combinations, but I'm still unable to achieve what I need
This is one version of my .htaccess file ():
DirectoryIndex site_down.html
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^test\/(.*)$ $1 [S=1]
RewriteRule ^(.*\.php)$ site_down.html
RewriteRule .* - [L]
</IfModule>
This code should rewrite all requests with "test/*" to "parent folder" and skip next rewrite rule and then terminate rewriting at RewriteRule .* - [L]. If there is no "test/" in url - all request should be rewritten to site_down.html
What am I doing wrong?
Could you suggest any valid solutions, please?
Thank you.
Essentially, you are searching for 2 rules. One rule will translate a virtual subdirectory to the working files. The other rule will translate the url to the working files to a splash page. We just have to make sure that if the first rule matches, the second rule doesn't match. We can do this by making sure " /test/" (including that leading space) was not in THE_REQUEST (or the string that the client sent to the server to request a page; something in the form of GET /test/mypage.php?apes=bananas HTTP/1.1). THE_REQUEST doesn't change on a rewrite, which makes it perfect for that. Skipping a rule like you did usually doesn't have the effect you expect, because mod_rewrite makes multiple passes through .htaccess until the resulting url doesn't change anymore, or it hits a limit and throws an error. The first time it will skip the rule, but the second time it will not do that.
RewriteCond %{THE_REQUEST} !\ /test/
RewriteRule \.php site_down.html [L]
RewriteRule ^test/(.*)$ $1 [L]

Apache URL Rewriting for multiple dynamic folder levels

Wondering if somebody can help me write some RewriteRule's for my website.
Take a look at the following URLs and see how I need to rewrite them.
http://www.example.com/essays-and-reports/
does not need to be re-written, it is a physical folder on the web server.
http://www.example.com/essays-and-reports/business/
needs to rewrite to (root)/first_level_template.php
http://www.example.com/essays-and-reports/dynamic_name2
needs to rewrite to (root)/first_level_template.php
http://www.example.com/essays-and-reports/business/financial-reports/
needs to rewrite to (root)/second_level_template.php
http://www.example.com/essays-and-reports/blah/financial-reports/C_B_2413_Report_on_savings.php
needs to rewrite to (root)/final_level_template.php
Note the rules must work regardless of a trailing slash. To sum-up, there are three levels which I need to re-write to their relevant template. None of above exists physically on the server including the PHP file for final level. The only thing that exists is the essays-and-reports folder which is main folder for the website.
I tried something like this but I get compile errors in the log.
RewriteRule ^([^/]+)/([^/]+)/?$ /second-level-template\.php [L]
If you could help me write the rules I need - I appreciate it greatly.
EDIT:
This code kind of works but it also rewrites the essays-and-reports folder which I don't want...
Options +FollowSymLinks
RewriteEngine On
RewriteBase /essays-and-dissertations/
RewriteRule ^[^/]+/[^/]+/[^/]+/?$ /final_level_template.php [L]
RewriteRule ^[^/]+/[^/]+/?$ /second_level_template.php [L]
RewriteRule ^[^/]+/?$ /first_level_template.php [L]
You could do this with 3 rules:
RewriteRule ^essays-and-reports/[^/]+/?$ /first_level_template.php [L]
RewriteRule ^essays-and-reports/[^/]+/[^/]+/?$ /second_level_template.php [L]
RewriteRule ^essays-and-reports/[^/]+/[^/]+/[^/]+/?$ /final_level_template.php [L]
You don't need to escape the dot in your redirect target, since that's not a regular expression.

Apache .htaccess RewriteRule

Here's my situation. I have a web root and several subdirectories, let's say:
/var/www
/var/www/site1
/var/www/site2
Due to certain limitations, I need the ability to keep one single domain and have separate folders like this. This will work fine for me, but many JS and CSS references in both sites point to things like:
"/js/file.js"
"/css/file.css"
Because these files are referenced absolutely, they are looking for the 'js' and 'css' directories in /var/www, which of course does not exist. Is there a way to use RewriteRules to redirect requests for absolutely referenced files to point to the correct subdirectory? I have tried doing things like:
RewriteEngine on
RewriteRule ^/$ /site1
or
RewriteEngine on
RewriteRule ^/js/(.*)$ /site1/js/$1
RewriteRule ^/css/(.*)$ /site1/css/$1
But neither of these work, even redirecting to only one directory, not to mention handling both site1 and site2. Is what I'm trying possible?
EDIT: SOLUTION
I ended up adapting Jon's advice to fit my situation. I have the ability to programatically make changes to my .htaccess file whenever a new subdirectory is added or removed. For each "site" that I want, I have the following section in my .htaccess:
RewriteCond %{REQUEST_URI} !^/$
RewriteCond %{REQUEST_URI} !^/index.php$
RewriteCond %{HTTP_COOKIE} sitename=site1
RewriteCond %{REQUEST_URI} !^/site1/
RewriteRule ^(.*)$ /site1/$1 [L]
Index.php is a file that lists all my sites, deletes the "sitename" cookie, and sets a cookie of "sitename=site#" when a particular one is selected. My RewriteConds check,
If the request is not for /
If the request is not for /index.php
If the request contains the cookie "sitename=site1"
If the request does not start with "/site1/"
If all of these conditions are met, then the request is rewritten to prepend "/site1/" before the request. I tried having a single set of Conds/Rules that would match (\w+) instead of "site1" in the third Condition, and then refer to %1 in the fourth Condition and in the Rule, but this did not work. I gave up and settled for this.
If the RewriteRules are in your .htaccess file, you need to remove the leading slashes in your match (apache strips them before sending it to mod_rewrite). Does this work?
RewriteEngine on
RewriteRule ^js/(.*)$ /site1/js/$1
RewriteRule ^css/(.*)$ /site1/css/$1
EDIT: To address the comment:
Yes, that works, but when I do RewriteRule ^(.*)$ /site1/$1, it causes Apache to issue internal server errors. But to me, it seems like that should just be a generic equivalent of the individual rules!
What's happening with that rule is when /something/ gets rewritten to /site/something/, and apache internally redirects, it gets rewritten again, to /site/site/something/, then again, then again, etc.
You'd need to add a condition to that, something like:
RewriteCond %{REQUEST_URI} !^/site/
RewirteRule ^(.*)$ /site/$1 [L]
You need to set up symlinks, which the rewrite rules will use so your absolute links at the server level can follow the symbolic links to the central site hosting account.

How to do a mod_rewrite redirection to relative URL

I am trying to achieve a basic URL redirection for pretty-URLs, and due to images, CSS etc. also residing in the same path I need to make sure that if the URL is accessed without a trailing slash, it is added automatically.
This works fine if I put the absolute URL like this:
RewriteRule ^myParentDir/([A-Z0-9_-]+)$ http://www.mydomain.com/myParentDir/$1/ [R,nc,L]
But if I change this to a relative URL, so that I don't have to change it each time I move things in folders, this simply doesn't work.
These are what I tried and all do not work, or redirect me to the actual internal directory path of the server like /public_html/... :
RewriteRule ^myParentDir/([A-Z0-9_-]+)$ ./myParentDir/$1/ [R,nc,L]
RewriteRule ^myParentDir/([A-Z0-9_-]+)$ myParentDir/$1/ [R,nc,L]
What is the right way to do a URL redirection so that if the user enters something like:
http://www.mydomain.com/somedir/myVirtualParentDir/myVirtualSubdir
he gets redirected to (via HTTP 301 or 302):
http://www.mydomain.com/somedir/myVirtualParentDir/myVirtualSubdir/
Thanks.
EDIT: Adding some more details because it does not seem to be clear.
Lets say I am implementing a gallery, and I want to have pretty URLs using mod_rewrite.
So, I would like to have URLs as follows:
http://www.mydomain.com/somedir/galleries/cats
which shows thumbnails of cats, while:
http://www.mydomain.com/somedir/galleries/cats/persian
which shows one image from the thumbnails of all cats, named persian.
So in actual fact the physical directory structure and rewriting would be as follows:
http://www.domain.com/somedir/gallery.php?category=cats&image=persian
So what I want to do is put a .htaccess file in /somedir which catches all requests made to /galleries and depending on the virtual subdirectories following it, use them as placeholders in the rewriting, with 2 rewrite rules:
RewriteRule ^galleries/(A-Z0-9_-]+)/$ ./gallery.php?category=$1 [nc]
RewriteRule ^galleries/(A-Z0-9_-]+)/+([A-Z0-9_-]+)$ ./gallery.php?category=$1&image=$2 [nc]
Now the problem is that the gallery script in fact needs some CSS, Javascript and Images, located at http://www.domain.com/somedir/css, http://www.domain.com/somedir/js, and http://www.domain.com/somedir/images respectively.
I don't want to hardcode any absolute URLs, so the CSS, JS and Images will be referred to using relative URLs, (./css, ./js, ./images etc.). So I can do rewriting URLs as follows:
RewriteRule ^galleries/[A-Z0-9_-]+/css/(.*)$ ./css/$1 [nc]
The problem is that since http://www.domain.com/somedir/galleries/cats is a virtual directory, the above only works if the user types:
http://www.domain.com/somedir/gallaries/cats/
If the user omits the trailing slash mod_dir will not add it because in actual fact this directory does not actually exist.
If I put a redirect rewrite with the absolute URL it works:
RewriteRule ^galleries/([A-Z0-9_-]+)$ http://www.mydomain.com/subdir/galleries/$1/ [R,nc,L]
But I don't want to have the URL prefix hardcoded because I want to be able to put this on whatever domain I want in whatever subdir I want, so I tried this:
RewriteRule ^galleries/([A-Z0-9_-]+)$ galleries/$1/ [R,nc,L]
But instead it redirects to:
http://www.mydomain.com/home/myaccount/public_html/subdir/galleries/theRest
which obviously is not what I want.
EDIT: Further clarifications
The solution I am looking for is to avoid hardcoding the domain name or folder paths in .htaccess. I am looking for a solution where if I package the .htaccess with the rest of the scripts and resources, wherever the user unzips it on his web server it works out of the box. All works like that apart from this trailing slash issue.
So any solution which involves hardcoding the parent directory or the webserver's path in .htaccess in any way is not what I am looking for.
Here's a solution straight from the Apache Documentation (under "Trailing Slash Problem"):
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^(.+[^/])$ $1/ [R]
Here's a solution that tests the REQUEST_URI for a trailing slash, then adds it:
RewriteCond %{REQUEST_URI} !(/$|\.)
RewriteRule (.+) http://www.example.com/$1/ [R=301,L]
Here's another solution that allows you to exempt certain REQUEST_URI patterns:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !example.php
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteRule ^(.*)$ http://domain.com/$1/ [L,R=301]
Hope these help. :)
This rule should add a trailing slash to any URL which is not a real file/directory (which is, I believe, what you need since Apache usually does the redirect automatically for existing directories).
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+[^/])$ $1/ [L,R=301]
Edit:
In order to prevent Apache from appending the path relative to the document root, you have to use RewriteBase. So, for instance, in the folder meant to be your application's root, you add the following, which overrides the physical path:
RewriteBase /
This might work:
RewriteRule ^myParentDir/[A-Z0-9_-]+$ %{REQUEST_URI}/ [NS,L,R=301]
However, I'm not sure why you think you need this at all. Just make your CSS / JS / image file rewrite rule look something like this:
RewriteRule ^galleries/([A-Za-z0-9_-]+/)*(css|js|images)/(.*)$ ./$2/$3
and everything should work just fine regardless of whether the browser requests /somedir/galleries/css/whatever.css or /somedir/galleries/cats/css/whatever.css or even /somedir/galleries/cats/persian/calico/css/whatever.css.
Ps. One problem with this rule is that it prevents you from having any galleries names "css", "js" or "images". You might want to fix that by naming those virtual directories something like ".css", ".js" and ".images", or using some other naming scheme that doesn't conflict with valid gallery names.
I'm not sure I complelty understand your problem.
The trailing slash redirection is done automatically on most Apache installation because of mod_dir module (99% of chance you'have the mod_dir module).
You may need to add:
DirectorySlash On
But it's the default value.
So. If you access foo/bar and bar is not a file in foo directory but a subdirectory then mod_dir performs the redirection to foo/bar/.
The only thing I known that could break this is the Option Multiviews which is maybe trying to fin a bar.php, bar.php, bar.a-mime-extension-knwon-by-apache in the directory. So you could try to add:
Option -Multiviews
And remove all rewriteRules. If you do not get this default Apache behavior you'll maybe have to look at mod-rewrite, but it's like using a nuclear bomb to kill a spider. Nuclear bombs may get quite touchy to use well.
EDIT:
For the trailing slash problem with mod-rewrite you can check this documentation howto, stating this should work:
RewriteEngine on
RewriteBase /myParentDir/
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^(.+[^/])$ $1/ [R]