Блокировщик файлов

Класс - блокировщик файлов, может использоваться при необходимости любых блокировок исполняемых скриптов-потоков и/или их ограничения. Т.е. гарантированно можно использовать какой то скрипт лишь в 1 поток, несмотря на множество запросов к нему. Либо запрещать другие потоки на уровне каждого отдельного пользователя используя в качестве ключа его идентификатор.

Пример использования:

Locker::lock('my-any-key')); // возвращает true если блокировка получена и false если поток существует и блокировка ещё не снята

Locker::unlock('my-any-key')); // снимает блокировку установленную текущим процессом

<?php

/**
 * Locker блокировщик файлов
 * 
 * отвечает за блокировку файлов, может использоваться при необходимости любых блокировок исполняемых потоков и их ограничения
 * usage example:
 *
 *  if (Locker::lock(basename(__FILE__, '.php'))) {
 *       Locker::unlock(basename(__FILE__, '.php'));
 *  }
 * 
 */

class Locker
{
    /** путь к каталогу, в котором будут храниться файлы блокировки. */
    const LOCK_PATH = __DIR__ . '/../../../temp';

    /** префикс файла блокировки. */
    const LOCK_PREFIX = 'lock';

    /** время блокировки в секундах */
    const CLEAN_TIME = 3600;

    /** Переменная класса, используется для хранения пути к файлу блокировки. */
    private static $path;

    /** Используется, чтобы определить, заблокировал ли текущий процесс файл. */
    private static $lock = false;

    /**
     * создает файл с именем блокировки и записывает текущее время плюс максимальное время, в
     * течение которого блокировка должна удерживаться в файле.
     * 
     * Если файл уже существует, проверяет, истек ли срок действия блокировки, и если да, то удаляет
     * файл и возвращает значение true.
     * 
     * Если срок действия блокировки не истек, возвращается false.
     * 
     * Если файл не существует, создает файл и возвращает true
     * 
     * @param int $id Имя - ключ файла блокировки.
     * @param int $max_time Максимальное время удержания блокировки в секундах.
     */
    public static function lock($id, $max_time = self::CLEAN_TIME)
    {
        self::setPath($id);
        if (file_exists(self::$path) && self::cleaner()) {
            return false;
        }
        $file = new \SplFileObject(self::$path, 'a+b');
        $file->flock(LOCK_EX);
        $file->rewind();
        $time = $file->fgets();
        $file->ftruncate(0);
        $file->fwrite(time() + $max_time);
        if (!$time) {
            touch(self::$path, time() + $max_time);
            $file->flock(LOCK_UN);
            self::$lock = true;
            return true; // блокировка получена
        }
        $file->flock(LOCK_UN);
        return false; // блокировка не получена
    }


    /**
     * создает каталог, если он не существует, а затем устанавливает в self::$path имя файла блокировки
     * 
     * @param Уникальный идентификатор блокировки, который используется для создания имени файла
     * блокировки.
     */
    private static function setPath($id)
    {
        try {
            file_exists(self::LOCK_PATH) or mkdir(self::LOCK_PATH, 0755);
            if (!file_exists(self::LOCK_PATH)) {
                throw new \Error('Path does not create');
            }
        } catch (\Throwable $th) {
            exit($th);
        }
        self::$path = self::LOCK_PATH . '/' . self::LOCK_PREFIX . '-' . $id . '.lock';
        file_exists(self::$path) && clearstatcache(true, self::$path);
    }

    /**
     * Удаляет файл блокировки
     * 
     * @param int $id Имя файла блокировки.
     * @param bool $forse истинное означает что блокировка будет снята, даже если она не была создана текущим процессом.
     */
    public static function unlock($id, $forse = false)
    {
        self::setPath($id);
        if (file_exists(self::$path) && (self::$lock || $forse)) {
            unlink(self::$path);
            return true;
        }
        return false;
    }

    /**
     * удаляет любые файлы блокировки, которые старше текущего времени.
     * 
     * @return bool Логическое значение, истинное означает что текущий файл блокировки по прежнему существует.
     */
    private static function cleaner()
    {
        foreach (glob(self::LOCK_PATH . '/' . self::LOCK_PREFIX . '-*.lock') as $path) {
            if (filemtime($path) < time() && intval(file_get_contents($path)) < time()) {
                unlink($path);
            }
        }
        return file_exists(self::$path);
    }
}

Разместил gorlovkamsbt 20.Apr.2023 https://wrong-mvc.com


.