Pull to refresh

Comments 15

А есть ли смысл делать не вывод с htmlentities(), а ввод? Ведь тогда получается, что обработка будет сделана только один раз. Или же в БД данные могут попасть не только от вредительствующих игроков?
Затем, что презентация данных не всегда делается через HTML. Может быть, вам надо будет текстовое письмо отправить, может в JSON завернуть, чтобы в API выдать, может в мобильное приложение передать и т.д. Данные должны храниться всегда в сыром виде.
Подпишусь

IMHO — данные внутри движка должны циркулировать в виде «что бы не стыдно было в базу положить». Т.е. со стандартизированной отбивкой строк (CR+LF или LF — кому что ближе. Главное — единообразно по всему движку и независимо от системы), без какого-либо HTML-форматирования (хочется форматирования? Используйте BBCode или аналоги!), естественно — без какого-либо PHP-кода под eval().

Еще очень полезно явно типизировать переменные. Если это целое — значит это именно integer 48, а не string '48'. Если логическая переменная — значит типа boolean true/false, а не integer 1/0 итд
Зачем учить новичков плохому…

поэтому бэкэнд (та часть, которая производит фактическую обработку данных на стороне сервера и записывает изменения в БД) ОБЯЗАН всегда повторять расчёты фронтенда
Наоборот, фронтенд обязан повторять расчеты бэкенда. Вернее даже не так. Фронтенд может повторять проверки бэкенда — для ускорения работы и улучшения UI, а может и не повторять. На бэкенде все проверки всегда должны быть в полном объеме.

Тут сразу начинаются пляски с бубном по поводу символа перевода строки.
Насколько я знаю, браузеры вполне неплохо сами разбираются с разными переводами строк. В любом случае, это исправляется простой заменой разных переводов строк на нужные в функции получения данных из файла.

И тут появляется великий HTML
Не надо путать текст и HTML. Если в файле есть <br&gt, значит это разметка, и не надо работать с ней как с текстом. Если разметка расположена вперемешку с текстовыми файлами, значит это проблема в архитектуре конкретного проекта. Исправить можно аналогично, через замену по регулярному выражению. Переводы строк тут ни при чем.

Кому приятно вместо отформатированного по параграфам текста увидеть что-то вроде
Это ошибка только в форматировании вывода. Любая замена переводов строк эту проблему не решит.

Какое число получится в переменной, если в PHP-бэкэнде написать intval('0123')
Выведет 123. Кстати, вам надо было поставить там ссылку на документацию по intval() (заодно и сами бы почитали).
Если записать без кавычек, то будет 83, но это уже изначально int, записанный в 8-ричной системе. Это аналогично записи 0x123 без кавычек для 16-ричной. Лидирующие нули в строках на результат не влияют. А для преобразования string в int лучше использовать приведение типов "(int)$var".

Отдельная песня — числа с плавающей точкой в PHP и их сравнение
PHP здесь ни при чем, так происходит во всех языках, это особенность представления таких чисел в процессоре.

Ну, это те самые веселые числа, объявленные как BIGINT(20,0) в БД
Откуда у INT дробная часть?
ALTER TABLE `test_table` ADD COLUMN `test_column` BIGINT(20,0) NOT NULL;
/* SQL Error (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 '0) NOT NULL' at line 1 */

«Что бы полностью понять суть проблемы», надо знать, что такое разрядность. Да и вообще, для большинства таблиц простого INT хватает. Не собираетесь же вы в каждой таблице по 3 миллиарда записей хранить?

htmlentities()
Рекомендуют использовать htmlspecialchars().

многострочные строки (даже нормированные) требуют разного отношения при выводе в HTML, JS или при сохранении в БД
Не знаю, что за задачи этого требуют, лично я ни разу не сталкивался. Обычно что сохраняем, то и выводим, плюс экранирование. Для javascript можно выводить через json_encode().
> Зачем учить новичков плохому…

Вполне нормальный ВВОДНЫЙ текст для новичка. В школе тоже не сразу теорвер дают, а в первых классах изучают арифметику.
Такое ощущение, что текст вы не читали или не вдумывались в него и спорите чисто что бы поспорить.

> Наоборот, фронтенд обязан повторять расчеты бэкенда. Вернее даже не так. Фронтенд может повторять проверки бэкенда — для ускорения работы и улучшения UI, а может и не повторять. На бэкенде все проверки всегда должны быть в полном объеме.

