I too am designing a system to deal with this problem. So far so great ideas have been discussed. But I still see problems. For one, this timeout thing can only be executed on the client. This means client dependent code, and regardless of how well you code it, it screws portability in the end. (ever browsed with lynx)?
So in my opinion javascript is just not the way to go. And for that matter, neither is CRON. If you're developing a highly portable system (ideally) then it should work on both IIS and unix/apache... CRON would allow for scheduled timeout checks independent of the client. And sure, there is CRON like functionality for windows, but what about users on a hosted site on IIS that dont have it? You're screwed again here. So at least CRON and javascript are out of the question.
Next we deal with how to represent this group data representation of locks then. Have a locks table, or a locks field, a locks file, etc. These are all valid representations. I would choose one which best fits your data size and access frequency.
Next, I think the solution lies completely within the interface areas defined by the application (in PHP). I suggest changing the entire metaphor of how data is updated. I suggest mirroring the metaphor of a library, where people check in/out books. This is much like how CSV/VSS work.
Each user of your 'portal' consciencely checks out records to edit. These records remain checked out to that user. Other users get the message the record is checked out for editing, and cant. They can see the time elapsed since the check out. You could even allow them a force/override checkout, which transfers control of the record to them. You could also have some god-mode functionality that provides an interface to who has what checked out and basic managerial functionality.
This would side step the problem of the connection being lost and the browser closed while the record is checked out.
On a related note, I think its smart to minimize the processing required, and thats why i would minimize the amount that needs to be locked. Records can always be selected for view. Even though some user is editing, you can still view the original record. Likewise, even though some user has the view of the data sitting on their client, you can begin editing anyways. So I would not lock read-only operations. Nor would I lock insert operations. I would only lock edit operations. And I would only allow delete operations from within the edit status.
You might say this is a cumbersome metaphor, but it successfully solves the problems, independent of the client.
Hope this helps. There is obviously more you could add to this concept, but I think you can do the rest.