Simple PHP config file and how to use it. Part I

This entry is part 1 of 1 in the series A simple PHP config file
A simple PHP config file
  • Simple PHP config file and how to use it. Part I

I’ve been coding PHP for awhile now, and over that time I’ve been adding too and tweaking a standard config file I use for sites/projects and developed a standardized method of implementation. Let’s take a quick look at the config file and then we’ll describe how to use it.

<?php
session_start(); //start the session for all files

date_default_timezone_set('America/New_York'); //make sure we have the right time zone
$display = 5; //pagination results per page

//Set the database access information as constants
DEFINE('DB_HOST','localhost');
DEFINE('DB_USER','databaseusername');
DEFINE('DB_PASSWORD','databasepassword');
DEFINE('DB_NAME','database');

//Make the connection.
$dbc = mysqli_connect(DB_HOST, DB_USER, DB_PASSWORD) OR trigger_error("MySQL Error: " . mysqli_error($dbc));

//Select the database.
mysqli_select_db($dbc, DB_NAME) OR trigger_error("MySQL Error: " . mysqli_error($dbc));

// Flag variable for site status:
$live = FALSE;

//email footer variable.
$efooter = "
Some Company Name
Email: ceo@company.com";

// Create the error handler.
function my_error_handler ($e_number, $e_message, $e_file, $e_line, $e_vars) {

	global $live;

	// Build the error message.
	$message = "An error occurred in script '$e_file' on line $e_line: \n<br />$e_message\n<br />";
	
	// Add the date and time.
	$message .= "Date/Time: " . date('n-j-Y H:i:s') . "\n<br />";
		
	//add variables, rarely required, if you're running into a tough error uncomment next line for more help
	#$msg .= "<pre>" . print_r ($e_vars, 1) . "</pre>\n<br />";
	
	if ($live) { // Don't show the specific error.
	
		error_log ($message, 0); // Send to system log
		
		// Only print an error message if the error isn't a notice.
		if ($e_number != E_NOTICE && $e_number != E_WARNING) {
			display('<div id="Error">A system error occurred. We apologize for the inconvenience.</div><br />');
		}
		
	} else { // Development (print the error).
		if ($e_number != E_NOTICE && $e_number != E_WARNING) {
			display('<div id="Error">' . $message . '</div><br />');
		}
	}

}

// Use my error handler.
set_error_handler ('my_error_handler');

function display($msg, $title="An Error Occured") {
	global $dbc;
	$title = "Site Name - $title";
	require_once('header.php');
	echo $msg;
	require_once('footer.php');
	mysqli_close($dbc);
	exit();
}

function do_pagination($start,$url,$records,$params) {
	global $display;
	$numPages = $records > $display ? ceil($records/$display) : 1;
	if ($numPages > 1) {
		$currentPage = ($start/$display) + 1;

		if ($currentPage != 1) {
			$msg .= "<a href=\"$url?s=" . ($start - $display) .  $params . '">Previous</a> ';
		}

		for ($i = 1; $i <= $numPages; $i++) {
			if ($i != $currentPage) {
				$msg .= "<a href=\"$url?s=" . (($display * ($i -1))) . $params . '">' . $i . '</a> ';
			} else {
				$msg .= $i . ' ';
			}
		}

		if ($currentPage != $numPages) {
			$msg .= "<a href=\"$url?s=" . ($start + $display) . $params . '">Next</a>';
		}
	}
	return "<div class='pagination'>$msg</div>";
}

//get rid of those trailing 0's
function clean_num($num) {
	return rtrim(trim($num, '0'), '.');
}

function clean_txt($data) {
	if (is_array($data)) {
		$clean = array();
		foreach ($data AS $index => $datum) {
			$clean[$index] = clean_txt($datum);
		}
		return $clean;
	} else {
		return htmlspecialchars(trim($data));
	}
}

//Preven SQL injection exploits
function escape_data ($data) {
	global $dbc;
	
	if (is_array($data)) {
		$clean = array();
		foreach ($data AS $index => $datum) {
			//Address Magic Quotes.
			if (ini_get('magic_quotes_gpc')) {
				$datum = stripslashes($datum);
			}
			$datum = mysqli_real_escape_string($dbc, trim($datum));
			$clean[$index] = $datum;
		}
		//return escaped array
		return $clean;
	} else {
		//Address Magic Quotes.
		if (ini_get('magic_quotes_gpc')) {
			$data = stripslashes($data);
		}
	
		$data = mysqli_real_escape_string($dbc, trim($data));
		// Return the escaped value.
		return $data;
	}
}

?>

The first thing you’ll probably notice is that we use mysqli extensions. If you absolutely have to, you can change them to mysql and everything should still work the same. Obviously if your project doesn’t use a database you can cut all mysqli related stuff out.

We start by accessing the session. This standardizes the session access for all pages so you’ll never have to remember if you set up access in this file yet or where in the code. Next we specifically define the timezone. This usually isn’t required, but some functions may give a warning if it’s not set so let’s just be on the safe side. After that is the default “display” value, used to define how many records are shown on paginated pages.

The next few lines set up our variables for connecting to the database and then make the actual connection. Since the connection is made in the same file you may ask why we bother setting up variables. It just makes for a cleaner look and just a little more portable.

The line after we get connected to the database is important. This sets up the status of the site. While developing we set this to FALSE (or 0) and once you get the bugs worked out and are ready to go live just “flip the switch” by changing it to TRUE (or 1).

The next line is a simple footer for all site e-mail traffic you can append to the body of all messages.

Next we start getting to the meat of the file. The first function sets up a custom error handler. As you can see we make use of the live variable we define and some built in PHP vars ($e_*). First thing we do is make the error message a little prettier and more informative. 9 times out of 10 you won’t need the value of every variable, but occasionally it can be a life saver. I tend to keep it commented it out but the option is yours. If the site is in development we give a very detailed error report with all the information we could want. If the site is live, we change to a few short words and an apology and logs the error to the system log. Depending on the project you may want a more proactive approach in which case change the line to: error_log($message,1,coder@e.mail) which will email the error to you.

Following the definition we go ahead and tell PHP to use our new error handler and then we define the display function. This is probably the most controversial aspect of my coding practices. Basically I set up a header and footer and then then the dynamic content area, the body if you will is passed to the display function as a single variable in the other scripts, index.php, about.php, etc. You’ll see how that works out in the next part. Basically I send 1 required and 1 optional variable. If a title isn’t supplied it’s assumed to be an error and then we add a little standardization to all the titles across the site.

Moving on is a basic pagination function. we pull in the global variable $display defined towards the top of the file which will limit how many records will appear on each page. The passed variables, in order, are: $start – which record we’re starting from,$url – URL for the paginated content,$records – very important it defines how many total records there are; you’ll probably set this with a query along the lines of SELECT COUNT(*) FROM… ,$params – this is used to pass additional values along in the pagination links, such as ordering methods, or search terms. The whole thing is returned in a div with a class already defined for your CSS markup.

A very short function next. This is useful if you’re storing data in a SQL database with a field of float, more likely, decimal. Suppose you are setting up quantities, but you need to have fractional amounts so the column definition may be: `qty` decimal(8,2) default ‘0.00’,. Well, when you pull that data back out you’re always going to have at least 2 decimal places and one whole value. If you stored .5 for one half it would be returned as 0.50 which just looks a little weird to most people. This function cleans that back up to .5. It’s important to use trim for the 0s but only rtrim for the decimal or 0.50 would get returned as 5 which definitely isn’t what you wanted.

Another little clean up function. This is used for displaying data to sanitize for XSS attacks. This is specifically for display, there’s still “wide UTF-7” attacks that can get past this simple function which could have bad consequences if you’re using user supplied data for values, such as CSS classes. The function is recursive which lets you clean an entire associative array instead of just a string, which is the default behavior of htmlspecialchars();

Last is a very important bit of code for database work. The most essential thing to remember is *ALWAYS SANITIZE DATE BEFORE A DATABASE CALL* Also, don’t trust magic quotes. Boo magic quotes. Magic quotes are probably the biggest problem I have with PHP (that and supervars but that’s another story for another day). It seems like a good idea on the surface, but really it just promotes laziness and the next thing you know you’ve got SQL Injection holes popping up in PHP aps all over. Our function gets rid of any magic quote interference and then cleans the variables up properly. The function can handle a single var or an array without a problem.

In the next part we will use our config file with a very basic site to get a feel for how everything words together.

Now for the acknowledgments:
A lot of this is a modification to stuff I found in PHP and MySQL for Dynamic Web Sites SE by Larry Ullman Amazon. Site.
As mentioned my XSS sanitation is rudimentary, but I still use it since it’s better than nothing and easier than the 2.6Mb HTML Purifier. Basically use with care.

source code

A simple PHP config file
  • Simple PHP config file and how to use it. Part I

Leave a Reply

You must be logged in to post a comment.