Skip to content

升级指南

从 5.5 升级到 5.5.42(安全发布)

Laravel 5.5.42 是 Laravel 的一个安全版本,建议所有用户立即升级。Laravel 5.5.42 还包含对 cookie 加密和序列化逻辑的重大更改,因此在升级应用程序时请仔细阅读以下说明。

此漏洞只有在您的应用程序加密密钥(APP_KEY 环境变量)被恶意用户访问时才可能被利用。 通常,应用程序的用户无法访问此值。但是,曾经有权限访问加密密钥的前员工可能会利用该密钥攻击您的应用程序。如果您有任何理由相信您的加密密钥已落入恶意方手中,您应始终将密钥旋转为新值。

Laravel 5.5.42 禁用了所有 cookie 值的序列化/反序列化。由于所有 Laravel cookies 都是加密和签名的,因此通常认为 cookie 值是安全的,不会被客户端篡改。但是,如果您的应用程序的加密密钥落入恶意方手中,该方可能会使用加密密钥制作 cookie 值,并利用 PHP 对象序列化/反序列化固有的漏洞,例如在您的应用程序中调用任意类方法。

禁用所有 cookie 值的序列化将使您的应用程序的所有会话失效,用户将需要重新登录应用程序。此外,您的应用程序设置的任何其他加密 cookie 将具有无效值。因此,您可能希望向应用程序添加额外的逻辑,以验证您的自定义 cookie 值是否与您期望的值列表匹配;否则,您应丢弃它们。

由于此漏洞无法在没有访问您应用程序的加密密钥的情况下被利用,我们选择提供一种方法来重新启用加密 cookie 序列化,同时您使应用程序与这些更改兼容。要启用/禁用 cookie 序列化,您可以更改 App\Http\Middleware\EncryptCookies 中间件 的静态 serialize 属性:

php
/**
 * 指示是否应序列化 cookie。
 *
 * @var bool
 */
protected static $serialize = true;
lightbulb

启用加密 cookie 序列化时,如果应用程序的加密密钥被恶意方访问,您的应用程序将容易受到攻击。如果您认为您的密钥可能已落入恶意方手中,您应在启用加密 cookie 序列化之前将密钥旋转为新值。

从 5.4 升级到 5.5.0

预计升级时间:1 小时

exclamation

我们尝试记录每一个可能的重大更改。由于这些重大更改中的一些位于框架的晦涩部分,因此只有一部分更改可能实际影响您的应用程序。

PHP

Laravel 5.5 需要 PHP 7.0.0 或更高版本。

更新依赖项

在您的 composer.json 文件中将 laravel/framework 依赖项更新为 5.5.*。此外,您应将 phpunit/phpunit 依赖项更新为 ~6.0。接下来,将 filp/whoops 包添加到 composer.json 文件的 require-dev 部分,版本为 ~2.0。最后,在 composer.json 文件的 scripts 部分,将 package:discover 命令添加到 post-autoload-dump 事件中:

php
"scripts": {
    ...
    "post-autoload-dump": [
        "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
        "@php artisan package:discover"
    ],
}

如果您正在使用 laravel/browser-kit-testing 包,您应在 composer.json 文件中将该包更新为 2.*

当然,不要忘记检查应用程序使用的任何第三方包,并验证您是否正在使用支持 Laravel 5.5 的正确版本。

Laravel 安装器

lightbulb

如果您经常通过 laravel new 使用 Laravel 安装器,您应使用 composer global update 命令更新您的 Laravel 安装器包。

Laravel Dusk

Laravel Dusk 2.0.0 已发布,以提供与 Laravel 5.5 和无头 Chrome 测试的兼容性。

Pusher

Pusher 事件广播驱动程序现在需要 Pusher SDK 的 ~3.0 版本。

Swift Mailer

Laravel 5.5 需要 Swift Mailer 的 ~6.0 版本。

Artisan

自动加载命令

在 Laravel 5.5 中,Artisan 可以自动发现命令,因此您不必手动在内核中注册它们。要利用此新功能,您应在 App\Console\Kernel 类的 commands 方法中添加以下行:

php
$this->load(__DIR__.'/Commands');

fire 方法

您 Artisan 命令中存在的任何 fire 方法应重命名为 handle

optimize 命令

随着 PHP 操作码缓存的最近改进,不再需要 optimize Artisan 命令。您应从部署脚本中删除对此命令的任何引用,因为它将在 Laravel 的未来版本中被移除。

授权

exclamation

从 Laravel 5.4 升级到 5.5 时,所有 remember_me cookies 将失效,用户将被注销。

authorizeResource 控制器方法

当将多字模型名称传递给 authorizeResource 方法时,生成的路由段现在将是“蛇”式命名,匹配资源控制器的行为。

basiconceBasic 方法

