Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

Flatfile Integrity: Please critic my code

Posted on 2008-11-04
5
Medium Priority
?
273 Views
Last Modified: 2012-05-05
I am working on a project that must work on all operating systems.
It should run on PHP4, PHP5 and PHP6 and may NOT require a database.

I know that a database would be preferable however it is NOT an option for this project.

Based on the responses I got to this question, I created some code:
http://www.experts-exchange.com/Web_Development/Web_Languages-Standards/PHP/Q_23870762.html

When reading or writing to/from a flatfile, my code verifies that data is correct, and if it is not correct, PHP waits for a few milliseconds and tries again.

I think that this solves both atomic and race condition issues.  But I am a novice at architecture.

Is my idea good or bad?
<?php
 
### To Write ###
if(file_put_verified_contents('data/file1.txt', 'Hello World')==false) {
   echo "<h1>There was a problem saving this data.</h1>";
   }
 
### To Read ###
   $page = file_get_verified_contents('data/file1.txt');
   if ($page === false) echo "<h1>Website Down for Maintenance</h1>";
 
   echo '<p>Data: ' . $page . '</p>';
 
 
function file_get_verified_contents ($file, $i=0) {
   ignore_user_abort(true);
   set_time_limit(0);
   $data = @file_get_contents ($file);
   if (substr($data, 0,7) != '##BOF##' || substr($data, -7) != '##EOF##')
	{
	usleep (200000);
        if ($i++<10) return file_get_verified_contents ($file, $i);
	else return false;
        }
   return substr($data, 7,-7);
}
 
function file_put_verified_contents ($file, $data, $i=0) {
   ignore_user_abort(true);
   set_time_limit(0);
   $fp = fopen($file, 'w');
   fwrite($fp, "##BOF##\n");
   fwrite($fp, $data);
   fwrite($fp, "\n##EOF##");
   fclose($fp);
	$newData = @file_get_contents ($file);
	if (substr($newData, 0,7) != '##BOF##' || substr($newData, -7) != '##EOF##')
	{
		usleep (20000);
		if ($i++<10) return file_put_verified_contents ($file, $data, $i);
		else return false;
        }
	else return true;
}
 
?>

Open in new window

0
Comment
Question by:hankknight
  • 3
  • 2
5 Comments
 
LVL 111

Expert Comment

by:Ray Paseur
ID: 22877516
Any time I see these two statements together, I know that catastrophe is not being left to chance:

ignore_user_abort(true);
set_time_limit(0);

Tell us again why you decided not to use flock()?

Thanks, ~Ray
0
 
LVL 16

Author Comment

by:hankknight
ID: 22878352
Ray,

I have been tasked to develop a PHP content management system that does not require a database and will work on PHP 4,5 and 6.

I have read that flock() is evil.

Look at the documentation on PHP's website (It has three warning in red):
http://www.php.net/flock

1. flock() will not work on NFS and many other networked file systems. Check your operating system documentation for more details.

2. On some operating systems flock() is implemented at the process level. When using a multi-threaded server API like ISAPI you may not be able to rely on flock() to protect files against other PHP scripts running in parallel threads of the same server instance!

3. flock() is not supported on antiquated filesystems like FAT and its derivates and will therefore always return FALSE under this environments (this is especially true for Windows 98 users).

After reading that I thought maybe flock() could also cause cancer.  That is why I decided not to use flock().

However after looking at my code again I realized that it does NOT prevent race condition conflicts......

So I modified my code:

Is my new code useful or useless?  I am at a loss and have a whole new appreciation for databases!
<?php
 
### To Write ###
if(file_put_verified_contents('data/file1.txt', 'Hello World')==false) {
   echo "<h1>There was a problem saving this data.</h1>";
   }
 
### To Read ###
   $page = file_get_verified_contents('data/file1.txt');
   if ($page === false) echo "<h1>Website Down for Maintenance</h1>";
 
   echo '<p>Data: ' . $page . '</p>';
 
function lockFile($file) { 
  clearstatcache();
  if((time()+10)-(filectime($file)) > 20)
  {
  	if (@rmdir("lock/".ereg_replace("[^A-Za-z0-9]", "", $file ), 0600)==true)   
     	return false; 
  }
 
  if (@mkdir("lock/".ereg_replace("[^A-Za-z0-9]", "", $file ), 0600)==true)   
     return true; 
  else { 
    usleep (200000); 
        return lockFile($file); 
        } 
} 
 
