PHP Datastorage Class

Many websites use databases for storing data for use by web applications. There are situations in which this is not the best solution, however. For light, moderate, or temporary storage requirements, you might prefer to use flat files, session variables, and cookies. This article will describe how to create a class that handle all of these. It is the first of two parts.

Web applications need data. Getting data in and out of an application with the minimum amount of code can be a challenge, and it can be rather easy to end up with something that is not portable or reusable in any way.

Many times databases are a natural choice for storing data for use by a web application. If you have ever worked on a site that makes extensive use of a database, however, you likely know the strain it can put on a system. A database isn’t always the best solution for light or temporary data storage, so it makes sense to have something else that fits your requirements.

In this article I will guide you through the design of a data storage class that can meet the needs of a long list of web applications requiring light to moderate or temporary storage requirements.

Where Will It All Go?

There are three places we can store data that will be useful to us. These are a flat file, session variables and cookies. The class described here can use all of these. If you were to add some sort of database abstraction class to it, database storage could be used as well.

This class has been used as the core of a number of different applications so far.

• A shopping cart.

• An email and web page hit counter.

• Storage of temporary customer registration information.

• A debugger logger for template based pages.

• A project management system.

• Multi-page form storage.

• Data conversion tool.

There are many more potential uses, and once you finish this article I’m hoping you will have some of your own ideas.

{mospagebreak title=Top of the Page}

This is a PHP class. As such it resides in its own file and is used by including it in your application documents. If you are using it with session variables you will need to use the session_start() function first for each page it is included in.

<?php
session_start();
require(“datastore.php”);
$items = new datastore(“s”,”cart”);
?>

One thing to note before we dig into the code of this class. If you use the cookie functionality, you will need to be aware of a few things.

First of all, the cookie-related code in this example is included for demonstration purposes only. Unlike the rest of the code in this class, the cookie code has not been extensively tested. It does however live happily in the code without interfering with any other operations.

Another thing to remember is that, when setting cookies, you must not have any whitespace before the line of code that sets it, and you definitely cannot have any other output to the browser preceding the setting of a cookie.

Finally, if you plan to use cookies with recent versions of Internet Explorer you might want to read up on something called P3P if you haven’t already. Otherwise it’s likely your cookies will never get saved.

The Internals

The first part of the class is the declaration.

class datastore
{
    //code
}

Everything in the class resides in between the curly braces.

Next we declare a few variables. If you are used to JavaScript you may recognize the keyword “var“. This is the only place in PHP where it is used.

    var $self = “”;
    var $data_dir = “”;
    var $items = null;
    var $dataname = “datastore”;
    var $edited = false;
    var $datafile = null;
    var $error = “”;
    var $mode = “”;

These variables need not be assigned values at this point, but as matter of style I usually do.

The next step is a constructor function. In PHP classes a constructor function is usually named the same as the class (prior to PHP 5 this was required). The purpose of the constructor is to initialize a newly created object based on the class. Variables can be set and internal methods called to tailor that instance to a particular situation. The code for the datastore constructor is below.

function datastore($mode=”s”,$name=””,$dir=””)
{
     $this->self = dirname(__FILE__);
     strtolower($mode);
     $this->mode = $mode;
     if($name != “”)
     {
           $this->dataname = $name;
     }
     if($mode == “s”)
     {
           if(isset($_SESSION[$this->dataname]))
           {
                $this->items = unserialize($_SESSION[$this->dataname]);
           }
           else
           {
                $_SESSION[$this->dataname] = “”;;
           }
     }
     else if($mode == “f”)
     {
           if($dir == “”)
           {
                $this->data_dir = $this->self.”/data”;
           }
           else
           {
                $this->data_dir = $this->self.”/”.$dir;
           }
           if(!is_dir($this->data_dir))
           {
                if(!mkdir($this->data_dir))
                {
                     $this->err(“Trouble making directory”,1);
                }
           }
           if(!file_exists($this->data_dir.$this->dataname.”.dta”))
           {
                if(!$this->datafile = fopen($this->data_dir.$this->dataname.”.dta”,”w”))
                {
                     $this->err(“Problem Creating Datafile”,1);/**/
                }
                else
                {
                     fclose($this->datafile);
                }
           }
           else
           {
                if(!$datastr = file_get_contents($this->data_dir.$this->dataname.”.dta”))
                {
                     $this->err(“Problem Opening Datafile”,1);
                }
                else
                {
                     $this->items = unserialize($datastr);
                }
           }
     }
}

When an instance of the datastore is created we use arguments to the constructor to decide where we are going to store the data and what we will label the container. In order to make the arguments optional and provide a default value for each we use the syntax $mode=”s” in the parenthesis.

The first of these arguments is the mode. A value of “s” will set a session variable for storage of our information. Using a value of “f” will use a flat file and “c”, as anyone who has watched Sesame Street will know, stands for “cookie”. The default is to use a session variable.

