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

I
На сайте с 23.12.2010
Offline
25
#31
LEOnidUKG:
Не верно, надо
if($balance <= 0){ exit("Недостаточно средств!"); }

эта строчка вообще лишняя, буквально в следующей опять та же проверка идет

dkameleon
На сайте с 09.12.2005
Offline
386
#32
goodier:
у меня все это работает на сервере и доступ дать не могу, так как работаю с деньгами.

выключайте нафиг :))

вас же чистят на бабки :)

а после этой темы атаки могут усилиться.

Дизайн интерьера (http://balabukha.com/)
I
На сайте с 23.12.2010
Offline
25
#33
goodier:
RoMaN444Ik,
Мой код который я привел в примере обрезан.

как вы хотите чтобы вам нашли баги, если код обрезан??? 😮

goodier:

В нем нет функций sleep(2) и mysql_escape_string($_post[blablabla])

а ведь это очень важно, дьявол в деталях

goodier:

Я в этой теме прошу помочь мне с решением проблемы без оплаты за помощь.
и думаю эта тема в будущем пригодится людям.

я вам уже предложил подумать, что будет если у вас есть пользователи vasya1, vasya2, vasya3 и vas%. Что вернет проверка баланса с вашим любимым like для пользователя vas% ? для какого реально пользователя будет возвращен баланс? я вот не знаю. и скажу вам по секрету, никто не знает.

это один вариант развития событий.

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

третий вариант событий. предположим пришел запрос, начинает выполняться, прошел проверку if($summa > balance($login)) и в этот момент приходит второй запрос. первый запрос перестает выполняться, выполняется второй запрос, выполнился полностью и процессор вернулся к выполнению первого запроса. заметьте, проверка баланса в первом запросе уже прошла, и прошла удачно, о том что деньги сняты вторым запросом, первый запрос ничего не знает. кстати именно во время sleep и происходит переключение контекста.

1. выложите весь код, если хотите получить советы по коду

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

3. отдайте эту часть сделать профессионалу, дешевле будет.

баян, но уж больно в тему

goodier
На сайте с 10.03.2009
Offline
36
#34
iopiop:
я вам уже предложил подумать, что будет если у вас есть пользователи vasya1, vasya2, vasya3 и vas%. Что вернет проверка баланса с вашим любимым like для пользователя vas% ? для какого реально пользователя будет возвращен баланс? я вот не знаю. и скажу вам по секрету, никто не знает.

В моем примере нет текста в запросе WHERE `login` LIKE '".$login."%'" я не использую знак %

ТИП колонки с балансом=varchar

Кодировка=utf8_general_ci

iopiop:

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

убираю все заменой

$summa = str_replace("-","", $summa);
$summa = str_replace("+","", $summa);
$summa = str_replace("`","", $summa);
$summa = str_replace("'","", $summa);
$summa = str_replace('"','', $summa);

iopiop:

третий вариант событий. предположим пришел запрос, начинает выполняться, прошел проверку if($summa > balance($login)) и в этот момент приходит второй запрос. первый запрос перестает выполняться, выполняется второй запрос, выполнился полностью и процессор вернулся к выполнению первого запроса. заметьте, проверка баланса в первом запросе уже прошла, и прошла удачно, о том что деньги сняты вторым запросом, первый запрос ничего не знает.
кстати именно во время sleep и происходит переключение контекста.

Первый запрос проходит проверку if($summa > balance($login)) и это условие не срабатывает так как баланс еще тот же и сразу после проверки в условии с баланса снимается сумма.

Второй запрос уже не должен пройти так как условии должно сработать ведь в функции проверяется баланс а не где то выше условия из БД.

Пишу все в фал типа login.txt и в нем нет ничего лишнего , а только то что должно придти.

Ragnarok
На сайте с 25.06.2010
Offline
239
#35
goodier:
В моем примере нет текста в запросе WHERE `login` LIKE '".$login."%'"

что если юзер зарегается с ником "vas%"?

goodier:
убираю все заменой
$summa = str_replace("-","", $summa);
$summa = str_replace("+","", $summa);
$summa = str_replace("`","", $summa);
$summa = str_replace("'","", $summa);
$summa = str_replace('"','', $summa);

$summa=$abs((int)$summa);

//TODO: перестать откладывать на потом
goodier
На сайте с 10.03.2009
Offline
36
#36
Ragnarok:
что если юзер зарегается с ником "vas%"?

При регистрации я проверяю - preg_match("/^[a-zA-Z0-9]{4,}$/",$login)

Я отредактировал все файлы в которых писал запрос с LIKE но уверен дело не в этом

Ragnarok:
$summa=$abs((int)$summa);

Я не могу использовать (INT) так как пользователь может снять сумму дробную сумму с точкой

и поэтому использую $summa = floatval($summa);

Что значит переменная $abs ???

I
На сайте с 23.12.2010
Offline
25
#37
goodier:

Первый запрос проходит проверку if($summa > balance($login)) и это условие не срабатывает так как баланс еще тот же и сразу после проверки в условии с баланса снимается сумма.
Второй запрос уже не должен пройти так как условии должно сработать ведь в функции проверяется баланс а не где то выше условия из БД.

читайте внимательно что вам пишут. повторю - выполняется первый запрос включая проверку if($summa > balance($login)). В этот момент, до снятия с баланса, приходит второй запрос. выполнение первого запроса может прерваться и процессор пойдет выполнять второй запрос. и может полностью отработать второй запрос и после этого вернуться продолжать выполнять первый запрос. деньги сняты вторым запросом, проверка в первом запросе уже пройдена. вероятность такого поведения сильно повышается если у вас в коде используются некоторые операторы, один из которых sleep.

добро пожаловать в многозадачные операционные системы.

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

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

iopiop Этот человек и до того как я добавил SLEEP() умудрялся снимать двойную сумму

Я отправил Вам файл в личку!

I
На сайте с 23.12.2010
Offline
25
#39
goodier:
iopiop Этот человек и до того как я добавил SLEEP() умудрялся снимать двойную сумму

sleep() - это только один из многих операторов который приводит к такому эффекту. напр. любой оператор IO тоже обладает таким же свойством. более того, sleep и иже с ним только резко повышают такой ход событий, на самом деле и без них такое может случится. выполнение вашего кода может быть прервано в абсолютно любой точке программы и вы на это влиять не можете. это называется "вытесняющая многозадачность".

та проблема о которой я написал лечится созданием флага, который говорит "сейчас этот скрипт занят, ждите". флагом может быть напр. просто файл. алгоритм

1. проверить, есть ли файл lock

2. если есть - спать 2-3 секунды, и идти к п.1

3. если нет - создать

4. после этого вся ваша функция

5. в конце функции удалять файл lock

о чем нужно беспокоится

а) у вас много exit() - соответственно нужно переделать, чтобы эти exit() удаляли файл lock перед выходом

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

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

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

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

Я так понял файл lock может иметь название какое угодно и если я его буду при обращении к обработчику создавать файл с таким же именем как у пользователя, то другие пользователи не пострадают?

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