InfinityQuest - Programming Code Tutorials and Examples with Python, C++, Java, PHP, C#, JavaScript, Swift and more

Menu
  • Home
  • Sitemap

Python Programming Language Best Tutorials and Code Examples

Learn Python Right Now!
Home
PHP
Locking a File in PHP
PHP

Locking a File in PHP

InfinityCoder December 26, 2016

You want to have exclusive access to a file to prevent it from being changed while you read or update it.

For example, if you are saving guestbook information in a file, two users should be able to add guestbook entries at the same time without clobbering  other’s entries.

Use flock() to provide advisory locking:

1
2
3
4
5
6
$fh = fopen('guestbook.txt','a')      or die($php_errormsg);
flock($fh,LOCK_EX)                    or die($php_errormsg);
fwrite($fh,$_POST['guestbook_entry']) or die($php_errormsg);
fflush($fh)                           or die($php_errormsg);
flock($fh,LOCK_UN)                    or die($php_errormsg);
fclose($fh)                           or die($php_errormsg);

In general, if you find yourself needing to lock a file, it’s best to see if there’s an alternative way to solve your problem.

Often you can (and should!) use a database (or SQLite, if you don’t have access to a standalone database) instead.

The file locking flock() provides is called advisory file locking because flock() doesn’t actually prevent other processes from opening a locked file; it just provides a way for processes to voluntarily cooperate on file access.

All programs that need to access files being locked with flock() need to set and release locks to make the file locking effective.
You can set two kinds of locks with flock(): exclusive locks and shared locks.

An exclusive lock, specified by LOCK_EX as the second argument to flock(), can be held only by one process at one time for a particular file.

A shared lock, specified by LOCK_SH, can be held by more than one process at one time for a particular file. Before writing to a file, you should get an exclusive lock. Before reading from a file, you should get a shared lock.
If any of your code uses flock() to lock a file, then all of your code should.

For example, if one part of your program uses LOCK_EX to get an exclusive lock when writing to a file, then in any place where you must read the file, be sure to use LOCK_SH to get a shared lock on the file.

If you don’t do that, a process trying to read a file can see the contents of the file while another process is writing to it.
To unlock a file, call flock() with LOCK_UN as the second argument. It’s important to flush any buffered data to be written to the file with fflush() before you unlock the file.

Other processes shouldn’t be able to get a lock until that data is written.
By default, flock() blocks until it can obtain a lock.

To tell it not to block, add LOCK_NB to the second argument, as shown:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$fh = fopen('guestbook.txt','a')                 or die($php_errormsg);
$tries = 3;
while ($tries > 0) {
    $locked = flock($fh,LOCK_EX | LOCK_NB);
    if (! $locked) {
       sleep(5);
       tries--;
    } else {
       // don't go through the loop again
       $tries = 0;
    }
}
if ($locked) {
  fwrite($fh,$_POST['guestbook_entry'])          or die($php_errormsg);
  fflush($fh)                                    or die($php_errormsg);
  flock($fh,LOCK_UN)                             or die($php_errormsg);
  fclose($fh)                                    or die($php_errormsg);
} else {
  print "Can't get lock.";
}

When the lock is nonblocking, flock() returns right away even if it couldn’t get a lock.
The previous example tries three times to get a lock on guestbook.txt, sleeping five seconds between each try.

Locking with flock() doesn’t work in all circumstances, such as on some NFS implementations and older versions of Windows.

To simulate file locking in these cases, use a directory as an exclusive lock indicator. This is a separate, empty directory whose presence indicates that the datafile is locked.

Before opening a datafile, create a lock directory and then delete the lock directory when you’re finished working with the datafile.

Otherwise, the file access code is the same:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// loop until we can successfully make the lock directory
$locked = 0;
while (! $locked) {
    if (@mkdir('guestbook.txt.lock',0777)) {
       $locked = 1;
    } else {
       sleep(1);
    }
}
$fh = fopen('guestbook.txt','a')             or die($php_errormsg);
 
if (-1 == fwrite($fh,$_POST['guestbook_entry'])) {
   rmdir('guestbook.txt.lock');
   die($php_errormsg);
}
if (! fclose($fh)) {
   rmdir('guestbook.txt.lock');
   die($php_errormsg);
}
   rmdir('guestbook.txt.lock')               or die($php_errormsg);

A directory is used instead of a file to indicate a lock because the mkdir() function fails to create a directory if it already exists.

This gives you a way, in one operation, to check if the lock indicator exists and create it if it doesn’t.

Any error trapping after the directory is created, however, needs to clean up by removing the directory before exiting.

If the directory is left in place, no future processes can get a lock by creating the directory.
If you use a file instead of a directory as a lock indicator, the code to create it looks something like this:

1
2
3
4
5
6
7
8
9
$locked = 0;
while (! $locked) {
   if (! file_exists('guestbook.txt.lock')) {
      touch('guestbook.txt.lock');
      $locked = 1;
   } else {
      sleep(1);
   }
}

This code fails under heavy load because it checks for the lock’s existence with file_exists() and then creates the lock with touch().

After one process calls file_exists(), another might call touch() before the first calls touch().

Both processes would then think they’ve got exclusive access to the file when neither really does.

With mkdir() there’s no gap between checking for existence and creation, so the process that makes the directory is ensured exclusive access.

Share
Tweet
Email
Prev Article
Next Article

Related Articles

Debugging the Raw HTTP Exchange in PHP
You want to analyze the HTTP request a browser makes …

Debugging the Raw HTTP Exchange in PHP

Exchanging Values Without Using Temporary Variables in PHP
You want to exchange the values in two variables without …

Exchanging Values Without Using Temporary Variables in PHP

About The Author

InfinityCoder
InfinityCoder

Leave a Reply

Cancel reply

Recent Tutorials InfinityQuest

  • Adding New Features to bash Using Loadable Built-ins in bash
    Adding New Features to bash Using Loadable …
    June 27, 2017 0
  • Getting to the Bottom of Things in bash
    Getting to the Bottom of Things in …
    June 27, 2017 0

Recent Comments

  • fer on Turning a Dictionary into XML in Python
  • mahesh on Turning a Dictionary into XML in Python

Categories

  • Bash
  • PHP
  • Python
  • Uncategorized

InfinityQuest - Programming Code Tutorials and Examples with Python, C++, Java, PHP, C#, JavaScript, Swift and more

About Us

Start learning your desired programming language with InfinityQuest.com.

On our website you can access any tutorial that you want with video and code examples.

We are very happy and honored that InfinityQuest.com has been listed as a recommended learning website for students.

Popular Tags

binary data python CIDR convert string into datetime python create xml from dict python dictionary into xml python how to create xml with dict in Python how to write binary data in Python IP Address read binary data python tutorial string as date object python string to datetime python

Archives

  • June 2017
  • April 2017
  • February 2017
  • January 2017
  • December 2016
  • November 2016
Copyright © 2021 InfinityQuest - Programming Code Tutorials and Examples with Python, C++, Java, PHP, C#, JavaScript, Swift and more
Programming Tutorials | Sitemap