Within your <VirtualHost ...>
definition you have a DocumentRoot
.
For example, say you are creating a website example.com
and place that website under:
/var/www/example.com/public_html/
Your <VirtualHost ...>
would look something like:
<VirtualHost *:80>
ServerAdmin webmaster@example.com
DocumentRoot /var/www/example.com/public_html/
ServerName example.com
... # other descriptions
</VirtualHost>
First, you can have a .htaccess
under /var/www/example.com/public_html/
. This is called your root folder.
Any sub-folder you have under that root folder can also include its own .htaccess
. A sub-folder .htaccess
has priority over the root or any parent folder.
For example, Drupal has a .htaccess
in its files
folder to prevent anyone from executing PHP code in that folder. That files
folder is where you can upload files from the Drupal front end. In other words, you could end up uploading a .php and then try to execute it. With that .htaccess
there, they prevent the possibility of such execution. The command they use is:
php_flag engine off
The /etc/apache2/sites-available/*.conf
configuration files, on the other hand, include commands just like what you'd put in the .htaccess
, so there is no need for any .htaccess
under /etc/apache2/...
.
The difference is that you use the <Directory ...>
directive to tweak the flags there. For that Drupal example, you would use:
<Directory "/var/www/example.com/public_html/sites/default/files">
php_flag engine off
</Directory>
This achieve exactly the same feat as the .htaccess
file and in most cases will be a lot faster.
The .htaccess
is great on a system like GoDaddy or Bluehost when you get shared hosting. That is useful because you do not have direct access to the /etc/apache2
files. Otherwise, turning off that feature will make things go faster because Apache won't have to check whether there is a .htaccess
file. For the files example above, this means checking the following directories:
/var/www/example.com/public_html/sites/default/files
/var/www/example.com/public_html/sites/default
/var/www/example.com/public_html/sites
/var/www/example.com/public_html
The first .htaccess
is used so in that specific case, it stops at the first directory. If you have many sub-directories and most don't have a .htaccess
, that's going to probe all of those over and over again. So not using those files (and turning off the feature in your /etc/apache2/...
settings) is going to save your server quite a few cycles.
Finally, to answer your question about how you usually execute a .php file when you want the user to just enter a normal path without the .php, you use an index.php (in most cases, you can really name that file anything you want) and from there you execute the necessary code using various include/require and so on. If your code is straight forward, a simple require will be enough.
The Apache code would look something like this:
<Directory "/var/www/example.com/public_html">
DirectoryIndex index.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]
</Directory>
This says to execute index.php
putting the path in the q
query string. (This is the Drupal way, you don't actually need the query string.) Personally, I used the following:
<Directory "/var/www/example.com/public_html">
DirectoryIndex index.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php [last,passthrough,qsappend]
</Directory>
But it may not work on your system depending on the other settings in your Apache2 server.
In your index.php you will get a path as the REQUEST_URI parameter:
$pos = strpos($_SERVER["REQUEST_URI"], '?');
if($pos === FALSE)
{
$path = $_SERVER["REQUEST_URI"];
}
else
{
// remove the query string if present
//
$path = substr($_SERVER["REQUEST_URI"], 0, $pos);
}
Now you have a path and you can run the corresponding code:
require $path . ".php";
However, I strongly recommend that you verify the $path
content as it can be strongly tainted. First if the file does not exist you want to return a 404:
$php = $path . ".php";
if(!file_exists($php))
{
http_response_code(404);
echo "<h1>Page Not Found</h1><p>Sorry Could Not Find Your Page...</p>";
}
switch($path)
{
case 'this-path-is-allowed':
case 'and/it/works/with/sub-paths':
require $php;
break;
default:
// emit another error, maybe a 403 or 500?
http_response_code(403);
echo "<h1>Page Not Accessible</h1><p>Sorry Not Authorized Here.</p>";
break;
}
As we can see, one can avoid the .php
that way and also better control what gets run and what doesn't. That way you can have many .php files, but only allow a very few to be run as expected (although putting those that should never be directly accessible by Apache outside of the root directory is way smarter, just not always doable depending on your host or the CMS you're using.)
Another way, although I never tried that, would be to test whether the .php exists and if so rewrite the path:
RewriteCond %{REQUEST_FILENAME}.php !-f
RewriteRule ^(.*)$ /$1.php [last,passthrough,qsappend]
Obviously, any .php file in your directory will then be executable from the front end. Something to keep in mind. When I write my own PHP code, though, I only put public files in the root directory and below so it's not a problem for me. This is why I have a public_html
sub-directory. My other PHP files will generally go under a separate php
directory:
/var/www/example.com/php -- server side only PHP files
/var/www/example.com/public_html -- public PHP, image, CSS, JS... files
Anything inside /var/www/example.com/php
can be included from the PHP file found under /var/www/example.com/public_html
, however, the client has not access to those files. Much more secure than WordPress, Drupal, etc. (and yet they rule the world?!)
Another important aspect of that. If you let the user access the file either way, with the .php and without (which some of my code above may do) then you should also put a canonical meta tag in your pages because otherwise Google is going to see duplication and frown about it.
/etc/apache2/sites-available
your document root? Or is something like/etc/apache2/sites-available/site1
your document root? Can you get anything to work in your .htaccess file? The directives you have so far might not be complete... what URLs are you trying to rewrite? You can more easily test rewrites by temporarily changing them to "temporary" (302) redirects ie. use the[R]
flag on theRewriteRule
..php
URLs - unlike the linked question!?)