Обновить
64K+

PHP *

Скриптовый язык общего назначения

54,32
Рейтинг
Сначала показывать
Порог рейтинга
Уровень сложности

chunk() пропустил половину рассылки

Уровень сложностиСредний
Время на прочтение10 мин
Охват и читатели9.1K

Раз в минуту четыре фоновые команды обходят таблицу на сотни тысяч чатов и решают, кому бот напишет первым: у кого обновились суточные лимиты, кто начал разговор и замолчал, у кого кончилась подписка.

Год назад выяснилось, что за один проход каждая обслуживает ровно половину тех, кого сама же выбрала. Ошибок при этом нет, лог чистый, метрика отправленных растёт. Виноват chunk(), который листает выборку через OFFSET: обработанная строка из этой выборки выпадает, и окно уезжает.

Разбор на живом проекте с 300 тысячами пользователей в месяц: как chunk() теряет строки и чем его заменить, почему withoutOverlapping() по умолчанию блокирует команду на сутки, откуда берутся дубли рассылки и зачем пришлось переворачивать порядок колонок в составном индексе.

Читать далее

Новости

Разбираемся с MCP на практике: сервер документации Swagger на Laravel

Уровень сложностиСредний
Время на прочтение16 мин
Охват и читатели8K

Разбираемся, как дать AI-ассистенту доступ к документации API, не загружая в контекст всю спецификацию. Импортируем Swagger PetStore в PostgreSQL и собираем на официальном пакете laravel/mcp сервер с четырьмя инструментами: поиск по документации, детали операции, именованная схема и список операций по тегу. Проверяем контракт в MCP Inspector и подключаем сервер к Claude Code.

Читать далее

Ложка мёда в бочке уязвимостей: разбираем цепочку SSRF → IAM → RCE + бонус

Уровень сложностиПростой
Время на прочтение14 мин
Охват и читатели7.6K

Привет, Хабр! Меня зовут Владимир Аламов, я инженер по информационной безопасности и комьюнити-лидер сообщества Security Champions в  Авито. 

Недавно AvitoTech совместно с SPbCTF организовали соревнование по спортивному хакингу HoneyBadger CTF. Участникам нужно было найти в системе дыру и через неё дотянуться до спрятанных данных. Лиги сделали две: «Медовую» для новых игроков и «Барсучью» для продвинутых.

В этой статье я расскажу про одно из самых сложных заданий «Медовой лиги» — МёдХантер. Это игрушечный сервис для поиска работы. В нём нужно пройти целую цепочку и достать из одной системы сразу три флага. Начинается всё с безобидного импорта резюме по ссылке, а заканчивается запуском своего кода на чужом сервере.

Читать далее

Два дня искали баг в Telegram-боте и нашли

Уровень сложностиПростой
Время на прочтение4 мин
Охват и читатели5.6K

Мы занимаемся веб-разработкой, CRM-системами и интеграциями. В одном из текущих проектов имеем CRM, где Telegram используется не просто для уведомлений, а как один из каналов взаимодействия с пользователем.

Наш telegram бот перестал работать.

Причём перестал весьма интересно: Telegram прекрасно принимал наши исходящие обращения через API, бот мог отправлять сообщения пользователю, но в обратную сторону — Telegram → наш webhook — запросы практически перестали доходить

Читать далее

Вебхук, в котором нельзя работать

Уровень сложностиСредний
Время на прочтение9 мин
Охват и читатели7.1K

Каждое нажатие кнопки в телеграм-боте — это HTTP-запрос от Telegram к вам. Около трёхсот тысяч человек в месяц, у каждого в сессии десятки нажатий, и всё это приходит в один POST-эндпоинт, у которого нет ни права на пятисотку, ни права подумать.

Пропускная способность считается до обидного просто: max_connections, делённое на время ответа. Отвечаете за 200 мс при сорока соединениях — двести апдейтов в секунду. Отвечаете за две секунды — двадцать. И ждёт при этом не абстрактный клиент, а конкретный пользователь, у которого следующее нажатие просто не доедет.

