khapugin |
Отправлено: 28 марта 2010 — 06:50
|
Newbie
Покинул форум
Сообщений всего: 33
Дата рег-ции: Авг. 2009
Репутация: 0
[+]
|
Помогите пожалуйста. Пишу партнёрку, нужен совет.
Нужно записывать IP адреса в файл, а потом брать их из него и сравнивать с тем который у пользователя. В интернете кто то советовал использовать для записи такой код. Будет ли скрипт эффективен в случае если он будет одновременно запущен несколькими пользователей, не приведёт ли это к обнулению файла? Посоветуйте как правильнее написать?
CODE:$lock = fopen("./partner/baseIP.db", "a"); //блокировка файла
if(flock($lock, 1)) {
copy ("./partner/baseIP.db", "./partner/tmpbaseIP.db");
$tmp=fopen("./partner/tmpbaseIP.db","a");
fputs($tmp, $IP."\r\n"); //запись строк
fclose($tmp); //закрытие файлка и переименование его
flock($lock, 3);
fclose($lock);
unlink("./partner/baseIP.db");
rename("./partner/tmpbaseIP.db", "./partner/baseIP.db");
} |
|
|
yura3d |
Отправлено: 28 марта 2010 — 10:37
|
ExBB Team ExBB Developer ExBB Mods Author
Покинул форум
Сообщений всего: 3394
Дата рег-ции: Февр. 2009
Откуда: Минск, Беларусь
Репутация: 353
|
khapugin пишет:Помогите пожалуйста. Пишу партнёрку, нужен совет.
Нужно записывать IP адреса в файл, а потом брать их из него и сравнивать с тем который у пользователя. В интернете кто то советовал использовать для записи такой код. Будет ли скрипт эффективен в случае если он будет одновременно запущен несколькими пользователей, не приведёт ли это к обнулению файла? Посоветуйте как правильнее написать?
CODE:$lock = fopen("./partner/baseIP.db", "a"); //блокировка файла
if(flock($lock, 1)) {
copy ("./partner/baseIP.db", "./partner/tmpbaseIP.db");
$tmp=fopen("./partner/tmpbaseIP.db","a");
fputs($tmp, $IP."\r\n"); //запись строк
fclose($tmp); //закрытие файлка и переименование его
flock($lock, 3);
fclose($lock);
unlink("./partner/baseIP.db");
rename("./partner/tmpbaseIP.db", "./partner/baseIP.db");
}
Тот вариант, который Вы привели, довольно странный. Не совсем понятно, что должен делать приведённый Вами фрагмент кода, но потенциальные проблемы такого подхода видны сразу. В самом начале идёт проверка на разделяемую (для чтения) блокировку:
CODE: if(flock($lock, 1)) {
А дальше идёт вообще полная ерунда: создание временного файла, запись в него информации и далее, собственно, сама ошибка, когда предпринимается попытка переименовать временный файл в основной. Ппри этом вполне возможно, что процессы чтения со стороны других пользователей не окончились или были запущены новые, и в этом случае Вы получите повреждение или обнуление данных в файле.
khapugin пишет:1. Код действительно безопасный для данных хранящихся в файле?
Предложенный Александром Михалицыном вариант классический с точки зрения решения проблемы с множественным доступом к файлам из PHP.
khapugin пишет:2. fflush служит для уменьшения нагрузки на сервер?
Читайте описание функции в мануале PHP: http://php.net/fflush
Эту функцию необходимо запускать, чтобы сбросить в файл все накопившиеся в буфере данные (поскольку непосредственно после записи данные могут в файл и не быть записаны, как правило запись в файл происходит только после накопления определённого объёма информации - это сделано для ускорения работы).
khapugin пишет:3. По вашему проверять заблокирован ли файл не обязательно?
Файл не будет заблокирован только в том случае, если соответствующая функция не поддерживается используемыми операционной или файловой системами. Поскольку с такими системами Вы, скорее всего, работать не будете, то делать проверку на блокировку не имеет смысла. Проверять установку блокировки нужно, если Вы используете блокировку с запретом подвисания, однако такая блокировка далеко не лучший вариант (она использовалась в ExBB FM 1.0 Beta и более старых версиях, поэтому на тех версиях были гораздо более частые проблемы с обнулением).
Ну и напоследок, если к файлам предполагается довольно частое обращение при хранении большого объёма данных, лучше подумать о MySQL |
|
|
yura3d |
Отправлено: 24 апреля 2010 — 09:09
|
ExBB Team ExBB Developer ExBB Mods Author
Покинул форум
Сообщений всего: 3394
Дата рег-ции: Февр. 2009
Откуда: Минск, Беларусь
Репутация: 353
|
khapugin пишет:проблема начинается как только скрипт натыкается на файлы или папки отличные от цифр
В Вашем случае список (массив) файлов и папок нужно предварительно отфильтровать таким образом, чтобы в нём остались только папки, названия которых состоят из цифр. Это необходимо для правильной работы функции PHP max():
CODE:function int_dir_filter($filename)
{
if (is_int($filename) && is_dir('../papka/'.$filename))
return true;
return false;
}
$spisokdir = array_filter(scandir('../papka/'), 'int_dir_filter');
$newpapka = max($spisokdir) + 1;
mkdir('../papka/' . $newpapka, 0777); // создаём папку
Подробнее про фильтрацию элементов массива при помощи функции обратного вызова можно почитать в документации PHP по функции array_filter(). |
|
|
Hast |
Отправлено: 24 апреля 2010 — 10:01
|
Newbie
Покинул форум
Сообщений всего: 7
Дата рег-ции: Апр. 2010
Репутация: 0
|
Достаточно перевести текст ошибки.
khapugin пишет:Warning: max() [function.max]: Array must contain at least one element
в массиве $spisokdir должен быть по крайней мере 1 элемент
khapugin пишет:Warning: mkdir() [function.mkdir]: File exists
папка которую ты пытаешься создать уже существует(Отредактировано автором: 24 апреля 2010 — 10:01) |
|
|
yura3d |
Отправлено: 24 апреля 2010 — 10:05
|
ExBB Team ExBB Developer ExBB Mods Author
Покинул форум
Сообщений всего: 3394
Дата рег-ции: Февр. 2009
Откуда: Минск, Беларусь
Репутация: 353
|
khapugin пишет:CODE:$filename != '.' && $filename != '..'
Такая проверка не имеет смысла, у Вас ведь уже есть проверка на то, чтобы имя принадлежало множеству целых чисел:
Очевидно, что имена переходов на предыдущий уровень этому множеству не принадлежат, поэтому Вы делаете лишнюю проверку, что в конечном итоге не самым лучшим образом скажется на производительности. Оставьте первоначальный предложенный мною вариант:
CODE:if (is_int($filename) && is_dir('../papka/'.$filename))
khapugin пишет:Warning: max() [function.max]: Array must contain at least one element
Всё просто. Предполагается, что у Вас в папке papka уже имеется хотя бы одна папка, соответствующая критериям фильтра. В противном случае функции max() передаётся пустой массив $spisokdir, что недопустимо. Если в Вашем случае допускается отсутствие первой папки, соответствующей критериям фильтра, то лучше сделать так:
CODE:function int_dir_filter($filename)
{
if (is_int($filename) && is_dir('../papka/'.$filename))
return true;
return false;
}
$spisokdir = array_filter(scandir('../papka/'), 'int_dir_filter');
$newpapka = ($spisokdir) ? max($spisokdir) + 1 : X;
mkdir('../papka/' . $newpapka, 0777); // создаём папку
В этом примере в строке:
CODE:$newpapka = ($spisokdir) ? max($spisokdir) + 1 : X;
вместо X Вам нужно указать имя первой папки, которая будет создана в папке papka. В дальнейшем все новые папки будут создаваться с числовым именем, на единицу большим, чем у предыдущей созданной папки. |
|
|
Hast |
Отправлено: 24 апреля 2010 — 10:09
|
Newbie
Покинул форум
Сообщений всего: 7
Дата рег-ции: Апр. 2010
Репутация: 0
|
Если конкретно по тому, что должен делать скрипт. Во-первых, пользователь которого ты пытаешься создать уже существует. Точнее, это ошибка, вытекающая из другой: max($spisokdir) возвращает 0, поэтому $newuser равняется единице.
Во-вторых
khapugin пишет:ещё заглянул в масив и обнаружил там две директории "." и ".." перехода выше.
Как-то не стыкуется. Скрипт утверждает что в массиве $spisokdir нет ни одного элемента. А тут ты говоришь, что заглянул в массив и нашёл там "." и "..". м?
(Добавление)
CODE:$newpapka = ($spisokdir)
Вроде как данное условие не всегда будет возвращать false. Ошибка "Array must contain at least one element" как бы предполагает, что $spisokdir уже инициализирован как массив, иначе ошибка звучала бы как "1st param must be an array". Или я не прав? Сейчас сервера под рукой нет, проверить не могу, к сожалению. Если я прав, то проверку нужно производить как CODE:$newpapka = ($spisokdir[0]) или
CODE:$newpapka = (count($spisokdir) > 0) (Отредактировано автором: 24 апреля 2010 — 10:17) |
|
|
yura3d |
Отправлено: 24 апреля 2010 — 11:02
|
ExBB Team ExBB Developer ExBB Mods Author
Покинул форум
Сообщений всего: 3394
Дата рег-ции: Февр. 2009
Откуда: Минск, Беларусь
Репутация: 353
|
Результатом работы функции array_filter() будет всегда массив, в частном случае это может быть пустой массив, если критерию фильтрации не соответствует ни один элемент. Поэтому проверка:
Hast пишет:CODE:$newpapka = ($spisokdir[0])
закончится нотисом Undefined offset: 0..., если массив пуст.
Hast пишет:CODE:$newpapka = (count($spisokdir) > 0)
В данном случае выражение в скобках справа от оператора присваивания (=) равнозначно выражению ($spisokdir), но последнее будет работать несколько быстрее.
Hast пишет:Вроде как данное условие не всегда будет возвращать false
Пруфлинк из официальной документации - для пустых массивов приведение к типу boolean (а выражение в конструкции if всегда к таковому приводится) даст false. Если массив содержит хотя бы один элемент, результат приведения будет true. |
|
|
khapugin |
Отправлено: 24 апреля 2010 — 11:08
|
Newbie
Покинул форум
Сообщений всего: 33
Дата рег-ции: Авг. 2009
Репутация: 0
[+]
|
Большое спасибо вам обоим))) Нашёл решение
кому нибудь пригодится рабочий код
CODE:<?php
function int_dir_filter($filename)
{
if (!is_int($filename) && is_dir('../user/'.$filename))
return true;
return false;
}
$spisokdir = array_filter(scandir('../user/'), 'int_dir_filter');
$newuser = max($spisokdir) + 1;
mkdir('../user/' . $newuser, 0777); // создаём папку
?>
проблема была !is_int($filename) в нём
____________________________________________________
is_int - определяет, является ли переменная integer.
Описание
bool is_int (mixed var)
Возвращает TRUE, если var является integer, FALSE - в ином случае.
теперь непонятно ведь насколько я понимаю !is_int($filename) это как раз обратное тому что мне нужно, но скрипт заработал
(Добавление)
yura3d пишет:$newpapka = ($spisokdir) ? max($spisokdir) + 1 : X;
у меня и без этой строки проблем не возникает когда удаляю все папки.(Отредактировано автором: 24 апреля 2010 — 11:21) |
|
|
yura3d |
Отправлено: 24 апреля 2010 — 11:48
|
ExBB Team ExBB Developer ExBB Mods Author
Покинул форум
Сообщений всего: 3394
Дата рег-ции: Февр. 2009
Откуда: Минск, Беларусь
Репутация: 353
|
khapugin пишет:теперь непонятно ведь насколько я понимаю !is_int($filename) это как раз обратное тому что мне нужно, но скрипт заработал
Вообще, честно говоря, всё правильно. Функция is_int() возвращает true только в том случае, если аргумент принадлежит типу integer. В нашем же случае имена файлов и папок принадлежат строковому типу string, поэтому is_int() возвращает false. Думаю, вместо is_int() лучше применить функцию ctype_digit(), она обрабатывает строковые переменные и возвращает true только в том случае, если все символы в строке являются цифрами.
Таким образом, правильным будет вариант:
CODE:function int_dir_filter($filename)
{
if (ctype_digit($filename) && is_dir('papka/'.$filename))
return true;
return false;
}
$spisokdir = array_filter(scandir('papka/'), 'int_dir_filter');
$newpapka = ($spisokdir) ? max($spisokdir) + 1 : 0;
mkdir('papka/' . $newpapka, 0777); // создаём папку
khapugin пишет:у меня и без этой строки проблем не возникает когда удаляю все папки.
Это из-за неразберихи с is_int() в предыдущих примерах. Если в исправленном варианте убрать данную проверку, то передача пустого массива функции max() приведёт к выводу предупреждения:
Цитата:Warning: max() [function.max]: Array must contain at least one element |
|
|
|