json_validate перед json_decode: один JSON разбирается дважды
Если данные сразу понадобятся в PHP, не нужно сначала вызывать
В проверенном примере
Когда использовать json_validate
Библиотека пхпшника
Если данные сразу понадобятся в PHP, не нужно сначала вызывать
json_validate. json_decode сам проверяет строку при разборе. С JSON_THROW_ON_ERROR невалидный JSON даст JsonException.json_validate полезен, когда нужен только ответ «это корректный JSON?», а массив или объект создавать не нужно. Функция доступна с PHP 8.3 и в таком сценарии требует меньше памяти, чем декодирование.В проверенном примере
{"port":8080} валиден, {"port":} — нет. При декодировании первого получаем значение 8080, второго — исключение. Валидная строка null тоже проходит проверку: синтаксис JSON ещё не гарантирует нужную вам структуру данных.Когда использовать json_validate
Библиотека пхпшника
Подпись защищает URL от подмены. Но сама по себе не мешает открыть одну ссылку несколько раз до истечения срока.
В разрабатываемом Symfony 8.2 у UriSigner появляется дополнительный аргумент $version. Он участвует в подписи, но не добавляется в URL.
Для сброса пароля версией может стать текущий хеш пароля:
$url = $uriSigner->sign(
$resetUrl,
new \DateInterval('PT30M'),
$user->getPassword(),
);
// При обработке ссылки:
$uriSigner->verify($request, $user->getPassword());
После сохранения нового пароля хеш изменится. Проверка старой ссылки с новым значением версии завершится исключением UnverifiedSignedUriException.
Важная деталь: verify() не погашает ссылку
Она остаётся действительной, пока состояние, выбранное в качестве версии, не изменилось. Поэтому нельзя считать такой механизм атомарной защитой от двух одновременных запросов: конкурентное выполнение нужно учитывать отдельно.
Возможность относится к будущему Symfony 8.2. Для текущего проекта сначала проверьте версию компонента.
Please open Telegram to view this post
VIEW IN TELEGRAM
Symfony
New in Symfony 8.2: Single-Use and Safer Signed URLs (Symfony Blog)
Symfony 8.2 lets you create single-use signed URLs and allows adding extra signed parameters to login links.
До 31 октября в Proglib Academy можно выбрать два курса и заплатить только за один.
Например, можно совместить:
💥 ИИ для разработчиков — применение нейросетей в повседневной разработке: работа с кодом, тестирование и ревью.💥 Разработка ИИ-агентов — архитектура агентов и создание собственных AI-решений.
Вместе курсы стоят 108 000 ₽, но по акции оба обойдутся в 59 000 ₽. Экономия — 49 000 ₽
Интересуют Python и ИИ или алгоритмы и архитектура? Можно выбрать любые два курса из каталога.
Please open Telegram to view this post
VIEW IN TELEGRAM
🥱3👾1
Приложение работает, тесты зелёные — пока не меняется движок базы данных.
В Pinkary первичный ключ questions.id был UUID. А поля parent_id и root_id создали через foreignId(), то есть как целочисленные столбцы:
$table->foreignId('parent_id');Гибкая типизация SQLite позволяла хранить там строки UUID. При переходе на MySQL несоответствие стало проблемой: тип столбца должен соответствовать реальным значениям и связанному ключу.
Здесь легко сделать слишком широкий вывод. Проблема была именно в явных вызовах foreignId('parent_id') и foreignId('root_id'). Метод foreignIdFor() умеет определять UUID-тип по модели — это другой случай.
Что проверить до переезда
Запустите миграции и характерные запросы на том движке, который будет в рабочей среде. Помимо типов, могут отличаться правила группировки, сравнения строк и порядок результатов при одинаковых временных метках.
ORM делает запросы удобнее, но не делает SQLite и MySQL взаимозаменяемыми во всех деталях.
Please open Telegram to view this post
VIEW IN TELEGRAM
Laravel
Migrating Pinkary from Laravel Forge to Laravel Cloud: An engineering playbook | Laravel - The clean stack for Artisans and agents
Pinkary's move from Laravel Forge to Laravel Cloud exposed SQLite and MySQL differences, query assumptions, and local-storage coupling. Here is the code-backed...
API получает userId. Проверить, что это строка, недостаточно: пользователь с таким идентификатором может не существовать.
В будущем Symfony 8.2 для этой задачи появится ограничение EntityExists из Doctrine Bridge:
use App\Entity\User;
use Symfony\Bridge\Doctrine\Validator\Constraints\EntityExists;
use Symfony\Component\Validator\Constraints as Assert;
final class AssignOrderCommand
{
#[Assert\NotBlank]
#[EntityExists(entityClass: User::class)]
public string $userId;
}
По умолчанию поиск идёт по идентификатору сущности. Можно выбрать другое поле через identifierField или задать собственный метод репозитория.
Зачем рядом NotBlank
EntityExists считает null и пустую строку допустимыми. Если поле обязательно, это отдельное правило.
Есть ещё две границы. Существование записи не означает, что текущему пользователю разрешено с ней работать. И успешная проверка не гарантирует, что запись не удалят до сохранения операции.
Поэтому авторизацию и ограничения целостности базы такая валидация не заменяет.
Please open Telegram to view this post
VIEW IN TELEGRAM
Symfony
New in Symfony 8.2: EntityExists, Cron and Audio Constraints (Symfony Blog)
Symfony 8.2 adds new constraints to validate Doctrine entity references, cron expressions and audio files.
❤1
Один staging на всю команду быстро превращается в очередь: пока дизайнер смотрит одну ветку, следующую выкатывать нельзя.
В Laravel Cloud можно настроить автоматизацию, которая создаёт окружение при открытии pull request. У него будут собственный URL и отдельно созданные ресурсы. Новые коммиты обновляют развёрнутую версию, а после закрытия или слияния PR автоматическая очистка может удалить окружение и созданные для него ресурсы.
Это возможность платформы Laravel Cloud, а не функция, которая автоматически появляется в любом Laravel-приложении.
Изоляция важнее дополнительного URL
Проверять миграции и фоновые задания безопаснее с отдельными базой, кешем и тестовыми ключами интеграций. Подключённая рабочая база превращает проверку ветки в реальные изменения данных.
Для простаивающих окружений предусмотрено масштабирование до нуля там, где ресурс его поддерживает. Но это не обещание полностью бесплатного стека: хранение данных и другие ресурсы могут продолжать оплачиваться.
Полезный результат — возможность проверить весь пользовательский сценарий, не перезаписывая чужой staging.
Please open Telegram to view this post
VIEW IN TELEGRAM
Laravel
Preview environments and scale to zero: Better together | Laravel - The clean stack for Artisans and agents
Give every pull request its own preview environment on Laravel Cloud. Share a link, test the full stack, and let idle previews scale to zero.
В Proglib Academy действует акция: покупаешь один курс, а второй получаешь в подарок.
Например, можно совместить два направления по работе с ИИ:
💥 ИИ для разработчиков — применение нейросетей в повседневной разработке: работа с кодом, тестирование и ревью.💥 Разработка ИИ-агентов — архитектура агентов и создание собственных AI-решений.
А если тебе интереснее Python, алгоритмы, backend или DevOps — выбирай другую пару курсов из каталога.
Акция действует до 31 октября включительно
Please open Telegram to view this post
VIEW IN TELEGRAM
🥱2
Контейнер уже знает, какие слушатели обрабатывают события. Зачем при создании диспетчера снова вызывать addListener() и создавать замыкания?
В разрабатываемом Symfony 8.2 сервис event_dispatcher использует CompiledEventDispatcher. Он получает заранее подготовленный массив идентификаторов сервисов и методов в нужном порядке. OPcache хранит массив в общей памяти, а локатор загружает слушателей по мере необходимости.
В приведённом микробенчмарке с 75 слушателями создание диспетчера сократилось с 33,7 до 0,48 микросекунды.
Это ускорение создания, а не всего приложения
Сама отправка событий работает с прежней скоростью. Слушатели по-прежнему создаются перед выполнением; если событие не отправлено или распространение остановлено, оставшиеся сервисы не создаются.
Добавление и удаление слушателей на общем event_dispatcher во время выполнения заставляет его перейти к обычному диспетчеру. В Symfony 8.2 такие вызовы помечаются устаревающими.
Перед обновлением стоит поискать addListener(), addSubscriber() и соответствующие удаления именно на общем сервисе.
Please open Telegram to view this post
VIEW IN TELEGRAM
Symfony
New in Symfony 8.2: Compiled Event Dispatcher (Symfony Blog)
Symfony 8.2 compiles event listeners into a PHP array to reduce dispatcher setup time and memory use.
🔥5👍1
У MCP-сервера десятки инструментов. Если клиент заранее добавляет каждое описание и полную схему параметров в контекст модели, значительная его часть расходуется ещё до первого полезного вызова.
В Laravel MCP 1.0 разработчики выбрали каталог с поиском: агент сначала находит подходящий инструмент, затем получает необходимую информацию для вызова. Размер начального tools/list при этом не растёт вместе со всем каталогом.
До этого команда пробовала другой подход: дать модели написать PHP, который вызовет несколько инструментов и обработает результаты внутри приложения.
Почему от eval() отказались
Сгенерированный код выполнялся в том же процессе, с доступом к окружению и базе приложения. Набор предложенных функций не ограничивал остальные возможности PHP. Успешные тестовые примеры не доказывали, что опасные действия невозможны.
Попытки добавить изоляцию усложнили решение. В итоге каталог оказался проще для этой задачи.
Это разбор конкретной реализации. Не каждый MCP-клиент заранее загружает все схемы, а поиск инструмента не заменяет проверку прав при его выполнении.
Please open Telegram to view this post
VIEW IN TELEGRAM
Laravel
A better way to build MCP servers with Laravel | Laravel - The clean stack for Artisans and agents
Every MCP tool loads on every request. Laravel MCP 1.0 fixes that with searchable tool catalogs: the same payload for 10 tools or 100.
❤1
21 октября вышли исправления двух критических уязвимостей PHP, допускающих удалённое выполнение кода без авторизации. Обновлённые версии: 8.5.12, 8.4.27, 8.3.36 и 8.2.35.
В инструкции для платформ Laravel разобраны действия для каждого способа размещения. На Laravel Cloud работающие приложения обновили автоматически. На Forge нужно нажать Update PHP для каждого сервера. На Vapor приложения с нативным runtime PHP 8.2 и новее требуется развернуть повторно; для собственного Docker-образа подготовить новое развёртывание.
Проверьте все окружения и процессы приложения: веб-сервер, очереди и задания по расписанию. Для контейнеров пересоберите образ с исправленной версией PHP и замените работающие экземпляры.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1
Два запроса одновременно запускают импорт каталога. Оба обработчика читают и изменяют одни данные. В готовящемся Symfony 8.2 для таких операций появится атрибут #[Lock]:
use Symfony\Component\HttpKernel\Attribute\Lock;
#[Lock('catalog-import', methods: 'POST')]
public function import(): Response
{
// Импорт каталога
}
Первый запрос получает блокировку. Конкурирующий запрос с тем же ключом по умолчанию получает
409 Conflict. Режим blocking: true позволяет дождаться освобождения блокировки.Это пригодится для импорта, генерации отчётов и других операций с общим ресурсом. Подберите ключ под этот ресурс и проверьте длительность обработки: стандартный TTL — 30 секунд. Для долгой работы блокировку нужно продлевать. При нескольких экземплярах приложения настройте общее хранилище блокировок.
Please open Telegram to view this post
VIEW IN TELEGRAM
👾1