Htaccess Match Random 6 characters, with exceptions? - apache

Alright, so I've been trying to wrap my head around (what I believe to be) a simple mod_rewrite case. Maybe it's not, but I'm hoping you can help me with that, Stack Overflow.
So what I want is this: there are several folders that need to be ignored (ie, "css", "js", "bootstrap", etc). If the url string doesn't match those, I want to check if it's a string of exactly six letters and numbers, and redirect that to one url. Otherwise, it gets redirected to another url.
This is what I have:
RewriteCond %{REQUEST_URI} !^/(index\.php|images|robots\.txt|bootstrap|phpmyadmin|css|js|font|recaptchalib.php|uploads)/
RewriteRule ^(a-z0-9+){6}$ /index.php/download/index/$1 [L]
RewriteRule ^(.*)$ /index.php/$1 [L]
If I take out the middle line, it works fine except I don't get the "match 6 random characters" functionality. With the middle line, I get a 500 error on every page.
Could someone help me out please?

You need to repeat the condition. A RewriteCond only applies to the immediately following RewriteRule. So you're second rule doesn't exclude all those folders in the pattern that you have in your condition. Try:
RewriteCond %{REQUEST_URI} !^/(index\.php|images|robots\.txt|bootstrap|phpmyadmin|css|js|font|recaptchalib.php|uploads)/
RewriteRule ^(a-z0-9+){6}$ /index.php/download/index/$1 [L]
RewriteCond %{REQUEST_URI} !^/(index\.php|images|robots\.txt|bootstrap|phpmyadmin|css|js|font|recaptchalib.php|uploads)/
RewriteRule ^(.*)$ /index.php/$1 [L]

You should let CodeIgniter handle this. Keep your .htaccess for routing to the index.php front controller, and use route(s) to handle the URI and where it should go from there.
This is especially true because now ANY six-letter URI is going to be defaulted. What if you have a controller like example.com/bloggers? It will always be assumed to be a download item, even if it's a real controller URI.
The "easiest" option (read: option that does not conflict with existing controllers/routes) is to utilize the 404_controller to check the URI and see if it's a valid download URL. Then you can run the appropriate code.
To explain a likely reason why your .htaccess code is not working: your regular expression for matching six alpha-numeric characters is wrong. Here's what you need:
^([a-zA-Z0-9]{6})$
This regex can be used as a CodeIgniter route, also, if you go that route (heh). Just remove the ^$ beginning/end characters, as CI puts them there for you.
As mentioned by Jon Lin, you also need to duplicate RewriteCond conditionals, as they are only good for one RewriteRule. After one, the conditionals reset.

Related

Block direct access to .php files, less the index.php file and ajax.php file

been looking for your help, i found a method, but it is not as i wish. if someone can help me.
What I want is that nobody can enter a direct URL with .php
example when I enter my domain.com/buy/product.php, I want it to be forbidden,
I was looking for information here, I found this code that worked for me but in .htaccess
RewriteEngine On
RewriteCond %{THE_REQUEST} "^.+? [^?]+\.php(?:[?/# ]|$)" [NC]
RewriteRule !^index\.php$ - [F,L,NC]
it worked fine for me, but the problem that I in a directory /include/ajax.php , I use an ajax. and it gives me error to execute the ajax by browsing.
Now what I'm thinking how to make it work with that htaccess code that you can enter the index.php and /include/ajax.php, I tried all means but it does not work for me.
In another case if you know any code to add to my php or how to do for my version which is version 7.3, but without ruining my code.
Rather than giving you the answer straight out, I'm going to give you some hints so that you aren't copying code you don't understand.
Each RewriteRule has three parts:
the pattern to match against the URL sent by the browser
the URL to rewrite to
an optional set of flags for extra options
Before each rule, you can optionally have one or more RewriteCond lines which apply extra conditions to the rule; each has three parts:
a variable to match against
the pattern to match
an optional set of flags for extra options
The most important flag in this case is [F], short for [forbidden], which says "if the rule matches, instead of rewriting or redirecting, just server a 403 response.
You should very rarely need to test against %{THE_REQUEST}, which is a raw version of the request line from the browser; much more often, you want %{REQUEST_URI} and/or %{QUERY_STRING}.
The patterns in both RewriteRule and RewriteCond can be negated (i.e. "must not match this pattern") by starting them with !
So, if you wanted to return a 403 for all URLs ending ".bad", except for URLs ending "not.bad" or "only-a-little.bad", you could write this (note that $ is the way to say "must end here" in the regex patterns):
RewriteCond %{REQUEST_URI} !not.bad$
RewriteCond %{REQUEST_URI} !only-a-little.bad$
RewriteRule .bad$ - [F]
Hopefully it should be straight-forward enough to see how to adapt that to your requirements.
The full list of options and variables available is in the Apache manual.
After 2 days of looking for some code, I was able to read and understand.
study how htaccess works.
Thanks to the users who guided me, I found the solution.
Although my title is not quite correct.
My intention was always to block all .php that always the user wanted to enter directly by .PHP, I had found the code above, but it did not work with a specific file in the /include/ajax.php folder, exactly it was an ajax, I could not find solution.
exactly it was an Ajax, I could not find the solution to make it work.
Until I managed to solve this way.
RewriteEngine on
RewriteCond %{THE_REQUEST} ajax\.php [NC]
RewriteRule ^ - [NC,L]
RewriteCond %{THE_REQUEST} .+\.php [NC]
RewriteRule ^ - [F,L]
This causes all .php to be blocked, except the index.php and the /include/ajax.php file.
This is how it worked for me.
If I am right or wrong, can you give me some guidance.
I leave this in case someone might find it useful in the future.
I was always recommended to route my php, that I would forget about these problems.
I will keep it in mind as I move forward in the future, to route my php.

