Tutorial: Text file data storage

by Barry Andrew, May 2004
Part 1 :: Introduction
Part 2 :: Page output
Part 3 :: Processing user actions
Download complete script

Requirements: PHP4, register_globals are assumed to be off. Ensure you define a path to a datafile in a directory which has write permission.

Introduction

Most PHP tutorials involving data storage are aimed at databases, usually MySQL. However there are many people who, for one reason or another, want or need to store data in a plain text file.

In this tutorial we will construct a page which allows the user to

  • enter new records
  • list the records
and, by clicking in the list,
  • edit existing records
  • delete records

For data storage I have elected to use an ini-file format, primarily for the ease with which data can be indexed and retrieved with this format. For those not familiar with this format, an ini file is a list of items with values and the file can be divided into sections. The format is like this

	[SECTION_1]
	item1=value1
	item2=value2
	
	[SECTION_2]
	item1=value3
	item2=value4
	item3=value5

For storing records we will adapt this format so that each section is a record with its id as the section name and the field names of the record will be the items. The data in each record will be:-

  • username (record id)
  • firstName
  • lastName
  • email

so our text file will be a series of records like this

	[jdoe]
	firstname=John
	lastname=Doe
	email=jd@domain.com

Many of the programming techniques used in this tutorial can also be used with data stored in a database.


Page output

The page will display a data form, so the user can enter new records, and a list of the current records in the file. By clicking on the ID field of a record, that record is selected for editing. The data to be changed will be displayed in the same form as that used for new records. When we are editing a record, only the form will be displayed and not the record list.

By clicking on an 'X' at the end of each record, the user can delete a record.

Input form

The data input form has four text boxes, one for each of the fields. These will normally be blank so the user can enter a new record. When the user wants to edit a record, the text boxes will contain the current values. The form looks like this

User data
User name
First name
Last name
Email address
 

The form code is

<FORM  method="POST" action="<?php echo $_SERVER['PHP_SELF']?>">
<INPUT TYPE="HIDDEN"  name="userdata" value="1">
<?php
	if (!empty($username))
        		echo "<INPUT TYPE=\"HIDDEN\"  name=\"username\" value=\"$username\">";
?>
<TABLE style="background: #E0E0E0; border: solid 2pt #666666" >
<TR>
    <TD colspan='2' style="border-bottom: solid 1pt #666666; font-weight: bold; text-align: center">
    User data
    </TD>
</TR>
<TR>
    <TD>
    User name
    </TD>
    <TD>
        <INPUT TYPE="TEXT"  name="username" size="10" maxlength="10"
                value='<?php echo $username ?>'
                <?php echo  empty($username) ? '' : ' DISABLED ' ?> >
    </TD>
</TR>
<TR>
    <TD>
    First name
    </TD>
    <TD>
    <INPUT TYPE="TEXT"  name="firstname" size="20" maxlength="20" value='<?php echo $firstname ?>'>
    </TD>
</TR>
<TR>
    <TD>
    Last name
    </TD>
    <TD>
    <INPUT TYPE="TEXT"  name="lastname" size="20" maxlength="20" value='<?php echo $lastname ?>'><br>
    </TD>
    </TR>
<TR>
    <TD>
    Email address
    </TD>
    <TD>
    <INPUT TYPE="TEXT"  name="email" size="30" maxlength="30" value='<?php echo $email ?>'><br>
    </TD>
</TR>
<TR>
     <TD>
      
     </TD>
     <TD>
    <INPUT TYPE="SUBMIT"  value="Send data">
    <?php
    if (!empty($username))
         echo "<INPUT TYPE=\"BUTTON\"  value=\"Cancel\"   onClick=\"history.go(-1);\">";
    ?>
    </TD>
</TR>
</TABLE>
</FORM>

A fairly standard table and form but the highlighted code may warrant further explanation.

<INPUT TYPE="HIDDEN"  name="userdata" value="1">

When we are processing the form, the existence of a 'userdata' item will tell us that data has been posted. Using a hidden field like this works whether the user clicks the submit button or just hits the enter key.

<?php echo  empty($username) ? '' : ' DISABLED ' ?> >

If the user wants to edit a record, the username will contain the id of the record to be edited. The username textbox will be greyed out when editing as we want the user to see but don't want them to be able to change it (because then we wouldn't know which record to update). We do this by disabling the text box

<?php
        if (!empty($username))
             echo "<INPUT TYPE=\"HIDDEN\"  name=\"username\" value=\"$username\">";
        ?>

Because the username textbox is disabled, the username would not be posted, so, if we're editing, we put the username in a hidden field. Similarly, a 'Cancel' button is placed on the form when a record is selected for editing which will take the user back to the record list.

 

Record List

The record list is produced by the function listData($data). This is a general purpose function that you can use to list in a table any similarly formatted text file by passing your data array to it ($data).