Что осталось внутри вебхука и что уехало в очередь, почему дедупликация по update_id обязана быть атомарной, зачем в ответ на вебхук можно вернуть вызов метода API — и четыре бага, которые нашлись в собственном коде, пока я это писал.

Читать далее

PHP: четыре Active Record в одной клетке — кто быстрее достаёт ваши данные

Уровень сложностиСредний
Время на прочтение10 мин
Охват и читатели7K

В прошлый раз я вытащил Active Record из Yii1 в отдельный composer-пакет и показал, что код Yii1 умеет жить без фреймворка. Но интереснее другое — насколько хорошо он это делает рядом с остальными. Поэтому я поднял четыре ORM на одной схеме, одних данных и одном железе и прогнал их через phpbench — код и данные лежат на GitHub. В клетке: Eloquent (Laravel), Yii2, Yiisoft Active Record (Yii3) и мой форк Active Record из Yii1 — yii1x/active-record, далее в статье — просто Yii1x.

Можно подумать: раз в предыдущем абзаце прозвучало «мой форк», то и замеры предвзяты. Признаюсь, изначально такой план и был — а потом я всё-таки постарался сделать всё максимально честно. Насколько получилось — судите по цифрам.

Читать далее

Чтобы поменять запятую в боте, нужен был деплой

Уровень сложностиСредний
Время на прочтение10 мин
Охват и читатели6.3K

255 — столько у нас было пар «экран × язык» в телеграм-боте, и каждая строчка текста лежала внутри PHP-класса. Чтобы поправить запятую в немецком, нужен был PR, ревью и деплой.

Рассказываю, как мы выносили экраны и переходы бота из кода в YAML на живом проде, без окна обслуживания: почему \n в PHP не равен \n в YAML, зачем понадобилось экранирование поверх экранирования, как 64 байта callback_data определили схему базы и почему стек навигации из JSON-колонки пришлось мигрировать совместимостью, а не конвертацией. Плюс чеклист из 12 пунктов.

Читать далее

Очереди, которых нет в конфиге: динамические супервизоры Laravel Horizon

Уровень сложностиСложный
Время на прочтение34 мин
Охват и читатели6.2K

Очереди задач — одна из тех вещей, которые настраивают один раз и боль­ше не тро­га­ют. Кон­фиг опи­сывает извест­ные по­то­ки фоно­вых ра­бот, деп­лой раска­тывает его, вор­керы подни­мают­ся и дела­ют своё дело. Так рабо­та­ет в по­дав­ляю­щем боль­шинст­ве про­ектов. А что если появ­ляется не­об­хо­ди­мость запус­кать мак­си­маль­но изо­ли­ро­ван­ные зада­чи, ко­то­ры­ми дол­жен управ­лять поль­зо­ва­тель, а не раз­работ­чик: соз­да­вать, за­пускать, оста­нав­ли­вать? Это еди­ни­ца, ко­то­рую надо изо­ли­ро­вать, по­яв­ля­ется и исчеза­ет между деп­лоя­ми, а единст­вен­ный спо­соб рас­сказать об этом сис­теме — от­ре­дак­тиро­вать кон­фиг и рас­ка­тать всё за­ново.

В Laravel Horizon доку­мента­ция закан­чи­вает­ся на конфи­ге и паре artisan-команд про то, как поднять супер­визо­ры, наст­роить ворке­ры, их масшта­биро­вание и указать очереди. А что, если нам нуж­но соз­дать свои собст­вен­ные очере­ди и их воркеры в ран­тайме? Об этом доку­мента­ция молчит. Но если про­читать ис­ход­ни­ки, выясня­ется, что конфиг — не единст­вен­ный источ­ник исти­ны.

