Как переименовать () файл в PHP, который должен оставаться заблокированным при этом? - PullRequest
0 голосов
/ 04 января 2019

У меня есть текстовый файл, который несколько пользователей будут редактировать одновременно (ограничено отдельной строкой на редактирование, на пользователя).Я уже нашел решение для части «редактирования строки» требуемой функциональности прямо здесь, на StackOverflow.com, в частности, 4-е решение (для больших файлов), предлагаемое @Gnarf в следующем вопросе:

как заменить определенную строку в текстовом файле с помощью php?

Он в основном переписывает все содержимое файла в новый временный файл (с учетом правки пользователя), а затем переименовывает временный файл воригинальный файл после завершения.Это здорово!

Чтобы избежать правки одного пользователя, вызывающей конфликт с правкой другого пользователя, если оба пытаются одновременно редактировать, я ввел функцию flock (), как видно из моего вариантакод здесь:

$reading = fopen($file, 'r');
$writing = fopen($temp, 'w');

$replaced = false;

if ((flock($reading, LOCK_EX)) and (flock($writing, LOCK_EX))) {

    echo 'Lock acquired.<br>';

    while (!feof($reading)) {

        $line = fgets($reading);

        $values = explode("|",$line);

        if ($values[0] == $id) {

            $line = $id."|comment edited!".PHP_EOL;
            $replaced = true;
        }

        fputs($writing, $line);
    }

    flock($reading, LOCK_UN);
    flock($writing, LOCK_UN);

    fclose($reading);
    fclose($writing);

} else {

    echo 'Lock not acquired.<br>';
}

Я убедился, что файл $ temp всегда имеет уникальное имя файла.Полный код здесь: https://pastebin.com/E31hR9Mz

Я понимаю, что flock () заставит любое другое выполнение сценария ожидать в очереди, пока не завершится первое выполнение и не будет выпущен flock ().Все идет нормально.

Однако проблема начинается в конце сценария, когда пришло время переименовать () временный файл для замены исходного файла.

if ($replaced) {

    rename($temp, $file);

} else {

    unlink($temp);
}

Из того, что я видел, rename () завершится неудачно, если в исходном файле все еще есть flock (), поэтому мне нужно освободить flock () до этого момента.Однако мне также нужно, чтобы он оставался заблокированным, иначе метод rename () завершится неудачно, когда другой пользователь, выполняющий тот же сценарий, сразу же откроет новый flock (), как только будет выпущен предыдущий flock ().Когда это произойдет, он вернет:

Warning: rename(temporary.txt,original.txt): Access is denied. (code: 5)

tl; dr: Кажется, я немного в Catch-22.Похоже, что rename () не будет работать с заблокированным файлом, но разблокировка файла позволит другому пользователю немедленно снова заблокировать его, прежде чем может произойти переименование ().

Есть идеи?

обновление: После некоторых обширных исследований того, как работает flock (), (с точки зрения непрофессионала, нет никакой гарантии, что другой скрипт будет уважать «блокировку», и, следовательно, он не является «блокировкой»)вообще как можно было бы предположить из буквального значения слова) я выбрал это решение вместо этого, которое работает как шарм:

https://docstore.mik.ua/orelly/webprog/pcook/ch18_25.htm

«Хороший замок» в ваших приключениях блокировки.

...