За последние 24 часа нас посетили 21499 программистов и 1025 роботов. Сейчас ищут 710 программистов ...

Следует ли строго придерживаться принципа: определи переменную перед конкатенацией?

Тема в разделе "Прочие вопросы по PHP", создана пользователем Вероломство, 8 мар 2021.

  1. Вероломство

    Вероломство Активный пользователь

    С нами с:
    19 июн 2017
    Сообщения:
    615
    Симпатии:
    24
    Есть у меня самописька одна

    PHP:
    1. <?php
    2.  
    3.  
    4. namespace core\base;
    5.  
    6.  
    7. use core\Db;
    8.  
    9. abstract class Model
    10. {
    11.     private static $table_names = [];
    12.  
    13.     public $id;
    14.     public $original_properties = [];
    15.  
    16.     public function __construct()
    17.     {
    18.         foreach ($this as $name => $value) {
    19.  
    20.             if (!is_array($value)) {
    21.                 $this->original_properties[$name] = $value;
    22.             }
    23.         }
    24.     }
    25.  
    26.     public static function count()
    27.     {
    28.         $table = self::getTableName();
    29.  
    30.         return Db::exec("select count(*) from {$table}")->fetchColumn();
    31.     }
    32.  
    33.     private static function getTableName()
    34.     {
    35.         if (!isset(self::$table_names[static::class])) {
    36.             $class_name = basename(str_replace('\\', '/', static::class));
    37.             $table_name = strtolower(preg_replace('~(?<!^)[A-Z]~', '_$0', $class_name));
    38.  
    39.             self::$table_names[static::class] = "`{$table_name}`";
    40.         }
    41.  
    42.         return self::$table_names[static::class];
    43.     }
    44.  
    45.     public static function countBy($params, $values = [])
    46.     {
    47.         $table = self::getTableName();
    48.  
    49.         return Db::exec("select count(*) from {$table} where {$params}", $values)->fetchColumn();
    50.     }
    51.  
    52.     /** @return static */
    53.     public static function findOne($id)
    54.     {
    55.         $table = self::getTableName();
    56.  
    57.         return current(Db::pdo("select * from {$table} where `id` = ?", [$id], static::class));
    58.     }
    59.  
    60.     /** @return static */
    61.     public static function findOneBy($params, $values = [])
    62.     {
    63.         $table = self::getTableName();
    64.  
    65.         return current(Db::pdo("select * from {$table} where {$params} limit 1", $values, static::class));
    66.     }
    67.  
    68.     public static function findAll()
    69.     {
    70.         $table = self::getTableName();
    71.  
    72.         return Db::pdo("select * from {$table}", [], static::class);
    73.     }
    74.  
    75.     public static function findAllBy($params, $values = [])
    76.     {
    77.         $table = self::getTableName();
    78.  
    79.         return Db::pdo("select * from {$table} where {$params}", $values, static::class);
    80.     }
    81.  
    82.     public function save()
    83.     {
    84.         $current_properties = get_object_vars($this);
    85.  
    86.         unset($current_properties['original_properties']);
    87.  
    88.         $properties_diff_array = array_diff_assoc($current_properties, $this->original_properties);
    89.  
    90.         if ($properties_diff_array) {
    91.             $table = self::getTableName();
    92.  
    93.             foreach ($properties_diff_array as $name => $value) {
    94.                 $params[] = "`{$name}` = ?";
    95.                 $values[] = $value;
    96.                 $this->original_properties[$name] = $value;
    97.             }
    98.  
    99.             $params = implode(', ', $params);
    100.  
    101.             if ($this->id) {
    102.                 $values[] = $this->id;
    103.  
    104.                 Db::exec("update {$table} set {$params} where `id` = ?", $values);
    105.             } else {
    106.                 Db::exec("insert into {$table} set {$params}", $values);
    107.  
    108.                 $this->id = $this->original_properties['id'] = Db::getInstance()->lastInsertId();
    109.             }
    110.         }
    111.     }
    112.  
    113.     public function delete()
    114.     {
    115.         $table = self::getTableName();
    116.  
    117.         Db::exec("delete from {$table} where `id` = ?", [$this->id]);
    118.  
    119.         unset($this->id, $this->original_properties['id']);
    120.     }
    121. }

    Меня интересует: можно ли отказаться от $table = self::getTableName() и конкатенировать в запросы сразу self::getTableName()?

    p.s. просто такой вот спортивный интерес возник в результате того, что я вспомнил, что сделал так, как это у меня сейчас, потому что когда-то один человек меня учил, что перед конкатенацией нужно сначала определить переменную, но я ведь никаких проверок не делаю, мне если что мускул отлуп сделает, если такой таблы нету и инъекции не получится, правильно?
     
    #1 Вероломство, 8 мар 2021
    Последнее редактирование: 8 мар 2021
  2. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.553
    Симпатии:
    631
    Инъекция может быть построена так чтобы поставить имя реальной таблицы сначала, а потом вредный запрос. Нужно просто взять за правило обезопашивать все подставляемые значения.
     
    Вероломство нравится это.
  3. Вероломство

    Вероломство Активный пользователь

    С нами с:
    19 июн 2017
    Сообщения:
    615
    Симпатии:
    24
    там PDO на плейсхолдерах у меня, вопрос про конкатенацию метода получающего имя таблы
     
  4. MouseZver

    MouseZver Суперстар

    С нами с:
    1 апр 2013
    Сообщения:
    7.752
    Симпатии:
    1.322
    Адрес:
    Лень
    Если кому интересно изначально - что происходит в getTableName
    PHP:
    1. <?php
    2.  
    3. namespace core\base
    4. {
    5.     class Test extends model
    6.     {
    7.      
    8.     }
    9.  
    10.     abstract class Model
    11.     {
    12.         public static $table_names;
    13.      
    14.         public function get()
    15.         {
    16.             $class_name = basename(str_replace('\\', '/', static::class));
    17.             $table_name = strtolower(preg_replace('~(?<!^)[A-Z]~', '_$0', $class_name));
    18.          
    19.             return $table_name;
    20.         }
    21.     }
    22. }
    23.  
    24. namespace
    25. {
    26.     echo (new \core\base\Test) -> get();
    27. }
    И как можно сократить ее магическим путем.

    PHP:
    1. private static function getTableName(): string
    2. {
    3.     self :: $table_names[static :: class] ??= strtolower ( substr ( strrchr ( static :: class, '\\' ), 1 ) );
    4.  
    5.     return self :: $table_names[static :: class];
    6. }
    Но и это считаю аморально нелепым. Изначально названия таблиц, содержаться в protected свойствах класса
    или
    в конфиг. файлах - для кастомизации "аля название не понравилось"
     
    Вероломство нравится это.
  5. Вероломство

    Вероломство Активный пользователь

    С нами с:
    19 июн 2017
    Сообщения:
    615
    Симпатии:
    24
    а нижнее подчёркивание при определении в имени модели-потомка заглавных букв не смущает тебя? ))))

    у меня модель TestTable будет работать с таблой test_table вообще-то :)

    а создать протектед свойство с именем таблы и дурак может ;)

    и да: вопрос о конкатенации метода в запрос
     
  6. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.553
    Симпатии:
    631
    Имя таблицы в запросе UPDATE
    Код (Text):
    1. users SET password=123;#
    Полный запрос в итоге
    Код (Text):
    1. UPDATE users SET password=123;# SET field = "very \"sanitized\"  data" WHERE id = 27382
    Плейсхолдер не помог.
     
  7. MouseZver

    MouseZver Суперстар

    С нами с:
    1 апр 2013
    Сообщения:
    7.752
    Симпатии:
    1.322
    Адрес:
    Лень
    Только тебе виднее, как классы твои называются. Это эквивалентно, что будешь использовать подчеркивания физически в именах, но такового смысла нет. Жесткое привязывание к тому чему не должно - это дурной тон самописа. Пока ты пишешь возможно лишь для себя, то да "мое болото, что хочу то и ворочу", но так же ты получаешь опыт и укрепляешь ими свой стиль кодинга.... Не дай бог встретить твое творение в будущем. Сейчас ты все равно на свой лад будешь делать, но завтра.. со временем.. начнешь понимать как это выглядело на какаху. Еще раз повторюсь - у тебя велосипед раздутый. Прими критику спокойно, а не дураки кругом и т.д.
    А разве он не решен еще ? Я смотрю глобально и указываю что не понравилось и делюсь своим мнением по этому поводу и за каждую строчку кода.
     
  8. Вероломство

    Вероломство Активный пользователь

    С нами с:
    19 июн 2017
    Сообщения:
    615
    Симпатии:
    24
    что это за дичь?

    имя таблицы У ТЕБЯ - users, где какие косяки - не вижу Я


    password=123;# SET field = "very \"sanitized\"

    )))) это вообще что, как оно попало в запрос? )))

    ты просто взял так и написал в запросе?
    --- Добавлено ---
    )))

    так какой ответ будет или пару дней почирикаем ещё в теме? :)
     
  9. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.553
    Симпатии:
    631
    Из метода же
    Код (Text):
    1. function getTableName () {
    2.      return "users SET password=123;#";
    3. }
     
  10. Вероломство

    Вероломство Активный пользователь

    С нами с:
    19 июн 2017
    Сообщения:
    615
    Симпатии:
    24
    как оно попало туда? )))

    ты просто понтуешься, дай мне: что должно быть в static::class моего метода, что бы вернуть "users SET password=123;# :)

    это во-первых, а во-вторых ты думаешь я не умею такие фокусы делать и поэтому просто так написал про отлуп мускула?

    вот как отработала эта дичь - SQLSTATE[42000]: Syntax error or access violation: 1064 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 'SET password=123;#' at line 1

    так что это ерунда какая-то :)
     
  11. MouseZver

    MouseZver Суперстар

    С нами с:
    1 апр 2013
    Сообщения:
    7.752
    Симпатии:
    1.322
    Адрес:
    Лень
    у него имена таблицы берутся только с имен родительских классов по его реализации, не внешней стороны или иного рода. Там Sql inj невозможен.

    Можно или нет - Это вопрос изначально основан на удобстве присвоение значения к чему-то.

    можно ли отказаться от:
    PHP:
    1. $table = self::getTableName();
    2.  
    3. return Db::exec("select count(*) from {$table}")->fetchColumn();
    В пользу:
    PHP:
    1. return Db::exec( 'select count(*) from ' . self::getTableName() )->fetchColumn();
    Не имеет значения, изначально. o_O
    --- Добавлено ---
    Если любая инфа с внешней среды будет подставляться напрямую в sql запрос, то отлупом тут не обойтись.
     
    Вероломство нравится это.
  12. Вероломство

    Вероломство Активный пользователь

    С нами с:
    19 июн 2017
    Сообщения:
    615
    Симпатии:
    24
    благодарю, просто я сократить хочу код, а то в каждом методе определяется переменная :)

    не ну инфа то проверяется перед вбросом, я про отлуп мускула, если ему имя таблы прилетит некорректное типа

    ок, порешали...
     
  13. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.553
    Симпатии:
    631
    Полный запрос покажи
    Так вопрос же о принципе. Тут принцип только один - эскейпить всё, что идёт в запрос. Чтобы прямо на месте было видно, что никакой инъекции не случиться. Сегодня имя идет из класса, завтра класс наследуется и имя берется из env. А чтобы не городить по 10 скобок, конечно лучше вытаскивать в переменную.
     
  14. MouseZver

    MouseZver Суперстар

    С нами с:
    1 апр 2013
    Сообщения:
    7.752
    Симпатии:
    1.322
    Адрес:
    Лень
    Тут без пива в 4 утра не понять.
    Надо срочно шары красные отключать.
     
  15. Вероломство

    Вероломство Активный пользователь

    С нами с:
    19 июн 2017
    Сообщения:
    615
    Симпатии:
    24
    ...но я ведь никаких проверок не делаю, мне если что мускул отлуп сделает...

    это всё касается метода получения имени таблы, весь вопрос только его и касается :)

    то есть я не проверяю, есть ли такая табла, я такого рода проверку имел в виду
     
  16. don.bidon

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

    С нами с:
    28 мар 2021
    Сообщения:
    863
    Симпатии:
    134
    Можно, но, например, у некоторых такой code style, что по головке не погладят, даже за
    PHP:
    1. return ...;
    вместо
    PHP:
    1. $result = ...;
    2. rerurn $result;
     
  17. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.553
    Симпатии:
    631
    @don.bidon когда есть переменая с каждым значением, отладка значительно упрощается
     
  18. don.bidon

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

    С нами с:
    28 мар 2021
    Сообщения:
    863
    Симпатии:
    134
    Вы-то читаете между строк, надеюсь, ТС узрит тоже )
     
  19. Вероломство

    Вероломство Активный пользователь

    С нами с:
    19 июн 2017
    Сообщения:
    615
    Симпатии:
    24
    что тут зрить? :)
     
  20. don.bidon

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

    С нами с:
    28 мар 2021
    Сообщения:
    863
    Симпатии:
    134
    ТС, Вы писатель, Вы не читатель )))
     
  21. Вероломство

    Вероломство Активный пользователь

    С нами с:
    19 июн 2017
    Сообщения:
    615
    Симпатии:
    24
    ты ТС
     
  22. don.bidon

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

    С нами с:
    28 мар 2021
    Сообщения:
    863
    Симпатии:
    134
    Завязывай уже с препаратами )
     
  23. Вероломство

    Вероломство Активный пользователь

    С нами с:
    19 июн 2017
    Сообщения:
    615
    Симпатии:
    24
    а зачем ты модеру пишешь
    Код (Text):
    1. ТС, Вы писатель, Вы не читатель )))
    и этот сраный спам мне на почту прилетает уведомлением я то жду дельного ответа