Содержание статьи
16 лет назад я написал на Хабре статью «Нетрадиционные животные в доме» – про то, каких экзотов держат дома и с какими проблемами сталкиваются их владельцы. Статья неожиданно собрала довольно живые комментарии и подняла мне карму.
С тех пор мало что поменялось, разе что оборудование, корма, террариумы и животных стало проще находить, в остальном же всё осталось по-прежнему. Есть старые форумы и разрозненные группы во «ВКонтакте». Есть несколько сайтов, часть из которых давно заброшена. Но нет места, где можно собрать «коллекцию» своих животных, вести журнал наблюдений, найти пару для разведения, составить вишлист и просто быть среди своих.
Прошло 16 лет. Проект, наконец, дозрел.
Что получилось
ЭкзоПуть – платформа для заводчиков экзотических животных.
Если без громких слов, это простенькая платформа, заточенная под террариумистов. Можно вести профиль, добавлять анкеты животных, заполнять журнал наблюдений, составлять вишлист, искать пары для разведения и делиться контактами на других площадках. Удобно, если вы что-то продаёте через Авито или свой магазин в том же ВК.
Никакой рекламы. Никаких платежей.
Проект родился не из желания заработать, а из собственной потребности. Я сам держу рептилий уже более 20 лет и давно хотел нормальный инструмент для учёта коллекции. Надоело записывать в Excel, какие у кого проблемы, кто когда сделал кладку, какие морфы и т.д.
В какой-то момент стало проще написать свой сервис. В начале это была закрытая система на моём сайте, а потом после очередного Рептилиума (выставка-продажа), мне предложили расшарить для всех.
Как это сделано и почему без фреймворка
С PHP мне проще, в своё время было достаточно опыта, поэтому выбор языка был очевиден.
Выбор «без фреймворка» тоже осознанный. Задачи проекта мне понятны, усложнения не нужны. Laravel со своим сервис-контейнером, Eloquent и прочими оркестрациями здесь, на мой взгляд, скорее, мешал бы. Можете смело сказать, что я не прав, даже спорить не буду.
Поэтому собрал всё сам:
— Собственный роутер с поддержкой параметров {username}, {id}, {slug}. Простой, ровно такой, какой нужен, без магии.
— Twig в качестве шаблонизатора. Он и без Laravel отлично живёт и спокойно лежит в /vendor/.
— PHPMailer для отправки писем (мопед не мой).
— PDO поверх MariaDB 10.1. Тут тоже не без приключений: на старой версии MariaDB в окружении хостинга пришлось включить эмуляцию prepared statements. С нативными часть запросов начинала вести себя странно, а разбираться с археологией десятилетнего стека мне в какой-то момент надоело.
— Дико перегруженный AdminController, когда-нибудь разобью его.
Всё.
Три внешние зависимости, вручную упакованные в /vendor/.
Никакого Composer.
Никакого PSR-4-автозагрузчика, кроме собственного самописного примерно на два десятка строк.
Точка входа – index.php. Он поднимает автозагрузчик, разбирает запрос, прогоняет его через роутер и отдаёт ответ.
Классика, проверенная годами.
С чем пришлось повозиться
Когда начинаешь делать «простенький сайт для своих», довольно быстро выясняется, что простенький сайт почему-то требует роутер, систему ролей, антиспам, кэширование, модерацию и больше 45 таблиц в базе.
Маршрутизация и редиректы
Свои URL – это связка из .htaccess, который перенаправляет запросы на index.php, и внутреннего роутера с regex-матчингом.
Пришлось предусмотреть нормализацию слешей, редиректы со старых URL и блокировку открытых редиректов. Сами редиректы живут в базе данных. Поддерживаются 301, 302 и 410, ведётся подсчёт переходов. Управляется всё через админку.
Зачем для небольшого проекта отдельная система редиректов?
Потому что однажды ты меняешь структуру URL. Потом ещё раз. Потом находишь старую ссылку в поисковике. А потом понимаешь, что проще было один раз нормально сделать таблицу redirects.
Защита от ботов и спама
Здесь получилась многоуровневая система.
Есть файловый rate limiter со скользящим окном:
— регистрация – пять запросов с одного IP за сутки;
— формы – 30 запросов в минуту;
— сайт в целом – 200 запросов в заданном окне.
Есть honeypot-поля в формах.
Есть блокировка примерно 180 доменов одноразовой электронной почты.
Есть CSRF-защита с HMAC-токенами и сравнением через hash_equals, чтобы не создавать себе лишних приключений с тайминг-атаками.
Проверяется и время заполнения формы. Если форма была открыта и отправлена быстрее чем за три секунды, запрос считается подозрительным.
Отдельная история – фильтрация по User-Agent.
Хардкорно? Да. Зато количество мусора сокращается радикально. К тому же держите в уме, что я давно уже не разработчик, поэтому пилю «как могу».
Понимаю, что User-Agent прекрасно подделывается. Это не «защита», а дешёвый первый фильтр против примитивного автоматизированного мусора.
Запрещённые виды животных
Отдельным квестом стало законодательство.
В мае 2025 года появилось Распоряжение Правительства РФ № 1163-р с перечнем животных, запрещённых к содержанию. Пришлось загрузить список видов в отдельную таблицу, прикрутить AJAX-проверку при добавлении питомца, показывать предупреждение и требовать обязательного подтверждения, что пользователь ознакомлен с ограничениями и берёт ответственность на себя.
Плюс появилась отдельная админка для управления списком.
Понятно, что галочка «я ознакомлен и несу ответственность» не превращается в магический юридический щит в РФ и влететь может именно мне, а не заводчику.
Про два кэша и их инвалидацию, а также структуру базы в 45 таблиц, писать на Хабре как-то смешно.
Что будет ломаться с ростом трафика
Сейчас проект маленький и всё «летает» на shared-хостинге. Но я уже примерно понимаю, где будет больно.
Файловый кэш
Сейчас HTML-страницы для гостей хранятся в файлах. Пока их сотни – нормально.
Когда появятся тысячи и возникнет параллельная нагрузка, файловая система начнёт буксовать.
План очевидный: Redis. Или хотя бы SQLite в качестве промежуточного варианта.
База данных
MariaDB 10.1 на shared-хостинге – комбинация почтенная. Когда запросов станет много, начнутся блокировки и веселье с производительностью.
Нужно будет внимательнее смотреть типовые запросы, добавлять индексы и разбираться с поиском. До настоящего шардирования проекту, надеюсь, ещё очень далеко.
Если мне действительно придётся шардировать базу террариумистов, значит, где-то я свернул не туда. Или, наоборот, очень правильно.
Модерация вручную
Пока фотографии может смотреть администратор вручную.
Когда активных пользователей станет хотя бы несколько сотен, это превратится в отдельную работу.
План – вводить уровни доверия:
— премодерация для новичков;
— упрощённая публикация для проверенных пользователей;
— автоматическая проверка подозрительного контента;
— возможно, ML-проверка на NSFW.
Делать полноценную автоматическую модерацию прямо сейчас бессмысленно. Но архитектурно возможность для неё оставлена.
Rate limiter
Сейчас он файловый. При нормальной конкурентной нагрузке начнёт спотыкаться об одновременный доступ к файлам. Переезд на Redis – вопрос времени.
Обработка фотографий
Если пользователь загрузит 20-мегапиксельную фотографию с современного телефона, PHP вполне может упереться в память или таймаут.
Сейчас обработка синхронная. В будущем нужно выносить её в очередь и обрабатывать через ImageMagick отдельным воркером.
Поиск по видам
Сейчас используется AJAX-поиск через LIKE с лимитом результатов.
Для текущего объёма данных этого хватает. Когда справочник и пользовательские данные разрастутся, придётся переходить на нормальный полнотекстовый поиск.
Sphinx, Manticore или хотя бы возможности самой базы – посмотрим по реальной нагрузке. Я стараюсь не решать проблемы, которых пока не существует.
Что я понял за время разработки
Самая большая проблема pet-проекта – не технологии. Не PHP. Не отсутствие Laravel. Не MariaDB десятилетней давности.
Самая большая проблема – продолжать что-то делать после того, как закончилась первая эйфория. Когда основная идея уже работает, начинается рутина.
Исправить форму. Добавить индекс. Переделать кэш. Поймать баг. Понять, что предыдущим исправлением ты создал ещё два бага. Проверить письма. Снова проверить письма.
Сегодня, например, я заметил, что не работает регистрация. А письма на Mail.ru не приходят, хотя домен добавлен в Postmaster, а там гордо отображается ноль ошибок. При этом у Google и Яндекс письма приходят и даже не попадают в спам.
То есть формально всё прекрасно. Кроме того, что письма не приходят. Пилить проект двумя кривыми руками – та ещё боль. Но, похоже, именно так и появляются pet-проекты.
Резюме
Проект живёт на чистом энтузиазме. Без бюджета. Без команды. На обычном хостинге.
Он нужен мне самому и, надеюсь, пригодится ещё паре сотен таких же увлечённых киперов.
Делать «по любви» – пожалуй, единственный способ довести такой проект до конца, когда первые недели эйфории прошли, а впереди остались баги, кэш и рефакторинг.
Проект: exoway.ru
Конструктивным замечаниям, найденным багам и пожеланиям буду рад.