Фронтенд первым производит валидизацию данных чисто по-определению фронтенда и бэкэнда. Поэтому именно бэкэнд должен повторять ВСЕ проверки фронтенда как минимум и, возможно, производить свои.

> Насколько я знаю, браузеры вполне неплохо сами разбираются с разными переводами строк. В любом случае, это исправляется простой заменой разных переводов строк на нужные в функции получения данных из файла.

… именно это и является «нормализацией данных» как я писал в статье.

> Не надо путать текст и HTML. Если в файле есть
, значит это разметка, и не надо работать с ней как с текстом. Если разметка расположена вперемешку с текстовыми файлами, значит это проблема в архитектуре конкретного проекта. Исправить можно аналогично, через замену по регулярному выражению. Переводы строк тут ни при чем.

Что значит «путать»? HTML является разновидностью текста. Ну и расскажите, что «не надо работать с разметкой, как с текстом» не мне, а десяткам авторов различных движков сайтов.

> Это ошибка только в форматировании вывода. Любая замена переводов строк эту проблему не решит.

Вы действительно не читали текст. Я же написал: «что случается при одновременной ошибке в нормализации данных и форматировании вывода.» Нормирование текста и замена символов новой строки на единообразные нужны, потому что часто в движка встречается не использование nl2br(), а конструкции вида str_replace("\r\n", '<br>', $string)

> Выведет 123. Кстати, вам надо было поставить там ссылку на документацию по intval() (заодно и сами бы почитали).

Тут кавычки не нужны, согласен. Поправил.

> PHP здесь ни при чем, так происходит во всех языках, это особенность представления таких чисел в процессоре.

А по сути есть сказать что? Я говорил конкретно про PHP — в нём эта проблема есть. В некоторых других языках изначально были специальные типы с фиксированной точностью.

> Ну, это те самые веселые числа, объявленные как BIGINT(20,0) в БД

Много работал с DECIMAL — поэтому автоматически поставил и здесь десятичную точность. Поправил.

> Не собираетесь же вы в каждой таблице по 3 миллиарда записей хранить?

А почему бы и нет?

> Рекомендуют использовать htmlspecialchars().

Абсолютно вредные рекомендации для новичка. htmlentities() дополнительно перекодируют одинарную кавычку — что бывает важным при выводе в JavaScript, а так же спецзнаки типа ©, ®, ™ и некоторых других. Таким образом — htmlentities() безопаснее в применении.

>> многострочные строки (даже нормированные) требуют разного отношения при выводе в HTML, JS или при сохранении в БД

> Не знаю, что за задачи этого требуют, лично я ни разу не сталкивался. Обычно что сохраняем, то и выводим, плюс экранирование. Для javascript можно выводить через json_encode().

Ну, естественно! Если вы не сталкивались — значит проблема не существует!
Только мой опыт ковыряния в чужих движках показывает — что проблема более чем актуальная. И новичку необходимо об этом знать, что бы он не напоролся на те же грабли, что и я в начале работы с чужим кодом браузерок.
Вы меня простите, но на сервере можно хранить текст таким, какой он есть, аля производя минимальные операции по изменению… На фронте же вы можете добавить обработку вызова и это, сюрприз-сюрприз, снимет с вас часть проблем.

> дополнительно перекодируют одинарную кавычку — что бывает важным при выводе в JavaScript
JSON должен быть в двойных кавычках. Если вы не используете json_encode, то проблемы на вашей стороне.
Все равно строка будет с кавычкой.
Скажите вариант, когда это не поможет?!
ю Вы меня простите, но на сервере можно хранить текст таким, какой он есть, аля производя минимальные операции по изменению… На фронте же вы можете добавить обработку вызова и это, сюрприз-сюрприз, снимет с вас часть проблем.

Именно об этом я и говорю другими словами. Хранить данные в «сыром» виде, всю обработку в общепринятый в движке (т.е. «нормализованный вид») проводить при вводе данных, преобразовывать формат для представления — при выводе.

>> дополнительно перекодируют одинарную кавычку — что бывает важным при выводе в JavaScript
> JSON должен быть в двойных кавычках. Если вы не используете json_encode, то проблемы на вашей стороне.
> Все равно строка будет с кавычкой.
> Скажите вариант, когда это не поможет?!

Когда движок — чужой и вообще по-первах непонятно, как там и что устроено.
Когда программист — новичок и вообще не представляет, что вообще можно сделать.

Еще раз — это БАЗОВАЯ и ПРОСТАЯ теория для НОВИЧКОВ, которые сами решили взяться за доработку чужого движка.

