.htaccess with 2 parameters messing up css, js, images paths - regex

I was working with URLs on my webpage but I can't solve issue for URLs with 2 parameters.
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([a-zA-Z0-9-z\-]+)/?$ index.php?strona=$1 [L]
RewriteRule ^([a-zA-Z0-9-z\-]+)/([a-zA-Z0-9-z\-]+)/?$ index.php?strona=$1&id=$2 [L]
URLs seem fine except that when my current URL has 2 parameters (for example I'm on http://example.com/subpage/5 whole webpage is broken (stylesheets, navigation etc) because .htaccess changed all links to:
(for example navigation):
http://example.com/subpage_with_2_parameters/home
instead of
http://example.com/home
Pages with one parameter (example: http://example.com/contact) work fine.
Only solution (which is horrible) I have on mind are absolute links.

You're not the only one dealing with this problem of css, js, images paths getting messed up after implementing so-called pretty URLs. I am seeing these problems being reported on SO almost every day.
You can solve this problem in 3 ways:
Best solution is to use absolute paths for images, css and js files i.e. start your path with / or http://
Another option is to use base href tag in HTML head section like this:
<base href="http://www.example.com/">
3rd option is via mod_rewrite
Put these lines above your other RewriteLine in your .htaccess file:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteCond %{DOCUMENT_ROOT}/$1 -f
RewriteRule ^[^/]+/([^.]+\.(?:js|css|jpe?g|png|gif))$ /$1 [L,R=301,NC]

It's not your rewrite rules which are breaking your stylesheets, but your actual HTML. The same thing would happen if you had an actual directory called foo and placed index.php in there.
If you write Home, that link is relative to the current directory (in URL-space) so on a page with a URL like http://example.com/foo/bar/baz it links to http://example.com/foo/bar/home.
What you want instead is for the link to be relative to the root of your domain; for that, you need a leading slash: Home
The only reason this seemed to work before is that all your URLs were in the root directory, so "current directory" and "root of domain" were the same thing.

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

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]

Redirecting specific parameters to subfolders

I've been searching around a bit, but unfortunately I'm still at a loss when it comes to this problem, and being far from a veteran with .htaccess, I've been unable to work out a solution to my problem.
The platform is Wordpress, but since I'm convinced that this issue can be resolved with .htaccess I don't think that that should make much of a difference.
I need to rewrite searches when they are made to a more friendly URL structure, unfortunately, just changing ?s=Test to /search/Test isn't going to cut it. I need to pull 3 of the parameters out of the search and use them as subfolders, and then append the remaining parameters to the end of the search. Here's an example:
Old url:
http://www.XXXXX.com/?s=Ford&z=59105&ci=Billings&st=MT&r=450&m=15000&pmin=1000&pmax=30000&status=Used&submit=Refine
New url:
http://www.XXXXX.com/search/Used/MT/Billings/?s=Ford&z=59105&r=450&m=15000&pmin=1000&pmax=30000&submit=Refine
As you can see, the parameters "status", "st" and "ci" respectively have been inserted into the url with all of the remaining parameters following behind.
So essentially, I need to redirect the old url to the new url, but have the new url display the page that corresponds to the old url.
I've got the following written so far: (EDIT: *Changed {QUERY_STRING} to [L,QSA] as suggested by Explosion Pills*)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^/?search/([^/]+)/([^/]+)/([^/]+)/?s=([^/]+)?$ /index.php?s=$4&ci=$3&st=$2&status=$1 [L,QSA]
And it kind of works; you can type in the new url and it will display the page, though it seems that the "Used" directory isn't posting data correctly. It's also only half of the puzzle, as it doesn't redirect the old URL to the new one. It simple allows the new URL to exist.
Thank you very much for your help! This one has had me stumped for several days. now.
You may try this in one .htaccess file at root directory:
Options +FollowSymlinks -MultiViews
RewriteEngine On
RewriteBase /
RewriteCond %{QUERY_STRING} s=([^&]+)&z=([^&]+)&r=([^&]+)&m=([^&]+)&pmin=([^&]+)&pmax=([^&]+)&submit=([^&]+) [NC]
RewriteCond %{REQUEST_URI} !index\.php [NC]
RewriteRule ^search/([^/]+)/([^/]+)/([^/]+) /index.php?s=%1&z=%2&ci=$3&st=$2&r=%3&m=%4&pmin=%5&pmax=%6&status=$1&submit=%7 [L,NC]
Maps silently:
http://www.XXXXX.com/search/Used/MT/Billings/?s=Ford&z=59105&r=450&m=15000&pmin=1000&pmax=30000&submit=Refine
to
http://www.XXXXX.com/index.php?s=Ford&z=59105&ci=Billings&st=MT&r=450&m=15000&pmin=1000&pmax=30000&status=Used&submit=Refine
For permanent redirection, replace [L,NC] with [R=301,L,NC]

.htaccess file access

i have a question regarding .htaccess file access for css files and js files
i have this:
RewriteEngine On
RewriteBase /
RewriteRule ^$ index.php?page=index [L,NC]
RewriteRule ^([a-z0-9]+)/?$ index.php?page=$1 [L,NC]
RewriteRule ^([a-z0-9]+)/([a-z0-9]+)/?$ index.php?page=$1&subpage=$2 [L,NC]
now, i realize some files (like js, css) load correctly without using:
RewriteCond %{REQUEST_URI} !-f
will it be better if I add it before my rules, or it doesnt matter?
Usually it is safe to include RewriteCond %{REQUEST_URI} !-f in Rewrite rules so that physical files like css, js, images etc are not affected by these rules.
However in your case none of your rules will impact these css, js, images files because you are not including dot character . in your matching reular expression.
To overcome your issue I recommend using 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 /.
js, css files will be cached by your browser.
But in your case, for the path mentioned in the comments & the rewrites mentioned above. it will not affect. But any future rewrite rules may have affect on these. So it is better to add RewriteCond %{REQUEST_FILENAME} !-f.

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.