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

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.

Related

Mod Rewrite (SEO Friendly URL's)

You'd think I'd easily be able to find the answer to this on S/O, but I've tried everything and after a few hours of frustration I'm giving in and seeing what the real experts think.
I'm "sure" this can be done with mod rewrite, but I'll defer to you.
Problem: I'm attempting to turn a URL like this...
http://domain.com/new-cars/state.php?stateCode=al
Into this at minimum...
http://domain.com/new-cars/al-new-cars
Though, ideally I'd get it to look like this (yes, I'm willing to rewrite some code to use the full state name as the $stateCode variable to make it easier!)...
http://domain.com/new-cars/alabama-new-cars
Ultimately the plan is to be able to use URL's in links such as...
http://domain.com/new-cars/alabama-new-cars
And have .htaccess take car of associating this SEO-friendly URL with the dynamic version and displaying the page properly.
Either way, I haven't been able to figure out how to do this like I need.
Here's what I've tried.
Options +FollowSymlinks
RewriteEngine on
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^new-cars/([^-]*)-new-cars/$ /new-cars/state.php?stateCode=$1 [L,QSA,NC]
And different variations that I've created using 2 different mod rewrite generators and various answers to other people's questions.
Absolutely nothing is working.
I expect when I go to
http://domain.com/new-cars/state.php?stateCode=AL
That it rewrites the URL to
http://domain.com/new-cars/AL-new-cars
...but it does not. Instead, it stays exactly the same dynamic URL I typed in. If I go to the "desired" rewrite URL I get a 404 error saying the page doesn't exist.
What am I doing wrong?
I thought maybe my .htaccess privileges weren't set right, but I can do a 301 redirect through .htaccess quite easily, so that's not it.
Maybe someone here can help. I've tried to so many permutations, even settling for the most basic rewrite just to see if I could get it to work - but nothing.
Any help is appreciated!
You can use:
Options +FollowSymlinks
RewriteEngine on
RewriteBase /
# external redirect from actual URL to pretty one
RewriteCond %{THE_REQUEST} \s/+new-cars/state\.php\?stateCode=([^\s&]+) [NC]
RewriteRule ^ /new-cars/%1-new-cars? [R=301,L,NE]
# internal forward from pretty URL to actual one
RewriteRule ^new-cars/([^-]*)-new-cars/?$ /new-cars/state.php?stateCode=$1 [L,QSA,NC]

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.

.htaccess mod_rewrite - Non-matching patterns

I'm having trouble getting non-matching (negation) mod_rewrite patterns to work.
In the example below I want all requests redirected to "/promo-page", however, don't allow a redirect loop (hence the RewriteCond).
### Request URL: http://example.com/promo-page ###
RewriteCond %{REQUEST_URI} !^/$
RewriteCond %{REQUEST_URI} !/promo-page
RewriteRule .* /promo-page [R=302,L]
When a request for "/promo-page" is made, the RewriteCond rule is ignored and a redirect loop occurs.
Any ideas why the Exclamation Mark (!) isn't working? Is the syntax incorrect?
Thanks in advance.
UPDATE
I've also tried these rules in an online mod_rewrite tester and they also don't work (if you use "home" as the URL and "/home" as the REQUEST_URI).
http://martinmelin.se/rewrite-rule-tester/
Remove RewriteCond %{REQUEST_URI} !^/$ - it will always be true, as Jon says.
Thanks all for your answers and thoughts. I finally tracked down the issue, so here's the details in the hope it may help someone else down the track.
What was confusing the situation was more rules further down in the .htaccess file. These weren't posted in my original question as I didn't believe they were relevant and would even affect the outcome.
These additional rules re-write the Clean URL's into a GET request. I was under the (false) impression that %{REQUEST_URI} also includes the GET variables tacked onto the end of URL's. It doesn't. You must use %{QUERY_STRING} to separately check the content of the GET query string.
Mod-Rewrite Logging was very useful in helping me debug this issue. I wasn't able to enable it on our live/production cPanel server, so I installed XAMPP on my PC, enabled logging and played with the rewrite rules locally until I got it working.

How does .htaccess work?

