Because web pages are disconnected (that is, there's no connection between the client and the server after the request has been fulfilled), there's no easy way to differentiate between a user who is still using the file and one who just neglected to check it back in.
There are a couple of ways to go about it, both using time.
You can decide that if a user has checked out a file but hasn't checked it back in after, for example, 4 hours, then it's just considered abandoned. In that case you'd have a (say) Checkout table with two columns (or just add a column to an existing table, as appropriate), one the ID of the file and the other a datetime field. When a user requests a file for checkout you'd find out if it had a checkout datetime that was less then 4 hours old. If it did then you'd deny the request, and if it didn't then you'd set the checkout time to now and allow the request. When a user checks the file back in you'd either eliminate the Checkout record or just set it to a time more than 4 hours ago.
The difficulty with such a system is setting a reasonable timeout. Should a user be able to get up and go have lunch with the file still checked out? Should he be able to check it out in the morning and not check it back in until the end of the day? If the timeout is short, shouldn't he be able to get up and use the restroom while it's checked out? Lots of issues.
So, if the "file" the user is checking out is really just a database row, and the user is manipulating it strictly in a web page, you can use a "refresh bug" trick, where you have a frame (or iframe) embedded in the record's page that simply tells the server "this page is still open" every x minutes, which updates the database with the "last refreshed" datetime. If the user just closes the page then the the frame/iframe will stop requesting refreshes, and using the above system you'll know that the record is effectively "checked in" now. This lets you set the timeout to x + 1 minutes (or 2x, or whatever makes sense to you).