Earlier in this chapter, you saw how you could run into problems if you ran the counter script and the file count.dat didn't exist, and you made sure you performed some basic error checking when you opened the file. That's a very simple approach—if something does go wrong, the user won't necessarily know what the problem is.
PHP provides some functions that enable you to access useful file information. For example, rather than just spewing out a standard error message when you fail to open a file, you can use file_exists() to discover whether the file exists. If it doesn't, you can infer that the current user is the first visitor to the site and create the data file. You can say:
file_exists("/home/chris/count.dat")
This returns True if count.dat exists in /home/chris/, and False otherwise. The error checking for your hit counter might now take this form:
<?php
//hit_counter_10.php
$counter_file = "./count.dat";
if(file_exists($counter_file)) {
if(!($fp = fopen($counter_file, "r+")))
die("Cannot open $counter_file");
$counter = (int) fread($fp, filesize($counter_file));
$counter++;
rewind($fp);
}
else {
if(!($fp = fopen($counter_file, "w")))
die("Cannot open $counter_file");
$counter = 1;
}
echo "You're visitor No. $counter.";
fwrite($fp, $counter);
fclose($fp);
?>
This is just one of a number of functions that return helpful information on a given file. In a similar fashion, you can use the filesize() function to determine exactly how many bytes should be read from the counter data file. Just as with file_exists(), this function takes a filename string argument directly instead of a file handle:
This returns the size of the specified file in bytes, or False upon error. You could use filesize() to determine how many bytes should be read from the data file to get the number of hits:
<?php
//hit_counterll.php
$counter_file = "./count.dat";
if(file_exists($counter_file)) {
if(!($fp = fopen($counter_file, "r+")))
die("Cannot open $counter_file");
$counter = (int) fread($fp, filesize($counter_file));
$counter++;
rewind($fp);
}
...
Time-Related Properties
Besides their contents, files have other properties that can provide useful information. These will principally depend on the operating system in which they are created and modified. On UNIX platforms such as Linux, for example, properties include creation date, modification date, last access date, and user permissions. With just a little extra code, you can make the hit counter show when the last access was made. The function fileatime() returns the last access time for a file in a UNIX timestamp format, and returns the last date on which the file was modified in a Windows format.
A UNIX timestamp is a long integer whose value can be interpreted as the number of seconds between the UNIX Epoch (January 1, 1970) and a specified time and date.
PHP provides two other time-related file functions:
- filectime() returns the time at which the file was last changed as a UNIX timestamp. A file is considered changed if it is created or written, or when its permissions have been changed.
- filemtime() returns the time at which the file was last modified as a UNIX timestamp. The file is considered modified if it is created or has its contents changed.
The getdate() function is also very useful when working with timestamps. It returns an associative array containing the date information present in a timestamp. The array includes such values as the year, the month, the day of the month, and so on. You can set a variable ($my_date) equal to the value returned by getdate(), and then access the month, for example, with $my_date['month].
Try it Out: Display the Last Access Time to the Counter Data File
This example uses the getdate() function to read the date values from the fileatime() function for the file named in the variable $counter_file.
<?php //last_counter_access.php $counter_file = "./count.dat"; if(file_exists($counter_file)) { $date_str = getdate(fileatime($counter_file)); $year = $date_str["year"]; $mon = $date_str["mon"]; $mday = $date_str["mday"]; $hours = $date_str["hours"]; $minutes = $date_str["minutes"]; $seconds = $date_str["seconds"]; $date_str = "$hours:$minutes:$seconds $mday/$mon/$year"; if(!($fp = fopen($counter_file, "r+"))) die("Cannot open $counter_file"); $counter = (int) fread($fp, filesize($counter_file)); $counter++; echo "You're visitor No. $counter."; echo "The last access was made at $date_str"; rewind($fp); } else { if(!($fp = fopen($counter_file, "w"))) die("Cannot open $counter_file"); $counter = 1; echo "You're visitor No. $counter."; } fwrite($fp, $counter); fclose($fp); ?>
How it Works
If the specified count.dat file exists, the script gets the last access time for the data file as a UNIX timestamp. This is converted to an associative array containing date information with the getdate() function, values are extracted from the appropriate elements, arranged, and stored in a string variable:
$counter_file = "./count.dat";
if(file_exists($counter_file)) {
$date_str = getdate(fileatime($counter_file));
$year = $date_str["year"];
$mon = $date_str["mon"];
$mday = $date_str["mday"];
$hours = $date_str["hours"];
$minutes = $date_str["minutes"];
$seconds = $date_str["seconds"];
$date_str = "$hours:$minutes:$seconds $mday/$mon/$year";
When you create, write to, or read from a file, UNIX considers the file to have been accessed (Windows is a bit different, and may consider the file changed only under other circumstances, and as we mentioned previously, may show the file creation time instead of the last access time). For this reason, you call fileatime() before reading from the data file. Still conditional on the actual existence of the count.dat file, you open it and read its entire contents into the variable $counter, increment that variable, and print it out along with the formatted date information. Then, rewind() the file position indicator (so that you're ready to write the new count) and close the body of the if statement:
if(!($fp = fopen($counter_file; "r+")))
die("Cannot open $counter_file");
$counter = (int) fread($fp, filesize($counter_file));
$counter++;
echo "You're visitor No. $counter. "
echo "The last access was made at $date_str";
rewind($fp);
}
Now look at the else clause; if the file count.dat didn't already exist, you create it with fopen(), specifying write-only. Initialize the counter at 1 and incorporate it in a displayed message:
else { if(!($fp = fopen($counter_file, "w"))) die("Cannot open $counter_file"); $counter = 1; echo "You're visitor No. $counter."; }
Finally, write the new counter value to the count.dat file, and close it with fclose():
fwrite($fp, $counter);
fclose($fp);