function unlockFile($file) { 
  if (@rmdir("lock/".ereg_replace("[^A-Za-z0-9]", "", $file ), 0600)==true)   
     return true; 
  else { 
    usleep (200000); 
        return unlockFile($file); 
        } 
} 
 
function file_get_verified_contents ($file, $i=0) {
   ignore_user_abort(true);
   set_time_limit(0);
   lockFile($file);
   $data = @file_get_contents ($file);
   if (substr($data, 0,7) != '##BOF##' || substr($data, -7) != '##EOF##')
	{
	usleep (200000);
        if ($i++<10) return file_get_verified_contents ($file, $i);
	else return false;
        }
   unlockFile($file);
   return substr($data, 7,-7);
}
 
function file_put_verified_contents ($file, $data, $i=0) {
   ignore_user_abort(true);
   set_time_limit(0);
   lockFile($file);
   $fp = fopen($file, 'w');
   fwrite($fp, "##BOF##\n");
   fwrite($fp, $data);
   fwrite($fp, "\n##EOF##");
   fclose($fp);
   unlockFile($file);
	$newData = @file_get_contents ($file);
	if (substr($newData, 0,7) != '##BOF##' || substr($newData, -7) != '##EOF##')
	{
		usleep (20000);
		if ($i++<10) return file_put_verified_contents ($file, $data, $i);
		else return false;
        }
	else 
	return true;
}
 
?>

Open in new window

0
 
LVL 111

Expert Comment

by:Ray Paseur
ID: 22878401
I share your pain!  Doing this without a data base is not a good idea at all.  I know it's none of my business, but you'll be forever playing catch-up to any CMS that has a data base.

Are you considering using chmod() against a file to grab and release?
0
 
LVL 16

Author Comment

by:hankknight
ID: 22878590
Ray, you asked if I would consider using chmod().

No, because this has to work well on ALL oporating systems.  Many flavors of Windows do NOT support chmod.  

I am about to the point of saying to !@#$ with it and if it causes me to loose my job so be it!....

So how bad is the last bit of code I posted?
0
 
LVL 111

Accepted Solution

by:
Ray Paseur earned 2000 total points
ID: 22878773
OK, wow - I can't imagine working in an environment that would assign me to do a technically incompetent thing (build a CMS without a data base).  How will you build and maintain relationships between data elements? But I digress..

As to your code above - I honestly can't tell.  I assume you have tested it, right?  Here is one other test I would apply.  Instead of hard-coding the times, set those to variables.  Then make the variables rather large so you can see the effect of locking and waiting at wall-clock time intervals.  That way you will be able to see that the locks were acquired and released at appropriate intervals.

Another concept you might want to employ is an OS-independent class or function to do the locks and releases.  That way when the locking structure changes in a future release of an operating system, you have one isolated piece of code to change.  Envision something like the code snippet...

Good luck!
function gimme($path_to_file) {
// ACQUIRE FILE LOCK - SPIN UNTIL DONE OR FAILURE
return TRUE;
// UNABLE TO ACQUIRE FILE LOCK
return FALSE;
}
 
function leggo($path_to_file) {
// RELEASE FILE LOCK
}
 
// GET EXCLUSIVE CONTROL AND UPDATE A FILE
if (!gimme($my_file)) {
  die('FILE LOCKING MECHANISM FAILED');
}
 
// UPDATE FILE
file_put_contents($stuff, $my_file);
 
// RELEASE LOCK
leggo($my_file);

Open in new window

0

Featured Post

Upgrade your Question Security!

Add Premium security features to your question to ensure its privacy or anonymity. Learn more about your ability to control Question Security today.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

These days socially coordinated efforts have turned into a critical requirement for enterprises.
3 proven steps to speed up Magento powered sites. The article focus is on optimizing time to first byte (TTFB), full page caching and configuring server for optimal performance.
Explain concepts important to validation of email addresses with regular expressions. Applies to most languages/tools that uses regular expressions. Consider email address RFCs: Look at HTML5 form input element (with type=email) regex pattern: T…
The viewer will learn how to create and use a small PHP class to apply a watermark to an image. This video shows the viewer the setup for the PHP watermark as well as important coding language. Continue to Part 2 to learn the core code used in creat…
Suggested Courses
Course of the Month21 days, 5 hours left to enroll

810 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question