htaccess->show file if in cache directory, if not continue - regex

Im playing arround with cache. What I want is the following logic:
if ( file_exist(/cache/$request_uri.txt) ){
1. show that file
2. Stop all rewrite actions, but perform other actions (like charset, error_pages)
}
else{
do whatever you normally do
}
Small example. I have the following files
http://domain.com/example-123.htm (the requested page)
http://domain.com/cache/example-123.htm.txt (the cache-version of that page)
http://domain.com/someDir/example-456.htm (the requested page)
http://domain.com/cache/someDir/example-456.htm.txt (the cache-version of that page)
Instead of getting the index.php to parse the url and build the page, I want to show that file and stop.
I though this would do it, but it doesn't:
RewriteCond ^cache%{REQUEST_URI}\.txt -f # check if the file exists in cache dir
RewriteRule ^(.*) /cache/$1\.txt [L] # i so, rewrite rule to it and stop
The [L] does, according to my cheatsheet, "Last - stop processing rules". If that only means the rewrite rules, than thats what I need.
I cant get it to work, I could use a push in the right direction :)
I've marked an answer as solution it, did exaclty what it should. The reason I want this in the .htaccess file is because this way my index.php doesn't get called, nor does the database. A very fast and light method.
However, this creates a new problem: Some items (like the menu) can change (often). That would mean I'd have to delete all cache files every change, which prohibits it from working efficient.
To tackle this problem, im going to see if I can use some clever .shtml files to fix that problem (might need to allow php to woth in shtml files).
I'll update this post as soon as I've got something nice working for those interested

You can try this rule:
# check if the file exists in cache dir
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{DOCUMENT_ROOT}cache/$1.txt -f
RewriteRule ^(.+?)/?$ /cache/$1.txt [L]

Related

RegEx for just displaying items in private folder

I want to have an regular expression witch just allows to access files in a private folder. This is my code so far:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !(.*)(/public/)(.*)
#RewriteCond %{REQUEST_FILENAME} !-f #not active in this example
RewriteRule . index.php [L]
It works fine as far as I can see it's working fine but there is one thing I'm wondering about:
if there is an directory structure like /localhost/test/public and I'm calling the same url I can see the folder content, but if there isn't a public folder localhost/test/ and I'm calling /localhost/test/public it will lead to the index.php
Why isn't it displaying a 404 page?
I think UnskilledFreak is right:
If you don't put a slash (/) at the end of an url, the server "thinks" you want a file and checks if it exists. If its a directory, it'll automatic use that; if not, your rewrite of filename will match and redirect to index.php

My apache rewrite only works for the first folder level

We have a website where we show clients creative work we have produced for them. We upload raw assets to a path like this:
x.com/clients/clientName/campaignName/size/
I have a PHP script which adds our branding, contact information and other information and pulls in the raw creative (usually a swf object). It is in this directory x.com/clients/index.php and it accepts a query string parameter ?path so it knows where to look for the creative.
I am trying to do an apache rewrite in .htaccess so that our designers can upload directly to the known folder structure but so that when you go to x.com/clients/clientName/campaignName/size/ it should rewrite to x.com/clients/index.php?path=clientName/campaignName/size/
I am currently using the following rewrite rule, which works for the first folder level e.g. x.com/clients/clientName/ does successfully rewrite, but any subsequent folders do not.
RewriteRule ^clients/([^/\.]+)/?$ /clients/index.php?path=$1 [L]
My RegEx's are terrible, so I'm stuck on what to do. Any help appreciated, thank you kindly.
Your regex is only matching urls like clients/xxxxxx/ because your pattern [^/\.]+ means one or many characters except "/" or "."
With your rule, it can't work for other subdirectories.
You can change your rule by this one
RewriteRule ^clients/(.+)$ /clients/index.php?path=$1 [L]
To avoid internal server error (code 500 which means an infinite loop in this case), you can do it this way
RewriteRule ^clients/index\.php$ - [L]
RewriteRule ^clients/(.+)$ /clients/index.php?path=$1 [L]
Is there a special reason you want to use regex? In my opinion you can just catch everything coming after /clients:
RewriteEngine on
RewriteCond %{REQUEST_URI} !^(.*/)?index\.php$ [NC]
RewriteRule ^clients/(.*)$ /clients/index.php?path=$1 [L]
The second line is to prevents redirect loops, because the index.php is also in the folder /clients and this would cause never ending redirects.

