Document being edited

Hi all,

I am writing a custom CMS and I am trying to get my head around protecting documents from being edited by 2 (or more) different people at the same time.

My idea is that the document will have a status.

‘S’ for submitted,
‘E’ being edited and
‘L’ for Live.

I will change the status of the document in the database to E so that it won’t show up in people’s feeds of submitted documents.

My problem is, what if they exit the browser abnormally and the document remains status ‘E’. No other user will be able to edit it and it may fall off the radar.

Is there a way of executing PHP code just before the page exits?

I’ve searched for this, but can’t find anything, any help much appreciated.

Cheers

Thanks Tom, I think that should do it…

look up register_shutdown_function() :slight_smile:

Again another good idea, but this is the question I really need answering:

Is there a way of executing PHP code just before the page exits?

Have I posted this in the right category?

Did you read what I wrote? I was suggesting a request that never finishes while the user has the page open. When it does finish (because the user closed the browser, browser crash, navigated away) it will trigger a shutdown function that unlocks the file.

depends on the complexity of the page, surely? I don’t know anything about the inner workings of sleep() but in theory at least, it should use very minimal cpu. Memory usage would be small since you don’t really need anything. You don’t even need to create the DB connection until the shutdown function.

I honestly don’t know, but surely having a HTTP request and DB connect/write every few seconds has its own performance impact. As I said it was purely speculative :slight_smile:

Then what if the user loses connection or has a power outage?

Javascript functions to ‘unlock’ a file when the user navigates away could fairly easily lead to a file being indefinitely locked.

A ‘lock booster’, where a signal is sent every so often, would be more effective.

Ahh, sorry I misread what you put!

Would a hypothetically endless request not make the browser/server crash?

I think that’s a pretty interesting idea, actually.

However, if you have a bunch of editors working at the same time, each holding a connection open, wouldn’t that affect the performance for other visitors/ users/ sites?

You can either use optimistic or pessimistic locking. Optimistic locking presupposes that nothing will go wrong, but catches it (and perhaps even resolves it) if it does. This is useful if the chances are relatively low. Pessimistic locking assumes that things goes wrong, and explicitly locks the resource before editing it. This is probably what you had in mind.

Pessimistic locking is generally a bit more complicated to implement, because you have all these issues with locks going stale etc. I would try to use optimistic locking if possible.

That’s a terrific overview, but has anyone got any specific examples with code?

Thanks

SituationSoap: that’s what I’m worried about too, hogging connections.

Still, it’s an interesting theory, so I might have a play with it (if only as a learning exercise).

You could have a background javascript call updating the article as ‘still being edited’, if this signal has not been received in x minutes, mark it as available for editing.

This gives you a window of x minutes for non-js users too.

There was an excellent article detailing how to this with some rather interesting points, I’ll see if I can dig it out.

This article may be useful for your situation: http://jim-mcbeath.blogspot.com/2009/02/concurrent-editing-without-locking.html

The difference is that an extended sleep still keeps open an HTTP connection with the client. Depending on how your server is configured, a sufficient number of concurrent users could lead to a situation where you exhaust the maximum number of concurrent connections allowed by your webserver, effectively DDoSing yourself.

Just a thought.

Many thanks Anthony, look forward to hearing back from you.

In my system I request a lock when an item is being edited, which is valid for 90 seconds. The edit page itself fires off periodical ajax requests (every 60 seconds) that re-locks the item for another 90 seconds.

That way, if a lock goes stale, it’s only for a maximum of 90 seconds.

If another editor wants to edit that item, a message is displayed that the item is being edited by someone else (including the other editor’s username).

This wouldn’t work without Javascript, of course, but this web-app requires javascript anyway. Building something similar without js would be tricky but not undoable (iframe with meta refresh).

Is there a way of executing PHP code just before the page exits?

As Tom suggested, look up register_shutdown_function().

Or do you mean ‘execute PHP code just before the user leaves a page’?
That’s a whole different ball-game :slight_smile:

I’m speculating here but couldn’t you do it with a single ajax request? Fire off an ajax request to a php page which never loads (using a loop/sleep), then use register_shutdown_function() because it should trigger a user abort when the user goes to a different page or closes the browser.

What I’ve done in the past is to have a field in the DB storing the data which stores the timestamp of when the data was last updated. When a user goes to update a record, a hash of the timestamp is stored in the session, and before the user is able to update the record, we compare the hash with the one stored in the session. If the two are identical, we know that no edits have taken place, but if they’re different then the record has changed while the user was editing it.

At that point, you offer the user the opportunity to save the information they were updating, and tell them that the record has changed and they’ll need to review the changes before updating.

This is pretty optimistic locking – it makes the assumption that your users will actually do that and not simply overwrite each others’ changes, so I can’t say for sure whether or not this will work in your environment. But, it’s an idea.