Аудит кода: плагин FAQ-Tastik для WordPress
Сегодня в моем блоге торжественно открывается новая рубрика – “Аудит кода”. В ней я буду смотреть код популярных и не очень PHP приложений, и высказывать свои мысли по этому поводу. Открывает рубрику плагин FUCK FAQ-Tastik для WordPress.
Плагин является самым популярным решением по созданию системы вопросов и ответов на сайте на базе WordPress. У него даже есть свой сайт – http://faq-tastik.com Плагин поставляется в обычной и PRO версии. Отличия расширенной версии в кастомизации дизайна, поддержки и ещё чем-то. А как вы думаете, как реализована защита плагина?
Не угадали. В коде есть функция is_pro()
function is_pro ()
{
return false;
}
и проверки дял кусков кода, которые вызываются то там, то сям.
// Reorder if page group
if(FAQ_Features::is_pro ()){
$group = QuestionGroup::get($group_id);
Не очень удачная по-моему защита. Ставим return true, и имеем “полнофункциональную” версию. Почему в кавычках, спросите вы. В коде есть триггер – наличие файла pro.php Если он есть – значит версия PRO, если нет то lite.
if (file_exists (dirname (__FILE__).’/pro/pro.php’))
include (dirname (__FILE__).’/pro/pro.php’);
else
include (dirname (__FILE__).’/models/lite.php’);
Может быть там есть какой-то дополнительный функционал, не знаю, а может это просто пустой файл, котоырй включает PRO версию.
Теперь пройдёмся по структуре БД. Вопросы хранятся в табличке wp_faqtastik_questions, а их мета-данные (автор и ещё что-то) в табличке с постами wp_posts. Как показала практика при наличии > 10 000 вопросов, весь сайт накрывается из-за этого плагина. Я вообще не понимаю, зачем хранить метаданные, которые ещё и не выводятся нигде именно там. На каждый вопрос создается свой пост, и получается 10 000 вопросов и 10 000 постов. Шедеврально!
Дальше интереснее. При редактировании вопроса (ответ на вопрос) в админке мы видим следующее:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | function edit_question ($id) { $question = Question::get ($id); $group = QuestionGroup::get ($question->group_id); $related = $question->get_related (); $groups = QuestionGroup::get_all (); $newgroups = array (); foreach ($groups AS $pos => $tmp) $newgroups[$tmp->id] = $tmp->name; $groups = $newgroups; $allquestions = Question::get_all(); if (count ($allquestions) > 0) { $newquestions = array (); foreach ($allquestions AS $pos => $quest) { if ( ($quest->id != $id) && ($quest->page_id > 0)) // 2009-06-01 restricted to Paged Questions only. ZB $newquestions[$quest->id] = substr ($quest->question, 0, 40); } $allquestions = $newquestions; } |
Ещё кое что. В плагине полностью отсутствует пагинация страниц с вопросами. Все вопросы будут на одной странице, и через некоторое время сайт с этим плагином будет если не открываться, то сильно подтормаживать, в случае частых обращений к странице с FAQ-Tastik.
Вот это ($allquestions = Question::get_all();) просто чудо. При редактировании конкретного вопроса из базы запрашиваются ВСЕ вопросы, ну хоть с постами не JOIN’ятся и то хорошо. Стоит ли говорить что при over 9000 вопросов ответить мы не сможем. Пришлось подправить плагин wp-paginate, чтобы сделат ьпгаинацию в FAQ. Также в форме вопроса не было капчи, что тоже очень печально. Заспамят по самое не балуй.
Нельзя сказать, что у плагина одни недостатки, есть и плюсы. Он выполнен по MVC архитектуре, чётко лежат модели и виды. Это здорово, я такого в плагинах WP не видел. Но вот в остальном.. тихий ужас.
Аудит на сегодня закончен, и хочется подвести некоторые итоги.
- Думаете, как машина. Представьте, как будет выполняться ваш код.
- Не грузите лишнее.
- Думаете, как будет работать ваш код в нестандартных условиях.
- Не давайте машине выбора. Например если вы ждете только два варианта в if() блоке, не пишите if(), else() а пишите if() elseif() а в else() пусть будет исключение.
Если знаете интересные экземпляры – велкам в комменты.
Спасибо, то что нужно!)
Подскажите как добавить пагинацию в этот плагин? очень надо
Подскажу. Пишите на мыло, есть одна идейка.