Removing a string of characters in a URL through htaccess

I'm struggling to come up with the correct code to do what I need. I've searched through SO and other sites and found answers close to what I want, but I just can't quite piece it all together right, and .htaccess is a huge weakness of mine.
I'm trying to make it so an entire folder level gets removed from all URLs on a site, otherwise preserving the structure. After that, I need to add ".html" to the end. The addition isn't anything hard, but I'm missing what I need to strip out the folder.
Starting URL: www.domain.com/ANYFOLDER/any-page-name
(Bonus: www.domain.com/ANYFOLDER/ANYDEPTH/any-page-name)
Ending URL: www.domain.com/any-page-name.html
We have a client who is moving from a static site to CMS-driven, has some great ranks/traffic for his URLs, and is petrified he will lose this (we will not take Permanent Redirects as a solution).
You can use this rule for this redirect:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(?:[^/]*/)*((?!.+?\.html$)[^/]*)$ /$1.html [L,R=302,NC]

mod_rewrite problem with relative path css/js

Hi I have a problem.
I want to get all requests to redirect to index file in main directory and I've achieved this but there are problems with relative paths.
When I put address like: mydomain.com/something it works ok as the paths are relative to the main directory.
The problem is when I put something like: mydomain.com/something/somethingelse.
the .htaccess file:
Options FollowSymLinks
RewriteEngine On
# ignore anything that's an actual file
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f
# redirect all other traffic to the index page
RewriteRule . index.php [L]
Any ideas on how to get css/js working?
Edit:
The problem is that css/js files aren't loaded when the path entered have multiple slashes like:mydomain.com/something/somethingelse
It is no doubt better to use absolute path for static files (css, js, images etc). But if you lots of those instances in several pages then consider using HTML base tag to specify a default URL for relative paths. eg:
<base href="http://www.example.com/static/" />
Using the <base>-tag is a nice solution and most browsers seem to handle it well. Except there are some issues with IE, as was to be expected... Apparently you can also run into some other funny problems, see discussion here.
So for people where this is not an option, i have looked into the alternative (the "hard way").
Usually you store css/js/static images/other stuff like this:
index.php
js/
css/
imgs/
and you want the javascript and stylesheets etc. to be available, no matter how many slashes there are in the url. If your url is /site/action/user/new then your browser will request
/site/action/user/css/style.css
/site/action/user/css/framework/fonts/icons.ttf
/site/action/user/js/page.js
/site/action/user/js/jquery/jquery.min.js
/site/action/user/js/some/library/with/deep/dir/structure/file.map
So here are some rewrite rules for apache to solve this... First, if the target actually exists on disk, do not rewrite:
RewriteCond %{REQUEST_FILENAME} -d [OR]
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^.*$ - [L,QSA]
In words, IF reqest filename is a directory OR IF request filename is a file then do not rewrite (-), last rule (L) and pass any GET parameters (QSA, query string append). You can also use
RewriteCond %{REQUEST_FILENAME} -d [OR]
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -l
RewriteRule ^.*$ - [L,QSA]
if you also need symlinks. Next we want the javascript and stylesheets to be found even if the requests assume a wrong base directory as shown above.
RewriteRule ^.*/js/(.*)$ js/$1 [L]
RewriteRule ^.*/css/(.*)$ css/$1 [L]
The pattern is pretty obvious, just replace 'css' with the directory name. There is still a problem with this, especially for large websites with lots of javascript and stylesheets, libraries etc. - The regex is greedy. For example, if you have a javascript directory like this:
js/some/library/js/script.js
and your request goes to /site/action/user/new, the browser will request /site/action/user/new/js/some/library/js/script.js, which the rewrite-engine will then rewrite to
js/script.js
because the first .* is greedy and matches /site/action/user/new/js/some/library. Switching to non-greedy regex does not really make sense, since "the rewrite engine repeats all the rules until the URI is the same before and after an iteration through the rules."
There is another problem, and that is that for every directory that needs to be exempted from rewriting, a relatively "expensive" regex is needed. Both problems can be fixed by just putting every static component into a subdirectory with an "unusual" name (and really this is the best solution imo - anyone with a better idea please post it).
The directory structure would then look like this:
index.php
mystrangedir/js/
mystrangedir/css/
mystrangedir/imgs/
Of course, this needs to be inserted everywhere in the code - for projects with a large existing codebase this can be tricky. However, you only need a single regex for directory exemption then:
RewriteRule ^.*/mystrangedir/(.*)$ mystrangedir/$1 [L]
Automated build systems (like gulp, grunt....) can be used to check if "mystrangedir" does not exist as directory anywhere below itself (which would again throw off the rewrite engine).
Feel free to rename mystrangedir to something more sensible like static_content but the more sensible it gets, the more probable it is that the directory name is already used in some library. If you want an absolutely safe directory name that has certainly never been used before, use a cryptographic hash, e.g. 010f8cea4cd34f820a9a01cb3446cb93637a54d840a4f3c106d1d41b030c7bcb. This is pretty long to match; you can make a tradeoff between uniqueness and regex performance by shorting it.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule . index.php [L]
Should obviously work despite the comments.
Try to add the RewriteLog and RewriteLogLevel directive to give us better details.
This is a path resolution issue: When using the relative path ./css on the base path /something it is resolved to /css while on /something/somethingelse it is resolved to /something/css.
This can’t (or rather shouldn’t) be fixed with mod_rewrite. Use absolute paths instead of relative paths, so /css instead of ./css.