Auth::basicAuth::onceBasic 现在在身份验证失败时抛出 \Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException,而不是返回 Response。默认情况下,这仍将导致向客户端发送 401 响应。但是,如果您的应用程序逻辑检查了 Auth::basic 的返回值以返回自定义响应或在身份验证失败时实现其他行为,您现在需要处理 UnauthorizedHttpException,无论是在 catch 块中还是在应用程序的异常处理程序中。

before 策略方法

如果策略类不包含与正在检查的能力名称匹配的方法,则不会调用 before 方法。

缓存

数据库驱动

如果您正在使用数据库缓存驱动,您应在首次部署升级后的 Laravel 5.5 应用程序时运行 php artisan cache:clear

Eloquent

belongsToMany 方法

如果您正在覆盖 Eloquent 模型上的 belongsToMany 方法,您应更新方法签名以反映新参数的添加:

php
/**
 * 定义多对多关系。
 *
 * @param  string  $related
 * @param  string  $table
 * @param  string  $foreignPivotKey
 * @param  string  $relatedPivotKey
 * @param  string  $parentKey
 * @param  string  $relatedKey
 * @param  string  $relation
 * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
 */
public function belongsToMany($related, $table = null, $foreignPivotKey = null,
                              $relatedPivotKey = null, $parentKey = null,
                              $relatedKey = null, $relation = null)
{
    //
}

BelongsToMany getQualifiedRelatedKeyName

getQualifiedRelatedKeyName 方法已重命名为 getQualifiedRelatedPivotKeyName

BelongsToMany getQualifiedForeignKeyName

getQualifiedForeignKeyName 方法已重命名为 getQualifiedForeignPivotKeyName

模型 is 方法

如果您正在覆盖 Eloquent 模型的 is 方法,您应从方法中移除 Model 类型提示。这允许 is 方法接收 null 作为参数:

php
/**
 * 确定两个模型是否具有相同的 ID 并属于同一表。
 *
 * @param  \Illuminate\Database\Eloquent\Model|null  $model
 * @return bool
 */
public function is($model)
{
    //
}

模型 $events 属性

模型上的 $events 属性应重命名为 $dispatchesEvents。此更改是因为许多用户需要定义 events 关系,这与旧属性名称发生冲突。

Pivot $parent 属性

Illuminate\Database\Eloquent\Relations\Pivot 类上的受保护 $parent 属性已重命名为 $pivotParent

关系 create 方法

BelongsToManyHasOneOrManyMorphOneOrMany 类的 create 方法已被修改,以为 $attributes 参数提供默认值。如果您正在覆盖这些方法,您应更新签名以匹配新定义:

php
public function create(array $attributes = [])
{
    //
}

软删除模型

删除“软删除”模型时,模型上的 exists 属性将保持为 true

withCount 列格式

使用别名时,withCount 方法将不再自动在结果列名称上附加 _count。例如,在 Laravel 5.4 中,以下查询将导致 bar_count 列被添加到查询中:

php
$users = User::withCount('foo as bar')->get();

然而,在 Laravel 5.5 中,将完全按照给定的别名使用。如果您希望在结果列上附加 _count,您必须在定义别名时指定该后缀:

php
$users = User::withCount('foo as bar_count')->get();

模型方法和属性名称

为了防止在使用数组访问时访问模型的私有属性,现在不可能拥有与属性或属性同名的模型方法。这样做将在通过数组访问($user['name'])或 data_get 辅助函数访问模型的属性时引发异常。

异常格式

在 Laravel 5.5 中,所有异常,包括验证异常,都会被异常处理程序转换为 HTTP 响应。此外,JSON 验证错误的默认格式已更改。新格式符合以下约定:

php
{
    "message": "给定的数据无效。",
    "errors": {
        "field-1": [
            "错误 1",
            "错误 2"
        ],
        "field-2": [
            "错误 1",
            "错误 2"
        ],
    }
}

然而,如果您希望保持 Laravel 5.4 JSON 错误格式,您可以将以下方法添加到 App\Exceptions\Handler 类中:

php
use Illuminate\Validation\ValidationException;

/**
 * 将验证异常转换为 JSON 响应。
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \Illuminate\Validation\ValidationException  $exception
 * @return \Illuminate\Http\JsonResponse
 */
protected function invalidJson($request, ValidationException $exception)
{
    return response()->json($exception->errors(), $exception->status);
}

JSON 身份验证尝试

此更改还影响通过 JSON 进行的身份验证尝试的验证错误格式。在 Laravel 5.5 中,JSON 身份验证失败将返回遵循上述新格式约定的错误消息。

关于表单请求的说明

如果您正在自定义单个表单请求的响应格式,您现在应覆盖该表单请求的 failedValidation 方法,并抛出包含自定义响应的 HttpResponseException 实例:

php
use Illuminate\Http\Exceptions\HttpResponseException;

/**
 * 处理验证失败尝试。
 *
 * @param  \Illuminate\Contracts\Validation\Validator  $validator
 * @return void
 *
 * @throws \Illuminate\Validation\ValidationException
 */
protected function failedValidation(Validator $validator)
{
    throw new HttpResponseException(response()->json(..., 422));
}

文件系统

files 方法

Illuminate\Filesystem\Filesystem 类的 files 方法已更改其签名以添加 $hidden 参数,现在返回 SplFileInfo 对象数组,类似于 allFiles 方法。以前,files 方法返回字符串路径名数组。新签名如下:

php
public function files($directory, $hidden = false)

邮件

未使用的参数

未使用的 $data$callback 参数已从 Illuminate\Contracts\Mail\MailQueue 合同的 queuelater 方法中移除:

php
/**
 * 将新的电子邮件消息排队发送。
 *
 * @param  string|array|MailableContract  $view
 * @param  string  $queue
 * @return mixed
 */
public function queue($view, $queue = null);

/**
 * 在 (n) 秒后将新的电子邮件消息排队发送。
 *
 * @param  \DateTimeInterface|\DateInterval|int  $delay
 * @param  string|array|MailableContract  $view
 * @param  string  $queue
 * @return mixed
 */
public function later($delay, $view, $queue = null);

队列

dispatch 辅助函数

如果您希望调度一个立即运行并从 handle 方法返回值的作业,您应使用 dispatch_nowBus::dispatchNow 方法来调度作业:

php
use Illuminate\Support\Facades\Bus;

$value = dispatch_now(new Job);

$value = Bus::dispatchNow(new Job);

请求

all 方法

如果您正在覆盖 Illuminate\Http\Request 类的 all 方法,您应更新方法签名以反映新的 $keys 参数:

php
/**
 * 获取请求的所有输入和文件。
 *
 * @param  array|mixed  $keys
 * @return array
 */
public function all($keys = null)
{
    //
}

has 方法

$request->has 方法现在即使输入值为空字符串或 null 也会返回 true。添加了一个新的 $request->filled 方法,提供 has 方法的先前行为。

intersect 方法

intersect 方法已被移除。您可以在调用 $request->only 时使用 array_filter 来复制此行为:

php
return array_filter($request->only('foo'));

only 方法

only 方法现在只会返回请求负载中实际存在的属性。如果您希望保留 only 方法的旧行为,您可以使用 all 方法代替。

php
return $request->all('foo');

request() 辅助函数

request 辅助函数将不再检索嵌套键。如果需要,您可以使用请求的 input 方法来实现此行为:

php
return request()->input('filters.date');

测试

身份验证断言

一些身份验证断言已重命名,以便与框架的其他断言更好地保持一致:

  • seeIsAuthenticated 重命名为 assertAuthenticated
  • dontSeeIsAuthenticated 重命名为 assertGuest
  • seeIsAuthenticatedAs 重命名为 assertAuthenticatedAs
  • seeCredentials 重命名为 assertCredentials
  • dontSeeCredentials 重命名为 assertInvalidCredentials

邮件伪造

如果您正在使用 Mail 伪造来确定在请求期间是否排队了可邮寄的内容,您现在应使用 Mail::assertQueued 而不是 Mail::assertSent。此区别允许您专门断言邮件已排队进行后台发送,而不是在请求期间发送。

Tinker

Laravel Tinker 现在支持在引用应用程序类时省略命名空间。此功能需要优化的 Composer 类映射,因此您应在 composer.json 文件的 config 部分中添加 optimize-autoloader 指令:

php
"config": {
    ...
    "optimize-autoloader": true
}

翻译

LoaderInterface

Illuminate\Translation\LoaderInterface 接口已移至 Illuminate\Contracts\Translation\Loader

验证

验证器方法

所有验证器的验证方法现在都是 public 而不是 protected

视图

动态“with”变量名

在允许动态 __call 方法与视图共享变量时,这些变量将自动使用“驼峰”命名。例如,给定以下内容:

php
return view('pool')->withMaximumVotes(100);

可以在模板中像这样访问 maximumVotes 变量:

php
{{ $maximumVotes }}

@php Blade 指令

@php blade 指令不再接受内联标签。相反,请使用指令的完整形式:

php
@php
    $teamMember = true;
@endphp

杂项

我们还鼓励您查看 laravel/laravel GitHub 仓库 中的更改。虽然其中许多更改不是必需的,但您可能希望使这些文件与您的应用程序保持同步。这些更改中的一些将在本升级指南中介绍,但其他更改,例如对配置文件或注释的更改,将不会介绍。您可以轻松地使用 GitHub 比较工具 查看更改,并选择哪些更新对您来说很重要。