RewriteCond Being Ignored? - apache

I am trying to use mod_rewrite on a Ubuntu 12.04 server to make my URLs more readable, however I want to add an exception for images and css files.
My input URLs are in the format \controller\action which is then re-written to index.php?controller=controller&action=action. I want to add an exception so that if an image or css file is specified, the URL is not re-written, e.g. \images\image.jpg would not be re-written.
My .htaccess code is as follows:
RewriteEngine on
RewriteCond %{REQUEST_URI} !(\.gif|\.jpg|\.png|\.css)$ [NC]
RewriteRule ^([a-zA-z]+)/([a-zA-z]+)$ test.php?controller=$1&action=$2 [L]
RewriteRule ^([a-zA-z]+)/([a-zA-z]+)/([^/]*)$ test.php?controller=$1&action=$2&$3 [L]
My re-write code is working fine and the URLs are coming out as intended, however even if I request an image, the URL is still being re-written. It appears that my RewriteCond is being ignored, anyone any suggestions as to why this might be?

The RewriteCond only applies to your first RewriteRule, it should be reproduced for the second rule. However, I think that is better to add a non-rewriting rule, before, to exclude existing stuffs.
# Do nothing for files which physically exist
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule .* - [L]
# your MVC rules
RewriteRule ^([a-zA-z]+)/([a-zA-z]+)$ test.php?controller=$1&action=$2 [L]
RewriteRule ^([a-zA-z]+)/([a-zA-z]+)/([^/]*)$ test.php?controller=$1&action=$2&$3 [L]

