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.
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
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.
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.
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.
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
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.