modZone.ru
138 subscribers
15 photos
3 files
57 links
Канал сайта modZone.ru
Download Telegram
Возможные проблемы безопасности сниппета pdoUsers мы уже обсуждали. Сейчас я хочу рассказать о возможных проблемах универсальности модификатора user (userinfo) шаблонизатора Fenom из pdoTools.

Как многие уже знают по модификатору resource, модификатор user также может работать и с именем поля и с id. Слава Богу, этот модификатор в отличие от сниппета удаляет важные данные (пароль, соль, id сессии), но некоторые данные он всё равно оставляет (remote_key, remote_data, hash_class). И они в некоторых случаях могут быть использованы злыми контент-менеджерами - {1 | user : 'remote_key'}.

Вот чтобы избежать этого в ZoomX есть 2 отдельных модификатора - user и userinfo. Первый выдает немного обрезанную информацию для текущего пользователя сайта. А второй ищет пользователя по id и максимально урезает выдаваемые данные, чтобы контент-менеджер не смог получить данные любого пользователя. Наш девиз -"Лучше перебдеть, чем не добдеть!". 😄
This media is not supported in your browser
VIEW IN TELEGRAM
Я не выдержал и всё-таки чуть исправил процесс сборки пакета в браузере. Надоело видеть пустую страницу несколько секунд без какой-либо обратной связи. Теперь загружается HTML страничка и выводится наглядная информация о процессе сборки. Хочу для себя форкнуть modExtra, добавить туда эту фичу и убрать все ненужные зависимости типа Office.

Ещё очень удивлён, что никто до сих пор не сделал запуск скрипта в index.php файле, чтобы не писать modExtra/_build/build.php.
Небольшая дискуссия на тему Smarty vs Fenom. Правда оппонент приводит данные для классического использования Fenom и не учитывает его реализацию для MODX.