$this->self = dirname(__FILE__);
strtolower($mode);
$this->mode = $mode;
if($name != “”)
{
     $this->dataname = $name;
}

We first establish the real location of the class file using the magic constant “__FILE__” (more on this in a moment). Then we ensure that the mode is lowercase, and that an instance variable is set to establish the storage mode we are using. The “name” argument will set the name of the data container. The default for this property is “datastore“. The flat file, session variable or cookie will be named accordingly. The next step is to handle the mode of storage.

if($mode == “s”)
{
     if(isset($_SESSION[$this->dataname]))
     {
           $this->items = unserialize($_SESSION[$this->dataname]);
     }
     else
     {
           $_SESSION[$this->dataname] = “”;
     }
}

The first mode to tackle is the session variable. If the appropriately named session variable exists, the object’s “items” property is set. This class stores and retrieves data using the serialize and unserialize functions. Serializing the data, especially when using flat files, allows the storage of complex data structures and even objects in an easily retrievable format, allowing them to retain their original structure. In this case, if the session variable we are looking for is there, we use the unserialize function to put the data into “items“.

The datastore class uses a very simple data structure that resembles a table with rows of records and fields of data in a database. A master associative array (items) can be considered the table. Within each labeled element of the array is another associative array that is much like a row in a database. Each of these arrays have elements or fields that have a key (field name) and value. The key for each row of data is the key for that array.

If the session variable is not present it is created.

{mospagebreak title=Flat Files}

If the mode is set to “f” then we will be storing the data in a flat file. All the usual permissions issues and security precautions are in force here, and the file may not be created if they aren’t followed.

else if($mode == “f”)
{
     if($dir == “”)
     {
           $this->data_dir = $this->self.”/data”;
     }
     else
     {
           $this->data_dir = $this->self.”/”.$dir;
     }
     if(!is_dir($this->data_dir))
     {
           if(!mkdir($this->data_dir))
           {
                $this->err(“Trouble making directory”,1);
           }
     }
     if(!file_exists($this->data_dir.$this->dataname.”.dta”))
     {
           if(!$this->datafile = fopen($this->data_dir.$this->dataname.”.dta”,”w”))
           {
                $this->err(“Problem Creating Datafile”,1);/**/
           }
           else
           {
                fclose($this->datafile);
           }
     }
     else
     {
           if(!$datastr = file_get_contents($this->data_dir.$this->dataname.”.dta”))
           {
                $this->err(“Problem Opening Datafile”,1);
           }
           else
           {
                $this->items = unserialize($datastr);
           }
     }
}

You may have noticed that I haven’t mentioned the third and final argument to the constructor. Until now it didn’t have any purpose; now it does.

The dir argument sets an optional directory for the files that datastore uses. The various if/else blocks in this code take care of determining whether the default directory or a user specified one should be used and creating that directory if it doesn’t yet exist. The default directory is called “data” and resides in the same directory as the datastore class regardless of the file that includes it. This is accomplished using the magic constant “__FILE__”. This built-in PHP constant returns the path to the file, unlike $PHP_SELF which always refers to the master page. Any includes lose their selfness when they are included by another file.

The cookie code is something we will deal with later. For now, this is the constructor method in its entirety.

{mospagebreak title=Getting Data In}

Our datastore class wouldn’t be much good if we couldn’t store anything in it, so that is the next thing to get into. The first method up is the add_new_item method.

function add_new_item($arr,$id)
{
     if(isarray($arr))
     {
           $keys = array_keys($arr);
           for($i= 0;$i < count($arr);$i++)
           {
                $this->items[$id][$keys[$i]] = $arr[$keys[$i]];
                $this->edited = true;
           }
     }
     else
     [
           $this->err(“First argument must be an array”,1);
     ]
}

This method accepts two arguments. The first is an associative array to serve as a row of records, and the second is a unique id to act as a key. It adds this array to the items array. If you are wondering why a loop is used, this is for future expansion of the method to allow processing of each element as it is set in the items array.

One suggestion for using this method is for storing html form field values directly. By using the versatile array functions provided by PHP you could process $_POST or $_GET array values and then store them directly into datastore with very little code. This is especially useful for multi-page forms that are processed once all the data is collected.

You also may have been wondering what the “err” method is. This is a method of datastore that will store the most recent error to allow easier debugging. The first argument is the error message and the second allows the method to both set and get error messages. If it is absent the method returns the current error.There is no error suppression in this datastore code, so once you have a good idea how to use it that may be something to include. You can then let the err method do the work of alerting you when something goes wrong.

function err($msg=””,$mode=0)
{
     if(!$mode)
     {
           if($this->error != “”)
           {
                $ret = $this->error;
                $this->error = “”;
                return $ret;
           }
           else
           {
                return “No Error”;
           }
     }
     else
     {
           $this->error = $msg;
     }
}

If you need to overwrite a specific item in the array or a specific field in an item you can use the set_item method.