Эта статья на приме­ре плат­фор­мы для email-рассылок рас­скажет про пост­рое­ние дина­мичес­ких очере­дей поверх стати­чес­ко­го конфига Laravel Horizon, исполь­зуя внут­рен­ние не­до­ку­мен­ти­ро­ван­ные ме­ха­низ­мы, кото­рые Horizon сам ис­поль­зу­ет внутри себя. Про архитек­туру с авто­мати­чес­ким восс­танов­ле­нием кон­сен­су­са, раз­ре­ше­нием оши­бок и оп­ти­ми­за­цией памя­ти для дол­го жи­ву­щих оче­ре­дей.

Читать далее

Anemic vs Rich entities: нечестная дилемма

Уровень сложностиСредний
Время на прочтение9 мин
Охват и читатели5.7K

Знаменитый тезис Мартина Фаулера «Anemic Domain Model — это Antipattern» знаком многим.

Тезис простой и звучит убедительно: если модель — это просто набор геттеров и сеттеров, а бизнес-логика живёт в сервисах, то это анемичная модель, процедурный код в объектной обёртке, шаг в сторону от объектного ориентирования. Звучит так себе. Правильнее — переносить поведение внутрь объекта, рядом с данными. Заказ должен уметь рассчитывать свою сумму, добавлять предметы и применять скидку. Данные и поведение живут вместе, инкапсуляция работает, сервисы превращаются в тонкие оркестраторы. Объекты — во главе вашего дизайна.

В статье порассуждаем, почему всё не так просто, как реальность иногда вмешивается в стройную теорию и что с этим можно сделать с примером реализации на PHP.

Читать далее

Сколько обходится содержание одного игрока — создание сервера MMORPG, ч. 22

Уровень сложностиПростой
Время на прочтение8 мин
Охват и читатели11K

Сколько сервера уходит на одного игрока 2D MMO — вместе с существами, которых он будит вокруг себя? Показываю, как платформа считает расход живого мира ещё до установки игры: по онлайну, плотности существ и цене каждой механики, — и что из этого вышло на мире из 26 карт.

Читать далее

Как перестать писать шаблонный код в Symfony: Практические DX‑трюки для ленивого разработчика

Уровень сложностиСредний
Время на прочтение7 мин
Охват и читатели9.3K

Всем привет! Меня зовут Антон Рыков и я backend-разработчик в компании "Исходный Код".

Пять CRUD-эндпоинтов. К обеду я понял: бизнес-логика заняла минут двадцать. Остальные два часа ушли на UUID вместо автоинкремента, одинаковые DTO с валидацией и ручную уборку временных файлов на стейджинге. Пальцы работали. Голова — нет.

Почти любая команда на Symfony рано или поздно упирается в ту же стену: фреймворк перестаёт быть помощником и превращается в конвейер. make:entity → вырезать integer id → прикрутить трейт дат → руками разобрать $request в контроллере. Снова. И снова.

DX — это не красивая тема в терминале. Это меньше трения между архитектурным решением и кодом. Правильная лень — точечная автоматизация того, что вы и так делаете каждый день.

В статье — четыре уровня, которые убрали это трение у меня. Настроите PhpStorm так, чтобы скелет JSON-экшена появлялся по Tab. Уберёте ручной json_decode и isset через MapRequestPayload и строгие DTO. Научите MakerBundle сразу генерировать сущности с UUID и вашими трейтами. Перенесёте cron в PHP через Scheduler - расписание

Читать далее

Как я переписал каталог из 500 000 SVG‑иконок с Laravel на Go и уменьшил сервер с 4/6 ГБ до 2/2 ГБ

Время на прочтение9 мин
Охват и читатели9.1K

Больше года назад я запустил SVG4 — каталог векторных иконок. Сейчас в нём больше 500 000 SVG‑файлов.

Первая версия была написана на Laravel. На тот момент выбор был простой: Laravel я хорошо знал, на нём можно было быстро собрать рабочий проект и проверить, нужен ли он вообще кому‑нибудь.

