flynn/field-mapper

HTTP请求字段转换工具,用于隐藏数据库真实字段名,支持Laravel和ThinkPHP框架

Installs: 1

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 0

Forks: 0

Open Issues: 0

pkg:composer/flynn/field-mapper

dev-main 2025-10-19 05:08 UTC

This package is auto-updated.

Last update: 2025-11-19 05:38:28 UTC


README

一个PHP Composer包,用于在HTTP传输数据时避免显示数据库真实字段名,提高API安全性。转换后的字段长度不大于6位,使用[a-z]字符集。支持Laravel和ThinkPHP框架。

功能特性

  • 自动生成安全的字段映射,隐藏数据库真实字段名
  • 支持正向映射(真实字段→安全字段)和反向映射(安全字段→真实字段)
  • 支持数组和对象的递归映射
  • 映射字段符合长度(≤6位)和字符集([a-z_-])要求
  • 提供Laravel框架集成支持
  • 支持ThinkPHP8框架集成
  • 提供中间件自动处理请求和响应
  • 支持映射关系的持久化存储和加载
  • 支持文件缓存和Redis缓存
  • 自动保存和加载映射关系

安装

使用Composer安装:

composer require flynn/field-mapper

基本使用

默认使用(文件缓存)

use Flynn\FieldMapper\FieldMapper;

// 创建映射器实例(默认使用文件缓存)
$fieldMapper = new FieldMapper();

// 映射单个字段
$mappedField = $fieldMapper->mapField('user_id'); // 返回类似 'abcde' 的3-6位小写字母

// 映射数组中的所有字段
$mappedData = $fieldMapper->mapArray([
    'user_id' => 1,
    'username' => 'admin',
    'email' => 'admin@example.com'
]);

// 反向映射字段
$realField = $fieldMapper->reverseMapField('abcde'); // 返回 'user_id'

// 反向映射数组
$realData = $fieldMapper->reverseMapArray([
    'abcde' => 1,
    'fghij' => 'admin',
    'klmno' => 'admin@example.com'
]);

// 保存映射关系到缓存
$fieldMapper->saveToCache();

使用Redis缓存

use Flynn\FieldMapper\FieldMapper;

// 创建Redis实例(注意使用完整命名空间)
$redis = new \Redis();
$redis->connect('127.0.0.1', 6379);

// 使用Redis缓存配置创建映射器实例
$fieldMapper = new FieldMapper([
    'cache_type' => 'redis',
    'redis' => $redis,
    'redis_key_prefix' => 'field_mapper:',
    'redis_ttl' => 86400, // 24小时过期
    'auto_load' => true,
    'auto_save' => true
]);

Redis不可用时的异常处理

当选择Redis缓存类型但Redis不可用时,系统会直接抛出异常,而不是自动降级到文件缓存。建议在使用Redis缓存时添加适当的错误处理:

use Flynn\FieldMapper\FieldMapper;

// 创建Redis实例
$redis = new \Redis();
$redis->connect('127.0.0.1', 6379);

try {
    // 尝试使用Redis缓存
    $fieldMapper = new FieldMapper([
        'cache_type' => 'redis',
        'redis' => $redis
    ]);
} catch (\Exception $e) {
    // Redis不可用时的处理逻辑
    echo "Redis cache initialization failed: " . $e->getMessage();
    // 可以在这里手动切换到文件缓存
    $fieldMapper = new FieldMapper([
        'cache_type' => 'file',
        'file_path' => './field-mapper.json'
    ]);
}

## 配置选项

