Laravel 5.2升级至10.20后解密数据出现序列化前缀问题求助
问题分析
Laravel 5.2 的 Encryptable trait 依赖的 Crypt::encrypt() 方法,底层会自动对传入数据执行 serialize() 序列化操作;而 Laravel 10 的 encrypted 类型转换使用的 Crypt::decryptString() 仅负责解密,不会自动反序列化数据。这就导致旧数据库中被序列化后加密的数据,在 Laravel 10 中解密后直接返回序列化格式的字符串(如s:11:"Hello World")。
另外,Laravel 5.2 的 Crypt::decrypt() 方法内部会自动调用 unserialize(),所以当时无需手动处理就能得到原始数据,这也是你在旧版本中能正常获取干净数据的核心原因。
解决方案
方案一:自定义属性访问器/修改器(兼容新旧数据)
如果暂时不想批量修改数据库数据,可以给加密字段自定义属性,同时处理旧数据的反序列化和新数据的正确加密:
use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Support\Facades\Crypt; protected function myEncryptedAttributeString(): Attribute { return Attribute::make( get: function ($value) { $decrypted = Crypt::decryptString($value); // 判断是否为PHP序列化格式,是的话反序列化 if (str_starts_with($decrypted, 's:') || str_starts_with($decrypted, 'a:') || str_starts_with($decrypted, 'i:')) { return unserialize($decrypted); } return $decrypted; }, set: function ($value) { // 新数据直接加密,不做序列化 return Crypt::encryptString($value); } ); }
配置完成后,移除模型中对应的encrypted类型转换项即可。
方案二:批量迁移数据库旧数据(永久解决)
如果希望统一遵循 Laravel 10 的加密规范,可以写一个脚本批量处理数据库中的旧加密数据:
- 创建自定义命令脚本:
php artisan make:command MigrateEncryptedData
- 编辑生成的命令文件:
<?php namespace App\Console\Commands; use App\Models\MyModel; use Illuminate\Console\Command; use Illuminate\Support\Facades\Crypt; class MigrateEncryptedData extends Command { protected $signature = 'migrate:encrypted-data'; protected $description = '迁移旧加密数据至Laravel 10格式'; public function handle() { // 分块处理避免内存溢出 MyModel::chunk(100, function ($models) { foreach ($models as $model) { // 解密旧数据 $oldDecrypted = Crypt::decryptString($model->my_encrypted_attribute_string); // 反序列化得到原始值 $originalValue = unserialize($oldDecrypted); // 用Laravel 10方式重新加密(不序列化) $model->my_encrypted_attribute_string = Crypt::encryptString($originalValue); $model->save(); } }); $this->info('加密数据迁移完成!'); } }
- 运行命令执行迁移:
php artisan migrate:encrypted-data
迁移完成后,即可正常使用 Laravel 10 的encrypted类型转换配置,无需额外处理。
内容的提问来源于stack exchange,提问作者HelloWorld
相关产品推荐
相关产品推荐