Проект вырос. Вместе с ним выросли база, количество страниц, поисковый трафик и нагрузка. Старая версия работала на сервере с 4 ядрами и 6 ГБ оперативной памяти. После переписывания на Go весь проект работает на 2 ядрах и 2 ГБ RAM.

При этом я не ставил задачу доказать, что Go быстрее PHP. За время переписывания изменилась не только технология, но и сама архитектура приложения. Именно об этом переходе и хочу рассказать.

Читать далее

Wi-Fi из PHP: сканирование, подключение, хотспот и watchdog для Raspberry Pi без монитора и клавиатуры

Уровень сложностиСредний
Время на прочтение5 мин
Охват и читатели6.9K

Библиотека для PHP, которая сканирует и подключает Wi-Fi, поднимает хотспот и держит на связи Raspberry Pi без монитора: если сеть пропала, watchdog переподключается сам, а если не выходит, поднимает точку доступа для настройки с телефона. Под капотом nmcli, wpa_cli и hostapd. Каждый релиз прогоняется на настоящем Pi, логи в репозитории.

Читать далее

Ближайшие события

Выбираем бэкенд в 2026 (PHP, Dart и C++ Drogon)

Уровень сложностиСредний
Время на прочтение8 мин
Охват и читатели13K

Поехали.

Вообще говоря, я всегда делал бэкенд исключительно на PHP. Я считаю его отличным языком для бэкенда, вернее не только для бэкенда, а отличным языком. Некоторые не любят PHP за малый порог вхождения. Типа через этот малый порог вхождения входит очень много непрограммистов, которые потом пишут говнокод. Но я придерживаюсь мнения, что PHP никак не виноват в этом. Скорее наоборот. На PHP логика просыпается даже у тех, кто кроме говнокода ничего написать не может. Поэтому в любом случае это отличный язык программирования, который каждый год хоронят, но никак похоронить не могут. И в 2026 году он живее всех живых и показывает отличные результаты.

Вторым в списке для сравнения я решил поставить Дарт. Дело в том, что самое узкое место применения Дарта — это как раз-таки применение на серверах. Потому что в мобильной разработке он уже как стандарт, веб, фронтенд мало-мальцевски он тоже подтягивает. Но вот на серверах пока что его используют очень мало. Одна из причин на то, что его мало используют на серверах, — это отсутствие библиотек, таких как, например, есть у PHP. Но, тем не менее, это совсем не значит, а тем более сейчас в эпоху LLM, это совсем не значит, что Дарт негоден на серверах. Как покажет сравнение, он очень-таки годен.

Третий кандидат для сравнения — это C++. Это его фреймворк Drogon, который в каком-то там 2014 или 2015 годах взлетел как самый быстрый фреймворк для серверов на бэкенде по скорости. Если честно, я ни разу не писал бэкенд на C++, поэтому это была первая попытка. Просто хотелось посмотреть, как C++ уничтожит двух других оппонентов со своей 100x производительностью.

Читать далее

Переезд с OpenCart 2 после двадцати лет работы: что лежит в дампе и откуда берутся восемь тысяч редиректов

Уровень сложностиСредний
Время на прочтение6 мин
Охват и читатели5.5K

Разбираем переезд интернет-магазина с OpenCart 2 на Next.js и PostgreSQL. Магазин оптовый, электронные компоненты, сайту двадцать лет, в каталоге 4 751 товар. Если у вас OpenCart и вы думаете уезжать, то будет полезно почитать, что может всплыть в самый неожиданный момент.

Магазин запущен в боевом режиме, поэтому всё ниже про то, что уже перенесено и работает. Про трафик после переключения домена говорить рано, замера ещё нет. Обмен с учётной системой - отдельная большая тема, и здесь его нет.

Читать далее

SOLID в реальном мире. ISP без микроинтерфейсов

Уровень сложностиСредний
Время на прочтение14 мин
Охват и читатели5.2K