Статья написана на основании собственного опыта ковыряния чужих движков — как новичком, так и в более опытном состоянии. Я искренне уверен, что мне бы вот такая статья очень сильно бы помогла в начале пути. Дала бы базовую теорию, указала на основные принципиальные подходы итд итп

Да, здесь нет глубокомысленных рассуждений о необходимости, скажем, Dependency Injection или автолоадеров по формату PSR-4… Так и в самописных движках, что доступны широкой публике обычно речь идёт не о том, что не используется DI или юнит-тесты, а о том. как бы рагрести HTML-CSS-PHP-SQL спагетти-код и хоть как-то закрыть игру от явных SQLi.
Ну, в плане новичков — согласен. За свои N лет разработки я уже переобучился писать так, чтобы никому не было больно…
В школе тоже не сразу теорвер дают

Я не сказал, что текст сложный, я сказал, что он дает неправильную информацию при объяснении особенностей. Конкретно:
— Про бэкенд. Из текста и из вашего комментария складывается впечатление, что бэкенд вторичен. На самом деле он «главнее», потому что в нем находится логика. Если на фронтенде нет проверок, а на бэкенде есть, проблем с данными не будет. А если на бэкенде нет проверок, а на фронтенде есть, то можно отправить неправильные данные вручную, без фронтенда. У вас в статье примерно то же самое, но акцент сделан не на том.
— Про intval. Тут вы поправили, но intval тут роли не играет. «echo 0123» тоже выведет 83. Это документированное обозначение 8-ричных чисел, так же как 0x123 обозначение для 16-ричных. Такое же обозначение используется, например, и в C++, и в Java, и в JavaScript. Из текста же складывается впечатление, что это какая-то фишка PHP, сходная с багом.
— Числа с плавающей точкой — проблема PHP. «Я говорил конкретно про PHP — в нём эта проблема есть». Это что-то вроде «у меня ваша программа не работает — так электричества же нет, поэтому компьютер не включается — ну и что, я же в вашей программе работаю».
— В проблеме с разрядностью про разрядность ничего не сказано. Не сказано, что в большинстве случаев такая разрядность не нужна, особенно в проектах начинающих. Если бы я не знал причину, у меня бы сложилось впечатление, что это опять какой-то косяк PHP.

HTML является разновидностью текста

А текст является разновидностью байтов. Это не значит, что надо с любыми данными работать как с байтовым массивом. У вас как-то все сумбурно — как будто разметка это разновидность перевода строк.

Ну, естественно! Если вы не сталкивались — значит проблема не существует

Там написано, что я с этой проблемой не сталкивался, я не сказал, что ее не существует. Вообще это был своего рода намек «Уважаемый автор, не расскажете ли вы, с какими именно задачами вы столкнулись, что там переводы строк это серьезная проблема. Я вот не сталкивался, вдруг понадобится, хоть буду знать». У вас половина статьи о том, что это важно, но нет никаких примеров, которые бы эту проблему иллюстрировали. Пара неправильно отформатированных строк это не примеры, потому что непонятно, как они появились.
> — Про бэкенд. Из текста и из вашего комментария складывается впечатление, что бэкенд вторичен. На самом деле он «главнее», потому что в нем находится логика. Если на фронтенде нет проверок, а на бэкенде есть, проблем с данными не будет. А если на бэкенде нет проверок, а на фронтенде есть, то можно отправить неправильные данные вручную, без фронтенда. У вас в статье примерно то же самое, но акцент сделан не на том.

У вас какое-то неправильно понимание. С точностью до «наоборот»: бэкенд должен КАК МИНИМУМ повторять все проверки фронтенда. Часто авторы движков полагаются на фронтенд, ослабляя проверки на бэкенде. Именно об этом данный параграф.

> Про intval. Тут вы поправили, но intval тут роли не играет. «echo 0123» тоже выведет 83. Это документированное обозначение 8-ричных чисел, так же как 0x123 обозначение для 16-ричных. Такое же обозначение используется, например, и в C++, и в Java, и в JavaScript. Из текста же складывается впечатление, что это какая-то фишка PHP, сходная с багом.

Опять — у вас какое-то странное понимание. Я написал про ОСОБЕННОСТЬ работы с числами — что 0123 не равно 123. И всё. Остальное вы сами додумали.

> Числа с плавающей точкой — проблема PHP. «Я говорил конкретно про PHP — в нём эта проблема есть». Это что-то вроде «у меня ваша программа не работает — так электричества же нет, поэтому компьютер не включается — ну и что, я же в вашей программе работаю».

