Робокасса не заносит данные в БД

108
28 февраля 2022, 23:30

Оплата проходит, но номер почему-то не меняется. В БД есть колонка с полем ordernum, там я планировал делать номер заказа +1 каждый раз. Изначальное значение ordernum = 10

Файл action php, который собирает данные и отправляет php:

if(!empty($_GET["username"]) && !empty($_GET["email"]) && !empty($_GET["sum"])){ // если был пост
    $name = trim(htmlspecialchars(strip_tags($_GET["username"]))); // принимаем параметры с формы
    $email = trim(htmlspecialchars(strip_tags($_GET["email"]))); // принимаем параметры с формы
    $out_summ = trim(htmlspecialchars(strip_tags($_GET["sum"]))); // принимаем параметры с формы
    $mrh_login = "Nextliferp"; // идентификатор магазина
    $mrh_pass1 = "U6A2yxKRDh4IpJ6t9mfC"; // пароль #1

    $sql = mysqli_query($link, "SELECT ordernum FROM accounts WHERE user_login ='DONTTOUCH' ");   //получаем номер заказа 
        $resul = mysqli_fetch_assoc($sql);
    $count = $resul['ordernum'];    
    $inv_id = (int)$count;

    $inv_desc = "Тестовая оплата"; // описание заказа
    $shp_item = 1; // тип товара
    $in_curr = ""; // предлагаемая валюта платежа
    $culture = "ru"; // язык

    $encoding = "utf-8"; // кодировка
    $crc  = md5("$mrh_login:$out_summ:$inv_id:$mrh_pass1:Shp_item=$shp_item:shp_mulo=$email:shp_names=$name"); // формирование подписи
    // Перенаправляем пользователя на страницу оплаты
    Header("Location: http://auth.robokassa.ru/Merchant/Index.aspx?MrchLogin=$mrh_login&OutSum=$out_summ&InvId=$inv_id&IncCurrLabel=$in_curr".
         "&Desc=$inv_desc&SignatureValue=$crc&Shp_item=$shp_item".
         "&Culture=$culture&Encoding=$encoding&shp_mulo=$email&shp_names=$name");
}

Если ставлю +1, то касса возвращает ответ 40 (заказ с тем же номером) и причем выводит номер 2. Я совершенно не понимаю, откуда берется цифра 2, делал трассировку, показывает 11.

И есть второй файл, который должен менять в БД данные о том, кто платит или добавлять новые.

result.php

// чтение параметров
$out_summ = $_REQUEST["OutSum"]; // по умолчанию (не трогать)
$inv_id = $_REQUEST["InvId"]; // по умолчанию (не трогать)
$shp_item = $_REQUEST["Shp_item"]; // по умолчанию (не трогать)
$crc = $_REQUEST["SignatureValue"]; // по умолчанию (не трогать)
$shp_mulo = $_REQUEST["shp_mulo"]; // принимаем дополнительный параметр
$shp_names = $_REQUEST["shp_names"]; // принимаем дополнительный параметр

$crc = strtoupper($crc); // переводим ключ в верхний регистр
$my_crc = strtoupper(md5("$out_summ:$inv_id:$mrh_pass2:Shp_item=$shp_item:shp_mulo=$shp_mulo:shp_names=$shp_names")); // формируем новый ключ
if ($my_crc != $crc) // проверка корректности подписи
{
  echo "bad sign\n";
  exit(); // останавливаем выполнение скрипта, если подписи не совпадают
}

$que = mysqli_query($link, "UPDATE accounts SET ordernum = '".$inv_id."' WHERE user_login ='DONTTOUCH'")

// конвертируем полученные данные в нормальный режим
$email_k = $shp_mulo;
$name_k = $shp_names;

$query = mysqli_query($link, "SELECT user_pay FROM accounts WHERE user_login='".$shp_names."' ");
if (mysqli_num_rows($query))
{
  $result = mysqli_fetch_assoc($query);
  $shp_total = $result['user_pay'] + $out_summ;
  $sql = "UPDATE accounts SET user_pay ='".$shp_total."' WHERE user_login='".$shp_names."'  ";
  $query = mysqli_query($link,$sql);
}
else
{
$string = "INSERT INTO accounts (user_login, user_email, user_pay) VALUES ('".$shp_names."','".$shp_mulo."','".$out_summ."' )";
$quer = mysqli_query($link,$string);
}
echo "OK$inv_id\n"; // признак успешно проведенной операции (обязательно!)

Вот с таким кодом ОПЛАТА ПРОХОДИТ, но данные совершенно не обновляются, ни данных об оплате, ни изменения номера платежа (Да и, собственно, как оно проходит оплату с одним номером я тоже не понимаю).

Я в отчаянии. Видит кто-нибудь ошибку, почему данные не заполняются, а оплата успешно проходит и редиректит на success.php?

Answer 1

Во-первых, у вас не правильно структурирована БД и скрипт с ней работает тоже не верно. По хорошему должно быть так:

Одна таблица для пользователей с их почтой, логином и счетом. Вторая таблица для заказов пользователей (для истории заказов).

