编程

Laravel 13.20 引入图片处理

26 2026-07-20 04:33:00

Laravel 13.20.0 为框架添加了第一方图像处理,并提供了一个不可变的、基于驱动的 API,用于转换来自上传、存储、URL 或原始字节的图像。该版本还带来了 WithoutMiddleware 控制器属性、Redis 的专用会话前缀以及一批 Eloquent 和队列附加功能。

  • 新增  Image facade 用于图片处理
  • 新增 #[WithoutMiddleware] 控制器注解
  • 配置了一个 Redis 专用会话前缀
  • Eloquent 模型的静默递增及递减
  • 枚举作为  WithoutOverlapping 队列键被接受
  • 等等

新增

图像处理

Laravel 13.20 引入了 Illuminate\Image 组件,用于在无需借助第三方工具的情况下处理图像大小、剪切、格式化转换以及存储。

原图不可变:每次转换都返回新的实例,并且当你请求结果时,队列转换方才应用。

最常见的路径是上传。

 Request::image() 返回特定文件键名的 Image 实例,如果该键名下没有对应的文件,则返回 null:

$request->image('avatar')
    ->cover(200, 200)
    ->toWebp()
    ->store('avatars');

你也可以从路径、URL 、二进制码、base64 或者磁盘中创建文件:

Image::fromPath('/path/to/photo.jpg');
Image::fromUrl('https://example.com/photo.jpg');
Image::fromBytes($bytes);
Image::fromStorage('photos/avatar.jpg', 's3');
Storage::disk('s3')->image('photos/avatar.jpg');

转换、输出选项和检查方法都可以在实例上使用:

// Transformations...
$image->cover(200, 200);
$image->contain(800, 600);
$image->crop(200, 200);
$image->resize(1024, 768);
$image->scale(1200, 800);
$image->rotate(90);
$image->blur(10);
$image->sharpen(10);
$image->grayscale();
$image->flip();
$image->flop();
$image->orient(); // Applies EXIF rotation...
 
// Output format and quality...
$image->toWebp();
$image->toJpg()->quality(80);
$image->optimize(); // WebP at quality 70...
$image->optimize('jpg', 85);
 
// Reading and inspecting...
$image->toBytes();
$image->toBase64();
$image->toDataUri();
$image->width();
$image->height();
$image->dimensions();
$image->mimeType();
$image->extension();

由于原图实例是不可变的,你可以从源图像中生成多个不同分支:

$image = $request->image('photo');
 
$image->cover(200, 200)->toWebp()->store('thumbnails');
$image->grayscale()->toWebp()->store('grayscale');

该组件随带两个驱动,均由 Intervention Image v4 支持:GD 和 Imagick。你可以根据每个图像选择一个驱动,Image Facade 允许你重写驱动程序处理给定转换的方式:

use Illuminate\Image\Transformations\Sharpen;
 
// Pick a driver per image...
$image->using('imagick');
$image->usingGd();
$image->usingImagick();
 
// Override how a driver handles a transformation...
Image::transformUsing('gd', Sharpen::class, function ($image, Sharpen $sharpen) {
    // Custom sharpen handling for the GD driver...
 
    return $image;
});

Intervention Image 是推荐使用的依赖,但不是必需的,你可以根据自己需要安装:

composer require intervention/image

#[WithoutMiddleware] 控制器注解

路由注解获得了 #[Middleware] 的对应项。当后者将中间件附加到控制器类或方法时,#[WithoutMiddleware] 会将其排除在外,从而在注解级别为你提供路由组的“排除中间件”行为:

use App\Http\Middleware\EnsureTokenIsValid;
use Illuminate\Routing\Controllers\Attributes\Middleware;
use Illuminate\Routing\Controllers\Attributes\WithoutMiddleware;
 
#[Middleware(EnsureTokenIsValid::class)]
class UserController
{
    public function index()
    {
        // Middleware applies here...
    }
 
    #[WithoutMiddleware(EnsureTokenIsValid::class)]
    public function profile()
    {
        // ...but not here.
    }
}

使用 ReflectionAttribute::IS_INSTANCEOF 匹配,以便 中间件的子类也排除掉。See #60709.

Redis 会话前缀

指向 Redis 上的 SESSION_DRIVERCACHE_STORE 的应用程序直到现在都有会话继承缓存前缀,这使得在清理或调试共享密钥库时很难找出会话密钥。 config/session.php 中的一个新前缀选项允许你设置一个单独的前缀:

'prefix' => env('SESSION_PREFIX', Str::slug((string) env('APP_NAME', 'laravel')).'-session-'),

 

The cache store is cloned before the session prefix is applied, so setting it does not affect cache keys. The option is opt-in and mirrors the existing session.connection setting. See #60700.

Eloquent 静默批量递增

Eloquent 已经有用于单列的 incrementQuietly()decrementQuietly()。此次发布添加了incrementEachQuietly() 和 decrementEachQuietly(),填补了压制模型事件时,一次性更新多条记录的空白:

$user->incrementEachQuietly(['posts_count' => 1, 'points' => 10]);

$user->decrementEachQuietly(['credits' => 3, 'tokens' => 2]);

See #60720 and the follow-up fix for dynamic calls in #60737.

Enums as Queue Overlap Keys

WithoutOverlapping 任务中间件现在接受 PHP枚举作为其键,因此,以枚举值为键不再需要手动转换为字符串:

class UpdateCategory implements ShouldQueue
{
    use Queueable;
 
    public function __construct(protected Category $category) {}
 
    public function middleware(): array
    {
        return [new WithoutOverlapping($this->category)];
    }
}

The change is backward compatible with existing string keys. See #60722.

其他修复和改进

  • beforePushing() and afterPushing() callbacks on QueueFake (#60689), and MailFake::assertQueuedTimes() is now public (#60710)
  • assertEmpty() added to the Storage facade (#60658), and memory usage reported on the WorkerStopping event (#60613)
  • make:migration now generates collision-free, ordered timestamp prefixes (#60771)
  • #[SensitiveParameter] applied to parameters carrying secrets, keeping them out of stack traces (#60753)
  • A capitalize parameter for Stringable::initials() (#60741)
  • Str::containsAll() no longer returns true for an empty needles array (#60746), and Number::forHumans() and abbreviate() no longer return -0 for tiny negative values (#60736, #60768)
  • Fixes for BelongsToMany::touch() when the related key is not id (#60708), TrustProxies with at:* and multiple proxies (#60726), and providesTemporaryUploadUrls() on the S3 driver (#60755)
  •  
下一篇