RewriteRule to remove version number

I have implemented a cache busting solution on a site where a version number is added to the end of the file name, before the file extension. However I am having an issue with one of the rules not working.
Typical requests:
/static/deploy/styles/site_78_direct.min.0.css
/static/deploy/styles/ie/site_78_direct.0.css
I need the above to be redirected to the following:
/static/deploy/styles/site_78_direct.min.css
/static/deploy/styles/ie/site_78_direct.css
I came up with the following which half works:
RewriteRule ^/static/deploy/styles/ie/(.*).([0-9]+).css$ /static/deploy/styles/ie/$1.css [L]
RewriteRule ^/static/deploy/(scripts|styles)/(.*).min.([0-9]+).(js|css)$ /static/deploy/$1/$2.min.$4 [L]
The above redirects properly but I want it to ignore the following:
/static/deploy/styles/ie/site_78_direct-blessed1.css
I basically only want to redirect if there is a number between fullstops, i.e. .0.css
Any help would be greatly appreciated.
Make sure to escape the dot otherwise it will match any character.
Besides just this single rule should work for both cases:
RewriteRule ^(/?static/deploy/.+?)\.\d+\.(js|css)$ $1.$2 [L,NC]

.htaccess how to force/automatic clean URL

I'm new to mod_rewrite but am trying my best to fix up my site with clean URLs.
Using RewriteRule I can get it so you can type in a clean URl and get to the right page, but what I'm having trouble with is automatically redirecting to the clean URL if a "messy" one is used (which is highly possible due to user submitted links and content etc)
Now, I have this bit of code which I found on another .htaccess forum, and it works in one situation, but not another. I'll explain:
# FORCE CLEAN URLS
RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s/+index\.php\?(.*)=([^\s]+) [NC]
RewriteRule ^ %1\/%2? [R=301,L]
This works fine on an address like this, for example: www.domain.com/index.php?cmd=login it automatically redirects to www.domain.com/cmd/login
But the problem comes when there is more than one query, like: www.domain.com/index.php?cmd=view-profile&user=bob
I can't figure out how to make it sort out that kind of URL when there could be up to 3 or more queries in the address.
I'm not fully competent with regex, so my attempts to amend the code snippet I have has failed thus far.
Any help would be appreciated! I would like them to be 301 redirects so that the site can get indexed properly and be SEO compliant no matter what type of clean or messy URL is used, but I'm open to suggestions!
EDIT
After playing around with the regex for a few hours, I've progressed but got stumped again.
If I make the expression to this:
index\.php\?(.*)=([^\s]+)(&(.*)=([^\s]+))?+
$1/$2/$3/$4/$5
It will match these 3 URLs from index.php onwards:
http://site.com/index.php?cmd=shop&cat=78
http://site.com/index.php?cmd=shop
http://site.com/index.php?cmd=shop&cat=78&product=68
BUT the resulted output varies depending on which it is. These are my results:
http://site.com/cmd=shop&cat/78///
http://site.com/cmd/shop///
http://site.com/cmd=shop&cat=78&product/68///
I'm nit sure how to get it to treat certain parts as optional so it groups properly.
You'll need to deal with each number of pairs of parameters separately. The one you have can be used to handle one name/value pair, then approach it similarly for 2, and 3 (and 4 if needed):
# To handle a single name/value pair in the query string:
RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s/+index\.php\?([^&=]+)=([^&\ ]+)(\ |$) [NC]
RewriteRule ^ /%1\/%2? [R=301,L]
# To handle 2:
RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s/+index\.php\?([^&=]+)=([^&\ ]+)&([^&=]+)=([^&\ ]+)(\ |$) [NC]
RewriteRule ^ /%1\/%2/%3/%4? [R=301,L]
# To handle 3:
RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s/+index\.php\?([^&=]+)=([^&\ ]+)&([^&=]+)=([^&\ ]+)&([^&=]+)=([^&\ ]+)(\ |$) [NC]
RewriteRule ^ /%1\/%2/%3/%4/%5/%6? [R=301,L]
Basically, you're adding another &([^&=]+)=([^&\ ]+) before the check for the end of the request, (\ |$), and adding another /%#/%# to the end of the target URI, where the #'s are appropriate incremented backreferences.

