Не правильно выполняю запрос MySQL, через PDO

178
22 октября 2018, 15:20

Я начал только-только начал учить PDO, но дело не в этом, а в том, что я не знаю где и почему я не правильно выполняю MySQL запрос.
Вот код функции которая выполняется (не судите строго, исправьте пожалуйста если что-то не правильно делаю, я только начал учить PDO):

//Класс aaa114net, только используемые функции показываю (Данные MySQL верные)...
function doTransaction($uname,$token,$transfer){
        try {
            $data = aaa114net::getMysqliLink();
            $DBH = new PDO("mysql:host=".$data['host'].";dbname=".$data['database']."", $data['username'], $data['password']);
            $DBH->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
            $DBH->beginTransaction();
            $DBH->exec('LOCK TABLES aaa114users');
            $ucoins = $DBH->query("SELECT `coins` FROM aaa114users WHERE `username`=$uname");
            $ucoins->setFetchMode(PDO::FETCH_ASSOC);
            $ucoins->fetch();
            $ucoins = (int) $ucoins[0] + $transfer;
            $pcoins = $DBH->query("SELECT `coins` FROM aaa114users WHERE `token`=$token");
            $pcoins->setFetchMode(PDO::FETCH_ASSOC);
            $pcoins->fetch();
            $pcoins = (int) $pcoins[0] - $transfer;
            $DBH->prepare("UPDATE `aaa114users` SET `coins`=$ucoins WHERE `username`=$uname")->execute();
            $DBH->prepare("UPDATE `aaa114users` SET `coins`=$pcoins WHERE `token`=$token")->execute();
            $DBH->commit();
            $DBH->exec('UNLOCK TABLES');
            $DBH = null;
        }
        catch(PDOException $e) {
            echo "An MySQL Error has been occurred. Please check your logs.";
            file_put_contents('PDOErrors.txt', $e->getMessage(), FILE_APPEND);
        }
    }
function cleanString($string,$maxlength) {
        $string = htmlentities($string, ENT_QUOTES, "UTF-8");
        $string = strip_tags($string);
        $string = stripslashes($string);
        $string = htmlspecialchars($string, ENT_QUOTES);
        $string = mb_substr($string, 0, $maxlength, 'UTF-8');
        return $string;
    }

Как я его выполняю:

$transfer = (int) (new aaa114net)->cleanString($_GET['transfer'],64);
$uname = (new aaa114net)->cleanString($_GET['username'],32);
(new aaa114net)->doTransaction($uname,$token,$transfer);

Вот данные для обработки из строки URL: transfer=3&username=username
Cookie с токеном присутствует, токен верный.

Результат выполнения:

An MySQL Error has been occurred. Please check your logs.

Что в логах выдаёт:

SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '' at line 1

Помогите пожалуйста исправить и объясните пожалуйста что я не так делаю... P.S. PHP 7.2.1, MySQL Сервер не поддерживает InnoDB тип таблиц.
Что есть в MySQL типах таблиц:

MEMORY              Hash based, stored in memory, useful for temporary tables
MRG_MyISAM          Collection of identical MyISAM tables
MyISAM              MyISAM storage engine
BLACKHOLE           /dev/null storage engine (anything you write to it disappears)
CSV                 CSV storage engine
PERFORMANCE_SCHEMA  Performance Schema
ARCHIVE             Archive storage engine
FEDERATED           FederatedX pluggable storage engine
Aria                Crash-safe tables with MyISAM heritage

Использую бесплатный веб хостинг...

Answer 1
  1. параметры соединения устанавливайте сразу (можно передать четвертым параметром массив опций в конструктор PDO).
  2. не склеивайте строки сами - используйте связывание переменных (иначе в чем смысл переходить на PDO вообще?).
  3. Если Вам нужно только одно значение из строки - так и используйте fetchColumn. И на всякий случай лучше закрывать курсор при выборке (если Вы не выберете все данные, то следующий запрос может не исполниться и выдать ошибку).
  4. Вообще лучше бы вместо функций типа cleanString завести функции, которые будут выполнять последовательно функции: подготовка запроса, исполнение с параметрами, выборка данных. Причем удобно иметь хотя бы три функции: для выбора ровно одного значения, ровно одной строки из базы и для выборки всего массива данных.

Вот так будет работать (скорее всего, если нет других ошибок в коде):

$DBH = new PDO("mysql:host=".$data['host'].";dbname=".$data['database']."", $data['username'], $data['password'], [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$DBH->beginTransaction();
$DBH->exec('LOCK TABLES aaa114users');
$stmt = $DBH->prepare("SELECT `coins` FROM aaa114users WHERE `username`=?");
$stmt->execute([$uname]);
$ucoins = $stmt->fetchColumn();
$stmt->closeCursor();
$ucoins = (int) $ucoins + $transfer;
$stmt = $DBH->prepare("SELECT `coins` FROM aaa114users WHERE `token`=?");
$stmt->execute([$token]);
$pcoins = $stmt->fetchColumn();
$stmt->closeCursor();
$pcoins = (int) $pcoins - $transfer;
$DBH->prepare("UPDATE `aaa114users` SET `coins` = ? WHERE `username` = ?")->execute([$ucoins, $uname]);
$DBH->prepare("UPDATE `aaa114users` SET `coins` = ? WHERE `token` = ?")->execute([$pcoins, $token]);
$DBH->commit();
$DBH->exec('UNLOCK TABLES');
$DBH = null;

Подробнее почитать можно про: prepare, execute.

Почему так следует делать можете прочитать тут: 1, 2.

Полезная инфа по PDO.

READ ALSO
Как убрать public из URL в проектах Laravel

Как убрать public из URL в проектах Laravel

У меня есть проект devru

168
Как удалить тег <a> с содержимым из строки в PHP?

Как удалить тег <a> с содержимым из строки в PHP?

Как удалить тег с содержимым из строки в PHP?

169
Проблема с парсером PHP Notice: Undefined offset: 1

Проблема с парсером PHP Notice: Undefined offset: 1

Есть парсер, при появлении капчи должен ее ловить

124