Skip Navigation

Setting Up the Fusebox 4 for PHP Core Files

Part 2

Phillip Harrington

Note:  This is a draft. It needs another rewrite, and pretty screen shots.

Welcome back! In our first tutorial we started setting up a working installation of the Fusebox for PHP core files. If you are new to Fusebox for PHP and you have not gone through the Part 1 of this tutorial, I recommend giving it a once over before continuing.

What Took Ya So Long?

One man's theory is represented in Figure 1. In the time since our Setting Up the Fusebox 4 for PHP Core Files, Part 1 there have been some interesting changes, and I've learned a few things along the way. I had promised at the end of Part 1 to discuss tightening down XML and the parsed directory with .htaccess, using the Globals plugin, and Layouts with Content Variables.

(fig 1. CS Screenshot)

Layouts with Content Variables

I received a lot (a lot!) of requests for the Part 2 article! For the most part people were interested in Layouts with Content Variables. To appease the masses I wrote a quick and dirty article discussing that topic. Please refer to that article for some basics. It's fun stuff.

Securing Fusebox XML Files

The Fusebox methodology relies on the existence of two XML files, a fusebox.xml.php file and at least one circuit.xml.php. Some developers might simply name these fusebox.xml and circuit.xml; the core files allow for either. Knowing these are files required by the Fusebox standard, you might be concerned that another developer could simply load those urls into a browser (i.e. www.yoursite.com/fusebox.xml.php) and view the contents. In the case of circuits it's a little harder to find them since the circuit alias doesn't have to match the path at all. For example, your circuit called "cart" could be in a path "circuits/ecommerce/shoppingCart". On the other hand, if they can read the fusebox.xml.php file they know all of your circuit paths; what's to stop them from reading your circuit.xml.php files? Furthermore, what's to stop them from loading up your PHP fuse files directly or attacking them?

Two things actually. Remember in Part 1 where I said there were two available naming conventions for your fusebox.xml.php file? You could name it with the .xml.php extension or simply with .xml. I said there are pros for going with either naming convention; both can be secured however.

Securing .xml.php Files (and All .php Fuse Files)

Both of our solutions will make use of an .htaccess file in Apache. If you are using a different web server, you'll have to check the documentation to see how these tips might best be implemented in your environment. If you're not familiar with the .htaccess file, there are several good tutorials explaining it. Briefly, this is a special file that allows you to override web server options on a per directory basis. In Apache, at the server level, a server administrator can decide which options to allow users to change in their .htaccess files, and also the name of the file. This file is named ".htaccess" by default and I've never actually seen it changed, although it's possible for someone to call it ".directory_options" or something. Check the Apache manual for more about setting up .htaccess. If you've installed Apache out of the box, you might need to tweak your configuration to get .htaccess working. Look up the AllowOverride Directive in the docs and your httpd.conf file.

Right now, we're going to use .htaccess to modify the configuration of PHP on the fly. Our good friend David Huyck showed us this trick when Fusebox 3 for PHP was released. In ColdFusion, you can place a file called Application.cfm in any directory, and that file will get pre-pended to any .cfm file in that directory as it is run. In PHP, we can achieve the same effect with a PHP setting called auto_prepend_file. In the root of your Fusebox application directory where you installed the Fusebox core files, create a file called .htaccess and put the following line in it:

php_value auto_prepend_file "C:\Inetpub\htdocs\fusebox4php\Application.php"

Recall from Part 1 that I was developing our sample application in C:\Inetpub\htdocs\fusebox4php. On Windows, Apache is usually happier if you enclose paths in quotes. If you are running on a flavor of *nix such as Linux your web root may be something like "/home/username/public_html" in which case your line would read:

php_value auto_prepend_file "/home/username/public_html/Application.php"

Contents of Application.php

With your .htaccess file in place, you are ready to create the Application.php file, but what should go in it? Our goal is to prevent visitors to our web site from viewing PHP files that are not our main index.php file. Let's express this idea in code, using the $_SERVER array and a simple IF statement.

<?
if ( ! preg_match("/index\.php$/i" , $_SERVER['SCRIPT_NAME'] ) ) {
	header( 'Location: /index.php' );
	exit();
}
?>

We grab the SCRIPT_NAME key out of the $_SERVER array and check it against the regular expression: "index\.php$" using preg_match. I personally prefer to use preg_match over ereg because I feel the Perl style flags make it more flexible. You could also have used:

if ( ! eregi("/index\.php$",$_SERVER['SCRIPT_NAME']) , $_SERVER['SCRIPT_NAME'] ) )

