Как в PHP запретить выполнение двух одновременных запросов

goodier
На сайте с 10.03.2009
Offline
36
#51

dkameleon, Многопользовательский вариант - это и есть лочить файл с названием юзера или нет , понять не могу

вот что нашел про flock:

В некоторых операционных системах flock() реализован на уровне процессов. При использовании многопоточных серверных API, таких как ISAPI, вы не можете полагаться на flock() для защиты ваших файлов от дугих PHP-скриптов, которые работают в параллельном потоке на том же сервере!

/*/*/*/*/*/*/

В итоге мне этот вариант не подходит?

Вот набросал такой код и думаю, что он неправильный.

Ведь если хакер пошлет 100 запросов в секунду, то некоторые сработают потому, что

в WHILE проверяется заблокирован ли файл, а он уже в условии блокируется так как я не знаю что возвращает команда flock и мой код начнет выполнятся.

<?php

session_start();

$login = $_SESSION['username'];

$fp = fopen("LOG_POST/".$login.".txt","a");

$try=false; while(!$try){

if( flock( $fp, LOCK_EX )) { /* уже блокирует файл в условии */

$try=true;

} else {

$try=false;

}

}

if($try){

/* мой скрипт обрабатывается */

if($payout > $userbalance){

flock($fp, LOCK_UN);

fclose($fp);

exit("Недостаточно средств!");

}

mysql_query( 'UPDATE table_users SET balance=balance-$payout WHERE login="'. $login.'"' );

flock($fp, LOCK_UN);

fclose($fp);

exit("Деньги выплачены!");

}

?>

B
На сайте с 03.02.2005
Offline
165
#52
goodier:
dkameleon, Многопользовательский вариант - это и есть лочить файл с названием юзера или нет , понять не могу

Да, это и есть. Но можно не париться, а лочить скрипт для всех. Операция не долгая, поэтому долго ждать не прийдётся.

goodier:

$fp = fopen("LOG_POST/".$login.".txt","a");

ИМХО, не получится открыть залоченый файл -> соотв. в while будет бесконечный цикл.

Надо написать ф-юю

Lock($login){

$fp = fopen("LOG_POST/".$login.".txt","a");

if( flock( $fp, LOCK_EX )) return true;

return false;

}

и проверять не if( flock( $fp, LOCK_EX )), а if(Lock($login))

Проверить можно так:

Перед

flock($fp, LOCK_UN);

fclose($fp);

поставить sleep(10);

А тут

/* мой скрипт обрабатывается */

добавить логирование времени

Запустить несколько запросов паралельно и посмотреть в лог, одновременно скрипты отработали, или дождавшись заверщения друг друга.

Интеграция сайтов с 1С (товары, контрагенты, документы, заказы). Консультации и услуги. Есть готовые решения - быстро и недорого. Приглашаю к сотрудничеству агентства и веб-студии.
dkameleon
На сайте с 09.12.2005
Offline
386
#53
goodier:
dkameleon, Многопользовательский вариант - это и есть лочить файл с названием юзера или нет , понять не могу

вообще я не сторонник лока файлов.

вот тут варнинги почитайте на всякий случай: http://php.net/manual/en/function.flock.php

Дизайн интерьера (http://balabukha.com/)
goodier
На сайте с 10.03.2009
Offline
36
#54

То есть если один раз сработает команда flock( $fp, LOCK_EX ) ,

то повторно она уже не сработает пока не произойдет flock($fp, LOCK_UN)

да или нет, вот этот момент у меня в голове не укладывается.

Ragnarok
На сайте с 25.06.2010
Offline
239
#55

не проще ли будет таки сделать так, как предлагали:

юзер создаёт заявку (или ошибочно несколько заявок)

заявка попадает в таблицу "заявки"

скрипт, запускаемый по крону каждую минуту, выполняет по одной заявке при каждом запуске

опционально, другой скрипт (или этот же, при запуске) проверяет, если есть 2 и более одинаковых заявок с одними и теми же данными,- оставляет только одну

//TODO: перестать откладывать на потом
B
На сайте с 03.02.2005
Offline
165
#56
goodier:
То есть если один раз сработает команда flock( $fp, LOCK_EX ) ,
то повторно она уже не сработает пока не произойдет flock($fp, LOCK_UN)
да или нет, вот этот момент у меня в голове не укладывается.

Не сработает.На обычной ОС. Пишут, что на какихто специальных многопоточных ОС - это не действует. Но как проверить я писал постом выше.

Но это всё ерунда, надо делать очередь заявок, юзер может только в очередь заявку послать, а непосредственно обрабатывает заявку независимый от юзера скрипт.

I
На сайте с 23.12.2010
Offline
25
#57
goodier:
То есть если один раз сработает команда flock( $fp, LOCK_EX ) ,
то повторно она уже не сработает пока не произойдет flock($fp, LOCK_UN)
да или нет, вот этот момент у меня в голове не укладывается.

да

используйте функцию GET-LOCK из MySQL вместо флок, это намного проще. в качестве имени лока используйте логин пользователя.

вначале своего скрипта дергаете эту функцию и все. если кто-то уже положил лок и держит его, то ваш вызов будет просто тупо ждать пока лок не освободится, никаких if не надо.

на выходе из скрипта делайте RELEASE_LOCK

siv1987
На сайте с 02.04.2009
Offline
427
#58

Можно просто формировать заявку и выдать кнопку бабло которая запустит независимый скрипт обработке заявки.

I
На сайте с 23.12.2010
Offline
25
#59
siv1987:
Можно просто формировать заявку и выдать кнопку бабло которая запустит независимый скрипт обработке заявки.

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

goodier
На сайте с 10.03.2009
Offline
36
#60

Написал скриптик для крона:

<?php
$path = "/var/www/UserName/data/www/Domain.ru/";
include($path."DB_conf.php");
$query = mysql_query("SELECT * FROM `pay_out` WHERE `state`='0' ORDER BY `id`");
if(mysql_num_rows($query) > 0)
{
$k = 0;
$protect = array('null');
while($res = mysql_fetch_array($query))
{
$k++;
$id = $res['id'];
$login = $res['login'];
$date = $res['date'];
$summa = $res['summa'];
$protect[$k] = $login."-".$date."-".$summa;

if($protect[$k] == $protect[$k-1])
{
mysql_query("UPDATE `users` SET `block`=2 WHERE `login`='$login'");
mysql_query("UPDATE `pay_out` SET `state`=2 WHERE `id`='$id'");

} else {

mysql_query("UPDATE `pay_out` SET `state`=1 WHERE `id`='$id'");
/* Отправляю данные через CURL на другой сервер для выплаты денег */
}
}
}
exit();
?>

Вручную создал 4 одинаковые записи в таблице с запросами на выплату
и подождал минуту, вроде работает пока правильно, но это работает в том случае если UNIX время одинаковое.

Ниже смотрите скрин из таблицы статистики платежей этого красавчика который меня грабит ))

Авторизуйтесь или зарегистрируйтесь, чтобы оставить комментарий