Большой архив статей, книг, документации по программированию, вебдизайну, компьютерной графике, сетям, операционным системам и многому другому
 
<Добавить в Избранное>    <Сделать стартовой>    <Реклама на сайте>    <Контакты>
  Главная Документация Новости ИТ Программы Книги Games   Обои   Экспорт RSS E-Books
 
Поиск по сайту

TOP-10 программ
Symantec Norton Ghost 9.0
Partition Magic 8.0.2 Pro
Xilisoft 3GP Video Converter v3.1.7.0616b
Norton AntiVirus 2005
Xilisoft 3GP Video Converter v2.1.52.831b
Антивирус Касперского Personal 5.0.303 beta 2
RAR Password Cracker 4.12
ABBYY PDF Transformer v1.00.820
MP3 To Ringtone Gold v3.02
Mobtime Cell Phone Manager v5.3.1
 
Наши сервисы
Рассылка новостей. Подпишитесь на рассылку сейчас и вы всегда будете в курсе последних событий в мире информационных технологий.
Новостные информеры. Поставьте наши информеры к себе и у вас на сайте появится дополнительный постоянно обновляемый раздел.
Добавление статей. Если вы являетесь автором статьи или обзора на тему ИТ присылайте материал нам, мы с удовольствием опубликуем его у себя на сайте.
 
 

  Раздел: Компьютерная документация -> Интернет технологии -> PHP

 

Php блокировка

Суть проблемы такова:
Есть база данных, используемая на сайте (например, база для регистрации пользователей, куда записывается их имя и email), она лежит в текстовом файле построчно (в дальнейшем, "file_base.dat".). Два пользователя активизируют сервер через командную строку в броузере, для ввода свох имен и email. Сервер отсылает их к скрипту. Оба пользователя "начинают движение" по скриптовому потоку (тексту php файла) сверху вниз, причем, Первый "бежит" на долю секунды быстрее Второго. Когда они достигают того места, где скрипт исполняет их запрос, движение по потоку останавливается, в их броузер выводится сгенерированная скриптом страница в виде html. Чтобы из file_base.dat прочитать данные, этот файл надо открыть на чтение (функция - @file), чтобы записать что-то в него, надо открыть на запись (функция - @fopen). В скрипте это выглядит так:

<?
……
// читаем данные из файла-базы
$f = @file ("file_base.dat", "r"); // здесь находится 2 пользователь
// здесь идет текст скрипта
// открываем файл-базу на запись
$fp = @fopen ("file_base.dat", "w"); // здесь находится 1 пользователь
// записываем в файл-базу данные из выше
// прочитанного file_base.dat - переменная $f
// и добавляем еще одну строку с данными нового пользователя
// закрываем файл-базу
@fclose ($fp);
……
?>

То есть, чтобы новый пользователь появился в нашей file_base.dat, мы считываем оттуда информацию, которую кладем в переменную $f, затем записываем в этот же файл эту переменную $f (при этом, file_base.dat переписываем полностью) и внизу дописываем еще одну строку с данными нашего нового пользователя. Мы видим, что на чтение и на запись file_base.dat открывается в разных местах нашего скрипта. Если оба пользователя, одновременно, достигли "своего" места в этом скрипте, но один из file_base.dat только начал читать данные, а другой уже их прочитал, продвинулся чуть ниже и, в этот момент, находится на отметке записи в файл file_base.dat своих данных. То, в этом случае, от нашего файла file_base.dat ничего не останется. В связи с этим, в Php была введена функция совместного доступа @flock, которая призвана не допускать совместный доступ к файлу на чтение и запись.

<?
……
// читаем данные из файла файла-базы
$f = @file ("file_base.dat", "r"); // здесь находится 2 пользователь
// здесь идет текст скрипта
// открываем файл-базу на запись
$fp = @fopen ("file_base.dat", "w"); // здесь находится 1 пользователь
// блокируем файл-базу на чтение
@flock ($fp, LOCK_EX)
// записываем в файл-базу данные из выше
// прочитанного file_base.dat - переменная $f
// и добавляем еще одну строку с данными нового пользователя
// снимаем блокировку
@flock ($fp, LOCK_UN)
// закрываем файл-базу
@fclose ($fp);
……
?>