function set_item($id,$stuff,$field=””)
{
     if($this->is_item($id))
     {
           if($field == “”)
           {
                if(is_array($stuff))
                {
                     $keys = array_keys($stuff);
                     for($i = 0;$i < count($stuff);$i++)
                     {
                           $this->items[$id][$keys[$i]] = $stuff[$keys[$i]];
                     }
                }
                else
                {
                     $this->err(“Third Argument Muat Be an Array”,1);
                }
           }
           else
           {
                if(isset($this->items[$id][$field]))
                {
                     $this->items[$id][$field] = $stuff;
                }
                else
                {
                     $this->err(“Item Not Found”,1);
                }
           }
     }
     else
     {
           return false;
     }
}

Arguments are the key of the item to alter, the data to store and an optional specific field to store the data in. If no field is specified then the second argument should be an associative array (data row) to replace the row specified. If a field is specified then the second argument should be the value you wish to store in that field.

{mospagebreak title=Getting Data Out}

One thing that our datastore doesn’t have yet is a way to get the data back into the chosen storage container. This is where the store method comes in. When using this class you will always use store() before you are done. That isn’t always easy to remember. I wrote this class, and yet, in the process of using it in an application that I was developing, I wondered why my data changes were not stored. Just remember the one thing they tell all new computer users: “SAVE YOUR WORK!”

function store($mode=”blank”)
{
//$this->mode cannot go in the arguments as this will
//throw a parse error. the if block below takes care of
//setting a default.
     if($mode == “blank”)
     {
           $mode = $this->mode;
     }
     if($mode == “s”)
     {
           if(isset($_SESSION[$this->dataname]))
           {
                $_SESSION[$this->dataname] = serialize($this->items);
           }
           else
           {
                $this->err(“There is no session variable by that name”,1);
           }
     }
     else if($mode == “f”)
     {
           if(file_exists($this->data_dir.$this->dataname.”.dta”))
           {
                if(is_writable($this->data_dir.$this->dataname.”.dta”))
                {
                     if($this->datafile = fopen($this->data_dir.$this->dataname.”.dta”,”w”))
                     {
                           $write_str = serialize($this->items);
                           fwrite($this->datafile,$write_str);
                           fclose($this->datafile);
                     }
                     else
                     {
                           $this->err(“Trouble Opening File for Writing”,1);
                     }
                }
                else
                {
                     $this->err(“Data File not Writable”,1);
                }
           }
           else
           {
                $this->err($this->data_dir.$this->dataname.”Data File is Missing or Has Not Been Created Yet”,1);
           }
     }
     else if($mode = “c”)
     {
           if(isset($_COOKIE[$this->dataname]))
           {
                $_COOKIE[$this->dataname] = serialize($this->items);
           }
     }
}       

If we are using a session variable, the store simply serializes the items array and stores it in the session. A series of if/else blocks attempts to ensure that all is okay and alert you if something goes wrong. Again as before, “f” is for file and “c” is for cookie. The cookie code in this case is pretty simple and is included in the example. You can use the store function more than once in your code. When the object is constructed, you may remember that we set a mode of operation for the storage, but it is possible to override this by providing an alternate storage method. This could allow you to go from one storage type to another, or to multiple ones within the same document.

Now being able to store your data in the storage mode of your choosing is great, but what happens when you want to output the data to a browser or perhaps store it in a more permanent location? This is where the readout method comes to the rescue. The readout method makes our data storage system versatile, and it is what makes this class useful for so many tasks.                  

function readout($mode,$file=””,$headers=true,$del=”:”)
{
     if($mode == “”)
     $m = 0;
     else
     $m = $mode;
     switch($m)
     {
           case 0://an array
                return $this->items;
                break;
           case 1://a query string
                return $this->to_query_string();
                break;
           case 2://query string of id’s
                return $this->id_query();
                break;
           case 3://an xslt result
                return $this->from_xslt($file);
                break;
           case 4://an xml formatted string
                return $this->get_xml();
                break;
           case 5://data dump into string
                return print_r($this->items);
                break;
           case 6://Excel compatibleCSV
                return $this->make_csv($headers);
                break;
           case 7://config file format
                return $this->make_config($del);
                break;
     }
}

This method acts as an interface to several methods designed to output stored data in a number of useful formats. The first argument is the mode, which is a number between 0 and 7. The other two we will look at in the next article.

Each mode causes readout to return all the data stored in a different format. A mode of 0 will return the items array as is. A mode of 1 will return an array of query strings that include all the key/value pairs of each item in the items array. A mode of 2 will return an array of query strings that include only the unique Id for each item. This can make it much easier to build links to display different stored data on different pages.

That’s all I have room for in this part. In the next part, I will cover modes 3-7 (where things get really interesting), utility methods that can make your life much easier when using the datastore, go into output methods in depth, and provide you with a “snack for the road.” See you next week!

[gp-comments width="770" linklove="off" ]

antalya escort bayan antalya escort bayan Antalya escort diyarbakir escort