PHP и Laravel дайджест новостей за апрель 2024 года
Всем привет!
Это PHP Дайджест от CutCode. Давайте посмотрим, что произошло за прошедший месяц в мире PHP.
Новости
Вышли PHP 8.1.28, PHP 8.2.18 и PHP 8.3.6
❗️В этих выпусках исправлены уязвимости CVE-2024-1874, CVE-2024-2756 и CVE-2024-3096, в PHP 8.3.6 также исправлена уязвимость CVE-2024-2757, которые исправляют:
Обход функции proc_open в Windows с экранированием аргументов для bat- и cmd-файлов
Обход куки __Host / __Secure
Бесконечный цикл в функции mb_encode_mimeheader
Обработка функцией password_hash значения $password с нулевым символом.
❗️Версия PHP 8.3.5 была пропущена, пожалуйста, не полагайтесь этот тег.
Заявление PHP об уязвимости в glibc/iconv
Шумиха вокруг CVE-2024-2961, связанная с PHP, была крайне преувеличена. У многих сложилось впечатление, что уязвимость существует в самом языке и оказывает огромное влияние на PHP-разработчиков. Однако это не так.
Уязвимость может быть удаленно использована только в том случае, если приложение использует функции и потоковые фильтры модуля iconv с не валидированными кодировками, полученными из внешних источников.
Не стоит ожидать выпуска патча от PHP, поскольку glibc является динамически подключаемой библиотекой и не компилируется вместе с интерпретатором. Обновления glibc будет достаточно.
Все, что нужно знать о бэкдоре в XZ
Если вы не следили за этой историей, то вот вкратце, что произошло.
Некто под GitHub-аккаунтом @JiaT75 в течение 2 лет вносил свой вклад в библиетеку liblzma, создавая SSH-бэкдор незаметно для других сопровождающих. Он сделал более 700 коммитов, из которых лишь небольшое количество было вредоносным и спрятано в тестовых файлах.
Странное поведение было случайно обнаружено при проведении микробенчмаркинга утилиты xz.
Скорее всего, эта атака не является единичным случаем. По крайней мере, OpenJS Foundation уже сообщал о неудачных попытках захвата их проектов.
Объединение усилий для разработки стандартов кибербезопасности с открытым исходным кодом
PHP Foundation будет сотрудничать с фондами Apache, Eclipse, Rust и Python для создания стандартов для закона о киберустойчивости.
Это первый в мире закон, регулирующий индустрию программного обеспечения в целом. Он заставит некоторые проекты с открытым исходным кодом предоставлять политику кибербезопасности, добровольно сообщать об инцидентах и уязвимостях, а также сотрудничать с органами надзора за рынком.
Главные новинки этой версии:
Автодополнение строки целиком с помощью локального ИИ
Поддержка Symfony AssetMapper
Новый терминал
Улучшения для Pest
Поддержка PHPUnit 11.0
Большинство новостей ядра PHP подробно освещаются в серии PHP Core Roundup от PHP Foundation, мы лишь быстро по ним пробежимся:
Хуки стали одним из самых больших и обсуждаемых RFC, в одном из предыдущих выпусках мы о них уже упоминали.
Они позволят разработчикам переопределять стандартное поведение "get" и "set" свойств объекта. Ларри Гарфилд и Илия Товилло вдохновлялись языками Kotlin, C# и Swift при разработке этого RFC.
RFC был принят подавляющим большинством голосов и мы с нетерпением ждем хуки в PHP 8.4.
?RFC: new MyClass()->method() without parentheses
RFC Валентина Удальцова, о котором мы говорили в конце прошлого года, перешел в стадию обсуждения.
У RFC положительные отзывы, ждем начала голосования, один голос у Валентина уже точно есть :)
На PHP-викторине, о которой мы поговорим чуть позже, Валентин также рассказал о своем RFC.
Джошуа Рюсвег (Joshua Rüsweg) предлагает добавить новую функцию для поиска первого элемента, для которого callback-функция возвращает значение true.
?RFC: Casing of acronyms in class and method names
Тим Дюстерхус (Tim Düsterhus) предлагает пересмотреть предыдущее решение RFC по именованию классов. Вместо того, чтобы относиться к аббревиатурам как к обычным словам, сделать имена классов согласованными с PascalCase.
✅ RFC: Deprecate GET/POST sessions
RFC о котором мы говорили в прошлом выпуске принят.
Сейчас PHP поддерживает два способа распространения идентификатора токена сессии: с помощью файлов cookie и с помощью параметров GET или POST.
В PHP 8.4, если параметр session.use_only_cookies отключен, а параметр session.use_trans_sid – включен, будет выдаваться предупреждение об устаревании.
В PHP 9.0 распространение идентификатора токена сессии с помощью параметров GET или POST будет удалено.
Поддержка безопасности для версий PHP увеличена на один год. Таким образом, каждая версия PHP будет поддерживаться 4 года: 2 года исправлений ошибок и 2 года исправлений безопасности.
Изменения применяются немедленно ко всем поддерживаемым в настоящее время веткам, а ветка PHP 8.1 получит дополнительный год исправлений безопасности.
По традиции, PHP 8.4 будут сопровождать два «новичка» релиз-менеджера: Саки Такамачи (Saki Takamachi), core-разработчик, поддерживаемая PHP Foundation, и Кельвин Бакли (Calvin Buckley), разработчик нескольких модулей PECL.
Им будет помогать ветеран релиз-менеджер PHP 8.3 Эрик Манн (Eric Mann).
На канале CutCode прошла вторая викторина «Своя игра» по PHP
Валентин Удальцов, Алексей Гагарин и Петр Мязин ответили на каверзные вопросы по PHP.
Обязательно посмотрите, если пропустили. А также пишите свои пожелания, замечания и вопросы для следующих игр - ссылка на форму.
Сервис по деплою приложений в один клик с нулевым временем простоя и контролем результата. Возможности аналогичные Envoyer, плюс есть дополнительные фичи. Подходит для деплоя приложений на PHP и Go.
Laravel дайджест
Обновления Laravel
11.2. Add fluent helper
https://github.com/laravel/framework/pull/50848
PR на тему Fluent объекта. Что за Fluent такой? Это дополнительный сахар. Там где у нас коллекции не справляются с сахаром, на помощь приходит Fluent объект. Давайте взглянем на примеры. Скажем, у нас есть коллекция.
Есть метод Get. Элемент массива с Fluent мы можем просто указывать как свойство объекта и получать также доступ:
$data = [
'user' => [
'name' => 'Philo',
'address' => [
'city' => 'Amsterdam',
'country' => 'Netherlands',
]
],
'posts' => [
[
'title' => 'Post 1',
],
[
'title' => 'Post 2',
]
]
];
❌ collect($data)->get('user');
✅ fluent($data)->user
Далее у нас в коллекциях через метод Get не поддерживается вложенность через метод DataGet во Fluent объекте. Теперь такая возможность есть, через точку можем обращаться к вложенным элементам:
❌ collect($data)->get('user')['name'];
✅ fluent($data)->get('user.name');
Также есть возможность Fluent объект трансформировать в коллекции:
❌ collect(collect($data)->get('posts'))->pluck('title');
✅ fluent($data)->collect('posts')->pluck('title');
И присутствует интересный метод Scope, который у нас под капотом содержит метод get, но возвращает новый instance fluent-объекта. И также нам демонстрирует пример, как удобно с помощью fluent-helper сделать JSON-Encode.
❌ json_encode(collect($data)->get('user')['address']);
✅ fluent($data)->scope('user.address')->toJson();
11.2. Add a new helper for context
https://github.com/laravel/framework/pull/50878
Следующий PR затрагивает context. У нас уже был context фасад. И пришло время для helper для функции context:
context(['user' => auth()->user()]); // Add user information to the context
$context = context(); // Retrieve the context object
$user = context('user'); // Retrieve user information from the context
11.2. Add default value for get and getHidden on Context
https://github.com/laravel/framework/pull/50824
Еще один PR по Context . У нас были методы-геттеры для получения элементов из контекста get и get-hidden. Но при этом мы не могли с вами указать дефолтное значение. Если такого ключа в контексте нет, то мы получаем с вами null:
$isUser = Context::get('is_user'); // If is not has in array return null forever
$isUser = Context::getHidden('is_user'); // If is not has in array return null forever
Не совсем привычно для гетеров в Laravel, так как всегда присутствует вторым параметром дефолтное значение, и теперь оно есть и в Context:
$isUser = Context::get('is_user', false); // If is not has in array return false
$isUser = Context::getHidden('is_user', false); // If is not has in array return false
11.2. Trim invisible characters
https://github.com/laravel/framework/pull/50832
PR затрагивает Middlewar trim strings. До этого была проблема, невидимые Unicode символы Trimstrings не чистил. PR решает эту проблему.
11.2. Do not wipe database if it does not exists
https://github.com/laravel/framework/pull/50838
Следующий PR по консольным командам. Проблема заключается в следующем. Если вы сделаете Migrate fresh и у вас еще не создана база данных, помощник вам подскажет создать её либо нет. И если вы отвечаете нет, то сработает исключение и вы получите ошибку.
Теперь мы не будем получать исключения, а команда просто не будет выполнена.
11.2. Str trim methods
https://github.com/laravel/framework/pull/50822
Следующий PR добавляет новый сахар в класс по работе со строками. Раньше был trim(), теперь есть ltrim() и rtrim().
11.3. Add Component: Multiline Text Input
https://github.com/laravel/prompts/pull/88
Новая фича в Laravel Prompts. Обожаю этот пакет, и теперь появился элемент формы textarea() с помощью которого можем в консоли пользоваться текстовым блоком.
11.3. Add pull methods to Context
https://github.com/laravel/framework/pull/50904
Этот PR добавляет в Context новый метод pull и pullHidden. Как и во всех pull в Laravel мы забираем значение из указанного элемента и после удаляем его из Context.
11.3. Add session hasAny method
https://github.com/laravel/framework/pull/50897
В объект сессий добавили метод hasAny, чтобы не плодить условия или и указать все в массиве через новый метод:
До:
if (session()->has('first_name') || session()->has('last_name')) {
// do something...
}
После
if (session()->hasAny(['first_name', 'last_name'])) {
// do something...
}
11.4. Introduces Exceptions facade
https://github.com/laravel/framework/pull/50704
PR от Nuno Maduro, новый фасад exceptions, который даст нам новые возможности в тестировании exception. В примерах показано, как в тестах мы можем переключить exceptions в fake и далее в тестах проверять, вызваны ли исключения, сколько раз вызваны, и так далее.
11.4. Allowing Usage of Livewire Wire Boolean Style Directives
https://github.com/laravel/framework/pull/51007
Следующий pull request, для фанатов livewire. Теперь в Blade-директивы можно будет отправлять параметры в boolean стиле. До этого при генерации HTML у нас добавлялся value:
{{-- Using like this --}}
<x-fetch wire:poll />
{{-- Generates this HTML --}}
<div ... wire:poll="wire:poll" />
Теперь же у нас если нет значения, то и при рендере его не будет:
<x-fetch wire:poll />
<div ... wire:poll />
11.4. afterQuery hook
https://github.com/laravel/framework/pull/50587
Следующий pull request добавляет новый метод в queryBuilder — autoquery, который исходя из названия будет вызван после того, как будет вызван запрос.
В pull request показан пример, где есть scope и мы после запроса итерируем продукты и устанавливаем определенный атрибут.
public function scopeWithIsFavoriteOf($query, ?User $user = null) : void
{
if ($user === null) {
return $query;
}
$query->addSelect([
// 'is_favorite' => some query ...
]);
}
$products = Product::withIsFavoriteOf(auth()->user())->get();
if (auth()->user() === null) {
$products->each->setAttribute('is_favorite', false);
}
Теперь же с помощью этого метода мы прямо в scope можем указать что у нас за логика будет после вызова запроса и здесь же ее и выполнить:
public function scopeWithIsFavoriteOf($query, ?User $user = null) : void
{
if ($user === null) {
$query->afterQuery(fn ($products) => $products->each->setAttribute('is_favorite', false));
return;
}
$query->addSelect([
// 'is_favorite' => some query ...
]);
}
Product::withIsFavoriteOf(auth()->user())->get();
11.4. Add RequiredIfDeclined validation rule
https://github.com/laravel/framework/pull/51030
Следующий pull request добавляет правила валидации requiredIfDeclined. У нас уже был requiredIfAccepted, теперь появился его “брат” - если у нас checkbox не выбран.
11.4. Adds support for enums on mapInto collection method
https://github.com/laravel/framework/pull/51027
В следующем pull request речь пойдет методе mapInto для коллекций. Теперь мы можем мапить в enum данные:
public function store(Request $request)
{
$request->validate([
'features' => ['array'],
'features.*' => [new Enum(Feature::class)],
]);
$features = $request
->collect('features')
->mapInto(Feature::class);
if ($features->contains(Feature::DarkMode)) {
// ?
}
}
11.4. Adds Reversible Forms to Prompts
https://github.com/laravel/prompts/pull/118
В Laravel Prompts добавилась новая фича. До этого мы могли через Form Builder, через Helper Form, строить формы и получать значение из всех элементов формы только после сабмита:
$responses = form()
->text('What is your name?')
->select('What is your favourite language?', ['PHP', 'JS'])
->submit();
Но бывают кейсы, когда скажем нам в select внутри нужно получить результат из предыдущего поля. До этого такой возможности не было, теперь появился метод add, где мы с вами будем иметь доступ к предыдущим ответам и на основе их, если необходимо, кастомизировать следующий элемент формы:
$responses = form()
->text('What is your name?')
->select('What is your favourite language?', ['PHP', 'JS'])
->add(fn ($responses) => note("Your name is {$responses[0]} and your language is {$responses[1]}"))
->submit();
11.5. Supercharge Blade
https://github.com/laravel/framework/pull/51143
PR, который затрагивает Blade, и ускоряет его работу. Теперь Blade будет работать в 15-25 раз быстрее.
11.5. Blade Component Loop Speed Improvement
https://github.com/laravel/framework/pull/51158
PR оптимизирующий loop внутри Blade - скорость увеличена на 7%.
11.5. Ability to generate URL's with query params
https://github.com/laravel/framework/pull/51075
PullRequest, который затрагивает URL-генератор. Появился новый метод Query, с помощью которого можно удобно строить URL вместе с Query-параметрами:
// http://localhost/products?sort=-name
url()->query('products', ['sort' => '-name']);
// http://localhost/products?columns[0]=name&columns[1]=price&columns[2]=quantity
url()->query('products', ['columns' => ['name', 'price', 'quantity']]);
Много возможностей, как видим из примеров. Крутая фича для URL генератора.
Видео-версия дайджеста: