Monday, January 15, 2007

3 basic files to work with

I haven't posted anything "code like" for some time huh ;)
Well now is the time to actually dig up some code!



I thought a lot about the topic to write on and it will be really a one for starters.
These 3 files I will show you are the solid foundation of all my projects. A project should have these files always. If a project does not contain those files or files like the one I will give you then it has a major drawback or is just too small so it doesn't actually needs it ;) but you need almost 99% of the time files that serve this purpose. So enough with the initial bla bla bla :) nets code ;)


I will follow this schema:

1. Describing why it is good to have it
2. Actual CODE
3. Tips and other options to this





NAME: config.php
1. Description

This is a configuration file which will give you the control over the server. As a server I mean that you will be able to tweak the php.ini file as you like. This file represents a large number of ini_set() function which will temporary change the scripts behavior. Changing the php.ini config or the scripts behavior is a big plus when developing a project which will be hosted on a server which is out of your touch and for example you can't touch the php.ini file to say hide the error reporting or so on. So having this allow us to change the preferences of PHP as expected by us, the developers! Take a note that some of the directives might not be changed so don't expect always to have a full control over the php.ini!

Besides PHP configuration this file represents a central unit for defining the PATH of our application or the USERNAMES, PASSWORDS and so on of say, the DATABASE server. So have a look a it!

2. The CODE


##################################################################
#
#===== CONFIGURAION FILE =====
#
#=================================================================
#
# php.ini directives
# database constants
# path constants
#
#=================================================================
#
# PHP 5.2 version
#
#=================================================================
#======= created by Yavor Ivanov | email: =======#
#=================================================================
##################################################################
//////////////////////////////////////////////////////////////////


#===== PHP.INI DIRECTIVES
ini_set("output_buffering" , 0); // OUTPUT BUFFER
ini_set("safe_mode" , 0); // SAFE MODE
ini_set("expose_php" , 0);
ini_set("max_execution_time" , "120");
ini_set("max_input_time" , "60");
ini_set("memory_limit" , "16M");
error_reporting(E_ALL | E_STRICT); // ERROR REPORTING
ini_set("display_errors" , 1); // DISPLAY ERRORS
ini_set("display_startup_errors" , 1);
ini_set("log_errors" , 1);
ini_set("report_memleaks" , 1);
ini_set("html_errors" , 1);
ini_set("error_log" , "syslog"); // ERROR LOG
ini_set("register_globals" , 0);
ini_set("magic_quotes_gpc" , 0);
ini_set("magic_quotes_runtime" , 0);
ini_set("file_uploads" , 1); // FILE UPLOADS
ini_set("upload_max_filesize" , "10M");
ini_set("session.use_cookies" , 0); // USE COOCKIES
ini_set("session.auto_start" , 1); // SESSION AUTO START
ini_set("session.cookie_lifetime" , 0);
ini_set("session.gc_probability" , "1");
ini_set("session.gc_divisor" , "100");
ini_set("session.gc_maxlifetime" , "1440");
ini_set("session.cache_expire" , "180");
ini_set("url_rewriter.tags" , ""); // URL REWRITER
#=================================================================


#===== DATABASE CONSTANTS
define("DBHOST" , "127.0.0.1");
define("DBUSER" , "username");
define("DBPASS" , "password");
define("DBNAME" , "database");
#=================================================================


#===== PATH CONSTANTS
define("BASE_PATH", str_replace('\\', '/', dirname(__FILE__)));

define("CLASSES" , BASE_PATH."classes/");
define("WEB_ROOT" , BASE_PATH."/web_root/");
#=================================================================
?>



3. Tips and other options to this

There aren't much words to be put in here for this piece of code but we can say that you are free to add some more directives or define more constants at your desire and need. The tricky thing you can do here is to put as much configuration options as possible so your team mates knows that they only need to go in here and change the desired thing.





NAME: session.inc.php
1. Description

Basically this is a file to be included always at the start of every file. Why? Because it starts the session every time and keeps it running trough the whole application and also protects from hijacing. But let us see the code!

2. The CODE


session_start();
session_regenerate_id(true);

// if the user is just accessing the server his session
// is empty so BUILD a unique hash and put it in
if (empty($_SESSION)) {
// md5 or sha1 might be used for increased security
// but it might become slower
$_SESSION['hash'] = $_SERVER['REMOTE_ADDR'] .
$_SERVER['HTTP_USER_AGENT'] . $_SERVER['REMOTE_PORT'];
} else{
// md5 or sha1 might be used for increased security
// but it might become slower
$hash = $_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT'] .
$_SERVER['REMOTE_PORT'];

// if the hash is different from the original one build
// when first accessing the SERVER
// there might be a second user who might be a hidjacker
// so we destroy the SESSION !!!
if ($_SESSION['hash'] != $hash) {
session_unset($_SESSION);
session_destroy();
session_start();
session_regenerate_id(true);
$err = "Sorry there was a problem accessing the page!";
exit($err);
}
}
?>



3. Tips and other options to this

So what you see here is changing the session on every click of the user ;) why? Why not :) Every switching of session id can make our un-welcomed harmful user have a hard time. Beside in php5 regenerate_id() has a param of true which will destroy our previous session. Also making a unique hash of some info about the user protects us from hijacing. You can do the hash more complex and unique :) just play with code a bit it is well documented and easy to read :) at least my team mates and I think so.




NAME: database.class.php
1. Description

What you will see in the source is a PHP 5 class which will connect automatically to the database, when you create the object and the cool thing about this class is that it will execute every single query as a custom method... what is so cool about it :)
Well if you decide that you will use postgres sql you will not change all the mysql_query with pg_query for example but instead you will change just the class methods ;) cool huh! And I made a special param called DEBUG when you give it TRUE it will print your query ;) so you can latter paste it in for example in phpMyAdmin or something of the sort and look at what is actually causing trouble and so on ;) yes you can do it some more advanced like putting error logging and so on so this is the reason you can use the class and upgrade it ;)

2. The CODE


##################################################################
#
#===== Database Interaction Class =====
#
#=================================================================
#
# Written for MySQL database server
# Easily modified to work for a different SQL server
#
#
#=================================================================
#
# PHP 5.2 version
#
#=================================================================
#======= created by Yavor Ivanov | yavor.xenium@gmail.com =======#
#=================================================================
##################################################################
//////////////////////////////////////////////////////////////////


class DBI {
private $init_db;


public function __construct() {
if ( !isset($this->init_db) ) {
$this->init_db = mysqli_connect( DBHOST , DBUSER , DBPASS , DBNAME );
}
}


public function __destruct() {
mysqli_close();
}


//============================================================


function query($sql , $DEBUG = false) {
if ( $DEBUG == true ) {
print "";
print "SQL: ";
print "
";
print $sql;
print "
";
print "
";
}
return mysqli_query($sql);
}


function fetch_array($sql) {
return mysqli_fetch_array($sql);
}


function query_and_fetch($sql , $DEBUG = FALSE) {
$result = $this->fetch_array($this->query($sql));

if ( $DEBUG == true ) {
print "";
print "SQL: ";
print "
";
print $sql;
print "
";
print "
";
}

return $result;
}


function num_rows($result) {
return mysqli_num_rows($result);
}


function get_last_id() {
list($value) = $this->query_and_fetch("SELECT LAST_INSERT_ID()");
return $value;
}


}
?>



3. Tips and other options to this

So as I said the cool thing is that you can actually change databases very easily with few mods of the class. Also adding error logging might be a good idea or for example you can make automated escapes of variables or just another method like EscapeParam for example ;)
Use you imagination here and automate as much as you can to ease your work! Notice I use mysqli so don't expect this to work on php4.

There are a lot of object persistent classes and abstract ones but this is something that is easily understood and is something that you can tweak around :) most of the persistent/abstract classes aren't very short and need time to go into the code while this is short and useful the other alternative (I mean the persistent/abstract classes) are much more powerful and offer much more things ;)




Well with this article I demonstrated the basic files each application should have. I hope those of you who didn't knew where to start now know the entry point and will start smooth ;)
The demonstrated here CODE isn't the best! Come on! Spare me all the critics you might have for it... it is far than a complete solution. The targeted audience isn't experienced programmers which know everything while sharing some ideas might enlightened them, it is new ones that could not find the path and I try to give them what is considered good.


So I hope you will find the CODE interesting and you got idea what to do with it so start the codding, have fun with it and.... CODE it secure ;)

5 comments:

Anonymous said...

Nice tips there, but I think the part with the php.ini directives would be better/faster to be loaded by the vhost configuration or an .htaccess file.

Явор Иванов said...

Well yes :)
but htaccess is slower than global config :) I am not sure about ini_set() it would be cool if someone submit a benchmark.

Oscar M. said...

check the documentation for ini_set, a few directives, like register_globals, can't be changed from within a PHP script for security reasons. For those, you have to use .htaccess or your server configuration to set them.

Явор Иванов said...

Yes! You are right about this. I haven't fully tested this but even looking at the table it isn't very clear how the things in php5 are. I think some options are allowed in version 5 while in 4 as the table said aren't. Until tested there isn't really a way to know ;)
So be careful and as I mention don't expect everything to work.

Anonymous said...

I'm not so found of the get_last_id function because it drops the ball if you do a query like insert into table (field1, field2) VALUES (1,2),(3,4).
It only gets the first inserted id.