Interface Segregation Principle часто понимают как требование дробить интерфейсы до одного метода. На примере PHP-проекта разберём, почему важен не размер интерфейса, а потребности его клиентов, как разделять контракты по акторам и сценариям и при этом не создавать зоопарк лишних абстракций.

Читать далее

Symfony Workflow: как реализовать сложную бизнес-логику через состояния и переходы

Время на прочтение11 мин
Охват и читатели6K

Заказ в интернет-магазине редко живёт по идеальной схеме «создан → оплачен → доставлен». В реальности жизненный цикл объекта нелинейный: клиент оформляет заказ, но может передумать и отменить его; товар приходит с браком и требуется возврат; часть позиций не успела прийти и нужно отправить их отдельно. Попытка реализовать такие альтернативные сценарии, проверки прав и сопутствующие действия «в лоб» быстро превращает бизнес-логику в хаос из разрозненных if/else, проверок статусов и обработчиков по всему проекту.

В статье разберём, как с помощью компонента Symfony Workflow описывать сложные бизнес-процессы в виде явной модели состояний и переходов. На практическом примере рассмотрим, как задавать допустимые переходы, добавлять бизнес-правила и проверки, обрабатывать события и отделять описание процесса от кода, выполняющего конкретные действия. В результате получим не просто механизм управления статусами, а инструмент, который делает сложную бизнес-логику понятной, предсказуемой и удобной для сопровождения.

Читать далее

150 запросов на один flush, и 4343 зелёных теста. Как я делал детектор N+1 и как он сам меня обманывал

Уровень сложностиПростой
Время на прочтение15 мин
Охват и читатели4.9K

Один open‑source тайм‑трекер на Symfony имеет 4343 теста, и все они проходят. При этом каждое сохранение записи времени отправляет в базу три дополнительных SELECT запроса: ставку самой записи, ставку проекта и ставку активности. Если в одном flush() 50 записей, а столько строк показывает страница массового редактирования, только за ставками уходит 150 запросов. Тесты этот код покрывают, но ни один не падает, в них нет ни одной проверки проблем с запросами к базе данных.

Для решения этой проблемы сделал инструмент, которого в конце августа ещё не существовало. Правда, ещё до проверок сторонних проектов на N+1, он успел несколько раз обмануть меня самого, и всегда одинаково, показывал зелёное там, где на самом деле не работал.

Читать далее

Снижение нагрузки на сервер через WAF: реальный кейс WordPress/WooCommerce

Уровень сложностиСредний
Время на прочтение16 мин
Охват и читатели9.8K

Реальный кейс снижения нагрузки WordPress/WooCommerce с помощью WAF

На WordPress/WooCommerce-сайте на shared-хостинге регулярно возникали серьёзные превышения нагрузки на веб-сервер и MySQL. Штатный антибот-фильтр хостинга проблему не решил. В этом кейсе я показываю, что изменилось после подключения внешнего WAF с индивидуальной фильтрацией трафика: какие запросы создавали лишнюю нагрузку, как отсеивались парсеры, сканеры и поведенческие боты и что происходило с поисковыми роботами.

По данным Beget, после замены фильтра суточная нагрузка сайта снизилась примерно в 45 раз, базы данных — примерно в 39 раз. При этом WordPress, WooCommerce, плагины, код и структура БД не изменялись. В статье — реальные графики, данные Яндекс Метрики, статистика WAF и разбор случаев, когда WAF, наоборот, не поможет решить проблему высокой нагрузки.

Читать далее

Бесплатный плагин для входа через VK ID на WordPress: как закрыли потребность, когда готовых решений не нашлось

Время на прочтение2 мин
Охват и читатели7.9K

Начал я делать очередной сайт на Wordpress и решил упростить регистрацию пользователям. По этому пошел по схеме вход через другие сервисы. Как стало нынче модно‑сковородно использовать авторизацию через ВК. Ее то я и решил прикрутить. Делал уже это раньше но вот сегодня столкнулся с проблемой.

И есть решение
1
23 ...