How can I make my .htaccess skip rules conditionally? - apache

I want to redirect all URLs that do not contain "_js","_css", "_img", etc., to my dispatch script. Somehow it doesn't work.
For instance, all files inside my /_js/ folder are unaccessible (meaning: they are sent to index.php instead of getting to the physical files residing in that folder).
Here is my htaccess:
IndexIgnore *
Options +FollowSymLinks
RewriteEngine on
# if the following conditions are met, SKIP the rewriteRules.
RewriteCond %{REQUEST_URI} ^/(_admin/¦_css/¦_js/¦_img/)
RewriteRule . - [S=9]
# Externally redirect to add missing trailing slash
RewriteRule ^(([a-z0-9._\-]+/)*[a-z0-9_\-]+)$ http://%{HTTP_HOST}/$1/?%{QUERY_STRING} [NC,R,L]
# SIX PARAMS
RewriteRule ^([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/?$ /index.php?section=$1&item=$2&menu=$3&content=$4&id=$5&title=$6&%{QUERY_STRING} [NC,L]
# FIVE PARAMS
RewriteRule ^([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/?$ /index.php?section=$1&item=$2&menu=$3&content=$4&id=$5&%{QUERY_STRING} [NC,L]
# FOUR PARAMS
RewriteRule ^([^/]+)/([^/]+)/([^/]+)/([^/]+)/?$ /index.php?section=$1&item=$2&menu=$3&content=$4&%{QUERY_STRING} [NC,L]
# THREE PARAMS : projects/touch/texts/
RewriteRule ^([^/]+)/([^/]+)/([^/]+)/?$ /index.php?section=$1&item=$2&menu=$3&%{QUERY_STRING} [NC,L]
# TWO PARAMS: downloads
RewriteRule ^downloads/([^/]+)/$ index.php?section=downloads&item=$1&%{QUERY_STRING} [NC,L]
# TWO PARAMS:
RewriteRule ^([^/]+)/([^/]+)/?$ /index.php?section=$1&item=$2&%{QUERY_STRING} [NC,L]
# TAG URL : index.php?tag=space%2C+navigable+music#5
RewriteRule ^tag/([a-z0-9_\-]+)/$ index.php?tag=$1&%{QUERY_STRING} [NC,L]
# ONE PARAM
RewriteRule ^([a-z0-9_\-]+)/$ index.php?section=$1&%{QUERY_STRING} [NC,L]
Edit:
Note my folder structure. Could it be the problem source?
I have a "v1" and "v2" folder structure. This .htaccess sits in the "v2" folder. one level above, i have a .htaccess that redirects all requests to "v2".
root
L.htaccess << dispatch between v1 and v2 folders
L v1 L v2 L.htaccess << the .htaccess code posted above
L _admin L all my website files & folders

You’re using the wrong character, ¦ (broken bar, U+00A6) instead of | (vertical line, U+007C), and wrong pattern for REQUEST_URI.
RewriteCond %{REQUEST_URI} ^/v2/(_admin/|_css/|_js/|_img/)
RewriteRule . - [S=9]
Or for the .htaccess file in your v2 directory just:
RewriteRule ^_(admin|css|js|img)/ - [S=9]

Here are some random fixes that may or may not fix the actual problem, which is not totally clear (see my comment) and which could be helped if you control the server and enable the RewriteLog, via:
RewriteLog "/tmp/rewrite.log"
RewriteLogLevel 9
but you have to put this in main server configuration.
That said, two main problems:
Lack of use of QSA flag (not really relevant)
Excessive use of slashes (probably relevant in the actual problem, see new version of the skipping rule)
Here goes the modified file
IndexIgnore *
Options +FollowSymLinks
RewriteEngine on
# if the following conditions are met, SKIP the rewriteRules.
RewriteCond %{REQUEST_URI} ^(_admin¦_css¦_js¦_img)
RewriteRule . - [L]
# Externally redirect to add missing trailing slash. Not really needed, AFAICS
# RewriteRule ^(([^/]+/)*[^/]+)$ http://%{HTTP_HOST}/$1/ [NC,R,L,QSA]
# SIX PARAMS
RewriteRule ^([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/?$ /index.php?section=$1&item=$2&menu=$3&content=$4&id=$5&title=$6 [NC,L,QSA]
# FIVE PARAMS
RewriteRule ^([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/?$ /index.php?section=$1&item=$2&menu=$3&content=$4&id=$5 [NC,L,QSA]
# FOUR PARAMS
RewriteRule ^([^/]+)/([^/]+)/([^/]+)/([^/]+)/?$ /index.php?section=$1&item=$2&menu=$3&content=$4 [NC,L,QSA]
# THREE PARAMS : projects/touch/texts/
RewriteRule ^([^/]+)/([^/]+)/([^/]+)/?$ /index.php?section=$1&item=$2&menu=$3 [NC,L,QSA]
# TWO PARAMS: downloads
RewriteRule ^downloads/([^/]+)/?$ index.php?section=downloads&item=$1 [NC,L,QSA]
# TWO PARAMS:
RewriteRule ^([^/]+)/([^/]+)/?$ /index.php?section=$1&item=$2 [NC,L,QSA]
# TAG URL : index.php?tag=space%2C+navigable+music#5
RewriteRule ^tag/([^/]+)/?$ index.php?tag=$1 [NC,L,QSA]
# ONE PARAM
RewriteRule ^([^/]+)/?$ index.php?section=$1 [NC,L,QSA]
EDIT: Given the folder structure explained, try adding to the v2 .htaccess at the beginning the following:
RewriteBase /
You still haven't explained if you can or cannot use RewriteLog (I presume you can't)

Related

Convert Query Parameters to Pretty URL

I have script file post.php which I'm using without .php extension using code below
Options -Indexes
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.*)$ $1.php [NC,L]
I want to use a pretty URL. For example, when I request the URL /post/12 it should give me $_GET parameter 12 like I'm using with a query string: post?id=12.
Is it possible? Also, I don't want to direct all requests to index.php. Only requests that are made to posts.php script.
Handle requests of the form /post/12 with a separate rule, before your generic rewrite that appends the .php extension.
Try it like this:
Options -Indexes -MultiViews
RewriteEngine On
# Remove trailing slash if not a directory
# eg. "/post/" is redirected to "/post"
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*)/$ /$1 [R=301,L]
# Rewrite "/post/<id>" to "/post.php?id=<id>"
RewriteRule ^(post)/(\d+)$ $1.php?id=$2 [L]
# Rewrite "/post" to "/post.php" (and other extensionless URLs)
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule (.*) $1.php [L]
Notes:
MultiViews needs to be disabled for the second rule to work.
Your initial rule that appends the .php extension was not quite correct. It could have resulted in a 500 error under certain conditions. However, the first condition was superfluous - there's no point checking that the request does not map to a file before checking that the request + .php does map to a file. These are mutually inclusive expressions.
Without the first rule that removes the trailing slash (eg. /post/ to /post) it raises the question of what to do with a request for /post/ (without an id) - should this serve /post.php (the same as /post) or /post.php?id= (empty URl param)? Both of which are presumably the same thing anyway. However, these would both result in duplicate content (potentially), hence the need for a redirect.

Configure htaccess for url rewriting

I need help for my url's rewriting. I want to organize my url's precisely by taking account of the current organization of my current tree:
-! /www
.htaccess,
index.php, ...
--! **/views**, /assets
pageA.php, pageB.php, pageC.php
---! **/pageA**, /pageB, /pageC, /errors (404.php, 500.php...)
pageA1.php, **pageA2.php**, pageA3.php
/!\ I use specific names for each pages, the prefixes and numbers are just for examples and for a better comprehension about connexions between files and folders. In reality I use pages names like: "contact-us.php", "our-product.php" ...
(1) When I going to pageA.php I would like this url path: www.mywebsite.fr/pageA
(2) When I going to pageA2.php, I would like: www.mywebsite.fr/pageA/pageA2
(3) I don't want extension files (.php, .html)
Actually, I can't go into the path (2) cause I have a 404 page.
I created folders with the same name as a specific php pages it's just for my own organization, but it can be a bad way (for SEO or anything else...) in fact, I don't know...
My rewrite module (in .htaccess of www) is:
<IfModule mod_rewrite.c>
Options +FollowSymlinks
RewriteEngine on
RewriteBase /
# Retirer les extensions des pages et les rendres accessibles en lecture
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /([^\ ]+)\.php
RewriteRule ^/?(.*)\.php$ /$1 [L,R=301]
# check to see if the request is for a PHP file:
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^/?(.*)$ /$1.php [L]
# Suppression d'un sous répertoire
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{DOCUMENT_ROOT}/views/$1.php -f
RewriteRule (.*) /views/$1.php [QSA,L]
</IfModule>
This is just off the top of my head, but it should work:
RewriteRule ^page([A-Z]{1})([1-9]?).php$ http://www.mywebsite.fr/page$1$2
RewriteRule ^page([A-Z]{1})([1-9]{1})$ http://www.mywebsite.fr/page$1/page$1$2 [L,R=301]
The first Rewrite directive checks for a filename match starting with
page
and ending (prior to the filename extension, .php) with
a single letter (from A to Z); and
(optionally) a single number (from 1 to 9)
If it does, it captures both the letter (and the optional number) and rewrites the URI without the .php file extension at the end.
For those URIs which do include the optional number, the second Rewrite directive captures both the letter and the number separately from each other.
It then builds the redirect according to the correct folder structure, deploying both the captured letter and the captured number.

Combination of rewrites in .htaccess doesn't work

I have different rules in my .htaccess file which work fine individually but combined in one file they don't.
Here are some examples of my file:
# take care of %C2%A0
RewriteRule ^(.+)\xc2\xa0(.+)$ $1-$2 [L,NE]
# executes **repeatedly** as long as there are more than 1 spaces in URI
RewriteRule "^(\S*) +(\S* .*)$" $1-$2 [L,NE]
# executes when there is exactly 1 space in URI
RewriteRule "^productdetails/617/6/(\S*) (\S*?)/?$" /$1-$2/302 [L,R=302,NE]
Also I've got the following:
RewriteCond %{QUERY_STRING} ^pid=617/?$
RewriteRule ^productdetails\.asp$ /Casio-CDP120-Digital-Piano-in-Black/302? [L,NC,R=301]
which still work fine.
I have now added the following:
RewriteRule "^categories/3/Kawai Digital Pianos/?$" /Compare/Kawai-Digital-Pianos [L,NC,R=301]
which used to rewrite:
mysite.co.uk/categories/3/Kawai%20Digital%20Pianos/ to mysite.co.uk/Compare/Kawai-Digital-Pianos
this does not work anymore
Any help to get the last rule working in combination with the others would be great
You just need to make sure order of rules is correct. For your examples following order should work:
RewriteRule "^categories/3/Kawai Digital Pianos/?$" /Compare/Kawai-Digital-Pianos [L,NC,R=301]
RewriteCond %{QUERY_STRING} ^pid=617/?$
RewriteRule ^productdetails\.asp$ /Casio-CDP120-Digital-Piano-in-Black/302? [L,NC,R=301]
# take care of %C2%A0
RewriteRule ^(.+)\xc2\xa0(.+)$ $1-$2 [L,NE]
# executes **repeatedly** as long as there are more than 1 spaces in URI
RewriteRule "^(\S*) +(\S* .*)$" $1-$2 [L,NE]
# executes when there is exactly 1 space in URI
RewriteRule "^productdetails/617/6/(\S*) (\S*?)/?$" /$1-$2/302 [L,R=301,NE]

send all /mod/users URLs to a folder called moderator

I have a .htaccess file in the root directory of my project, that contains all the rewrite rules for the site to functions. Most of these rules belong to the mod section of the site, and only two of them belong to the front end, which the users use.
Problem is, when a front end user uses the site, apache ends up matching all the rules including the ones for the mods and signup etc, until it reaches the one for the end user, which I feel is unnecessary. I've checked this in the .htaccess log.
How can I place all rules for the moderator, signup and signin in their own directories, and do a rewrite rule in the root .htaccess file, that when it detects a url with mod, like /mod/all will send that request to the moderator directory. That way the root .htaccess file will have only the last two rules for the front end user along with others like no hot linking ones.
Something like:
If (URL Starts with '/mod/')
then send it to the '/moderator/' folder where the RewriteRules there will apply)
If (URL Starts with '/signup/'
then send it to the '/acc/' folder where the RewriteRules there will apply)
and so on.
My directory structure is as follows:
/acc/ ...handles account login and creation
/display/ ... handles front end display
/moderator/ ...the sites administrator
part of my .htaccess file
# Mod RewriteRules, some 12 in all
RewriteRule ^/?(mod)/(all|new|edit|redo|reject)/(push)/?$ /moderator/index.php?mode=$2&push=0 [NC,L]
RewriteRule ^/?(mod)/(all|new|edit|redo|reject)/?$ /moderator/index.php?mode=$2 [NC,L]
#signUp - Again, not always needed
RewriteRule ^/?(signup)/?$ /acc/signup/index.php?a=signUp [NC,L]
RewriteRule ^/?(signup)/(process)/?$ /acc/signup/process/index.php [NC,L]
#signIn - Again, not always needed
RewriteRule ^/?(signin)/?$ /acc/signin/index.php?a=signIn [NC,L]
RewriteRule ^/?(signin)/(process)/?$ /acc/signin/process/index.php [NC,L]
#signOut - Again, not always needed
RewriteRule ^/?(signout)/?$ /acc/signout/index.php [NC,L]
# These are the only two that a front end user will use
# category/subCategory
RewriteRule ^/?([a-z-]+)/([a-z0-9-]+)/?$ /display/index.php?t=$1&s=$2 [NC,L]
# category
RewriteRule ^/?([a-z-]+)/?$ /display/index.php?t=$1 [NC,L]
If you look at the above rules, the last two are the only ones that a user using the front end will use. However, the cannot be placed on top, because they'll end up catching anything first, because of the way they are.
Have root .htaccess like this:
RewriteEngine On
# forward mod|signup|signin|signout to /moderator/
RewriteRule ^(mod|signup|signin|signout)(/.*)?$ /moderator%{REQUEST_URI} [L,NC]
# These are the only two that a front end user will use
# category/subCategory
RewriteRule ^/?([a-z-]+)/([a-z0-9-]+)/?$ /display/index.php?t=$1&s=$2 [NC,L,QSA]
# category
RewriteRule ^/?([a-z-]+)/?$ /display/index.php?t=$1 [NC,L,QSA]
Then have /moderator/.htaccess like this:
RewriteEngine On
RewriteBase /moderator/
RewriteRule ^/?(mod)/(all|new|edit|redo|reject)/(push)/?$ index.php?mode=$2&push=0 [NC,L,QSA]
RewriteRule ^/?(mod)/(all|new|edit|redo|reject)/?$ index.php?mode=$2 [NC,L,QSA]
#signUp - Again, not always needed
RewriteRule ^/?(signup)/?$ /acc/signup/index.php?a=signUp [NC,L,QSA]
RewriteRule ^/?(signup)/(process)/?$ /acc/signup/process/index.php [NC,L,QSA]
#signIn - Again, not always needed
RewriteRule ^/?(signin)/?$ /acc/signin/index.php?a=signIn [NC,L,QSA]
RewriteRule ^/?(signin)/(process)/?$ /acc/signin/process/index.php [NC,L,QSA]
#signOut - Again, not always needed
RewriteRule ^/?(signout)/?$ /acc/signout/index.php [NC,L,QSA]

URL rewriting : Apache configuration to prevent loading default folder index.html

With the exact same .htaccess file, my local LAMP server (via mamp pro) and the production server behave differently. I suppose there is a different configuration at stake, but which one?
On my local server, http://domain.com/section/item/ redirects correctly to http://domain.com/index.php?section=$1&item=$2
On my production server, http://domain.com/section/item/ gives access to http://domain.com/section/item/index.html
What can i do to make the production server behave like the development server?
Here is the htaccess file content in case it helps.
<IfModule mod_rewrite.c>
RewriteEngine on
Options +FollowSymLinks
#--------------------------------------------
# PRETTY URLS
#--------------------------------------------
# if the following conditions are met, SKIP the rewriteRules.
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule . - [L]
# Externally redirect to add missing trailing slash
RewriteRule [^/]$ %{REQUEST_URI}/ [R,L]
# SIX PARAMS
RewriteRule ^([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/?$ index.php?section=$1&item=$2&menu=$3&content=$4&id=$5&title=$6 [NC,L,QSA]
# FIVE PARAMS
RewriteRule ^([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/?$ index.php?section=$1&item=$2&menu=$3&content=$4&id=$5 [NC,L,QSA]
# FOUR PARAMS
RewriteRule ^([^/]+)/([^/]+)/([^/]+)/([^/]+)/?$ index.php?section=$1&item=$2&menu=$3&content=$4 [QSA,L]
# THREE PARAMS : projects/touch/texts/
RewriteRule ^([^/]+)/([^/]+)/([^/]+)/?$ index.php?section=$1&item=$2&menu=$3 [QSA,L]
# TWO PARAMS: downloads
RewriteRule ^downloads/([^/]+)/$ index.php?section=downloads&item=$1 [QSA,L]
# TWO PARAMS:
RewriteRule ^([^/]+)/([^/]+)/?$ index.php?section=$1&item=$2 [QSA,L]
# TAG URL : index.php?tag=url+encoded+keyword
RewriteRule ^tag/([\w-]+)/$ index.php?tag=$1 [NC,L,QSA]
# ONE PARAM
RewriteRule ^([\w-]+)/$ index.php?section=$1 [L,QSA]
#--------------------------------------------
# END PRETTY URLS
#--------------------------------------------
</IfModule>
Try making 2 changes.
Add this line on top of your .htaccess file:
DirectoryIndex index.php
Then change your 1st rule to this:
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
EDIT: Also try this:
Options +FollowSymLinks -MultiViews
yes, both file directory structures are exactly the same
I don't know how exactly you've got everything setup, but it's possible that the order of modules being loaded is different between development and production (a long-shot), which could influence the order modules are being applied in the URL processing pipeline. It the order or something like mod_autoindex or mod_dir is different, thus causing a request for /section/item/ to get resolved to /section/item/index.html before mod_rewrite gets a chance to do anything. That means this condition becomes true:
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule . - [L]
And none of your other rules get applied, and thus /section/item/index.html gets served.
As to how to fix something like this, I suppose you can try turning off directory index in your server config (by commenting it out, everywhere), or set it to something non-existent in the directories that they are getting served:
DirectoryIndex _index.php