function listData($data) {
     if (count($data) > 0) {
         echo "<TABLE border='0' cellspacing='1' cellpadding='2'>\n";
         # headings
         echo "<tr style='background: #C0C0C0'><th>ID</th>";
         list ( $key, $dataArray) = each($data);
         foreach($dataArray as $k=>$v) {
                 echo "<th>$k</th>";
         }
         echo "<th>Del</th></tr>";

         #data
         $i = 0;
         foreach ($data as $key=>$dataArray) {
                 $bg = ++$i % 2 ? "#FFFFFF" : "#EEEEEE";
                 echo "<tr style='background: $bg'>
                        <td>
                        <a href='$_SERVER['PHP_SELF']?changeid=$key'>$key<a>
                        </td>";
                 foreach ($dataArray as $v) {
                           echo "<td>$v</td>";
                 }
                 echo "<td>[<a href='$_SERVER['PHP_SELF']?delid=$key'>X<a>]</td></tr>";
        }
        echo "</TABLE>";
    }
    else echo "<p>No data</p>";

}

Let's have look at what it does

    if (count($data) > 0) {
         echo "<TABLE border='0' cellspacing='1' cellpadding='2'>\n";
         # headings
         echo "<tr style='background: #C0C0C0'><th>ID</th>";
Check we have data. Create a table and put 'ID' in the first column of the headings
         list ( $key, $dataArray) = each($data);
Read the first item in the data array. The record id is placed in $key and the data items for the record are placed in $dataArray.
         foreach($dataArray as $k=>$v) {
                 echo "<th>$k</th>";
         }
Take each data item in turn, putting the fieldname in $k and its value in $v. At this point we are interested only in the fieldnames. Create a column heading in the table for each fieldname
         echo "<th>Del</th></tr>";
Write 'Del' to the final column heading.
         foreach ($data as $key=>$dataArray) {
We now want each element of the data array to list the data
                 $bg = ++$i % 2 ? "#FFFFFF" : "#EEEEEE";
Set alternating row background colours (white and light grey)
                 echo "<tr style='background: $bg'>
                        <td>
                        <a href='$_SERVER[PHP_SELF]?
			changeid=$key'>$key<a>
                        </td>";
Start new row. Put the record key in the first column making it a hyperlink to this page passing "changeid=recordid" in the url
                 foreach ($dataArray as $v) {
                           echo "<td>$v</td>";
                 }
Take each data item and put its value in a new column
                 echo "<td>[<a href='$_SERVER[PHP_SELF]
			?delid=$key'>X<a>]</td></tr>";
	}
Put '[X]' in the final column making it a hyperlink to this page passing "delid=recordid" in the url
        echo "</TABLE>";
End the table

Processing User Actions

We want to do all the processing and updating before we display the page again so any changes are immediately displayed. This section is therefore placed above the opening <html> tag.

The first thing we do is initialise our variables and define data file

# initialise variables
$username = $firstname = $lastname = $email = "";
$data = array();
$changed = false;

# define your data file and its path, ensure you have write permission to folder
$myTextFile = 'data/mydata.txt';
 

Read the data from the current text file, if it exists, storing it i the array '$data'.

    if (file_exists($myTextFile))
        $data = parse_ini_file($myTextFile, true);
Parse_ini_file() reads the file into the data array. Because we want the section headers, the second parameter is set to 'true'

Now check if data was submitted using the form. If it is a new record, it will be added to the $data array. If it's and edit, the current values will be updated. The $data array is a two-dimaensional array where the first key is the username and the second key is the data field name. If the userdata item was posted we know form data was sent. Username is our section key and the data items are firstname, lastname and email. Add the items to out $data array (or update if it is already there)

if (isset($_POST['userdata'])) {
  if (!empty($_POST['username']) && !empty($_POST['email']) ) {
        # add new data (or update if exists already)
    $data[$_POST['username']]['firstname'] = $_POST['firstname'];
    $data[$_POST['username']]['lastname'] = $_POST['lastname'];
    $data[$_POST['username']]['email'] = $_POST['email'];

    $changed = true;
  }
else echo "<p>Must have username and email</p>";}
Make sure username and email were entered
Set changed to true so we know we need to update the file

	
	

Deletions and edit request come via links in the data table and use query strings to pass the record id's. In these instances we need to look at the $_GET data.

If a deletion has been requested, 'delid' will have a value.

if (isset($_GET['delid'])) {

    # remove deleted item from the array
    unset($data[$_GET['delid']]);
    $changed = true;
}
unset() removes an array item.
Again, set changed to true

If the user has requested to edit a record, changeid has a value

This time, all we do is get the data to be displayed in the edit form

if (isset($_GET['changeid'])) {
        # get the items we want to edit so they can appear in the form
        $username = $_GET['changeid'];
        $firstname = $data[$username]['firstname'];
        $lastname = $data[$username]['lastname'];
        $email = $data[$username]['email'];
}
 

Now check to see if the file needs to be updated, If it does, $changed will be 'true'.

if ($changed) {
    # now create new output file, writing in ini file format
    $fp = fopen('mydata.txt', 'w');

Open the data file in write mode
	
	
 
    ksort($data);
Sort the array keys. This puts the array in username order before we write to the file
    foreach ($data as $key=>$dataArray) {
             fwrite($fp, "[$key]\n");
Taking each record in turn, write section header as '[username]'
             foreach ($dataArray as $k => $v) {
                      fwrite($fp, "$k=$v\n");
             }
             fwrite($fp, "\n");
    }
    fclose($fp);
}
Because it is a 2D array, the value assigned to the first level key is itself an array. Loop through this array so each data field item is written as 'fieldname=value'. Leave a blank line between each record (for clarity) and close the file when finished



© Copyright 2003-2023 www.php-editors.com. The ultimate PHP Editor and PHP IDE site.