```php
$config = [
    // 缓存类型:'file' 或 'redis'
    'cache_type' => 'file',
    
    // 文件缓存配置
    'file_path' => './field-mapper.json',
    
    // Redis缓存配置
    'redis' => null, // Redis实例
    'redis_key_prefix' => 'field_mapper:',
    'redis_ttl' => 0, // 0表示永不过期
    
    // 自动加载映射
    'auto_load' => true,
    
    // 自动保存映射
    'auto_save' => true
];

$fieldMapper = new FieldMapper($config);

缓存操作方法

// 从缓存加载映射关系(根据配置自动选择文件或Redis)
$mapper->loadFromCache();

// 保存映射关系到缓存(根据配置自动选择文件或Redis)
$mapper->saveToCache();

// 获取缓存实例
$cache = $mapper->getCache();

// 设置自定义缓存实例(需要实现CacheInterface接口)
$mapper->setCache($customCache);

// 获取缓存配置
$config = $mapper->getCacheConfig();

// 获取映射表
$mappings = $mapper->getMappings();

// 获取反向映射关系
$reverseMappings = $mapper->getReverseMappings();

// 清除所有映射关系
$mapper->clearMappings();

Laravel 集成

注册服务提供者

config/app.php 文件中的 providers 数组中添加:

Flynn\FieldMapper\FieldMapperServiceProvider::class,

发布配置

运行以下命令发布配置文件:

php artisan vendor:publish --provider="Flynn\FieldMapper\FieldMapperServiceProvider" --tag="config"

配置选项

config/field-mapper.php 中可以配置:

return [
    /*
    |--------------------------------------------------------------------------
    | 缓存类型
    |--------------------------------------------------------------------------
    |
    | 指定使用的缓存类型:'file' 或 'redis'
    |
    */
    'cache_type' => 'file',
    
    /*
    |--------------------------------------------------------------------------
    | 文件缓存配置
    |--------------------------------------------------------------------------
    |
    | 当cache_type为'file'时使用
    | 在Laravel环境中,默认使用storage_path
    |
    */
    'file_path' => storage_path('field-mapper.json'),
    
    /*
    |--------------------------------------------------------------------------
    | Redis缓存配置
    |--------------------------------------------------------------------------
    |
    | 当cache_type为'redis'时使用
    |
    */
    'redis' => [
        'host' => '127.0.0.1',
        'port' => 6379,
        'password' => '',
        'database' => 0,
        'key_prefix' => 'field_mapper:',
        'ttl' => 0, // 0表示永不过期
    ],
    
    /*
    |--------------------------------------------------------------------------
    | 自动加载映射
    |--------------------------------------------------------------------------
    |
    | 是否在初始化时自动加载映射关系
    |
    */
    'auto_load' => true,
    
    /*
    |--------------------------------------------------------------------------
    | 自动保存映射
    |--------------------------------------------------------------------------
    |
    | 是否在应用关闭时自动保存映射关系
    |
    */
    'auto_save' => true
];

使用依赖注入

use Flynn\FieldMapper\FieldMapper;

class ApiController extends Controller
{
    protected $mapper;
    
    public function __construct(FieldMapper $mapper)
    {
        $this->mapper = $mapper;
    }
    
    public function index()
    {
        $users = User::all()->toArray();
        return response()->json($this->mapper->mapArray($users));
    }
    
    public function store(Request $request)
    {
        // 将请求中的安全字段名转换回真实字段名
        $validatedData = $this->mapper->reverseMapArray($request->all());
        // 处理数据...
    }
}

使用 Facade

可以在配置文件中添加 Facade 别名,或者直接使用服务容器:

// 使用服务容器
$mapper = app('field-mapper');

// 或者使用 app() 辅助函数
$mapper = app(FieldMapper::class);

ThinkPHP8框架集成

注册服务

config/service.phpapp/provider.php 中注册服务:

return [
    'services' => [
        '\Flynn\FieldMapper\ThinkPHP\FieldMapperService',
    ],
];

配置文件

ThinkPHP的配置会自动从包中加载。你也可以复制配置文件到项目中自定义:

// 复制到项目后,配置会自动加载
// config/field_mapper.php
return [
    /*
    |--------------------------------------------------------------------------
    | 缓存类型
    |--------------------------------------------------------------------------
    |
    | 指定使用的缓存类型:'file' 或 'redis'
    |
    */
    'cache_type' => 'file',
    
    /*
    |--------------------------------------------------------------------------
    | 文件缓存配置
    |--------------------------------------------------------------------------
    |
    | 当cache_type为'file'时使用
    | 在ThinkPHP环境中,默认使用runtime目录
    |
    */
    'file_path' => App::getRuntimePath() . 'field-mapper.json',
    
    /*
    |--------------------------------------------------------------------------
    | Redis缓存配置
    |--------------------------------------------------------------------------
    |
    | 当cache_type为'redis'时使用
    |
    */
    'redis' => [
        'host' => '127.0.0.1',
        'port' => 6379,
        'password' => '',
        'database' => 0,
        'key_prefix' => 'field_mapper:',
        'ttl' => 0, // 0表示永不过期
    ],
    
    /*
    |--------------------------------------------------------------------------
    | 自动加载映射
    |--------------------------------------------------------------------------
    |
    | 是否在初始化时自动加载映射关系
    |
    */
    'auto_load' => true,
    
    /*
    |--------------------------------------------------------------------------
    | 自动保存映射
    |--------------------------------------------------------------------------
    |
    | 是否在应用关闭时自动保存映射关系
    |
    */
    'auto_save' => true,
    
    // 映射字段最大长度
    'max_length' => 6,
];

使用中间件(推荐)

app/middleware.php 中添加中间件,自动处理请求和响应:

return [
    '\Flynn\FieldMapper\ThinkPHP\middleware\FieldMapperMiddleware',
];

控制器中使用

namespace app\controller;

use app\BaseController;
use think\facade\Db;
use think\facade\App;

class UserController extends BaseController
{
    public function index()
    {
        // 方法1: 使用服务容器获取实例
        $mapper = App::get('field-mapper');
        
        // 查询用户数据
        $users = Db::name('users')
            ->field(['id', 'username', 'email'])
            ->select();
        
        // 映射字段名
        $mappedUsers = $mapper->processResultSet($users);
        
        return json([
            'code' => 200,
            'data' => $mappedUsers
        ]);
    }
    
    // 方法2: 使用中间件后无需手动处理
    public function store()
    {
        // 请求数据已被中间件自动反向映射
        $data = $this->request->param();
        
        // 直接使用转换后的数据(已映射为真实字段名)
        Db::name('users')->insert($data);
        
        // 响应也会被中间件自动正向映射
        return json(['message' => 'success']);
    }
}

ThinkPHP特殊处理

// 处理查询结果集的便捷方法
$mapper = App::get('field-mapper');

// 处理单条记录
$user = Db::name('users')->find(1);
$mappedUser = $mapper->processResultSet($user);

// 处理多条记录
$users = Db::name('users')->select();
$mappedUsers = $mapper->processResultSet($users);

// 支持对象和数组混合的情况

安全说明

  1. 本包可以帮助隐藏数据库字段名,但并不能替代其他安全措施
  2. 对于敏感数据,建议同时使用加密和本包的字段映射功能
  3. 定期备份映射关系文件,避免映射关系丢失
  4. 考虑使用环境变量或其他安全方式配置映射文件路径
  5. 支持自动保存映射关系,确保映射一致性
  6. 确保在生产环境中配置适当的缓存TTL,避免映射关系永久存储
  7. 当使用Redis缓存时,确保Redis服务器配置了适当的访问控制

测试

运行测试:

composer test

许可证

本项目采用 MIT 许可证 - 详情请查看 LICENSE 文件