ExBB Community » » PHP/Perl » Есть ли ошибки в скрипте?

Страниц (2): [1] 2 »
 

1. khapugin - 28 марта 2010 — 06:50 - перейти к сообщению
Помогите пожалуйста. Пишу партнёрку, нужен совет.
Нужно записывать 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");
}
2. Александр Михалицын - 28 марта 2010 — 07:06 - перейти к сообщению
khapugin,
к чему столько сложностей? Код можно проще переписать.

CODE:
//Реализация:
function add_ip_to_db($ip)
{
$fp = fopen('ip.db', 'a');//Открываем файл
flock($fp, LOCK_EX);//Блокируем файл
fwrite($fp, $ip . "\r\n");//Пишем в файл
fflush($fp);//Сбрасываем буфер (в PHP существует система буферизации записи)
flock($fp, LOCK_UN);//Снимаем блокировку
fclose($fp);//Закрываем файл
}

//Использование (пример):
add_ip_to_db($_SERVER['REMOTE_ADDR']);//Добавляем в базу айпи посетителя.
3. khapugin - 28 марта 2010 — 08:54 - перейти к сообщению
Вот такие вот умельцы в интернете Улыбка) Говорят, что так можно избежать потери данных если несколько пользователей одновременно будут писать в файл свой ip.

Можно тогда несколько вопросов по вашему коду?
1. Код действительно безопасный для данных хранящихся в файле?
2. fflush служит для уменьшения нагрузки на сервер?
3. По вашему проверять заблокирован ли файл не обязательно?
4. yura3d - 28 марта 2010 — 10:37 - перейти к сообщению
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
5. khapugin - 28 марта 2010 — 11:05 - перейти к сообщению
Спасибо ребята Хорошо

Цитата:
Ну и напоследок, если к файлам предполагается довольно частое обращение при хранении большого объёма данных, лучше подумать о MySQL

ох и не люблю я эту MySQL, а частое это примерно сколько? 1000? 2000? обращений в сутки? Сколько примерно?
6. Леголегс - 28 марта 2010 — 19:10 - перейти к сообщению
fflush можно выкинуть, но только вместе с unlock. fclose автоматиччески делает сброс буфера и разблокировку.
khapugin пишет:
а частое это примерно сколько? 1000? 2000? обращений в сутки? Сколько примерно?
В данном случае это запросы в секунду.
7. khapugin - 24 апреля 2010 — 07:35 - перейти к сообщению
Помогите пожалуйста, мучаюсь уже часов 6...
задача на первый взгляд простая, но я уже задолбался нифига у меня не выходит(((

Суть задачи такая, есть некая директория в которой несколько папок с порядковыми именами 1, 2, 3, 4 и файл index.html задача скрипта выявить папку самого высокого названия в данном случае 4 прибавить к этому числу единицу и создать новую папку. Выполняется это тремя строчками.

CODE:
$spisokdir = scandir('../papka/');
$newpapka = max($spisokdir) + 1;
mkdir('../papka/' . $newpapka, 0777); // создаём папку


получаем список файлов и папок в дирректории
находим максимальное название числа и создаём папку на единицу больше, проблема начинается как только скрипт натыкается на файлы или папки отличные от цифр
8. yura3d - 24 апреля 2010 — 09:09 - перейти к сообщению
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().
9. khapugin - 24 апреля 2010 — 09:49 - перейти к сообщению
непонимаю почему но код не работает Однако

ошибки
Warning: max() [function.max]: Array must contain at least one element in Y:\home\test1.ru\www\myphp\1.php on line 9
Warning: mkdir() [function.mkdir]: File exists in Y:\home\test1.ru\www\myphp\1.php on line 10

CODE:
function int_dir_filter($filename)
{
if (is_int($filename) && is_dir('../user/'.$filename) && $filename != '.' && $filename != '..')
return true;
return false;
}
$spisokdir = array_filter(scandir('../user/'), 'int_dir_filter');
$newuser = max($spisokdir) + 1;
mkdir('../user/' . $newuser, 0777); // создаём папку

Я ещё заглянул в масив и обнаружил там две директории "." и ".." перехода выше. их я тоже проверяю, но всё равно ошибка... в чём же дело?
10. Hast - 24 апреля 2010 — 10:01 - перейти к сообщению
Достаточно перевести текст ошибки.

khapugin пишет:
Warning: max() [function.max]: Array must contain at least one element

в массиве $spisokdir должен быть по крайней мере 1 элемент
khapugin пишет:
Warning: mkdir() [function.mkdir]: File exists

папка которую ты пытаешься создать уже существует
11. yura3d - 24 апреля 2010 — 10:05 - перейти к сообщению
khapugin пишет:
CODE:
$filename != '.' && $filename != '..'

Такая проверка не имеет смысла, у Вас ведь уже есть проверка на то, чтобы имя принадлежало множеству целых чисел:
CODE:
is_int($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. В дальнейшем все новые папки будут создаваться с числовым именем, на единицу большим, чем у предыдущей созданной папки.
12. Hast - 24 апреля 2010 — 10:09 - перейти к сообщению
Если конкретно по тому, что должен делать скрипт. Во-первых, пользователь которого ты пытаешься создать уже существует. Точнее, это ошибка, вытекающая из другой: 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)
13. yura3d - 24 апреля 2010 — 11:02 - перейти к сообщению
Результатом работы функции array_filter() будет всегда массив, в частном случае это может быть пустой массив, если критерию фильтрации не соответствует ни один элемент. Поэтому проверка:
Hast пишет:
CODE:
$newpapka = ($spisokdir[0])

закончится нотисом Undefined offset: 0..., если массив пуст.

Hast пишет:
CODE:
$newpapka = (count($spisokdir) > 0)

В данном случае выражение в скобках справа от оператора присваивания (=) равнозначно выражению ($spisokdir), но последнее будет работать несколько быстрее.

Hast пишет:
Вроде как данное условие не всегда будет возвращать false

Пруфлинк из официальной документации - для пустых массивов приведение к типу boolean (а выражение в конструкции if всегда к таковому приводится) даст false. Если массив содержит хотя бы один элемент, результат приведения будет true.
14. khapugin - 24 апреля 2010 — 11:08 - перейти к сообщению
Большое спасибо вам обоим))) Нашёл решение
кому нибудь пригодится рабочий код
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;

у меня и без этой строки проблем не возникает когда удаляю все папки.
15. yura3d - 24 апреля 2010 — 11:48 - перейти к сообщению
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

Яндекс.Метрика   

Powered by ExBB
[Script Execution time: 0.0282]     [ ]