That's not a typo. We're using eregi here, the case-insensitive version of ereg, or the equivalent of adding the i flag to our preg_match. Or we could have used:

if ( ! substr( $_SERVER['SCRIPT_NAME'] , -9) != 'index.php' )

If you are working in a subdirectory, replace "/index.php" in the Location statement with "/your/sub/dir/index.php" as appropriate. In our example we'll use "/fusebox4php/index.php." Note that we don't have to check for the subdirectory in the test line since that line only grabs the end of the script name regardless of what subdirectory we are in.

How we check for the file name is not important, but what we do with it is. If we find that a visitor is not requesting the index.php file in our root, we redirect using the header command and exit() so that no code is executed after that statement. Since this is in the Application.php file and is run first, before any other code, this will prevent any requests to fusebox.xml.php or circuit.xml.php files from being served by the web server. Also your dsp, qry and act fuse files will be safe and sound.

Since this script may try to return headers, make sure there is no white space between the top of the file and your first PHP escape ("<?"). Otherwise the server might consider the white space to be content, and send normal HTTP headers before you have a chance to change them. This is the case with any PHP script that sets a header or sets a Cookie (since those are set in the HTTP response headers too).

Securing Fusebox .xml Files

Due to some unexplained devotion to aesthetic, I prefer to name my Fusebox XML files with an .xml extension. Call me crazy ("You're crazy, Harrington!"). One of the benefits of naming the file with an .xml extension is I can load the file in a browser like Firefox and check for bad syntax. The XML file will not render if it is not "well formed." When I do this, the PHP auto_prepend_file trick doesn't work obviously because .xml is not .php. Instead, I put these few lines into my .htaccess file.

<Files fusebox.xml>
	<Limit GET>
		Deny from all
	</Limit>
</Files>

<Files circuit.xml>
	<Limit GET>
		Deny from all
	</Limit>
</Files>

These lines tell Apache to deny access to files named "fusebox.xml" and "circuit.xml." If I place this in my .htaccess file in my web root it will take effect for all subdirectories that don't specifically change this setting. This is good because I don't have to duplicate this file in all of my subdirectories.

Then How Do You Load It?

If you're keeping score at home, I said first I like to load the file in a browser to check for bad syntax and then gave instructions on how to get your web server to prevent access to these two files. There are two ways around this. One is simple: Load the file locally. If your xml file is "C:\InetPub\htdocs\fusebox4php\circuit.xml" simply load that in your browser and bypass the web server's permissions completely.

The other way is a little sneakier. After the "Deny from all" lines in the code above, add this line:

Allow from 127.0.0.1

Make sure to place this file after the "Deny from all" lines in both "Files" blocks. Also be sure to replace 127.0.0.1 with your IP address.

If you're running a server locally, and browsing that server from your own computer, your IP is probably 127.0.0.1. If not, you can test your IP address with this script in your index.php file, before any other PHP code (but inside the PHP escape <?):

<?
echo $_SERVER['REMOTE_ADDR'];
exit();

# etc...

Then load index.php and view the results. We used index.php for a quick test because if we put this code in another .php file in our Fusebox directory, Application.php would have caught it and redirected us back to index.php.

That's the not-so-quick do-it-with-PHP method. Alternatively, you could simply go to IP Chicken and see what it says. Prediction:  In the future a barn-yard animal will adorn all great web services.

The upshot is Apache will deny access to my fusebox.xml and circuit.xml files from any IP address except the ones I have specified. For my personal web site, I have this configured to be the two IP addresses I access the site from, so I can quickly check for XML errors when developing new circuits. A misplaced end quote or slash can give you unexplained errors that are hard to debug if you don't know your XML is bad.

You may be asking, "Why not use both, Harrington?" Good question. Actually, you can use both of these tricks in conjunction. It's what I used to do on my site. I had the first trick protecting my .php fuse files, and the second watching out for my .xml files. Now-a-days I take advantage of the feature in Fusebox 4.1 that allows you to separate your webroot, application root, and core files. Also, I have a completely different trick in my .htaccess for someone looking for a fusebox.xml or circuit.xml file. Try it sometime.

Global Scope

You might be thinking, with that auto_prepend_file trick, you could put all kinds of code in there that you wanted to run on every page. Well yes, you could do that, but there is actually a Fusebox way of doing the same thing. There are two ways, old and new. For my money, if you have a choice between something language specific and something from the Fusebox methodology, go for the standardized Fusebox method, for the benefit of future programmers who may have to understand your code.

