Flatfile Integrity: Please critic my code

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

LVL 16
hankknightAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Ray PaseurCommented:
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
hankknightAuthor Commented:
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
Ray PaseurCommented:
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
hankknightAuthor Commented:
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
Ray PaseurCommented:
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

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
PHP

From novice to tech pro — start learning today.