Теперь, вроде бы все нормально, файл блокируется на чтение, когда в него что-то пишут. Но, что произойдет в нашем случае, когда, 1 пользователь прочитал данные файла и пришел к отметке открытия file_base.dat на запись, оркыл его и заблокировал на чтение функцией @flock, а 2 пользователь, именно в этот момент пришел к точке, где данные из файла считываются функцией @file? 2 пользователь ничего не прочитает из этого файла, потому что file_base.dat блокирован 1 пользователем командой @flock на чтение. 2 пользователь просто "пробежит" дальше по потоку скрипта ничего из файла file_base.dat не прочитав, то есть наша переменная $f будет пустой. Но, дальше-то он будет записывать в этот файл, то что ранее с него считал. В итоге, в наш file_base.dat запишется только одна строка с его именем и email. То есть, file_base.dat будет потерян.
В связи с чем, была придумана функция: read_file

function read_file($path)
{
if(!is_file($path)) {return false; }
elseif(!filesize($path)) {return array(); }
elseif($array=file($path)) {return $array; }
else { while(!$array=file($path)){sleep(1);} return $array; }
}

Суть ее такова: пока файл блокирован на чтение, пользователь, который хочет считать из него информацию, находится в цикле, то есть, как бы "стоит" на месте, не "бежит" дальше по тексту скрипта, ожидая, когда файл разблокируется на чтение. В итоге наш скрипт принимает такой вид:

<?
function read_file($path)
{
if(!is_file($path)) {return false; }
elseif(!filesize($path)) {return array(); }
elseif($array=file($path)) {return $array; }
else { while(!$array=file($path)){sleep(1);} return $array; }
}
……
// проверяем заблокирован ли файл на чтение,
// если заблокирован, назначаем цикл с остановкой,
// пока блокировка не будет снята, после снятия блокировки,
// читаем данные из файла файла-базы
$f = read_file ("file_base.dat", "r"); // здесь находится 2 пользователь
// здесь идет текст скрипта
// открываем файл-базу на запись
$fp = @fopen ("file_base.dat", "w"); // здесь находится 1 пользователь
// блокируем файл-базу на чтение
@flock ($fp, LOCK_EX)
// записываем в файл-базу данные из выше
// прочитанного file_base.dat - переменная $f
// и добавляем еще одну строку с данными нового пользователя
// снимаем блокировку
@flock ($fp, LOCK_UN)
// закрываем файл-базу
@fclose ($fp);
……
?>

Вроде бы все нормально. Когда 1 пользователь начал записывать свои данные в file_base.dat, 2 "спит" одну секунду, ожидая разблокировки file_base.dat, когда file_base.dat разблокирован, он считывает из него информацию и начинает движение дальше. Но, есть одно "но". Если 2 пользователь чуть быстрее 1 пользователя "добежал" до "своего" места, прочитал половину данных из нашего file_base.dat, который еще не был блокирован, и, именно, в этот момент, 1 "добежал" по тексту скрипта до @flock ($fp, LOCK_EX), то есть заблокировал наш файл, то переменная $fp будет иметь только половину данных из нашего file_base.dat, потому что, именно, в этот момент file_base.dat был заблокирован. В итоге, в наш file_base.dat будет записана половина информации из нашей базы + одна сторка нового пользователя. То есть, опять, file_base.dat мы потеряли.

Суть подхода, который предлагаем мы для решения этой проблемы такой:
Во время считывания из файла или записи в него данных, на сайте появляется текстовая строка с названием этого файла, когда из файла информация прочиталась или записалась, эта текстовая строка удаляется. Пока она есть, значит кто-то уже использует базу данных на чтение или запись, пользователь, который хочет обратиться к этой базе на чтение или запись, находится в цикле, ожидая пока текстовая строка исчезнет. Как только она исчезает, он читает или пишет в базу данных, сам при этом создавая такую же текстовую строку, тем самым препятствуя доступу двух и более пользователей к базе. 

