Есть у меня самописька одна Спойлер: AR на минималках PHP: <?php namespace core\base; use core\Db; abstract class Model { private static $table_names = []; public $id; public $original_properties = []; public function __construct() { foreach ($this as $name => $value) { if (!is_array($value)) { $this->original_properties[$name] = $value; } } } public static function count() { $table = self::getTableName(); return Db::exec("select count(*) from {$table}")->fetchColumn(); } private static function getTableName() { if (!isset(self::$table_names[static::class])) { $class_name = basename(str_replace('\\', '/', static::class)); $table_name = strtolower(preg_replace('~(?<!^)[A-Z]~', '_$0', $class_name)); self::$table_names[static::class] = "`{$table_name}`"; } return self::$table_names[static::class]; } public static function countBy($params, $values = []) { $table = self::getTableName(); return Db::exec("select count(*) from {$table} where {$params}", $values)->fetchColumn(); } /** @return static */ public static function findOne($id) { $table = self::getTableName(); return current(Db::pdo("select * from {$table} where `id` = ?", [$id], static::class)); } /** @return static */ public static function findOneBy($params, $values = []) { $table = self::getTableName(); return current(Db::pdo("select * from {$table} where {$params} limit 1", $values, static::class)); } public static function findAll() { $table = self::getTableName(); return Db::pdo("select * from {$table}", [], static::class); } public static function findAllBy($params, $values = []) { $table = self::getTableName(); return Db::pdo("select * from {$table} where {$params}", $values, static::class); } public function save() { $current_properties = get_object_vars($this); unset($current_properties['original_properties']); $properties_diff_array = array_diff_assoc($current_properties, $this->original_properties); if ($properties_diff_array) { $table = self::getTableName(); foreach ($properties_diff_array as $name => $value) { $params[] = "`{$name}` = ?"; $values[] = $value; $this->original_properties[$name] = $value; } $params = implode(', ', $params); if ($this->id) { $values[] = $this->id; Db::exec("update {$table} set {$params} where `id` = ?", $values); } else { Db::exec("insert into {$table} set {$params}", $values); $this->id = $this->original_properties['id'] = Db::getInstance()->lastInsertId(); } } } public function delete() { $table = self::getTableName(); Db::exec("delete from {$table} where `id` = ?", [$this->id]); unset($this->id, $this->original_properties['id']); } } Меня интересует: можно ли отказаться от $table = self::getTableName() и конкатенировать в запросы сразу self::getTableName()? p.s. просто такой вот спортивный интерес возник в результате того, что я вспомнил, что сделал так, как это у меня сейчас, потому что когда-то один человек меня учил, что перед конкатенацией нужно сначала определить переменную, но я ведь никаких проверок не делаю, мне если что мускул отлуп сделает, если такой таблы нету и инъекции не получится, правильно?
Инъекция может быть построена так чтобы поставить имя реальной таблицы сначала, а потом вредный запрос. Нужно просто взять за правило обезопашивать все подставляемые значения.
Если кому интересно изначально - что происходит в getTableName PHP: <?php namespace core\base { class Test extends model { } abstract class Model { public static $table_names; public function get() { $class_name = basename(str_replace('\\', '/', static::class)); $table_name = strtolower(preg_replace('~(?<!^)[A-Z]~', '_$0', $class_name)); return $table_name; } } } namespace { echo (new \core\base\Test) -> get(); } И как можно сократить ее магическим путем. PHP: private static function getTableName(): string { self :: $table_names[static :: class] ??= strtolower ( substr ( strrchr ( static :: class, '\\' ), 1 ) ); return self :: $table_names[static :: class]; } Но и это считаю аморально нелепым. Изначально названия таблиц, содержаться в protected свойствах класса или в конфиг. файлах - для кастомизации "аля название не понравилось"
а нижнее подчёркивание при определении в имени модели-потомка заглавных букв не смущает тебя? )))) у меня модель TestTable будет работать с таблой test_table вообще-то а создать протектед свойство с именем таблы и дурак может и да: вопрос о конкатенации метода в запрос
Имя таблицы в запросе UPDATE Код (Text): users SET password=123;# Полный запрос в итоге Код (Text): UPDATE users SET password=123;# SET field = "very \"sanitized\" data" WHERE id = 27382 Плейсхолдер не помог.
Только тебе виднее, как классы твои называются. Это эквивалентно, что будешь использовать подчеркивания физически в именах, но такового смысла нет. Жесткое привязывание к тому чему не должно - это дурной тон самописа. Пока ты пишешь возможно лишь для себя, то да "мое болото, что хочу то и ворочу", но так же ты получаешь опыт и укрепляешь ими свой стиль кодинга.... Не дай бог встретить твое творение в будущем. Сейчас ты все равно на свой лад будешь делать, но завтра.. со временем.. начнешь понимать как это выглядело на какаху. Еще раз повторюсь - у тебя велосипед раздутый. Прими критику спокойно, а не дураки кругом и т.д. А разве он не решен еще ? Я смотрю глобально и указываю что не понравилось и делюсь своим мнением по этому поводу и за каждую строчку кода.
что это за дичь? имя таблицы У ТЕБЯ - users, где какие косяки - не вижу Я password=123;# SET field = "very \"sanitized\" )))) это вообще что, как оно попало в запрос? ))) ты просто взял так и написал в запросе? --- Добавлено --- ))) так какой ответ будет или пару дней почирикаем ещё в теме?
как оно попало туда? ))) ты просто понтуешься, дай мне: что должно быть в 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 так что это ерунда какая-то
у него имена таблицы берутся только с имен родительских классов по его реализации, не внешней стороны или иного рода. Там Sql inj невозможен. Можно или нет - Это вопрос изначально основан на удобстве присвоение значения к чему-то. можно ли отказаться от: PHP: $table = self::getTableName(); return Db::exec("select count(*) from {$table}")->fetchColumn(); В пользу: PHP: return Db::exec( 'select count(*) from ' . self::getTableName() )->fetchColumn(); Не имеет значения, изначально. --- Добавлено --- Если любая инфа с внешней среды будет подставляться напрямую в sql запрос, то отлупом тут не обойтись.
благодарю, просто я сократить хочу код, а то в каждом методе определяется переменная не ну инфа то проверяется перед вбросом, я про отлуп мускула, если ему имя таблы прилетит некорректное типа ок, порешали...
Полный запрос покажи Так вопрос же о принципе. Тут принцип только один - эскейпить всё, что идёт в запрос. Чтобы прямо на месте было видно, что никакой инъекции не случиться. Сегодня имя идет из класса, завтра класс наследуется и имя берется из env. А чтобы не городить по 10 скобок, конечно лучше вытаскивать в переменную.
...но я ведь никаких проверок не делаю, мне если что мускул отлуп сделает... это всё касается метода получения имени таблы, весь вопрос только его и касается то есть я не проверяю, есть ли такая табла, я такого рода проверку имел в виду
Можно, но, например, у некоторых такой code style, что по головке не погладят, даже за PHP: return ...; вместо PHP: $result = ...; rerurn $result;
а зачем ты модеру пишешь Код (Text): ТС, Вы писатель, Вы не читатель ))) и этот сраный спам мне на почту прилетает уведомлением я то жду дельного ответа