The rewriteCond rule is only applied for the next RewriteRule.
So you need to at least repeat the rewriteCond for your seconde RewriteRule.
No there is certainly better things to do.
For example a usual way of doing it is to test that the url is matching a real static ressource. If all your php code is outside the web directory (in libraries directory, except for index.php) then all styatic ressources available directly on the the document root can only be js files, css files, or image files.
So this is the usual way of doing it:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([a-zA-z]+)/([a-zA-z]+)$ test.php?controller=$1&action=$2 [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([a-zA-z]+)/([a-zA-z]+)/([^/]*)$ test.php?controller=$1&action=$2&$3 [L]
But this is a starting point. We could certainly find something to avoid doing 2 rules for this (maybe I'll have a look later)

Related

Why does the following file does not exist condition not work in htaccess?

Don't know why the following rewrite rules do not work. The file-not-exist condition always triggers even though the file article/1.html file does exist. The requested URL is:
https://exampledomain.com/test-a-1.html
RewriteCond %{REQUEST_FILENAME} ^(.*)-a-([0123456789_]*)\.html$
RewriteCond %{DOCUMENT_ROOT}/article/%2.html !-f [NC,OR]
RewriteCond %{QUERY_STRING} !^$
RewriteRule ^(.*)-a-([0123456789_]*)\.html$ news.php?article=$2&%{QUERY_STRING}
RewriteRule ^(.*)-a-([0123456789_]*)\.html$ /article/$2.html
If I comment out the !-f RewriteCond it nicely falls through to the second rule and accesses article/1.html. If this condition is active it never rewrites to article/1.html but always goes to news.php?article=1
With your shown samples, please try following. Please make sure to clear your browser cache before testing your URLs.
RewriteEngine ON
##Rules when .html file is not present in system.
RewriteCond %{DOCUMENT_ROOT}/article/$2.html !-f [NC]
RewriteRule ^([^-]*)-a-([0-9_]*)\.html/?$ news.php?article=$2&%{QUERY_STRING} [NC,L]
##Rules when .html file is present in system.
RewriteCond %{DOCUMENT_ROOT}/article/$2.html -f [NC]
RewriteRule ^([^-]*)-a-([0-9_]*)\.html/?$ article/$2.html [NC,L]
I finally figured out the answer to my question. There is nothing wrong with my rewrite conditions or rules. They are exactly what they should be. However, %{DOCUMENT_ROOT} does not point to where the Apache documentation says it points to. On my Ionos managed server it points to /var/www/html. However, my actual document root is something like /kunden/homepages/... So the solution is to use the actual absolute path rather than %{DOCUMENT_ROOT}. Now everything works as it should.

RewriteRule for several parameters

I'm currently working on a project powered by a home-made CMS and I'm experiencing some issues with URL rewriting.
Here's the thing: all the website is centralized around the index.php located in the main directory. Depending on what he gets thought the URL, the index.php displays the right page (the pages are included from a inc/pages/ folder)
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [L,R=301]
RewriteRule ^([A-Za-z0-9-]+)/?$ index.php?page=$1 [NC]
For a single parameter, it works great. http://demo.com/subscribe/ or demo.com/subscribe does transmit a $_GET['page'] to the index.
For some pages, I do need a second parameter. So it's not required for each single pages. Per example, http://demo.com/edit/I-love-Stackoverflow should transmit a $_GET['snd_param')
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [L,R=301]
RewriteRule ^([A-Za-z0-9-]+)/([A-Za-z0-9-]+)?$ index.php?page=$1&snd_param=$2 [NC]
I tried this but this isn't working well. First, if the second parameter is not mentioned (demo.com/edit) it's not working. The index doesn't receive the right $_GET['page']. Secondly, when the second parameter is mentionned, it "works" but apache believes this is a directory. My index page is then located in the fictive "I-love-Stackoverflow" folder and loading the CSS, images and javascript fails.
I hope I explained my issue pretty clearly ! Thanks in advance for helping me
You should treat the rules separately. All Conditions preceding rules only apply to a single rule, so basically the second RewriteRule is not executed at all.
You can use something like this:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]+)$ index.php?page=$1 [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]+)/([^/]+)$ index.php?page=$1&snd_param=$2 [L]
My index page is then located in the fictive "I-love-Stackoverflow"
folder and loading the CSS, images and javascript fails.
You are probably load your assets using relative paths, so the browser only knows for the unmodified url ( http://demo.com/edit/I-love-Stackoverflow ) in your case, and the wrong urls are created when browser load the assets. If you load resources with absolute paths instead of relative, you will be okay.

CMSMS htaccess rewrite for ListIt2 module

i'm creating a website with CMS made simple version 1.11.11 and i use the listit2 module version 1.4.1 .
Now this module only can generate urls in this form:http://example.com/listit2/item-alias/page-id
Now, i don't care about the page id which is used to show the correct template,
but since this is a multilingual website i would like listit2 to apear behind my (virtual) language folder: http://example.com/lang/listit2/item-alias/page-id
so i added 2 rewrite lines in my htaccess file,
right before the general rewrite rules of CMSMS.
RewriteCond %{HTTP_HOST} ^lang/listit2 [NC]
RewriteRule ^lang/listit2(.*)$ listit2$1
# Rewrites urls in the form of /parent/child/
# but only rewrites if the requested URL is not a file or directory
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)$ index.php?page=$1 [QSA]
but that doesn't seem to work since it generates the summary overview instead of a detail page like the content from http://example.com/listit2/page-id
How, can i solve this?
This does the trick
RewriteEngine on
RewriteBase /
#Virtual folders for listit2
RewriteRule ^lang/listit2(.*)$ index.php?page=listit2$1
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)$ index.php?page=$1 [QSA]
It isn't a .htaccess issue. It is a URL generation issue within the ListIt2 module.
Within your summary template, instead of using the standard variable for the detail_url, you will need to put your own custom URL in the href.
For example something like this (this code isn't test, check documentation for the actual variables)
Read More...

htaccess rewrite .html not required / is optional

I have a working website, with atleast 500 pages ranked in Google.
All pages have .html at end of page.
Now I want to remove .html of all pages, but let the pages in Google (with .html) keep there index.
After searching I cant find the correct answer.
I know the ? is for optional. I tried 2 Rules behind eachother but didnt work too.
Here is what my htaccess now is:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*).html$ find_page.php?redirect=$1&%{QUERY_STRING} [L,QSA]
I tried with adding:
RewriteRule ^(.*)$ find_page.php?redirect=$1&%{QUERY_STRING}
So if URL contains no extension use this rule, else use the normal rule (with htaccess)
I should expect my rule should be something like this: ^(.*)(?\.html)$
So my goal is: With or without html should work, but .php shouldnt be work :-)
Why look for a complex solution?
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)\.html$ find_page.php?redirect=$1 [L,QSA]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)?$ find_page.php?redirect=$1 [L,QSA]
This rewrites all request to that php script, adding the original "file name" as parameter "redirect" and preserves all query parameters. That is what you asked for in your question.
But a warning: you can do this and it will allow to rewrite requests to for example page "redirection" as .../redirection?somearg or .../redirection.html?somearg. But for google both request are completely different pages. This will not help you to preserve any ratings when shifting to the new request scheme.
And a general side note: if you have control over the http server configuration, then you should always prefer to place such rules in the hosts configuration instead of using .htaccess style files. Such files are notoriously error prone, make things complex, are hard to debug and really slow the server down. They should only be used in two cases: if you do not have control over the http server configuration or if you require your scripts to do dynamic changes to your ruleset (which is always a very insecure thing).
Ok solved my problem.
RewriteEngine On
RewriteCond %{THE_REQUEST} ^[A-Z]+\ /([^/]+/)*[^.#?\ ]+\.html([#?][^\ ]*)?\ HTTP/
RewriteRule ^(([^/]+/)*[^.]+)\.html find_page.php?redirect=$1&%{QUERY_STRING} [L,QSA]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ find_page.php?redirect=$1&%{QUERY_STRING} [L,QSA]
With this option there will be checked if the page has .html optional at end. If it has, will the first rule be matched, else will go further and use the second rule which has no html at the end
Try
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ $1.html
You don't need find_page.php for redirection. As it mentioned in other answer http://server/folder/file and http://server/folder/file.html becomes the same for the user but different for the Google.
This does not affect to PHP, folders and other content. It just tries to add «.html» to requested URL if it does not point a file or folder.
I've checked, it works fine even user queries uri with anchor like 1.html#bookmark1

Is it possible to chain RewriteCond in htaccess?

I am going to be doing some basic %{HTTP_HOST} work in my .htaccess file and was wondering if it would be possible to do something similar to this:
RewriteCond %{HTTP_HOST} ((foo|bar|baz).com)$
RewriteCond %{DOCUMENT_ROOT}/apps/%1/webroot%{REQUEST_URI} -d [OR]
RewriteCond %{DOCUMENT_ROOT}/apps/%1/webroot%{REQUEST_URI} -f
RewriteRule %{DOCUMENT_ROOT}/apps/%1/webroot%{REQUEST_URI} [L]
RewriteRule ^(.*)$ index.php?uri=$1 [QSA,L]
basically, if someone visits foo.com on any sub-domain, I want them to be served files directly from that folder but also have any requests that aren't for specific files sent to my index.php file for processing (which will do the routing)
The reason I am asking is because what I have written above does not actually work, so is there a way to do it? (also if this SHOULD work then it'll obviously be a problem with the rest of my .htaccess file, but it all works when dealing with just one application folder)
The other (messy IMO) way would be to route everything to the folders and have a second .htaccess file for each domain, but I'd rather not do this if it can be done in one file!
Your first rewrite rule is missing a regex, which makes the rewrite engine thing you are trying to match (as a regular expression) %{DOCUMENT_ROOT}/apps/%1/webroot%{REQUEST_URI} and you want to rewrite that to [L]. I suspect you want that to look like:
RewriteRule ^ /apps/%1/webroot%{REQUEST_URI} [L]
The ^ matches anything, since you've already vetted the request with your 3 conditions.
Now you need to add a few conditions to your last rule so that it doesn't blindly get applied to everything. You probably want something like:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?uri=$1 [QSA,L]