Shorten URLs with mod_rewrite

I am currently trying to make a URL shortener feature for one of my projects; what I want to do if a user visits the site with a URL that does not contain any slashes (for directories) or file extensions, it should redirect to a PHP script that will serve up the correct file. For example:
http://example.com/A123 would be rewritten as http://example.com/view.php?id=A123
but
http://example.com/A123/ would not be rewritten, and
http://example.com/A123.png would not be rewritten either. I have been messing with mod_rewrite for a few hours now and for the life of me I cannot get this to work...
With no way to identify the URI that needs to be shortened you need to exclude all other possibilities. This will likely require you to build a lengthy list of exclusions. Below is a starting point. Each of these conditions verifies the requesting URI does NOT match (signified by the !). When it doesn't match all conditions the rule is run.
RewriteCond %{REQUEST_URI} !^/view.php
RewriteCond %{REQUEST_URI} !.html$
RewriteCond %{REQUEST_URI} !/$
RewriteRule ^/(.*)$ http://example.com/view.php?id=$1 [QSA]
The above also requires you (as you have requested) to break a standard practice rule, which is to handle directory requests without a trailing slash. You are likely to come across other issues, as the rules above break your Apache server side directory rules.
Rethinking the logic. If you had some way to identify the URL that is to be shortened it would be much easier. For example 's', http://example.com/s/A123.
RewriteCond %{REQUEST_URI} ^/s/
RewriteRule ^/s/(.*)$ http://example.com/view.php?id=$1 [QSA]
I'm definitely no guru at this, but its similar to what I'm trying to accomplish (see my yet unanswered question)
However, if I understand correctly, this (untested) RewriteRule may work:
RewriteRule ^([^\.\/]*)$ view.php?id=$1 [L]
The magic part is the [^\.\/]* which says: 1 or more (*) instances of a charactor ([]) which is not ([^ ]) a period or a slash (\ escapes these charactors).
Like I said, I haven't tested this, nor am I an expert, but perhaps this will help.

mod_rewrite with GET requests

I have mod_rewrite working on most of my site. Right now I have a search that normally would point to
search.php?keyword=KEYWORD
And I'm trying to rewrite that to
search/?keyword=KEYWORD
Just to make it a little bit cleaner. So here's my mod_rewrite. (There are other rules I'm just posting the one that isn't working.)
RewriteRule ^search/?keyword=([^/\.]+)/?$ search.php?search=$1
When I type a search in the address bar way I want it to be, I get a page telling me its a "broken link" (I'm guessing that that's Chrome's equivalent of a 404 error). So what am I doing wrong? I think that the problem is the '=' or the '?' sign in the rule (the first part) because when I take the ?keyword= part out, it works. Does that make sense?
EDIT: This is my full .htaccess code:
RewriteEngine on
RewriteRule ^$ index.php
RewriteRule ^thoughts$ archives.php
RewriteRule ^thoughts/$ archives.php
RewriteRule ^about$ about.php
RewriteRule ^about/$ about.php
RewriteRule ^search/\?keyword=([^/]+)$ search.php?search=$1
RewriteRule ^tags/([^/]+)$ tags.php?tag=$1
RewriteRule ^thoughts/([^/]+)$ post.php?title=$1 [L]
Still getting an error page...
If you just want to transform:
search.php?keyword=KEYWORD
into:
search/?keyword=KEYWORD
all you need to do is:
RewriteRule ^search/$ search.php [QSA]
The QSA flag means "query string append", and passes to search.php whatever you request via GET:
search/?keyword=KEYWORDD
search/?name=value&name2=value2
You may also want to check out Apache MultiViews, which sends every /foo request to any foo.* file it finds in the / directory, although they are considered bad.
RewriteRule ^search/\?keyword=([^/.]+)/?$ search.php?search=$1
The question mark character has special meaning in a regex. You need to escape it.
Additionally, the dot has no special meaning when inside a character class; you need not escape it (you're requiring that keyword contain no forward slashes and dots).