Explain this .htaccess snippet

Can someone explain the following htacess lines, I understand parts, but would like a deeper knowledge. As a note I assumes it works as intended, this is not currently live, I am just reading through some workbooks and this was printed.
// Don't understand this line
Options -Multiviews
// Don't understand this line
Options +FollowSymLinks
// Understand this line
RewriteEngine On
// Don't ~fully~ understand this line, esp. in context
RewriteBase /portfolio
// Don't ~fully~ understand this line
// I understand that its asking if the filename is a valid file or dir
// but is it overall saying if valid file or valid dir perform rewrite?
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
// Don't understand, $1 is the STRING, and the rest the condition, but
// how do you read this condition?
RewriteCond $1 !^(index\.php|images|robots\.txt|css)
// Don't understand (but do understand the RewriteRule PATTERN REPLACE, but is it
// saying replace 'all' with index.php/all ?
RewriteRule ^(.*)$ index.php?/$1
Options -Multiviews
This disables the Multiviews Apache option. Basically, the option allows the server to look for content in the same directory using different file names based on the content types and languages accepted by the client. The directive is just disabled in this case to make sure Apache doesn't serve any unexpected files.
Multiviews enables content negotiation, which is explained at: http://httpd.apache.org/docs/current/content-negotiation.html
Options +FollowSymLinks
This makes sure the FollowSymLinks option is enabled. This setting allows Apache to follow symbolic file links in the directory if they exist. This setting exists in case there are symbolic file links to make files physically exist elsewhere on the server than what is requested.
Longer explanation at: http://www.maxi-pedia.com/FollowSymLinks
RewriteBase /portfolio
This setting is for defining the base path for the url used by the rewrite engine. When the rewrite engine rewrites the url in .htaccess, it strips away the path to the current directory. Once the url rewriting is complete, it will add it back based on the current file directory. However, sometimes the url that is requested does not have the same path as the directory structure on the server itself. The RewriteBase tells the rewritengine what the URL path is to the current directory. In this case, for example, the files may be stored in /foo/bar, but they are accessed via the browser as www.example.com/portfolio. The RewriteBase tells the engine to add /portfolio to the url, instead of /foo/bar.
For complete explanation, see: http://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewritebase (the url also contains explanations to the other Rewrite parts of the .htaccess).
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
These lines make sure that any url that is an actual existing file or directory wont get rewritten. The ! before the condition is negation. So these two conditions should be read as ifNotFile AND ifNotDirectory.
RewriteCond $1 !^(index\.php|images|robots\.txt|css)
The $1 here refers to the sub pattern capture 1 of the actual rewrite. In other words, it means the part captured by (.*) in the RewriteRule. Basically, this rule simply checks that the RewriteRule wont rewrite any url that starts with "index.php", "images", "robots.txt" or "css".
RewriteRule ^(.*)$ index.php?/$1
This simply tells the rewrite engine that any request (that isn't prevented by the rewrite conditions, of course) should be rewritten to index.php? with the actual request following it. Just like you said, a request foo/bar will be forwarded to index.php?foo/bar. The point is to allow index.php to handle the file requests (which can access them via $_SERVER['QUERY_STRING']), which is very common practice in CMS systems and frameworks.
I hope these explanations will help. I don't have extensive experience on all these directives, so slight inaccuracies may exist, please comment if so.