Лучший способ заменить файл на сервере - PullRequest
3 голосов
/ 01 октября 2010

Я должен написать скрипт на PHP, который будет динамически заменять некоторые файлы на сервере время от времени.Легкая вещь, но проблема в том, что я хочу избежать ситуации, когда пользователь запрашивает этот файл во время замены.Затем он может получить неполный файл или даже ошибку.

Лучшее решение для меня - заблокировать доступ к моему сайту во время замены, например, установив .htaccess, перенаправив все запросы на страницу с информацией о коротком перерыве.Но обычно файл .htaccess уже существует, поэтому может возникнуть ситуация, когда сервер получит некомпилированный файл .htaccess.

Есть ли способ его решить?

Редактировать: СпасибоВы так много для всех ответов, ребята.Вы великолепны.

@ ircmaxell Ваша идея звучит великолепно для меня.Я читаю то, что написали парни из PHP.net, и я не знаю, правильно ли я все понимаю.

Итак, скажите мне: если я сделаю все шаги, которые вы написали, и добавьте apc.file_update_protection в мой php.ini,не будет способа получить незавершенный файл пользователем в любое время?Всегда будет один, правильный файл?Вы уверены на 100%?

Для меня очень важно, потому что эти замены будут очень часто, и есть большой шанс запросить файл во время переименования.

Ответы [ 5 ]

5 голосов
/ 01 октября 2010

Вот что-то простое, и оно будет работать на любой локальной файловой системе linux:

  1. Загрузить (или записать) файл во временное имя файла
  2. Переместить файл (используяmv (переместить) команду, либо по FTP, либо из командной строки и т. Д., Либо команду rename в PHP), чтобы перезаписать существующую.

Когда вывыполнить команду mv, она в основном удаляет старый указатель файла и записывает новый.Поскольку это делается на уровне файловой системы, это атомарная операция.Таким образом, клиент не может получить старый файл ...

APC рекомендует сделать это , чтобы предотвратить возникновение этих проблем ...

Также обратите внимание, что вымог бы использовать rsync, чтобы сделать это также (поскольку это в основном делает это за кадром) ...

1 голос
/ 01 октября 2010

Разве это не работает уже? Я никогда не проверял это специально, но я сделал то, что вы делаете, и эта проблема никогда не обнаруживалась. Кажется, для операционной системы легко набрать

  1. Загрузка / запись во временный файл
  2. Когда запись завершена, заблокируйте доступ к исходному файлу (сделайте запрос на ожидание файла)
  3. Удалите файл, переименуйте временный и удалите все блокировки

Я вполне уверен, что именно это должна делать ОС для копирования. Если вы пишете содержимое файла самостоятельно с помощью PHP, вам просто нужно сделать это самостоятельно ...

1 голос
/ 01 октября 2010

Попробуйте безрельсовый Capistrano или метод, который они используют:

в каталоге у вас есть две вещи:

  1. Папка, содержащая папки, каждая подпапка являетсяrelease
  2. Мягкая ссылка на текущую папку релиза

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

0 голосов
/ 01 октября 2010

Вариант 1. Если у вас много пользователей, и эта замена выполняется не так часто, вы можете настроить обслуживание на сайте (заблокировать доступ), и никто не будет входить в систему через определенное время, и, наконец, отключиться.все, кто вошел в систему, когда вы собираетесь выполнить замену.

Вариант 2: если замена файла выполняется часто (в этом случае вы не должны выполнять обслуживание каждый день), сделайте этокод.Имейте два одинаковых файла (одну и ту же папку, если хотите).Затем, по коду, когда вы собираетесь заменить файл, просто дайте ему копию, а вы замените тот, который вам нужен.Вы можете сделать это с простым IF.

Псевдокод:

if (replaceTime - 15 seconds <= currentTime <= replaceTime + 15 seconds){
    // allows 30 seconds for another script to bring in the new image into 'myImage.jpg'
    <img src="/myFiles/myOldImage.jpg" />
} else {
    <img src="/myFiles/myImage.jpg" />
}

Нет необходимости обновлять базу данных или перемещать / копировать / переименовывать файл вручную.

После того, как replaceTime + 15 прошло:

copyFileTo("myImage.jpg","myOldImage.jpg");
// Now you have the copy ready for the next time to replace
0 голосов
/ 01 октября 2010

возможно, попробуйте это так:

  1. удалите файл и сохраните его путь
  2. ln -nfs movefilepath pathtosorrypage.html
  3. загрузите файл во временную папкуна сервере
  4. удалить символическую ссылку
  5. mv newfile movefilepath
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...