I'm trying to make my website display the other pages as a www.example.com/pageone/ link instead of www.example.com/pageone.html.
Problem is, i'm reading up on ways to do that using .htaccess and its getting me confused because i don't understand the commands.
I understand that the first step, however, is to write this in the .htaccess file:
RewriteEngine On
After this step, i have absolutely no idea whats !-d nor {REQUEST_FILENAME} nor ^(.*) and all that programming text. Is there a documentation that i can refer to?
Or can anyone provide me a simple explanation on how to configure the .htaccess file to understand that if i want to go to
www.example.com/pageone.html
, all i need to type into the URL is
www.example.com/pageone/
and PHP files, etc as well?
First of all, there's the Official Documentation. To solve your specific problem, I would go about this way:
RewriteEngine on #Turn on rewrite
RewriteCond %{REQUEST_FILENAME} !-f #If requested is not a filename...
RewriteCond %{REQUEST_FILENAME} !-d #And not a directory
RewriteRule ^([^/]+)/?$ /$1.html [L] #Preform this redirect
The RewriteConds only apply to the next following rule. If you were to have multiple rules, you'd need to write the conditions for each one.
Now, the Apache server matches the requested path (everything after www.example.com/), to see if it matches any of the rules you've specified. In which case, there is only one:
^([^/]+)$
This regular expression matches any number of characters, which are not slash /, followed by an optional trailing slash. If the match was found, it will rewrite the request to the second parameter: /$1.html, $1 means "Whatever was matched between the brackets", which in our case is all of the non-slash characters.
The [L] flag, tells the rewriting engine to stop looking for rules if this rule was matched.
So to conclude, www.example.com/whatever/ will be rewritten sliently at the server to www.example.com/whatever.html
RewriteEngine on
RewriteBase /
RewriteRule ^([^/]+)$ /$1.html
That should be all you need for this rewrite. It basically says "Anything that is not a forward slash will be assigned to the variable $1. So /foo would point to /foo.html
For official documentation you can look here Apache httpd mod_rewrite.
On Google you can search with keywords such as url rewriting tutorial.
The weird characters are called regular expressions. It's not an easy part to learn but there is a lot of tutorial about them.
PS: this is not a straight answer but some stuff to let you go further and understand how url rewriting works.

Why would mod_rewrite rewrite twice?

I only recently found out about URL rewriting, so I've still got a lot to learn.
While following the Easy Mod Rewrite tutorial, the results of one of their examples is really confusing me.
RewriteBase /
RewriteRule (.*) index.php?page=$1 [QSA,L]
Rewrites /home as /index.php?page=index.php&page=home.
I thought the duplicates might have had been caused by something in my host's configs, but a clean install of XAMPP does the same.
So, does anyone know why this seems to parse twice?
And, to me this seems like, if it's going to do this, it would be an infinite loop -- why does it stop at 2 cycles?
From Example 1 on this page, which is part of the tutorial linked in your question:
Assume you are using a CMS system that rewrites requests for everything to a single index.php script.
RewriteRule ^(.*)$ index.php?PAGE=$1 [L,QSA]
Yet every time you run that, regardless of which file you request, the PAGE variable always contains "index.php".
Why? You will end up doing two rewrites. Firstly, you request test.php. This gets rewritten to index.php?PAGE=test.php. A second request is now made for index.php?PAGE=test.php. This still matches your rewrite pattern, and in turn gets rewritten to index.php?PAGE=index.php.
One solution would be to add a RewriteCond that checks if the file is already "index.php". A better solution that also allows you to keep images and CSS files in the same directory is to use a RewriteCond that checks if the file exists, using -f.
1the link is to the Internet Archive, since the tutorial website appears to be offline
From the Apache Module mod_rewrite documentation:
'last|L' (last rule)
[…] if the RewriteRule generates an internal redirect […] this will reinject the request and will cause processing to be repeated starting from the first RewriteRule.
To prevent this you could either use an additional RewriteCond directive:
RewriteCond %{REQUEST_URI} !^/index\.php$
RewriteRule (.*) index.php?page=$1 [QSA,L]
Or you alter the pattern to not match index.php and use the REQUEST_URI variable, either in the redirect or later in PHP ($_SERVER['REQUEST_URI']).
RewriteRule !^index\.php$ index.php?page=%{REQUEST_URI} [QSA,L]