Fusebox has several plugin points; one of them is called "preprocess." This point occurs before any of your fuseactions are run.

What's a Plugin?

A plugin is a part of the Fusebox methodology that lets us extend Fusebox without having to modify the core files. It's useful for developing extensions that you might not want on every single application or as part of the specified methodology (appropriate for the core files) and for code that you might need to be a little more general; not specific to one web application (appropriate for fuse files). One of these days, I may get around to writing more about plugins, when I personally understand them more. (I have a great idea for a plugin, but I want to see if it will work before I talk about it here, just in case it makes no sense.) Suffice it to say, plugins are part of the methodology and there exists a plugin for Global Settings that exist across fuses. Coincidentally, it's called the "Globals" plugin.

Since my first article, Fusebox 4.1 has been released. This version makes use of a new file called fusebox.init.php, which is effectively a global file. If it exists (it's optional), it is loaded before any fuseactions are run, but after the application and attributes scopes are established. For all of my coding, this has effectively replaced the need for using the Globals plugin. Plugins are interesting; particularly their ability to span execution phases in their own scope. For those of you still using Fusebox 4, here's a brief overview of the Globals Plugin.

The Globals Plugin

We're going to use a file called Global.php. You can download that file here (or I thought you could? Maybe I should host this file...). Place it in the plugins subdirectory you created in Part 1. I've been using "C:\InetPub\htdocs\fusebox4php\" as my Fusebox root, so I would place my file in "C:\InetPub\htdocs\fusebox4php\plugins\". I'm not going to go into the code in this file in depth, but it basically sets-up itself as a plugin in the Fusebox memory structure and includes another file called "myGlobals.php". We'll talk about this file in a minute. First let's set up our fusebox.xml.php to run the Globals plugin.

In your fusebox.xml.php (or fusebox.xml file, if I convinced you how cool that is), look for the plugins section:

<plugins>
<!-- etc... -->
</plugins>

The first plugin point is named "preProcess". In that section add a call to the Globals plugin.

<phase name="preProcess">
	<plugin name="Global" template="Globals.php" />
</phase>

The myGlobals.php File

Now in your Fusebox root (in my case "C:\InetPub\htdocs\fusebox4php\") create a file called myGlobals.php. This is the file that the Globals plugin attempts to run. Why two files? One merely specifies the default location of the myGlobals.php file, the other is the actual myGlobals.php file. If you hack Globals.php, you can change the name or location of the myGlobals.php file if you wanted to. What goes in myGlobals.php? Anything at all. It's just an included PHP file for global stuff.

Self and Myself

One suggestion for the content of the myGlobals.php file is to use it as a convenient place to set $self and $myself. These are two common variables found a lot in Fusebox, although it is a misconception that they are set by the core files. They are not. The $self variable is usually a pointer to the index.php file, and $myself is a pointer to the index.php with "?fuseaction=" appended. Here's how we make that happen:

<?
# myGlobals.php

$self='index.php';
$myself=$self . '?' . $application['fusebox']['fuseactionVariable'] . '=';

?>

The New Way

As I mentioned, Fusebox 4.1 makes using a plugin for Global Scope obsolete. If you're using Fusebox 4.1, you can forget about needing Globals.php in your plugins directory and you can take out the Plugin reference in your fusebox.xml file. All you have to do now is simply rename myGlobals.php to fusebox.init.php and everything else will work the same. In the case of Fusebox 4.1 and fusebox.init.php, it must be in the application root directory if that is different than your web root directory. Gee, now we need another article explaining that whole thing. Damn.

<?

# fusebox.init.php
$self='index.php';
$myself=$self . '?' . $application['fusebox']['fuseactionVariable'] . '=';

?>

Because fusebox.init.php loads after the application and attributes scopes are loaded, it's a fun place to do all kinds of interesting things like security. Mike of Fusebuilder has done some interesting work with security in fusebox.init.php.

Conclusion

That's it for now. Hopefully these tricks have helped you tighten down your Fusebox application a little bit more. Be sure to check out Part 1 and Layouts with Content Variables for more info. Bug me about writing something about the different roots in fusebox. Thanks again for reading.

Note:  This is a draft. It needs another rewrite, and pretty screen shots.

This page has been viewed at least 1776 times, since we started counting, which was years after this page was up in the first place.

"Thus the metric system did not really catch on in the States, unless you count the increasing popularity of the nine-millimeter bullet." - Dave Barry