本文目录导读:

在PHP项目中实现后台操作日志,通常有几种成熟的方案,以下是几种常见实现方式,从简单到复杂:
使用数据库记录日志
创建日志表
CREATE TABLE `admin_logs` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`admin_id` int(11) NOT NULL COMMENT '操作管理员ID',
`admin_name` varchar(50) NOT NULL COMMENT '操作人',
`type` varchar(20) NOT NULL COMMENT '操作类型:create/update/delete/login',
`module` varchar(50) NOT NULL COMMENT '操作模块',
`action` varchar(100) NOT NULL COMMENT '操作描述',
`request_data` text COMMENT '请求数据',
`ip_address` varchar(45) COMMENT 'IP地址',
`user_agent` varchar(255) COMMENT '浏览器信息',
`created_at` timestamp DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_admin_id` (`admin_id`),
KEY `idx_type` (`type`),
KEY `idx_created_at` (`created_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
日志记录类实现
<?php
class AdminLogger {
private $db;
public function __construct($db) {
$this->db = $db;
}
public function log($admin_id, $admin_name, $type, $module, $action, $request_data = null) {
$data = [
'admin_id' => $admin_id,
'admin_name' => $admin_name,
'type' => $type,
'module' => $module,
'action' => $action,
'request_data' => json_encode($request_data),
'ip_address' => $this->getClientIp(),
'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? ''
];
$stmt = $this->db->prepare("INSERT INTO admin_logs (admin_id, admin_name, type, module, action, request_data, ip_address, user_agent) VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
return $stmt->execute(array_values($data));
}
private function getClientIp() {
$ip = '0.0.0.0';
if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
} elseif (!empty($_SERVER['REMOTE_ADDR'])) {
$ip = $_SERVER['REMOTE_ADDR'];
}
return $ip;
}
}
?>
使用中间件/AOP方式(推荐)
定义日志注解(PHP 8+)
<?php
#[Attribute]
class LogAnnotation {
public function __construct(
public string $type,
public string $module,
public string $action
) {}
}
?>
使用中间件自动记录
<?php
class LogMiddleware {
private $logger;
public function __construct(AdminLogger $logger) {
$this->logger = $logger;
}
public function handle($request, $next) {
// 获取当前路由和控制器信息
$route = $request->getRoute();
$controller = $route->getController();
$method = $route->getMethod();
// 执行原操作
$response = $next($request);
// 记录日志
if ($this->shouldLog($controller, $method)) {
$this->logger->log(
$request->admin_id,
$request->admin_name,
$this->getLogType($method),
get_class($controller),
"执行了{$method}操作",
$request->all()
);
}
return $response;
}
private function shouldLog($controller, $method) {
return true; // 根据实际情况决定
}
}
?>
使用事件驱动的方式
<?php
// 定义事件
class AdminOperationEvent {
public $admin_id;
public $admin_name;
public $type;
public $module;
public $action;
public $data;
public function __construct($admin_id, $admin_name, $type, $module, $action, $data = []) {
$this->admin_id = $admin_id;
$this->admin_name = $admin_name;
$this->type = $type;
$this->module = $module;
$this->action = $action;
$this->data = $data;
}
}
// 事件监听器
class LogEventListener {
public function handle(AdminOperationEvent $event) {
// 记录到数据库
$logModel = new AdminLogModel();
$logModel->create([
'admin_id' => $event->admin_id,
'admin_name' => $event->admin_name,
'type' => $event->type,
'module' => $event->module,
'action' => $event->action,
'request_data' => json_encode($event->data)
]);
// 可选:同时记录到文件
$logFile = storage_path('logs/admin_operation.log');
$line = sprintf("[%s] %s %s %s %s\n",
date('Y-m-d H:i:s'),
$event->admin_name,
$event->type,
$event->module,
$event->action
);
file_put_contents($logFile, $line, FILE_APPEND | LOCK_EX);
}
}
?>
最佳实践建议
日志分级
<?php
class LogLevel {
const INFO = 'info';
const WARNING = 'warning';
const ERROR = 'error';
const CRITICAL = 'critical';
}
// 使用示例
$logger->log(LogLevel::INFO, '用户登录成功');
$logger->log(LogLevel::WARNING, '尝试使用弱密码');
$logger->log(LogLevel::ERROR, '数据更新失败');
?>
敏感信息过滤
<?php
class LogCleaner {
private $sensitiveFields = ['password', 'token', 'secret', 'credit_card'];
public function cleanData($data) {
foreach ($this->sensitiveFields as $field) {
if (isset($data[$field])) {
$data[$field] = '***FILTERED***';
}
}
return $data;
}
}
?>
使用现成日志库
- monolog/monolog:PHP最流行的日志库
- KLogger:轻量级日志类
composer require monolog/monolog
<?php
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
$log = new Logger('admin_operation');
$log->pushHandler(new StreamHandler('path/to/your.log', Logger::WARNING));
$log->warning('Admin operation', [
'admin_id' => 123,
'action' => 'delete_user',
'target_id' => 456
]);
?>
日志查询功能
<?php
// 后台日志查询
class AdminLogService {
public function search(array $filters, $page = 1, $perPage = 20) {
$query = AdminLogModel::query();
if (isset($filters['admin_id'])) {
$query->where('admin_id', $filters['admin_id']);
}
if (isset($filters['type'])) {
$query->where('type', $filters['type']);
}
if (isset($filters['start_date'])) {
$query->where('created_at', '>=', $filters['start_date']);
}
if (isset($filters['end_date'])) {
$query->where('created_at', '<=', $filters['end_date']);
}
if (isset($filters['keyword'])) {
$query->where('action', 'like', "%{$filters['keyword']}%");
}
return $query->orderBy('created_at', 'desc')
->paginate($perPage, ['*'], 'page', $page);
}
}
?>
注意事项
- 性能考虑:日志操作不应影响主业务流程,建议使用异步记录
- 存储策略:定期清理过期日志,或使用日志归档
- 安全防护:日志本身也需要保护,防止被篡改
- 合规性:遵守数据保护法规(如GDPR),不记录敏感信息
- 可追溯性:确保日志的完整性和不可否认性
推荐在实际项目中选择中间件自动记录 + 关键操作手动记录的组合方案,既保证全覆盖又灵活可控。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播