<?php
require_once('Driver.php');
require_once('System/SharedMemory.php');
/**
* A driver that use plain filesystem as data store
*/
class AJAX_Locking_Driver_File extends AJAX_Locking_Driver
{
var $dir;
/**
* Constructor
*
* @return AJAX_Locking_Driver
*/
function AJAX_Locking_Driver_File($dir = '/tmp', $timeout = false)
{
parent::AJAX_Locking_Driver($timeout);
$this->dir = realpath($dir);
}
/**
* Locks an object
*
* @param mixed $user id of the user who wants to lock
* @param string $type type/classname of the object
* @param mixed $id id of the object
* @return boolean true if the unlock was successfull, false otherwise
*/
function lock($user, $type, $id)
{
$key = $this->_getKey($type, $id);
$value = $this->_get($key);
if (empty($value)) {
// object is unlocked: lock it
$value = $this->_getValue($user, $type, $id);
$this->_set($key, $value);
return true;
} else {
// object is locked: check if lock expired
list($owner, $type, $id, $time) = $this->_parseValue($value);
if (time() - $time > $this->timeout) {
// lock expired: remove it and lock
$this->_rm($key);
$this->_set($key, $value);
return true;
} else {
// object properly locked by (another?) user
return ($owner == $user);
}
}
}
/**
* Unlocks an object
*
* @param mixed $user id of the user who wants to unlock
* @param string $type type/classname of the object
* @param mixed $id id of the object
* @return boolean true if the unlock was successfull, false otherwise
*/
function unlock($user, $type, $id)
{
$key = $this->_getKey($type, $id);
$value = $this->_get($key);
if (empty($value)) {
// object was not locked
return false;
} else {
// check if user is owner of the lock
list($owner, $type, $id, $time) = $this->_parseValue($value);
if ($user == $owner) {
// unlock it
$this->_rm($key);
return true;
} else {
// user cannot unlock it
return false;
}
}
}
/**
* Returns the status of the object (lock or unlocked)
*
* @param mixed $user id of the user who wants to know the object's status
* @param string $type type/classname of the object
* @param mixed $id id of the object
* @return string the status and the owner of the object
*/
function status($user, $type, $id)
{
$key = $this->_getKey($type, $id);
$value = $this->_get($key);
if (empty($value)) {
// object is unlocked
return AJAX_LOCKING_UNLOCKED . '~' . 'noboby';
} else {
// object is locked:
// 1. check if current user is owner of the lock
// 2. check if lock expired
list($owner, $type, $id, $time) = $this->_parseValue($value);
$timeout = (time() - $time > $this->timeout);
if ($owner == $user) {
if ($timeout) {
// lock expired: remove it and inform it's ower
$this->_rm($key);
return AJAX_LOCKING_TIMEOUT . '~' . $owner;
} else {
return AJAX_LOCKING_OWNED . '~' . $owner;
}
} else {
if ($timeout) {
// lock expired: remove it
$this->_rm($key);
return AJAX_LOCKING_UNLOCKED . '~' . 'nobody';
} else {
return AJAX_LOCKING_LOCKED . '~' . $owner;
}
}
}
}
/**
* Returns the list of all active locks for administration purpose
*
* @return array of locks (owner, type, id), false if not implemented
*/
function getLocks()
{
$files = array();
$dh = opendir($this->dir);
while (false !== ($filename = readdir($dh))) {
if (strstr($filename, AJAX_LOCKING_PREFIX) == $filename) {
$files[] = $filename;
}
}
$locks = array();
foreach ($files as $f) {
$value = file_get_contents($this->dir . DIRECTORY_SEPARATOR . $f);
if ($value) {
list($owner, $type, $id, $time) = $this->_parseValue($value);
$timeout = (time() - $time > $this->timeout);
if (!$timeout) {
$locks[] = array(
'owner' => $owner,
'type' => $type,
'id' => $id
);
}
}
}
return $locks;
}
/**
* Administrately delete lock
*
* @param string $type
* @param mixed $id
*
* @return true if the lock is deleted successfully, false otherwise
*/
function deleteLock($type, $id)
{
$key = $this->_getKey($type, $id);
$this->_rm($key);
}
/**
* Returns the values stored in file $key
*
* @param string $key
* @return string
*/
function _get($key)
{
$value = '';
$filename = $this->dir . DIRECTORY_SEPARATOR . $key;
if (file_exists($filename)) {
$value = file_get_contents($filename);
}
return $value;
}
/**
* Puts the value $value into file $key
*
* @param string $key
* @param string $value
*/
function _set($key, $value)
{
$filename = $this->dir . DIRECTORY_SEPARATOR . $key;
$fp = fopen($filename, 'w');
fwrite($fp, $value);
fclose($fp);
}
/**
* Remove the file $key
*
* @param string $key
*/
function _rm($key)
{
$filename = $this->dir . DIRECTORY_SEPARATOR . $key;
return @unlink($filename);
}
}
?>