|
|
|
| Добрый день! =))
У меня такая проблема.... Полностью рабочий код, иногда стирает файл, который сам же и записывает!
Фрагмент кода....
<?php
// Учет посещаемости
@include("prosmotry.php");
// Небольшая обработка и изменение данных из файла
if($fprosm = @fopen("prosmotry.php","wb"))
{ fwrite($fprosm,'<? $prosm = array (');
foreach($prosm as $time => $info)
fwrite($fprosm,"\r\n$time=>array(/* информация */),");
fwrite($fprosm,"\r\n); ?>");
fclose($fprosm);
}
?>
| Почему это может происходить?
У меня возникло только одно предположение...
При практически одновременном обращении 2х разных пользователей к этому коду, первый еще пишет, второй уже читает, в результате второй читает "", соответственно в файл ничего не пишет.... Результат - обнуление =((
Подумал вставить перед include() задержку строкой:
while(filesize("prosmotry.php") == 0);
|
но написав такой вот локальный код:
<?php
$f = fopen("Edit1.htm","wb");
echo filesize("Edit1.htm")."<br>";
fwrite($f,"sdfsdfs");
echo filesize("Edit1.htm")."<br>";
fclose($f);
echo filesize("Edit1.htm")."<br>";
?>
| увидел 3 нуля.... Боюсь такой способ приведет к бесконечному циклу =((
Как решить эту проблему? | |
|
|
| |
|
|
|
|
для: cheops
(01.02.2005 в 14:31)
| | Вот такая модификация будет работать корректно?...
<?php
if(file_exists("prosmotry.php"))
while(!flock("prosmotry.php", LOCK_EX));
@include("prosmotry.php");
// Обработка
if($fprosm = @fopen("prosmotry.php","wb"))
{ fwrite($fprosm,'<? $prosm = array (');
foreach($prosm as $time => $info)
fwrite($fprosm,"\r\n$time=>array(/* информация */),");
fwrite($fprosm,"\r\n); ?>");
fclose($fprosm);
}
flock("prosmotry.php", LOCK_UN);
?>
|
| |
|
|
|
|
|
|
|
для: Sfinks
(01.02.2005 в 23:04)
| | Да, она не позволит побить файл. | |
|
|
|
|
|
|
|
для: cheops
(01.02.2005 в 23:08)
| | БОЛЬШОЕ СПАСИБО =)) | |
|
|
|
|
|
|
|
для: cheops
(01.02.2005 в 23:08)
| | Ой, вообще-то я ошибся... функция flock() должна в качестве первого параметра принимать дескриптор файла, т.е. она вызывается после функции fopen()... и до функции fclose() | |
|
|
|
|
|
|
|
для: cheops
(01.02.2005 в 23:25)
| | А как же тогда сделать задержку до освобождения (окончания записи другим пользователем) файла, перед include()?
Нужно чтоб он includ'ился при любых раскладах....
Может так....
<?php
while(!isset($prosm))
@include("prosmotry.php");
// Обработка
if($fprosm = @fopen("prosmotry.php","wb"))
{ flock($fprosm, LOCK_EX)
fwrite($fprosm,'<? $prosm = array (');
foreach($prosm as $time => $info)
fwrite($fprosm,"\r\n$time=>array(/* информация */),");
fwrite($fprosm,"\r\n); ?>");
flock($fprosm, LOCK_UN);
fclose($fprosm);
}
?>
|
| |
|
|
|
|
|
|
|
для: Sfinks
(02.02.2005 в 00:40)
| | Тогда открывать файл следует до include, а в include не открывать а пользоваться уже открытым дескриптором файла. | |
|
|
|
|
|
|
|
для: cheops
(02.02.2005 в 01:45)
| | А что не так в коде в моем предыдущем вопросе?
Ну, для гарантии можно еще написать:
<?php
if(isset($prosm)) unset($prosm);
while(!isset($prosm))
@include("prosmotry.php");
....
?>
| $prosm определяется в prosmotry.php, следовательно пока файл не заинклюдится, код дальше не пойдет.
А залочивание происходит ток при записи....
-----------------------------------------------------------------------------------------------------------------
Или вот такой вариант (в prosmotry.php используется return()).....
<?php
if(file_exists("prosmotry.php"))
while(!@include("prosmotry.php"));
if($fprosm = @fopen("prosmotry.php","wb"))
{ while(!flock($fprosm, LOCK_EX));
// Обработка массива $prosm
fwrite($fprosm,'<? $prosm = array (');
foreach($prosm as $time => $info)
fwrite($fprosm,"\r\n$time=>array(/* информация */),");
fwrite($fprosm,"\r\n); return(true); ?>");
flock($fprosm, LOCK_UN);
fclose($fprosm);
}
?>
|
| |
|
|
|
|
|
|
|
для: cheops
(02.02.2005 в 01:45)
| | Хм.... Вот последний вариант весьма корректно работает, ток объясните мне пожалуйста одну вешь....
Я смоделировал ситуацию совместного доступа следующим образом: создал 2 файла с таким кодом и в первом перед разлочкой вставил sleep(10); Обращаюсь к первому, тут же ко второму.... Все верно: второй ждет первого и ток потом выполняется, НО!!!!
На localhost'е в WinXP файл все-равно обнуляется, однако на реальном UNIX-сервере все работает правильно.... данные сохраняются!
Почему это происходит?... | |
|
|
|
|
|
|
|
для: Sfinks
(02.02.2005 в 05:36)
| | В Windows есть определённые проблемы с блокировкой и может давать вклад include("prosmotry.php"). UNIX специально предназначен для работы в таком режиме. | |
|
|
|
|
|
|
|
для: cheops
(02.02.2005 в 09:25)
| | ААААААААААААААААААААААААААААААААААААААА
ОН СНОВА ОБНУЛИЛСЯ =(((((((((((((((((((((((((
ЧТО ДЕЛАТЬ?!?!?!?!?!?!?!?????!???!!!! | |
|
|
|
|
|
|
|
для: Sfinks
(02.02.2005 в 17:46)
| | Сейчас файлы везде блокируются или только в одном месте? Ситуация с обнулением не воспроизводится? Не может обнуляться она случайно при записи туда пустого значения?
У вас информация не добавляется в конце файла, а каждый раз затирает предыдущие изменения - это нормальное поведение? Ведь передав пустой цикл - можно обнулить файл. | |
|
|
|
|
|
|
|
для: cheops
(02.02.2005 в 23:52)
| | >Сейчас файлы везде блокируются или только в одном месте?
Я Вам на e-Mail (письмо автору) скинул полный код основного файла!
>Ситуация с обнулением не воспроизводится?
Обнулялся в 16 с копейками, в 20 с копейками.
>Не может обнуляться она случайно при записи туда пустого значения?
Не знаю! Я уже не представляю что думать! Что интересно, остальные файлы проекта перезаписываются таким же образом, но они (тьфу-тьфу-тьфу) ни разу не обнулялись. Может какие-то проблемы с типами значений, или я уже не знаю....
>У вас информация не добавляется в конце файла, а каждый раз затирает
>предыдущие изменения - это нормальное поведение?
Во-первых, я не разобрался со смещениями курсора в файле при дописывании, а во-вторых, в данном конкретном счетчике возможно проще дописывать, но в файле пользователей, это сложнее, так как пользователя нужно искать по всему файлу. Но если Вы мне напишите фрагменты "редактирования" файлов, вместо "перезаписи", буду благодарен! Структуру файлов данных Вы поймете из кода на e-Maile.
>Ведь передав пустой цикл - можно обнулить файл.
Если предыдущим обращением файл сохранен корректно, то передать пустой массив невозможно, так как он инифиализируется инклюдом из этого же файла, непосредственно перед сохранением! | |
|
|
|
|
|
|
|
для: cheops
(02.02.2005 в 23:52)
| | Вот щас посреди файла откуда-то взялась пустая строка! Как такое возможно? =(( | |
|
|
|
|
|
|
|
для: cheops
(02.02.2005 в 23:52)
| | Вот в 23-30 снова обнулился =((
А файл пользователей размером в 30 раз больше не обнуляется уже 3 недели!
Вся глобальная разница массивов - имена подмассивов первого уровня! | |
|
|
|
|
|
|
|
для: cheops
(02.02.2005 в 23:52)
| | Так что же мне сделать? =(( Он снова упал =(( | |
|
|
|
|
|
|
|
для: Sfinks
(03.02.2005 в 15:51)
| | Опишите пожалуйста логику Web-приложения, может вместе придумаем другую схему (более надёжную). | |
|
|
|
|
|
|
|
для: cheops
(03.02.2005 в 16:12)
| | Это скорее Mobile-приложение.
Примитивно логику можно описать так....
Пользователь BeeLine отправляет смс с командой, команда попадает в основной php файл, в зависимости от команды, возвращается разный текст. Кроме этого php получает идентификатор пользователя и доп.инфо и ведет статистику.
Статистика должна иметь такую структуру, чтобы из нее можно было получить следующие данные:
1. Количество обращений каждого из зарегистрированных пользователей.
2. Количество обращений любых пользователей за указанный период времени (например 7.12.05 с 0:00 до 12:00), сколько из них являются обращениями от пользователей, у которых это минимум пятое обращение за все время пользования сервисом, общее количество обратившихся пользователей и сколько из них являются новыми пользователями (обратились впервые).
Вот сейчас структура данных обоих статистик аналогична:
По первой статистике:
<? $users = array (
'HW9GN4'=>array('reg'=>'СПб','acc'=>276,'tim'=>2),
..................
'9H1FN4'=>array('reg'=>'Москва','acc'=>230,'tim'=>3),
); return(true); ?>
|
По второй статистике (реализованы ток кол.нов.польз. и общее кол.обращений):
<? $visits = array (
'501290102'=>array('acc'=>1,'new'=>array('ASDF',)),
'501290103'=>array('acc'=>5,'new'=>array('DFGH','SDFG',)),
'501290104'=>array('acc'=>18,'new'=>array('FGHJ','GHJK','HJKL','JKLM',)),
..................
'501290828'=>array('acc'=>1,'new'=>array('RLXEU4',)),
); return(true); ?>
|
Вот с первым все нормально, а второй постоянно падает!
Правда частота перезаписи у второго в 100 раз больше.
И судя по всему, второй файл (или то, что мы придумаем), нужно разбивать на отдельные файлы, каждый из которых будет за определенную дату, тк только за сутки размер этого файла приближается к 100 кб. | |
|
|
|
|
|
|
|
для: cheops
(03.02.2005 в 16:12)
| | А я вот что подумал,....
А если не писать в файл vizity.php, а писать во временный файл, например, vizity_1.php (или следующий порядковый номер, в зависимости от наличия), а по завершении записи переименовывать его в vizity.php?... М? Ведь переименование это лишь исправление FAT? Значит процесс практически мгновенный? Будет ли это надежно?
Или Вы мне все-таки предложите что-либо? | |
|
|
|
|
|
|
|
для: sfinks
(04.02.2005 в 00:42)
| | А вы как опеределяете числа
501290102
501290103
501290104
|
1) Можно вот какой финт сделать - под хранение этого числа завести ещё один файл и хранить там это значение, открытие, чтение и перезапись одного короткого файла будет происходить много быстрее, чем перезапись 100 Кб файла, а в 100 Кб файл останется только дописывать уже готовую информацию и не открывать его для анализа. Правда это не спасёт от порчи файла - здесь вы правы - нужно по датам разбивать - чем короче файл, тем больше у него шансов выжить.
2) Можно вот ещё чего сделать - под текущий период завести 10 файлов, и писать в файлы по датчику случайных чисел, а потом, когда данные будут отправляться в архив - объединять их в один файл. Вот этим можно здорово снять нагрузку с файла, а хранение индекса в отдельной файле не позволит сбиться со счёта. | |
|
|
|
|
|
|
|
для: cheops
(04.02.2005 в 07:37)
| | Числа 502010112 и т.д. - это время - (int)date("ymdHi",time());
Вот как выглядит фрагмент перезаписи....
<?php
if(file_exists("vis.php"))
while(!@include("vis.php"));
if($fvis = @fopen("vis.php","wb"))
{ while(!flock($fvis, LOCK_EX));
$dt = (int)date("ymdHi",time());
$visits[$dt]["acc"]++;
$old = false;
if(isset($visits))
foreach($visits as $info)
if(isset($info["new"]))
if(in_array($pid,$info["new"]))
{ $old = true;
break;
}
if(!$old)
$visits[$dt]["new"][] = $pid;
fwrite($fvis,'<? $visits = array (');
if(isset($visits))
foreach($visits as $time => $info)
{ fwrite($fvis,"\r\n$time=>array('acc'=>".$info["acc"]);
if(isset($info["new"]))
{ fwrite($fvis,",'new'=>array(");
foreach($info["new"] as $u_pid)
fwrite($fvis,"'$u_pid',");
fwrite($fvis,")");
}
fwrite($fvis,"),");
}
fwrite($fvis,"\r\n); return(true); ?>");
flock($fvis, LOCK_UN);
fclose($fvis);
}
?>
|
те при каждом обращении увеличивается счетчик обращений за текущую минуту (порой доходит до 18ти), и проверяет весь массив на наличие идентификатора обратившегося пользователя. Если он не найден, значит это новый пользователь и его PID дописывается в список новых за эту минуту.
Фактически, разбиение ускорения не даст, т.к. всерн придется просматривать все файлы, но надежность увеличится.... но не достаточно =(( Не достаточно, т.к. файл падает несколько раз за сутки. А разбивать по 2 часа, это уже паранойя =((
Нужно какой-то другой выход.....
Наверняка Вы задаете себе вопрос, почему я не использую MySQL.... по нескольким причинам.... 1. Я его совсем не знаю... Абсолютно 0! А учить с 0 для этого конкретного проекта уже некогда. 2. Выкачать его по GPRS.... ну сами понимаете. 3. Это нужно на хосте подключать доп услугу... снова дорого. Поэтому хочу решить так.
Да, и способ с переименованием на 2 поста выше - эт разве не выход? | |
|
|
|
|
|
|
|
для: Sfinks
(04.02.2005 в 12:46)
| | Плохо вот что... вы открываете файл и начинаете очень долго что-то вычислять в циклах, а потом по кусочкам записываете файл - это слишком долго, не мудрено, что они сыпятся... Лучше всё вычислить не спеша и записать в строку, а затем файл открыть, быстренько строку записать и закрыть файл, т.е. не держать его долго в открытом состоянии и писать в него по возможности всё сразу. | |
|
|
|
|