Для чего, на сайте создадим папку для хранения текстовых строк. Например, lock. Наш файл на сайте лежит в папке database, значит в папке lock надо создать папку database. Теперь, когда пользователь обращается к file_base.dat, для чтения или записи в него, абсолютный путь http://наш_сайт.ru/database/file_base.dat, в папке http://наш_сайт.ru/lock/database/ появляется файл-строка file_base.dat.tmp, абсолютный путь - http://наш_сайт.ru/lock/database/file_base.dat.tmp, закрывая доступ к file_base.dat, как только пользователь считал или записал информацию в наш файл-базу, текстовая строка  file_base.dat.tmp удаляется, открывая доступ другим пользователям к file_base.dat.

<?
// объявляем директорию для временных файлов
$Lock_dir = "lock";
// функция для создания временных текстовых файлов
function touchString($file) {
global $Lock_dir;
$tmp = "$Lock_dir/".$file.".tmp";
while(1) {
if (is_file($tmp))
{
while(file_exists($tmp))
{
$file_exist++;
if($file_exist > 10){break;}
clearstatcache();
sleep(1);
}
}
return touch($tmp);
}
}
// функция удаляющая временные текстовые файлы
function delString($file) {
global $Lock_dir;
$tmp = "$Lock_dir/".$file.".tmp";
return unlink($tmp);
}
// альтернатива функци @file
function FileArray($file) {
if (!is_readable($file)) return FALSE;
touchString($file);
$bufer = file($file);
delString($file);
return $bufer;
}
// альтернатива функци @fopen
function OpenFile($file, $mode) {
touchString($file);
return fopen($file, $mode);
}
// альтернатива функци @fclose
function CloseFile($fido, $file) {
$sito = fclose($fido);
delString($file);
return $sito;
}
……
// проверяем есть ли временный файл, запрещающий
// чтение и запись в файл-базу, если он есть, останавливаем
// пользователя в цикле, где он ожидает пока временный файл
// исчезнет, как толко он исчезает, сами создаем такой же временный
// файл, запрещая доступ к файлу-базе, только после этого читаем данные из
// файла-базы, удаляем временный файл, открывая доступ к базе
// другим пользователям
$f = FileArray ("database/file_base.dat"); // здесь находится 2 пользователь
// здесь идет текст скрипта
// проверяем есть ли временный файл, запрещающий
// чтение и запись в файл-базу, если он есть, останавливаем
// пользователя в цикле, где он ожидает пока временный файл
// исчезнет, как толко он исчезает, сами создаем такой же временный
// файл, запрещая доступ к файлу-базе, только после этого открываем
// файл-базу на запись, временный файл не удаляется, закрывая доступ к базе
// другим пользователям
$fp = OpenFile ("database/file_base.dat", "w"); // здесь находится 1 пользователь
// записываем в файл-базу данные из выше
// прочитанного database/file_base.dat - переменная $f
// и добавляем еще одну строку с данными нового пользователя
// закрываем файл-базу, удаляем временный файл, открывая доступ к базе
// другим пользователям
CloseFile ($fp, "database/file_base.dat");
// обратите внимание, что в CloseFile два аргумента: $fp и
// database/file_base.dat
……
?>

В этой ситуации мы видим, что когда один пользователь достиг точки считывания с file_base.dat или, наоборот, другой пытается записать в file_base.dat информацию, нам ничего не страшно. Потому что, как в одном, так и в другом случае, появился маленький текстовый файл file_base.dat.tmp, который не дает ни одному ни другому совместно читать или писать в file_base.dat.