Работа таблицы заказов пользователей такая:

  1. Номер заказа - это главный ID строки (PRIMARY KEY, AI), он автоматически создается при добавлении записи.
  2. В момент создания заказа ваш скрипт делает запись в БД, получает ответом созданный ID и отправляет по нему пользователя на оплату.
  3. При получении CALLBACK об успешной оплате в строке меняется значение столбца статуса на оплаченный, записывается сумма оплаты.
  4. Отдельным запросов в БД с аккаунтом пользователя к его балансу прибавляется сумма оплаты.

Такая структура позволит вывести в дальнейшем в личном кабинете историю заказов с правильными суммами оплаты. (например: +25 р, +50 р, +1500 р, +11 р, и т.д.) В текущем коде будет выводиться примерно так: 1, 15, 6, 52, 7 и т.д. (значение баланса при достижении которого пользователь решил заплатить).

Вполне возможно, что вы не записываете новые строки для каждого платежа, а пытаетесь работать с одной строчкой на 1 пользователя. В таком случае решение найдете в самом конце.

Давайте посмотрим что можно сделать в вашем случае:

Вот структура вашей БД как я её понимаю.

$sql = mysqli_query($link, "SELECT ordernum FROM accounts WHERE user_login ='DONTTOUCH' ");   //получаем номер заказа 
    $resul = mysqli_fetch_assoc($sql);
$count = $resul['ordernum'];    
$inv_id = (int)$count;

Вот здесь вы выбираете ПЕРВУЮ запись в БД и из неё ordernum которые есть у пользователя с логином DONTTOUCH.

$name = "adudnik";
$sql = mysqli_query($link, "SELECT ordernum FROM robo_test WHERE user_login = '$name' ");   //получаем номер заказа
$resul = mysqli_fetch_assoc($sql); // первая строчка из БД
$count = $resul['ordernum'];
var_dump($resul );
var_dump($count);

Результат работы скрипта у меня. Как видите берется только первое значение из БД, а не последнее.

mysqli_fetch_assoc создан для того, чтобы потом перебирать его через while.

Чтобы получить последнюю запись из БД нужен следующий запрос.

SELECT ordernum FROM robo_test WHERE user_login = '$name' ORDER BY id DESC LIMIT 1

Если же у вас нет как у меня колонки с ID которая AI и PRIMARY KEY и по которой можно надежно сортировать, то работаем с WHILE.

$sql = mysqli_query($link, "SELECT ordernum FROM robo_test WHERE user_login = '$name'");   //получаем номер заказа 
$count = NULL;
while ( $resul = mysqli_fetch_assoc($sql) ) {
    $count =  $resul['ordernum'];
}

Если $count = null, значит записи нет и её нужно создать, если же любое другое значение - то оно вам и нужно.

Теперь по поводу обновлений в БД.

$que = mysqli_query($link, "UPDATE accounts SET ordernum = '".$inv_id."' WHERE user_login ='DONTTOUCH'")

Вот такой записи быть в принципе не должно. Для каждого номера заказа - своя строка. Но если уж решили обновлять по логину - почему DONTTOUCH? Где переменная логина? Убедитесь что все строчки с логинами уникальные (иначе будете обновлять только первую по описанным выше причинам).

  $sql = "UPDATE accounts SET user_pay ='".$shp_total."' WHERE user_login='".$shp_names."'  ";

Вот здесь должна быть проверка не по user_login, а по полученному от робокассы id платежа.

Тем не менее, если решили обновлять по логину, то почему DONTTUCH а не переменная логина? Убедитесь что у вас нет дублей строк с логином.

$string = "INSERT INTO accounts (user_login, user_email, user_pay) VALUES ('".$shp_names."','".$shp_mulo."','".$out_summ."' )";

Лучше создайте отдельную таблицу для платежей и так обновляйте её, а в аккаунте используйте UPDATE таблица с пользователями SET поле с балансом WHERE логин пользователя

Если вам ну ОЧЕНЬ не хочется делать отдельную таблицу - используйте в качестве id платежа временную метку UNIX или случайно сгенерированное число знаков на 6.

Получайте такой ID в момент создания платежа пользователю. Тут же обновляйте в своей БД по user_login (или создавайте нового пользователя), затем направляйте с таким ID заказа на робокассу, получайте ответ и обновляйте баланс.

Если обновлять по id платежа:

Ошибка будет только если два человека начнут пополнять кошелек в одну и ту же секунду на сайте (в случае метки UNIX) или в таблице будет два случайно сгенерированных одинаковых числа. В рамках вашего проекта ни первое, ни второе практически невозможно.

Если обновлять по user_login:

Ошибка будет в случае дублирования строк с user_login в БД.

Настоятельно рекомендую разделить таблицы платежей и пользователей. Это вам будет полезно как для расширения ЛК пользователя, так и для решения проблем по запросу пользователей.

READ ALSO
Как правильно скачивать файлы с удаленного сервера?

Как правильно скачивать файлы с удаленного сервера?

Как правильно скачивать статические файлы с удаленного сервера? 1 запуск скрипта = 1 скачивание файла, те keep-alive не рассматривается

86
Как вытащить данные из json на php

Как вытащить данные из json на php

Всем привет, такой вопрос: как проверять массив?

198
Подключение к php c++

Подключение к php c++

В интернете часто вижу: Если у вас долго выполняется php function, то советуем сделать её на c++

188
Angular + Laravel PHP Routing in .htaccess

Angular + Laravel PHP Routing in .htaccess

Доброго времени суток

81