Javascript-форум (https://javascript.ru/forum/)
-   Серверные языки и технологии (https://javascript.ru/forum/server/)
-   -   Фокус с синтаксисом БД (https://javascript.ru/forum/server/76918-fokus-s-sintaksisom-bd.html)

Alessio18911 27.02.2019 01:01

Фокус с синтаксисом БД
 
Привет всем! Нужно через с помощью php добавлять в БД (MySQL) новые строки (работаю с MySQL 5.7 и PHP 7.1). Сделал функцию:
function add_task($link, array $post, array $files, int $user_id): bool {
    $name = $post['project'];
    $category_id = $post['name'];
    $expires_at = !empty($post['date']) ? date_format(date_create($post['date']), 'Y-m-d') : NULL;

    foreach($files as $file) {
        $file_path = $file['name'] ? __DIR__ . '\\'. $file['name'] : NULL;
    }

    $sql_add_task = "INSERT INTO tasks(user_id, category_id, name, expires_at, file_path) VALUES($user_id, $category_id, $name, $expires_at, $file_path)";

    $result = mysqli_query($link, $sql_add_task);

    if(!$result) {
        die("Ошибка MySQL: " . mysqli_error($link));
    }

    return $result;
}

А вот структура таблицы, куда нужно будет вставлять строки:
CREATE TABLE tasks (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
category_id INT,
name CHAR(128) NOT NULL,
created_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
done_at DATE NULL DEFAULT NULL,
status INT DEFAULT 0,
expires_at DATE NULL DEFAULT NULL,
file_path CHAR(128)
);

Проблема в строке с запросом INSERT. Он обёрнут в " ". В нём $category_id и $name обязательны, это строки. А $expires_at и $file_path - факультативны, если они есть - это строки, если нет - тогда NULL. Если в таком виде запустить функцию, то возникает ошибка:
Ошибка MySQL: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'народ с балкона золотыми монетами, 2019-02-28, W:\d' at line 2

var_dump выводит такую строку запроса:
string(251) "INSERT INTO tasks(user_id, category_id, name, expires_at, file_path) VALUES(1, 1, Осыпать народ с балкона золотыми монетами, 2019-02-28, W:\domains\216812-doingsdone\1024-31-snowpark.psd)"

Проблема в том, что переменные name, expires_at, file_path изначально типа string. А учитывая, что весь вопрос обёрнут тоже в " ", внутри кавычки вокруг значений, в которые превращаются переменные, я так понимаю, убираются. В итоге - ошибка.

Оборачивать переменные в ' ' - не выход, ибо вместо некоторых может быть NULL - опять ошибка. Подскажите, как быть в такой ситуации

laimas 27.02.2019 03:47

$expires_at = !empty($post['date']) ? date_format(date_create($post['date']), 'Y-m-d') : NULL;

А входные данные обрабатываются или как есть? А если что пришло тому и верим, то !empty(" ") есть истина, и какая же в таком случае дата должна быть создана?

Строковые значения всегда и везде заключаются в кавычки. Только вы используете РНР 7, а в тоже время не используете возможностей mysqli. Вы думаете она сама по себе занимается экранированием в запросах? Как бы не так. А ведь есть же mysqli_stmt::prepare, mysqli_stmt::bind_param и т.д., которые как раз и решат ваши проблемы, и обезопасят запрос.

Alessio18911 27.02.2019 09:55

Спасибо огромное, проблема действительно разрешилась! Единственное, всё же непонятным осталось, почему в изначальном случае в строке запроса кавычки вокруг string после интерполяции переменных убирались.

Nexus 27.02.2019 10:02

Цитата:

Сообщение от Alessio18911
Единственное, всё же непонятным осталось, почему в изначальном случае в строке запроса кавычки вокруг string после интерполяции переменных убирались.

А почему они остаться-то должны были?
Кавычки указывают границу строки и не входят в саму строку.

Белый шум 27.02.2019 12:17

Alessio18911,
Код:

$ php -r 'echo "строка\n";'
строка
$ php -r 'echo "\"строка в кавычках\"\n";'
"строка в кавычках"


Alessio18911 28.02.2019 20:08

Цитата:

Сообщение от Nexus (Сообщение 504155)
А почему они остаться-то должны были?
Кавычки указывают границу строки и не входят в саму строку.

Ну, я проводил аналогию, если писать запросы без переменных. Тогда бы он ведь выглядел так:
INSERT INTO tasks(user_id, category_id, name, expires_at, file_path) VALUES(1, 1, 'Напасть на след бременских музыкантов', '2019-05-05', '');
Вот я и подумал, что кавычки должны сохраниться..
Хорошо, а можно было бы выкрутиться в данном ситуации БЕЗ функций mysqli, типа mysqli_prepare и т.д.? И как? Ведь в коде строки вставляются через переменные....

Alessio18911 28.02.2019 20:09

Цитата:

Сообщение от Белый шум (Сообщение 504163)
Alessio18911,
Код:

$ php -r 'echo "строка\n";'
строка
$ php -r 'echo "\"строка в кавычках\"\n";'
"строка в кавычках"


Ага, спасибо! )

laimas 01.03.2019 12:40

Цитата:

Сообщение от Alessio18911
можно было бы выкрутиться в данном ситуации БЕЗ функций mysqli, типа mysqli_prepare и т.д.? И как?

Цитата:

Сообщение от Alessio18911
Ага, спасибо! )

Можно, но средствами не РНР, а mysqli - mysqli_real_escape_string. Вот только зачем это делать. Подготовленный запрос может использовать метки вместо самих переменных (в mysqli есть только не именованные метки), и подготовленный единожды будет использоваться, подставляя в него значения следующего запроса. В случае подготовленных запросов экранированием занимается сам драйвер, без явного указания этого в запросе. А экранирование запросов нужно делать обязательно, и не только ради "борьбы" с кавычками, а для того чтобы обезопасить запрос.

Alessio18911 04.03.2019 12:39

Понятно. Очень признателен за детальные и понятные ответы. Спасибо!:)


Часовой пояс GMT +3, время: 23:20.