diff --git a/_init.php b/_init.php index 74a0ef4..b9df621 100644 --- a/_init.php +++ b/_init.php @@ -17,5 +17,4 @@ if (!defined('DC_RC_PATH')) { class initActivityReport { public const ACTIVITY_TABLE_NAME = 'activity'; - public const CACHE_DIR_NAME = 'activityreport'; } diff --git a/src/ActivityReport.php b/src/ActivityReport.php index e92746a..7ae3a40 100644 --- a/src/ActivityReport.php +++ b/src/ActivityReport.php @@ -61,8 +61,8 @@ class ActivityReport /** @var ActivityReport $instance ActivityReport instance */ private static $instance; - /** @var null|resource $lock File lock for update */ - private $lock = null; + /** @var null|string $lock File lock for update */ + private static $lock = null; /** * Constructor sets activity main type. @@ -495,75 +495,49 @@ class ActivityReport } /** - * Lock update. - * * Lock a file to see if an update is ongoing. * - * @return bool The lock success + * @return bool True if file is locked */ public function lockUpdate(): bool { try { - # Need flock function - if (!function_exists('flock')) { - throw new Exception("Can't call php function named flock"); - } # Cache writable ? if (!is_writable(DC_TPL_CACHE)) { throw new Exception("Can't write in cache fodler"); } # Set file path - $f_md5 = md5((string) dcCore::app()->blog?->id); - $cached_file = sprintf( + $f_md5 = md5((string) dcCore::app()->blog?->id); + $file = sprintf( '%s/%s/%s/%s/%s.txt', DC_TPL_CACHE, - My::CACHE_DIR_NAME, + My::id(), substr($f_md5, 0, 2), substr($f_md5, 2, 2), $f_md5 ); - # Real path - $cached_file = (string) Path::real($cached_file, false); - // make dir - if (!is_dir(dirname($cached_file))) { - Files::makeDir(dirname($cached_file), true); - } - //ake file - if (!file_exists($cached_file)) { - !$fp = @fopen($cached_file, 'w'); - if ($fp === false) { - throw new Exception("Can't create file"); - } - fwrite($fp, '1', strlen('1')); - fclose($fp); - } - // open file - if (!($fp = @fopen($cached_file, 'r+'))) { - throw new Exception("Can't open file"); - } - // lock file - if (!flock($fp, LOCK_EX | LOCK_NB)) { - //throw new Exception("Can't lock file"); + + $file = Lock::lock($file); + if (is_null($file) || empty($file)) { return false; } - $this->lock = $fp; + self::$lock = $file; return true; } catch (Exception $e) { - // what ? throw $e; } } /** - * Unlock update. + * Unlock file of update process. */ public function unlockUpdate(): void { - if ($this->lock) { - @fclose($this->lock); - $this->lock = null; + if (!is_null(self::$lock)) { + Lock::unlock(self::$lock); + self::$lock = null; } } diff --git a/src/Lock.php b/src/Lock.php new file mode 100644 index 0000000..6b4cdca --- /dev/null +++ b/src/Lock.php @@ -0,0 +1,148 @@ + + */ + protected static $lock_stack = []; + + /** + * Locked files status stack. + * + * @var array + */ + protected static $lock_disposable = []; + + /** + * Last lock attempt error + * + * @var string + */ + protected static $lock_error = ''; + + /** + * Lock file. + * + * @param string $file The file path + * @param bool $disposable File only use to lock + * + * @return null|string Clean file path on success, empty string on error, null if already locked + */ + public static function lock(string $file, bool $disposable = false): ?string + { + # Real path + $file = Path::real($file, false); + if (false === $file) { + self::$lock_error = __("Can't get file path"); + + return ''; + } + + # not a dir + if (is_dir($file)) { + self::$lock_error = __("Can't lock a directory"); + + return ''; + } + + # already marked as locked + if (isset(self::$lock_stack[$file]) || $disposable && file_exists($file)) { + return null; + } + + # Need flock function + if (!function_exists('flock')) { + self::$lock_error = __("Can't call php function named flock"); + + return ''; + } + + # Make dir + if (!is_dir(dirname($file))) { + Files::makeDir(dirname($file), true); + } + + # Open new file + if (!file_exists($file)) { + $resource = @fopen($file, 'w'); + if ($resource === false) { + self::$lock_error = __("Can't create file"); + + return ''; + } + fwrite($resource, '1', strlen('1')); + //fclose($resource); + } else { + # Open existsing file + $resource = @fopen($file, 'r+'); + if ($resource === false) { + self::$lock_error = __("Can't open file"); + + return ''; + } + } + + # Lock file + if (!flock($resource, LOCK_EX | LOCK_NB)) { + self::$lock_error = __("Can't lock file"); + + return ''; + } + + self::$lock_stack[$file] = $resource; + self::$lock_disposable[$file] = $disposable; + + return $file; + } + + /** + * Unlock file. + * + * @param string $file The file to unlock + */ + public static function unlock(string $file): void + { + if (isset(self::$lock_stack[$file])) { + fclose(self::$lock_stack[$file]); + if (!empty(self::$lock_disposable[$file]) && file_exists($file)) { + @unlink($file); + } + unset( + self::$lock_stack[$file], + self::$lock_disposable[$file] + ); + } + } + + /** + * Get last error from lock method. + * + * @return string The last lock error + */ + public static function getlastLockError(): string + { + return self::$lock_error; + } +} diff --git a/src/My.php b/src/My.php index 32eca3d..6536825 100644 --- a/src/My.php +++ b/src/My.php @@ -24,9 +24,6 @@ class My /** @var string Activity database table name */ public const ACTIVITY_TABLE_NAME = 'activity'; - /** @var string Cache sub directory name */ - public const CACHE_DIR_NAME = 'activityreport'; - /** @var int Incremental version by breaking changes */ public const COMPATIBILITY_VERSION = 3;