В нашем варианте есть одна "дыра", если вдруг пользователь обратился к базе данных, создав текстовую строку блокировки, незакончил как-бы цикл (свет погас и компьютер выключился), и эта текстовая блокирующая строка осталась лежать в папке Lock, то наша программа "подвиснет", не давая никому пройти, из-за этого оставшегося флага. Мы не стали усложнять функции проверкой на удаление этого файла-флага, а, просто ввели в функции его создающей, предел "подвисания" компьютера 10 секунд ($file_exist++; if($file_exist > 10){break;}), через 10 секунд он автоматически выйдет из цикла и сотрет временный файл. В этом кроется опасность, но она ничтожна мала по сравнению с теми, которые были описаны выше. Считаем, что подход описанный выше, защитит от обвала базы данных, которая лежит в текстовом файле и не будет особо заметно флагов блокировки, когда на сайте ее, одновременно использует до 10 человек. Мы знаем, что наш скрипт сервером исполняется 0,5 сек, в этом случае его пропускная способность в час составит до 1800 человек. Уменьшим ее вдвое, 900 человек, за сутки 21600 человек. Согласитесь, и без MySql можно обойтись.

Для проверки работоспособности этих функций запишите вручную в папку Lock этот самый блокирующий файл file_base.dat.tmp, в нашем случае, это: http://наш_сайт.ru/lock/database/file_base.dat.tmp, тем самым, блокируя доступ к базе http://наш_сайт.ru/database/file_base.dat, запустите программу, обратитесь к базе, вы увидите, что флаг работает и броузер "стоит" на месте, удалите file_base.dat.tmp файл (разблокируя) и подвисание закончится.

Теперь у нас есть функции:
1. FileArray , заменяющая @file
2. OpenFile , заменяющая @fopen
3. CloseFile , заменяющая @fclose

Источник: www.omsk777.ru

Ссылки по теме
Внутренние функции
Обработка строк в РНР
PHP и всё такое...
Пишем PHP код, устойчивый к ошибкам
Полезные скрипты на PHP
Почтовые функции в РНР
Полезные функции для работы с файловой системой

Вся документация PHP

 

Компьютерная документация от А до Я - Главная

 
Популярные книги

Photoshop CS2 для пользователя

Подробнее

Общая информатика. Универсальный курс

Подробнее

Ремонт и обслуживание компьютера дома

Подробнее


 
Новости ИТ
04.12.2008  В Windows 7 запуск приложений Direct3D 10/10.1 будет возможен на CPU
04.12.2008  eGo BlackBelt и Encrypt - пара новых портативных HDD Iomega с зашитой данных
04.12.2008  A-DATA выпускает двух- и трёхканальные наборы памяти DDR3-1800+ в серии XPG Plus
04.12.2008  MOTOROKR EM35
04.12.2008  Шведский производитель ковриков для мышей выпустил игровую гарнитуру
04.12.2008  eGo BlackBelt и Encrypt - пара новых портативных HDD Iomega с защитой данных
04.12.2008  Вышла вторая бета-версия Windows Vista SP2
04.12.2008  Внешний SSD-накопитель с поддержкой eSATA и USB
04.12.2008  Флэшка OCZ со встроенным кард-ридером
04.12.2008  Весрия «ПАУ» 1.8.2 будет содержать новый функционал
04.12.2008  Компания «Русские Информационные Технологии» подготовила бета-версию программы «Печать конвертов!»
04.12.2008  Телефон премиум-класса с двумя SIM-картами
04.12.2008  High-end десктопы Asus Eee Box
04.12.2008  Видеокарта NVIDIA Quadro FX 4800 для профессионалов
04.12.2008  Экстремальные внешние HDD от Iomega
04.12.2008  MSI EX300 - 13.3 дюйма для развлечения
04.12.2008  SATA 3.0 появится в следующем году
04.12.2008  Mini-ITX-плата Zotac на основе логики NVIDIA и с поддержкой Wi-Fi
04.12.2008  Корпус NZXT Zero 2: улучшенное охлаждение и строгий дизайн
04.12.2008  Конвертеры: Xilisoft Video Converter v.5.1.7.1128
 
Полезно

 
Copyright © CompDoc.Ru
При цитировании и перепечатке ссылка на www.compdoc.ru обязательна. Карта сайта.
 
Rambler's Top100