https://modzone.ru/blog/2021/01/20/comparison-of-template-engines/#comment-673
В последние дни я много времени уделяю MODX и особенно 3-ей версии. А ещё меня включили в список интеграторов на GitHub. В связи с этими фактами я в ближайшее время выпущу адаптированные к третьей версии MODX свои дополнения controlErrorLog и modalConsole. Они очень выручают при разработке и тестировании. Дополнение tagElementPlugin по идее должно работать на тройке. А вот другие мои дополнения требуют глобальной переработки. Поэтому их я оставлю на следующую итерацию выпуска MODX3.
Вышла новая мажорная версия библиотеки modHelpers. Основные изменения
- Добавлена новая функция "build_tree", формирующая древовидную структуру данных.
- Добавлена новая функция "reading_time" для подсчёта времени чтения текста.
- Добавлена новая функция "sanitize_path", исключающая возможность манипулирования путями.
- Добавлена новая функция "value". Аналог одноимённому хелперу из Laravel, но позволяет указать дефолтное значение для null.
- Удалена функция "faker" и соответствующее дополнение Faker. Используется крайне редко и только при разработке. В продакшене не нужен. Даже урезанный занимает больше половины объема пакета. Кроме того, автор перестал её поддерживать.
- Функция "dump" теперь может принимать несколько аргументов.
- В функции "login" и "logout" добавлен параметр "ctx", позволяющий указать контекст.
- Исправлен баг с добавлением вложений в классе Mailer (#2).
Как и обещал, выпустил controlErrorLog, адаптированный для MODX3. Может пригодится.
Статья, раскрывающая подробности новой версии modHelpers.

https://modzone.ru/blog/2021/05/03/modhelpers-v4-0-0/
Частенько, ковыряя код ядра MODX, встречаешь такие вещи, которые просто просятся в рубрику "Так лучше не делать". Несколько лет назад я даже записывал их. Правда теперь найти не могу.

Хотел спросить - было бы интересно выкладывать такие вещи здесь с моим альтернативным решением? Предвосхищая обвинения в подрыве репутации MODX сразу скажу, что тут речь больше про прокачку PHP навыков, а MODX просто как источник примеров.
Рубрика "Так лучше не делать"

Итак, первое, с чего бы хотелось начать, использование ссылок в аргументах методов. Это встречается практически во всех классах MODX, которые не являются объектами базы данных. А ещё при вызове событий, если в них передаются объекты. А также во многих компонентах MODX.

Это наследие PHP4. В PHP5 работу с объектами переосмыслили. Теперь они хранятся в хэш таблицах. А переменная объекта хранит всего лишь ссылку на объект в этой хэш таблице, а не сам объект. Поэтому начиная с PHP5 нет необходимости принудительно передавать ссылку. Но даже в MODX3, требующей PHP7.1, данный легаси остался нетронутым.

Обратите внимание на картинку. Плагин PHP Inspections (PhpStorm) так об этом и говорит.

П.С. Про ссылки можно более подробно прочитать у меня на сайте https://modzone.ru/blog/?tag=PHP
Помню, в сообществе периодически возникала дискуссия на тему - почему компонент, который создаёт в базе данных свои таблицы, не чистит базу от этих таблиц при своём удалении?
За последние пару лет я не встречал подобных вопросов. А кто-нибудь знает, как правильно удалять таблицы при деинсталяции компонента?
Класс modX
Рубрика "Так лучше не делать"

Разберём следующий пример легаси кода. Практически в любом классе MODX вы найдёте открытые наружу (public) свойства. Это нарушает один из принципов ООП - инкапсуляцию. И рикошетом бьёт по остальным.

Напомню, что всего этих принципов 4:
1. Абстракция
2. Инкапсуляция
3. Наследование
4. Полиморфизм

Современные стандарты программирования допускают использование открытых свойств только в исключительных случаях. Например, при использовании объектов DTO. В большинстве случаев свойства должны быть закрыты. А управление ими лучше организовать при помощи открытых методов. Таким образом вы сможете создавать абстракции с помощью интерфейсов, использовать наследование и полиморфизм. Кроме того, если вдруг потребуется, вы всегда можете повысить уровень видимости в классе-наследнике. А вот обратная операция невозможна - Fatal Error. А изменение модификатора в исходном классе нарушает обратную совместимость.

Открытые свойства в некоторых случаях могут пригодится для тестирования. Но их главный недостаток - невозможность их контролировать. Обратите внимание на картинку выше. Вы можете напрямую указать любые классы менеджера запросов (Request), менеджера ответа (Response), контекста, парсера, вместо массива с конфигами указать строку. Ну и т.д. Кстати говоря, метод modX::getRequest() проверяет класс и создаёт нужный, но открытое свойство сводит на нет данную проверку.

Ну и последнее замечание. Пустому свойству нет необходимости присваивать значение null. Достаточно просто его объявить без значения -private $property;.
Рубрика "Так лучше не делать"

Допустим, у вас стоит задача сформировать путь к файлу $path . $file и надо проверить, есть ли в конце $path слеш. В MODX эту задачу решили так
public function postfixSlash($path) {
$len = strlen($path);
if (substr($path, $len - 1, $len) != '/') {
$path .= '/';
}
return $path;
}

Идёт проверка последнего символа в строке пути. Если это не слеш, то нужно добавить его к строке. Но есть решение гораздо короче и проще
rtrim($path, '/') . '/';
К пути всегда добавляется слеш, но если путь оканчивается слешем, то функция rtrim его удалит. Коротко и ясно. И не нужно писать отдельный метод.
В коде MODX можно найти много примеров, когда нужно получить первый символ строки. Например в парсере, в зависимости от первого символа в теге элемента, определяется соответствующая логика.
$token= substr($tagName, 0, 1);

В PHP есть возможность обращаться к строке как к массиву
$token= $tagName[0];

Так проще и нагляднее.
Рубрика "Так лучше не делать"

Ещё одно наследие из далёкого PHP4. Тогда не было модификаторов доступа (public, protected, private), и названия закрытых методов начинали с нижнего подчёркивания. А так как есть инерция мышления, то даже при переходе на PHP5 такой подход остался в силе. В MODX можно найти public методы, начинающиеся с нижнего подчёркивания. В современных стандартах разработки такой подход считается плохим примером кодирования.

Кстати, так делают и в ванильном javascript. Там нет модификаторов.
Рубрика "Так лучше не делать"

В исходниках MODX можно нередко встретить такой код. Но давайте разберёмся почему это яркий пример говнокодинга.

В данном случае функция empty() возвращает или true или false. Т.е. мы уже получаем булево значение. В итоге парсер PHP видит это так -
true ? true : false;
// или так
false ? true : false;
Т.е. если true, то возвращаем true. Если false, то false. Явный перебор.

Часто попадаются такие конструкции
$var == 'value' ? true : false;
И тут первая часть возвращает булево значение. Но бывают случаи использования тернарного оператора без явного булева значения. Например, в кэш менеджере есть такая конструкция -
$results['system_settings'] = $this->generateConfig($partOptions) ? true : false;
В данном случае достаточно явно привести значение к булеву типу -
$results['system_settings'] = (bool)$this->generateConfig($partOptions);
Кто-нибудь может мне объяснить, чем сборщики скриптов на javascript принципиально лучше сборщиков на PHP? Лично я вижу только повальную моду на JS.
У них обязательная зависимость от NodeJS. Они не умеют собирать скрипты на лету. И как следствие не могут собирать их со страницы как может делать тот же MinifyX. Для меня это явные минусы. Так в чем их преимущество?
Рубрика "Так лучше не делать"

Практически все авторы компонентов для MODX складывают все свои классы в папку model, которая, исходя из названия, предназначена для классов моделей, т.е. объектов в базе данных. Классы сервисов и другие вспомогательные классы должны размещаться в отдельных папках - services, src и т.п.
Рубрика "Так лучше не делать"

Начиная с седьмой версии PHP активно двигается в сторону строгой типизации. До этого разработчикам в помощь были только статические анализаторы. MODX в этом плане выступает антипримером. На картинке выше видно, что используется строковый ключ для обращения к массиву с числовыми ключами. PHP так позволяет делать используя неявное преобразование типов. И если пробежаться по коду, то можно найти и другие примеры. Часто вместо true и false указывают 1 и 0.
curl_setopt($ch, CURLOPT_NOBODY, !empty($options['curlopt_nobody']) ? $options['curlopt_nobody'] : 0);
Иногда неявное преобразование используется в проверках
if ($foo) {...}  // А если $foo = 'false'?
В общем, старайтесь избегать неявного преобразования типов. Это вводит в заблуждение разработчиков и может приводить к ошибкам.
Рубрика "Так лучше не делать"

В MODX в условиях проверки можно часто встретить такой код. Что же тут не так? А дело в том, что эта проверка избыточна. Если заглянуть в документацию, то мы узнаем, что функция isset проверяет существование переменной. А вот что написано про функцию empty
"Проверяет, считается ли переменная пустой. Переменная считается пустой, если она не существует или её значение равно false."

Т.е. она делает то же самое, что и isset, плюс проверяет на false.

В ядре MODX таких проверок очень много -
isset($_REQUEST['ctx']) && !empty($_REQUEST['ctx'])
...
isset($source['baseUrlRelative']) && !empty($source['baseUrlRelative'])
...
isset($_SERVER['HTTPS']) && !empty($_SERVER['HTTPS'])
...
isset($_FILES) && !empty($_FILES)
...
if ($filters && isset($filters[1]) && !empty($filters[1]))
и т.д.


Я был очень удивлен, что даже Томас Джакоби (Jako), являющийся одним из контрибьютеров MODX, не знал этого.
Уверен, многие знают библиотеку pdoTools. В основном её использование ограничивается сниппетами, входящими в библиотеку, и шаблонизатором Fenom. Но продвинутые разработчики используют ещё и API. Самые основные - это методы getChunk и runSnippet. Они не только расширяют функциональные возможности аналогичных методов MODX, включая байндинги (@INLINE, @FILE и т.д.), но и оптимизируют их.
Но не все разработчики знают, что для сниппетов добавлена возможность управления кэшированием как в тегах шаблонизатора. Т.е. для вызова некэшированного сниппета нужно перед именем указать знак "!". Это главное отличие от modX::runSnippet(), который никогда не кэширует результат. А некоторые забывают про это и в результате получают кэшированные данные.
А вот pdoTools::getChunk() безразличен к признаку кэширования. Он никогда не кэширует полученный результат.

П.С. Вообще и у шаблонизатора Fenom из pdoTools присутствует непродуманность функционала кэширования. Об этом я писал на своём сайте про сравнение шаблонизаторов.