За последние 24 часа нас посетили 36724 программиста и 7752 робота. Сейчас ищут 1846 программистов ...

Экранирование спецсимволов перед вставкой в базу

Тема в разделе "PHP для новичков", создана пользователем roman_php, 5 янв 2023.

  1. roman_php

    roman_php Активный пользователь

    С нами с:
    20 сен 2009
    Сообщения:
    39
    Симпатии:
    1
    Доброго времени суток, я понимаю тема избитая и скорее всего есть массу ответов на мой вопрос, но у меня не получается, прошу помочь разобраться.
    У меня есть скрипт которые принимает значения из глобального массива (для простоты сделал из $GET, у меня скрипт намного больше выполняет функционала, я просто оставил все что касается моего вопроса, остальное убрал) для записи в базу.
    PHP:
    1. <?php
    2. $db = mysqli_connect('localhost','root', 'motorola', 'yz');
    3. if (!$db) {
    4.     die("Connection failed: " . mysqli_connect_error());
    5. }
    6. //обрезаем пробелы в начале и в конце значений массива $_GET
    7. $_GET = array_map(function($items) {
    8.     if (is_array($items))
    9.         foreach ($items as $key => $value)
    10.             $items[$key] = trim($value);
    11.     else $items = trim($items);
    12.     return $items;
    13. }, $_GET);
    14.  
    15. if (!empty($_GET)){
    16.     $query1 = "INSERT INTO `baza` SET ";
    17.     foreach ($_GET as $key => $value) {
    18. //для каждого элемента массива GET
    19.         if(empty($value)){
    20.             //если пустой то NULL
    21.             $value = NULL;
    22.         }
    23.         //если не массив
    24.         if (!is_array($value) && $value!=null) {
    25.             //добавим к строке запроса 1
    26.             $query1 .= " $key = '$value' ,";
    27.         }
    28.     }
    29.     $query1 = rtrim($query1, ',');
    30.     echo 'Запрос 1 '.$query1.'<hr/>';//это получившаяся строка запроса ее нужно проверить.
    31.     $rec = mysqli_query($db,$query1);//если строка устраивает тогда выполнить запрос
    32.     //закрываем соединение с базой
    33.     mysqli_close($db);
    34.     if ($rec != TRUE){
    35.         echo 'Запись в базу не произведена';
    36.     } else {
    37.         echo 'Запись в базу произведена';
    38.     }
    39. }
    40. ?>
    и если в адресной строке пропишем например:
    Код (Text):
    1. http://uz/ecran.php?adres=Vladimir&shema=LLL
    то все хорошо, запись в базу производится и получаем вывод скрипта
    Код (Text):
    1. Запрос 1 INSERT INTO `baza` SET adres = 'Vladimir' , shema = 'LLL'
    2. Запись в базу произведена
    Но естественно в значениях массива может закрасться спецсимвол, например одинарная кавычка '.
    Код (Text):
    1. http://uz/ecran.php?adres=Vla'dimir&shema=LLL
    Тогда получаю естественно ошибку:
    Код (Text):
    1. Запрос 1 INSERT INTO `baza` SET adres = 'Vla'dimir' , shema = 'LLL'
    2.  
    3. Fatal error: Uncaught mysqli_sql_exception: 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 'dimir' , shema = 'LLL'' at line 1 in F:\server\OpenServer\domains\uz\ecran.php:31 Stack trace: #0 F:\server\OpenServer\domains\uz\ecran.php(31): mysqli_query() #1 {main} thrown in F:\server\OpenServer\domains\uz\ecran.php on line 31
    Для этих целей вроде как существует специальная функция mysqli_real_escape_string.

    Я пробую ее применить так:
    PHP:
    1. <?php
    2. $db = mysqli_connect('localhost','root', 'motorola', 'yz');
    3. if (!$db) {
    4.     die("Connection failed: " . mysqli_connect_error());
    5. }
    6. //обрезаем пробелы в начале и в конце значений массива $_GET
    7. $_GET = array_map(function($items) {
    8.     if (is_array($items))
    9.         foreach ($items as $key => $value)
    10.             $items[$key] = trim($value);
    11.     else $items = trim($items);
    12.     return $items;
    13. }, $_GET);
    14.  
    15. if (!empty($_GET)){
    16.     $query1 = "INSERT INTO `baza` SET ";
    17.     foreach ($_GET as $key => $value) {
    18. //для каждого элемента массива GET
    19.         if(empty($value)){
    20.             //если пустой то NULL
    21.             $value = NULL;
    22.         }
    23.         //если не массив
    24.         if (!is_array($value) && $value!=null) {
    25.             //добавим к строке запроса 1
    26.             $query1 .= " $key = '$value' ,";
    27.         }
    28.     }
    29.     $query1 = rtrim(mysqli_real_escape_string($db, $query1), ',');
    30.     echo 'Запрос 1 '.$query1.'<hr/>';//это получившаяся строка запроса ее нужно проверить.
    31.     $rec = mysqli_query($db,$query1);//если строка устраивает тогда выполнить запрос
    32.     //закрываем соединение с базой
    33.     mysqli_close($db);
    34.     if ($rec != TRUE){
    35.         echo 'Запись в базу не произведена';
    36.     } else {
    37.         echo 'Запись в базу произведена';
    38.     }
    39. }
    40. ?>
    При этом вижу что заикранировалась не только одинарная кавычка в слове Vla'dimir, но и все одинарные кавычки в запросе, это вызывает ошибку.
    Код (Text):
    1. Запрос 1 INSERT INTO `baza` SET adres = \'Vla\'dimir\' , shema = \'LLL\'
    2.  
    3. Fatal error: Uncaught mysqli_sql_exception: 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 '\'Vla\'dimir\' , shema = \'LLL\'' at line 1 in F:\server\OpenServer\domains\uz\ecran.php:31 Stack trace: #0 F:\server\OpenServer\domains\uz\ecran.php(31): mysqli_query() #1 {main} thrown in F:\server\OpenServer\domains\uz\ecran.php on line 31
    Что я делаю не так?
     
  2. roman_php

    roman_php Активный пользователь

    С нами с:
    20 сен 2009
    Сообщения:
    39
    Симпатии:
    1
    Спасибо, я сам разобрался, нужно было просто не все экранировать. Но может есть способ более элегантный?
    PHP:
    1. <?php
    2. $db = mysqli_connect('localhost','root', 'motorola', 'yz');
    3. if (!$db) {
    4.     die("Connection failed: " . mysqli_connect_error());
    5. }
    6. //обрезаем пробелы в начале и в конце значений массива $_GET
    7. $_GET = array_map(function($items) {
    8.     if (is_array($items))
    9.         foreach ($items as $key => $value)
    10.             $items[$key] = trim($value);
    11.     else $items = trim($items);
    12.     return $items;
    13. }, $_GET);
    14.  
    15. if (!empty($_GET)){
    16.     $query1 = "INSERT INTO `baza` SET ";
    17.     foreach ($_GET as $key => $value) {
    18. //для каждого элемента массива GET
    19.         if(empty($value)){
    20.             //если пустой то NULL
    21.             $value = NULL;
    22.         }
    23.         //если не массив
    24.         if (!is_array($value) && $value!=null) {
    25.             //добавим к строке запроса 1
    26.             $value = mysqli_real_escape_string($db, $value);
    27.             $query1 .= " $key = '$value' ,";
    28.         }
    29.     }
    30.     $query1 = rtrim($query1, ',');
    31.     echo 'Запрос 1 '.$query1.'<hr/>';//это получившаяся строка запроса ее нужно проверить.
    32.     $rec = mysqli_query($db,$query1);//если строка устраивает тогда выполнить запрос
    33.     //закрываем соединение с базой
    34.     mysqli_close($db);
    35.     if ($rec != TRUE){
    36.         echo 'Запись в базу не произведена';
    37.     } else {
    38.         echo 'Запись в базу произведена';
    39.     }
    40. }
    41. ?>
     
  3. AnteFil

    AnteFil Активный пользователь

    С нами с:
    14 янв 2014
    Сообщения:
    531
    Симпатии:
    4
    Делаешь вот такой класс
    PHP:
    1. class job_db
    2. {
    3.     private $db;
    4.     public function __construct(){
    5.     try {
    6.             $this->db = new PDO('mysql:host=localhost;charset=UTF8;dbname=name', 'name', 'pas');
    7.           } catch (PDOException $e) {
    8.             print "Error!: " . $e->getMessage();
    9.             die();
    10.           }
    11.     }
    12.     public function query($sql, $params = []){
    13.         $stmt = $this->db->prepare($sql);
    14.         if(!empty($params)){
    15.             foreach ($params as $key =>$val){
    16.                 $stmt->bindValue(':'.$key, $val);
    17.             }
    18.         }
    19.         $stmt->execute();
    20.         return $stmt;
    21.     }
    22.     public function fetchAll($sql, $params = []){
    23.         $result = $this->query($sql, $params);
    24.         return $result->fetchAll(PDO::FETCH_ASSOC);
    25.  
    26.     }
    27.   public function update($sql, $params = []){
    28.         $result = $this->query($sql, $params);
    29.         return $result->rowCount();
    30.     }
    31. }
    Функции можешь дописывать любые.

    Затем на любой другой странице пишешь в начале страницы или в функции
    PHP:
    1. require 'config.php';
    2. $job_db = new job_db();
    А что бы обратиться к базе пишешь так
    PHP:
    1. $params = [
    2.         'name'=> $name,
    3.   'id'=> $id,
    4.             ];
    5. $result = $job_db->update("UPDATE `aaa` SET `name`= :name WHERE `id`=:id", $params);
    И Всё защищено и всё работает
     
    #3 AnteFil, 5 янв 2023
    Последнее редактирование: 5 янв 2023
    aliensgroup нравится это.
  4. MouseZver

    MouseZver Суперстар

    С нами с:
    1 апр 2013
    Сообщения:
    7.840
    Симпатии:
    1.338
    Адрес:
    Лень
  5. roman_php

    roman_php Активный пользователь

    С нами с:
    20 сен 2009
    Сообщения:
    39
    Симпатии:
    1
    Интересно, надо попробовать.
     
  6. don.bidon

    don.bidon Активный пользователь

    С нами с:
    28 мар 2021
    Сообщения:
    947
    Симпатии:
    147
  7. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.497
    Симпатии:
    1.726
    А чего? Он же релизнулся уже