Отсутствие врождённой способности оперировать с числами фиксированной точности и необходимость использовать для этого сторонние библиотеки и/или подключаемые плагины — это конкретно проблема PHP и достаточно серьезная, если игра оперирует числами типа float — в частности, если сравнивает такие числа. Особенно остро эта проблема стоит, когда в MySQL поле объявлено как DECIMAL — т.е. с фиксированной точностью.

> В проблеме с разрядностью про разрядность ничего не сказано. Не сказано, что в большинстве случаев такая разрядность не нужна, особенно в проектах начинающих. Если бы я не знал причину, у меня бы сложилось впечатление, что это опять какой-то косяк PHP.

Я уже не понимаю — какую статью вы читали? Указано на разницу в количестве разрядов в primary-ключе MySQL и максимальным количеством разрядов в целом числе PHP.
Нужна такая разрядность или нет — очевидно, решать не вам. И не мне. И даже не новичку, который разбирается в чужом движке. Это решил за него автор — и вопрос, на который должен ответить новичок — соблюдает ли автор движка свои же соглашения и везде ли корректно оперирует с полной разрядностью идентификаторов.
Я обозначил проблему. А то, что работать с целыми числами за пределами PHP_INT_MAX можно только с использованием специальных библиотек (а не просто используя стандартные операторы) — это действительно косяк PHP.

> Там написано, что я с этой проблемой не сталкивался, я не сказал, что ее не существует. Вообще это был своего рода намек «Уважаемый автор, не расскажете ли вы, с какими именно задачами вы столкнулись, что там переводы строк это серьезная проблема. Я вот не сталкивался, вдруг понадобится, хоть буду знать».

Очевидно — я видел это в одном из движков, которые ковырял. И проблема была именно в ненормированности данных — часть многострочных строк выводилась в JS нормально, часть — нет. В результате в лучшем случае не работал JavaScript на странице, а в худшем — появлялся мусор или вообще открывалась уязвимость для внедрения своего скрипта, потому что разработчик «запамятовал», что вводимые данные от игрока могут быть и некорректными.

> У вас половина статьи о том, что это важно, но нет никаких примеров, которые бы эту проблему иллюстрировали. Пара неправильно отформатированных строк это не примеры, потому что непонятно, как они появились.

Вы читал начало статьи? А её окончание? По-моему — нет. Иначе было бы очевидно, что эта — одна из статей цикла. Дальше будет (наверное — через неделю. Не снялся recovery mode) еще теория, а потом пойдут сплошные примеры.
Интересно, почему статью минусуют. Она, конечно, никакого отношения к играм не имеет, но как ликбез по хранению и вводу/выводу данных веб-приложения — вполне правильная.
Выше уже разобрали ошибки статьи, да и суть статьи умещается в одну банальную строчку «не доверяйте пользовательским данным из веба», которая встречается в почти каждом руководстве «php для чайников». Для ликбеза как минимум не сказано о том что картинки и любые пользовательские файлы, сохраняемые на сервере, ттоже должны досконально проверяться. Стороние ссылки тоже проверяться и зарещаться, все sql запросы подвержены sql инъекциям и т.д., вообще правил создания безпопасного приложения намного больше чем описано в статье.
Ошибки либо мелкие, либо холиварные, часть уже поправлена. К чему минусовать полезную для кого-то статью в которой есть не всё, вместо того чтобы дополнить её/привести ссылку на более полную статью?
Просто «не доверяйте» — это общие слова. А тут приведен хороший список вполне конкретных граблей. Плюс ещё описано, что данные должны храниться в сыром виде, а необходимые трансформации должны делаться на вводе/выводе. Причём encoding должен делаться именно на выводе. Это всё совершенно правильные вещи, в которых сплошь и рядом программисты делают ошибки, которые приводят к уязвимостям разного рода.
Вообще-то это очередная статья цикла. И в конце анонсированы темы для дальнейшего рассмотрения — в том числе и SQL-injections. Все-все-все рекомендации можно, конечно, уместить в одну статью — но она тогда будет на сотни символов и её мало кто прочитает. Плюс — будет слишком много информации и поэтому она будет тяжело усваиваться.

В «разборе» ошибок два указания на действительные неточности (опечатки по факту), несколько придирок и один вреднейший совет для НАЧИНАЮЩЕГО программиста, который имеет дело с ЧУЖИМ как правило НИЗКОКАЧЕСТВЕННЫМ движком, в котором обычно сделаны все возможные базовые ошибки новичка.
Sign up to leave a comment.

Articles