Комментарии 60
mysqli_connect? Серьезно?
Дополню, а то выглядит коммент не очень :)
Если вы пишете для новичков, то приучайте их сразу не писать на PHPк хорошему. Как минимум использовать PDO для работы с БД.
Это был один из самых простых вариантов реализации и я писал, что сам новичок и хочу помочь другим, если у них появится та же проблема, что и у меня.
Спасибо за обратную связь
С каких пор PDO стал чем-то хорошим? Это два разных инструмента для разного вида задач. В том же PDO нет поддержки асинхронных запросов (в отличие от mysqli), например.
Я уж не говорю о том, что PDO — забагованный (проверял на PHP 8.0 + 8.1) и содержит кучу косяков, начиная с очевидных, вроде флагов PDO::ATTR_ERRMODE, который работает только в том случае, если его вызвать через setAttribute (при передаче через конструктор — не срабатывает в препейрах), заканчивая поломанной работой с транзакциями, если выставлен флаг PDO::ATTR_CASE (казалось бы, как это связано, но как бы вот).
А если говорить о mysqli, то он хоть и прибит гвоздями к одной БД, но зато гибче и надёжнее.
А можно какие-то пруфы всем этим заявлениям?
У всего мира PDO::ATTR_ERRMODE прекрасно работает в конструкторе.
Асинхронность же мускулявых запросов сильно преувеличена. Учитывая, что запрос в любом случае может быть только один, какой-то разумный вариант применения этой асинхронности в РНР мне как-то не приходит в голову.
А можно какие-то пруфы всем этим заявлениям?
У всего мира PDO::ATTR_ERRMODE прекрасно работает в конструкторе.
Если говорить про реальные пруфы, которые прям вот сейчас можно взять и проверить, то вот тут: ExecutableQuery.php#L86 не будет возникать никаких исключений, если убрать вот эту строчку: Connection.php#L30 Сама опция ATTR_ERRMODE
в конструктор, если что, передаётся: Отсюда Driver.php#L49 вот сюда Driver.php#L52
Это всё на sqlite + php 8.1 воспроизводится 146%. Именно на этом кейсе столкнулся. Если неудобно через git clone проверить и убедиться, то могу попробовать собрать какой-нибудь гист попроще, без всякого лишнего кода.
P.S. Но вообще выглядит какая-то магия, судя по вашей ссылке, т.к. я не копал глубже, проставил дополнительно setAttribute
, оно всё починилось и я забил.
Но я же выше уже сделал такой гист. Вот он же с синтаксической ошибкой. Всё прекрасно бросается. Что я делаю не так?
Да, всё верно. Проблема была именно в синтаксической ошибке. Более того — не имеет смысла даже запускать тот код, что выше по моим ссылкам — там тоже не воспроизводится больше. Не знаю с чем было связано, возможно из-за того что я что-то проглядел, возможно из-за того что это был PHP 8.1 RC что-то там, но саму строчку с setAttribute я спецом коммитил, чтоб пофиксить конкретно эту проблему.
А на счёт ATTR_CASE + транзакций я уже забыл кейс. roxblnfk можешь напомнить пожалуйста что там было? Я точно помню что я показывал тебе этот магический баг в пдо. И кажется эта проблема была именно при работе с mysql.
Оба коммента выглядят не очень по совсем другой причине.
Как и многие новички, вы путаете два понятия, драйвер для работы с БД и безопасное составление запросов.
Сам по себе драйвер не панацея. Точно так же у автора будут те же самые инъекции и с PDO.
Поэтому свою мысль надо формулировать немного по-другому, не "PDO rulez, mysqli suxx!!!", а "переменные не должны помещаться напрямую в запрос, а передаваться через привязку к подготовленному выражению". А уж через какой драйвер это делается - дело сто тыщ десятое.
Почему бы не работать напрямую с $exif['IFD0']['Keywords'] ? судя по коду и $key и $setting являются ключами массива, значит к ним можно получить доступ напрямую, не делая лишних foreach.
Кодировку можно задать после соединения с базой, например так: mysqli_query($con,"SET NAMES utf8mb4_bin"); mysqli_query($con,"SET CHARSET utf8mb4");mysqli_query($con,"SET SESSION collation_connection = 'utf8mb4_bin'");
Если функция select_sql() вызывается часто то есть смысл делать соединение с базой вне функции, ну или проверять наличие соединения внутри функции, чтобы не пересоединяться с базой данных ради одного запроса
Ну и сейчас должны пойти комментарии от других комментаторов :)
Отвечу по пунктам:
Спасибо, учту
Я пробовал что-то подобное, но у меня всё равно выводилось NULL, но я перепроверю
Об этом я написал в конце статьи, что это тупой скрипт для локальной БД для обучения, что по хорошему вынести в отдельный скрипт - понимаю.
Спасибо за обратную связь!
.2.Можно, но не нужно. Для этого есть специальная функция mysqli::set_charset()
И при этом очень желательно не путать collation и charset.
Я не особо знаю пхп, но вот это вот:
$sql_select = "SELECT filename FROM test WHERE keywords LIKE '%$key%'";
выглядит как возможность для sql-иньекции...
Скажу честно, ещё не изучал защиту от sql-инъекций. Это лишь начало моего пути, прежде чем браться за какой либо проект, я обязательно изучу данный вопрос.
Спасибо за обратную связь!
Судя по
<img src="".$row['filename']."" style=" width: 200px" />
Через инекцию можно будет вытянуть любой файл. Возможно что-то даже записать и повысить привилегии.
используйте хранимые процедуры и это не будет поводом для боязни инъекций
Спасибо
Хранимые процедуры уменьшают поверхность атаки, но не являются панацеей от инъекций.
Автору лучше изучить ORM, это на данном этапе развития даст больше чем закапывание в дебри SQL.
Учить ORM не выучив SQL - это стрелять себе даже не в ногу, а сразу в голову.
уменьшают настолько, что мне показали только один вариант, но для этого надо было написать специально подготовленную для этого хранимую процедуру.
Вот именно, что только один вариант и что под каждый запрос свою процедуру. То есть в реальном коде это невозможно будет использовать.
Подготовленный запрос сделать в сто раз проще и надёжнее.
люди делают проекты с 1000+ процедурами - и не останавливаются. возможности хранимых процедур намного больше "подготовленных запросов"
если для Вас невозможно использовать - "Вы проста не умеете их готовить..."
а если говорить о mssql - то хранимые процедуры ещё и компилируются, что так же повышает скорость их работы.
:)))
Как-то вы очень резко перешли от "Мне тут пацаны показали" к "вы не умеете" :)
Давайте вы будете говорить только на основании собственного опыта. Итак, сколько процедур написали лично вы? Можете показать пример одной?
А я пока дам вам несколько советов:
1000 запросов - это маленькая домашняя страничка. Не забывайте, что вы начали разговор про процедуры в контексте защиты от инъекций. То есть каждый запрос в приложении должен выполняться через хранимую процедуру.
Возможности хранимых процедур действительно больше подготовленных запросов (в кавычки брать совсем не обязательно, это не инопланетная технология), но и поддержка тоже сложнее. Поэтому использовать их для защиты от инъекций - это из пушки по воробьям.
Никогда не ввязывайтесь в дискуссию на тему, про которую вы только что-то слышали краем уха. Тем более в таком снисходительном тоне.
я не просто слышал, я видел этот проект в разработке. и да, я каждый запрос держу в хранимой процедуре, поддержка хранимых процедур не чуть не сложнее любого программного кода , если пользоваться заточенного для этого инструмента. рекомендую DbForge. защита от инъекций в данном случае как приятный бонус.
редактор с подсветом, пошаговая отладка, синхронизация баз. рефакторинг. и куча других плюшек делают работу с базой приятной и быстрой.
вызов хранимки в коде прост, ничуть не сложнее чем запроса. но только одна строка.
в ide основного кода нет подсветки кода sql, это строка, обыкновенная строка. а запросы бывают на 1-3 экрана . в ide для sql его автоматом отформатируют, разукрасят, проверят. одно нажатие и выполнение.
Я не буду комментировать всю ту многословную чушь, которую вы тут понаписали вместо одного короткого примера кода из вашего "реального" проекта, а просто порекомендую вылезти из-под той коряги, под которой вы провели последние лет десять, и поставить себе какую-нибудь современную IDE :)
когда нечего сказать - начинаются такие ответы.
любая современная ide не круче другой современной ide специально узко заточенной под конкретную субд.
Верно, не круче. Но вы-то утверждаете, что она хуже
Что, мягко говоря, не проходит проверку реальностью ;-)
кто сказал хуже? посмотрите линейку продуктовDbForge - под каждую субд -своя ide. я пользуюсь для mysql и очень доволен.
Интересно, что два года назад вы уже участвовали в дискуссии про защиту от инъекций с тем же самым тезисом, и, хотя ваш оппонент и сам не понимает ни как работают процедуры, ни как с их помощью можно сделать защиту, вроде бы даже согласились с его правотой.
Я не буду здесь углубляться в тонкости синтаксиса процедур, а приведу куда более простой пример инъекции на базе кода из того топика
$id = "0);DELETE FROM users; -- "
$db->query('CALL get_order(' . $id . ')');
"Ну что, сынку - помогли тебе твои ляхи?" :)
прежде чем такое советовать надо проверять
вот это 0);DELETE FROM users; --
в виде like "%0);DELETE FROM users; --%" и будет искаться в поле keywords
Совершенно верно! Проверять надо обязательно! Вот и проверьте :)
Введите строчку
get_order(0);DELETE FROM users; -- )
В своем клиенте базы данных, и посмотрите на результат. Только очень прошу - не на боевой базе!
я то проверял, вот только надо быть полным идиотом, что такое в коде допустить.
я делаю так:
String f = String.format("{call %s(%s,'%s')}", "x13", s[0], s[1]);
CallableStatement proc = con.prepareCall(f);
О! Да вы не настолько безнадежны, каким хотите казаться :)
Но вам надо определиться: всё таки "вот это 0);DELETE FROM users; --<br>в виде like "%0);DELETE FROM users; --%" и будет искаться в поле keywords ", или "надо быть полным идиотом"
Потому что неувязочка получается :)
если есть паранойя инъекций - то можно проверять всё что угодно перед вызовом. если у Вас такая строка
get_order(0);DELETE FROM users; -- ) считается реальной ситуацией то мне нечего на это сказать.
ЗЫ <br> заменяется Shift+Enter
Во-первых, хочу поблагодарить за доставленное удовольствие! Я прекрасно скоротал время перед концертом !
А во-вторых осмелюсь напомнить исходную фразу, с которой и началась эта увлекательная дискуссия:
используйте хранимые процедуры и это не будет поводом для боязни инъекций
На мой не искушённый взгляд он немного противоречит утверждению "если вас заедает паранойя, то надо проверять что-то ещё".
Или, выражаясь немного вульгарно, вы окончательно заврались :))
Ахаха, вы добавили код к своему комментарию! Он просто прекрасен! Вы просто семимильными шагами осваиваете реальную защиту от инъекций! Вы уже продвинулись на целый шаг!
Мы пока оставим в стороне неудобный вопрос, *а зачем нам вообще тогда нужна процедура*, и займёмся куда более насущным - а именно, вопросом *экранирования кавычек* в SQL запросах, который прекрасно освещен в известном комиксе про мальчика по имени Bobby Tables. Вам же, несомненно, он знаком? ;)
если Вас пугают кавычки - то они должны вас пугать и в использовании простых запросах.
я не параноик, поэтому я останавливаюсь на приемлемой стадии защиты.
Все верно. Пугают. Как и любого разработчика, знакомого с SQL инъекциями. Именно поэтому я и использую не "простые" запросы, а подготовленные. Видите, вы тоже можете прийти к этому простому выводу. Но ваше самомнение, помноженное на совершенно дремучее невежество, вам в этом очень мешает.
Вы ответили на этот комент, но на комент с проверкой промолчали....
обозвали меня вруном, невежей, и прочее.
и, скорее всего, Вы минуснули в карму.
И это называется демократия по хабру.
могли бы показать Ваши хвалимые подготовленные запросы.
.те же хранимые процедуры могут иметь вид ваших подготовленных запросов
String SQL = "{call getlastname (?, ?)}";
CallableStatement cs = cn.prepareCall(SQL);
cs.setInt(1, 1658468);
cs.registerOutParameter(2,java.sql.Types.VARCHAR);
cs.execute();
String lastName = cs.getString(2);
о чем Вы скромно промолчали.
Могут. И должны. И все нормальные разработчики именно так и поступают.
Но тогда возникает вопрос - а зачем нам тогда вообще каждый запрос заворачивать в процедуру? Если всё затевалось вроде бы для защиты от инъекций, но оказывается и сам вызов процедуры надо защищать? Именно защищать, без всех этих клоунских "нужно быть идиотом", "если у вас паранойя", "если пугают кавычки".
Но если запрос УЖЕ защищён, если подготовленным запросом можно безопасно выполнить как обычный запрос, так и вызвать процедуру, то зачем тогда нам тогда вообще процедуры? Да, сами по себе, иногда процедуры бывают нужны. Но каждый-то запрос тогда зачем? Если всё равно эта "защита" не работает, и при этом есть действительно надежный способ, который к тому же гораздо проще? Зачем заворачивать каждый запрос в отдельную процедуру? Зачем при изменении запроса не только обновлять код на сервере, но и накатывать миграцию в БД? Зачем писать лишний код и совершать лишние телодвижения?
И это мы ещё не переходили к содержимому процедур, которое вы скромно стесняетесь показывать. И правильно стесняетесь. Потому что сама по себе процедура - не какая-то волшебная палочка, положил в неё запрос, и он "в домике". Сам код процедуры тоже надо писать строго определенным образом. И если этого не делать, то инъекция будет уже в нём.
я показал проверку - Вы в кусты.
зачем заворачивать? если Вам приятно разглядывать в коде строку на несколько экранов без подсветки - Ваше право. Если Вам нравится отлаживать запрос компилируя код - Ваше право.
я предпочитаю все это делать предназначенным для этого инструментом.
да , конечно, код процедуры надо писать строго определённым методом - справа на лево. иначе злой чебурашка в него залезет и скушает.
где увидели в процедурах лишний код?
Вы так усиленно просили выполнить код - я выполнил, он выдал полную несостоятельность Ваших утверждений, причём на практике. поэтому я делаю вывод, что и остальные Ваши претензии имеют такой же уровень осведомлённости. следовательно нет смысла дальше дискутировать.
не поленился , проверил
вот такой код
String f = String.format("{call %s();DELETE FROM TABLE1 ;-- }", "page3_xxx010 ");
вот что получаю:
java.sql.SQLSyntaxErrorException: 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 'DELETE FROM TABLE1 ;-- ()' at line 1 at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:120)
Не надо повторять эту чушь, пожалуйста.
Ув. автор, вместо траты время на написания этой статьи в стиле ответа на Stack Overflow, лучше потратьте время на прочтения вот этой статьи PHP: Правильный Путь.
А еще лучше, чтобы избежать многих простых ошибок, установите и настройте в своей IDE: Psalm, PHPStan или PhpCsFixer.
Ничего личного, просто при виде этого кода мои глаза наполнились слезами, и это не слезы счастья, увы.
Статья напоминает AI компилятор.
Человек пишет код, а потом в комментариях ему пишут его ошибки.
Зачем это тут на Хабре? Ужасный код начинающего программиста
Если данный код настолько ужасен, будьте добры, объясните почему. Без какого либо аргументирования не очень приятно читать подобные комментарии
Вам этих аргументов уже насовали полную панамку.
С БД не умеете работать совсем.
Героическая борьба с кодировками на пустом месте, какой-то ад с пересадками.
Банальное неумение обратиться к массиву по индексу (это совсем уж какой-то детский сад)
Если этого мало - классический винегрет из SQL и HTML, которые в нормальном коде вообще никогда не должны пересекаться. Неумение правильно обрабатывать ошибки.
В итоге без ошибок вам удалось написать только одну команду - glob(). И вы всё ещё не уверены, что с вашим кодом не так? Всё ещё терзают сомнения?
Но самое плохое, из-за чего я уже жалею, что исправил вам карму - ваши ответы похожи на реплики китайского болваничка: "учту", "прочитаю", "приму к сведению". Когда? Когда-нибудь потом? Вы не задали ни одного уточняющего вопроса. Не попытались разобраться ни в одной теме сразу же. Не сделали самостоятельно ни одного вывода из сделанных вам замечаний. Не открыли для себя ничего нового.
Вот всё это - действительно очень плохо. Ошибки в коде - это ерунда. Но если не горят глаза, если нет интереса сразу же закатать рукава и разобраться, если все исправления сразу же откладываются в долгий ящик - вот тогда ошибки и останутся неисправленными.
Я не готов задавать уточняющие вопросы до того, как адекватно прочту на что мне указали и с чем это едят.
Мои глаза не потухли, даже с учётом количества какашек в моей "панамке", просто сейчас я пытаюсь уложить тонну материала в голове.
И да, я прекрасно понимаю, что у меня получился "костыль", "говнокод" и мало что здесь можно найти хорошего. Действительно дали кучу полезных комментариев с указанием того, на что стоит обратить внимание, но при этом я не вижу смысла заходить с вердиктом "Говнокод!" без аргументов, если до тебя это уже сказали (это относится к пользователю varanio).
А за карму отдельное спасибо, потому что это одна из причин, почему глаза не потухли после этой статьи
Как я exif данные из JPEG вытаскивал и в БД запихивал (а потом доставал)