本文目录导读:

在 PHP 中自动记录操作人信息,通常有几种实现方式,下面我会提供最实用、最安全的几种方案,并附上代码示例。
核心思路
- 获取当前用户:从 Session、JWT Token 或 API 密钥中识别用户
- 自动注入:利用框架中间件、魔术方法或 Trait 自动填充
- 记录字段:
created_by、updated_by、deleted_by(软删除时)
基于 Laravel 框架(最推荐)
使用 Trait 自动填充
创建一个 Trait,在模型的 creating 和 updating 事件中自动填充操作人。
<?php
// app/Traits/Blameable.php
namespace App\Traits;
use Illuminate\Support\Facades\Auth;
trait Blameable
{
public static function bootBlameable()
{
static::creating(function ($model) {
if (Auth::check()) {
$model->created_by = Auth::id();
}
});
static::updating(function ($model) {
if (Auth::check()) {
$model->updated_by = Auth::id();
}
});
// 可选:软删除记录操作人
static::deleting(function ($model) {
if (Auth::check() && !$model->isForceDeleting()) {
$model->deleted_by = Auth::id();
$model->save();
}
});
}
}
在模型中使用
<?php
// app/Models/Post.php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\Traits\Blameable;
class Post extends Model
{
use Blameable;
protected $fillable = ['title', 'content'];
// 关联用户
public function creator()
{
return $this->belongsTo(User::class, 'created_by');
}
}
数据库迁移
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('content');
$table->unsignedBigInteger('created_by')->nullable();
$table->unsignedBigInteger('updated_by')->nullable();
$table->unsignedBigInteger('deleted_by')->nullable();
$table->timestamps();
$table->softDeletes();
});
原生 PHP 全局函数
如果不使用框架,可以通过全局函数或静态类实现。
<?php
// helpers.php
function getCurrentUser() {
session_start(); // 确保 session 已启动
return $_SESSION['user_id'] ?? null;
}
function autoRecord($model, $action = 'create') {
$userId = getCurrentUser();
switch ($action) {
case 'create':
$model->created_by = $userId;
$model->updated_by = $userId;
break;
case 'update':
$model->updated_by = $userId;
break;
case 'delete':
$model->deleted_by = $userId;
break;
}
return $model;
}
使用示例:
<?php
require 'helpers.php';
class Post {
public $created_by;
public $updated_by;
public $deleted_by;
public function save() {
// 保存逻辑
echo "保存成功,操作人ID: {$this->updated_by}\n";
}
}
// 创建操作
$post = new Post();
$post->title = "Hello";
$post->content = "World";
autoRecord($post, 'create');
$post->save();
// 更新操作
autoRecord($post, 'update');
$post->save();
使用中间件(适合 REST API)
Symfony/其他框架示例
<?php
// Middleware/AuditMiddleware.php
class AuditMiddleware
{
public function handle($request, $next)
{
// 获取当前用户
$user = $this->getUserFromToken($request);
// 将用户信息绑定到请求上下文
$request->attributes->set('current_user_id', $user['id']);
return $next($request);
}
private function getUserFromToken($request) {
$token = $request->headers->get('Authorization');
// 解析 JWT Token
return json_decode(base64_decode($token), true);
}
}
继承基类(面向对象)
<?php
// BaseModel.php
class BaseModel {
protected $db;
protected $currentUserId;
public function __construct($userId = null) {
$this->currentUserId = $userId ?? $this->getSessionUserId();
}
public function create($data) {
$data['created_by'] = $this->currentUserId;
$data['updated_by'] = $this->currentUserId;
// 插入数据库
}
public function update($id, $data) {
$data['updated_by'] = $this->currentUserId;
// 更新数据库
}
public function softDelete($id) {
$this->db->update(
'your_table',
['deleted_by' => $this->currentUserId, 'deleted_at' => date('Y-m-d H:i:s')],
"id = $id"
);
}
private function getSessionUserId() {
return $_SESSION['user_id'] ?? 0;
}
}
高级技巧:自动记录操作日志
如果还需要记录完整的操作日志(什么时间、谁、做了什么),可以扩展:
trait AuditLoggable {
protected static function bootAuditLoggable() {
static::saved(function ($model) {
// 检查是创建还是更新
$action = $model->wasRecentlyCreated ? 'CREATE' : 'UPDATE';
AuditLog::create([
'user_id' => Auth::id(),
'action' => $action,
'table_name' => $model->getTable(),
'record_id' => $model->id,
'old_data' => json_encode($model->getOriginal()),
'new_data' => json_encode($model->getAttributes()),
'ip_address' => request()->ip(),
'user_agent' => request()->userAgent(),
'timestamp' => now(),
]);
});
}
}
实战建议
| 场景 | 推荐方案 | 说明 |
|---|---|---|
| Laravel 项目 | Trait + Event | 最优雅,自动化程度高 |
| 原生 PHP | 全局函数 | 简单直接 |
| 大型系统 | 中间件 + 日志系统 | 可追踪性强 |
| 微服务 | JWT + 过滤器 | 适合分布式 |
注意点
- 外键约束:建议设置
created_by等字段为可空,避免系统自动任务时报错 - 权限校验:记录操作人的同时,务必校验用户是否有操作权限
- 日志保留:大型系统建议定期归档日志
- 性能考虑:高频操作表可考虑异步写日志
最终推荐
如果使用 Laravel,强烈建议使用方案一(Trait),这是目前最主流且维护性最好的方式。
如果使用原生 PHP,建议封装一个 AuditService 类,统一管理操作人记录逻辑。
有任何特定框架或场景需求,欢迎告诉我,我可以提供更针对性的代码!