本文目录导读:

我来为您介绍PHP后台访问日志的完整实现方案:
基础日志类设计
<?php
/**
* 访问日志记录类
*/
class AccessLogger {
private $logPath;
private $logFile;
private $maxFileSize = 10485760; // 10MB
public function __construct($logPath = '/var/logs/php/') {
$this->logPath = $logPath;
if (!file_exists($logPath)) {
mkdir($logPath, 0755, true);
}
}
/**
* 记录访问日志
*/
public function log($data = []) {
$logData = array_merge([
'ip' => $this->getClientIp(),
'method' => $_SERVER['REQUEST_METHOD'] ?? 'GET',
'url' => $_SERVER['REQUEST_URI'] ?? '',
'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? '',
'referer' => $_SERVER['HTTP_REFERER'] ?? '',
'timestamp' => date('Y-m-d H:i:s'),
'session_id' => session_id() ?: '',
'user_id' => isset($_SESSION['user_id']) ? $_SESSION['user_id'] : 0,
'request_data' => json_encode($data)
], $data);
$logLine = json_encode($logData, JSON_UNESCAPED_UNICODE) . "\n";
$this->writeLog($logLine);
}
/**
* 获取客户端IP
*/
private function getClientIp() {
$ipAddresses = [
'HTTP_CLIENT_IP',
'HTTP_X_FORWARDED_FOR',
'HTTP_X_FORWARDED',
'HTTP_X_CLUSTER_CLIENT_IP',
'HTTP_FORWARDED_FOR',
'HTTP_FORWARDED',
'REMOTE_ADDR'
];
foreach ($ipAddresses as $key) {
if (isset($_SERVER[$key])) {
if ($key == 'HTTP_X_FORWARDED_FOR') {
$ipList = explode(',', $_SERVER[$key]);
return trim($ipList[0]);
}
return $_SERVER[$key];
}
}
return 'unknown';
}
/**
* 写入日志(自动轮转)
*/
private function writeLog($content) {
$this->logFile = $this->logPath . date('Y-m-d') . '_access.log';
if (file_exists($this->logFile) && filesize($this->logFile) > $this->maxFileSize) {
$this->rotateLog();
}
file_put_contents($this->logFile, $content, FILE_APPEND | LOCK_EX);
}
/**
* 日志轮转
*/
private function rotateLog() {
$archiveFile = str_replace('.log', '_' . time() . '.log', $this->logFile);
rename($this->logFile, $archiveFile);
file_put_contents($this->logFile, "【" . date('Y-m-d H:i:s') . "】日志轮转\n");
}
/**
* 查询日志
*/
public function queryLogs($filters = [], $page = 1, $perPage = 10) {
$logs = [];
$files = glob($this->logPath . '*_access.log');
if (empty($files)) return ['total' => 0, 'list' => []];
// 按时间倒序排列文件
rsort($files);
foreach ($files as $file) {
$handle = fopen($file, 'r');
if (!$handle) continue;
while (($line = fgets($handle)) !== false) {
$logData = json_decode($line, true);
if (!$logData) continue;
if ($this->matchFilters($logData, $filters)) {
$logs[] = $logData;
}
}
fclose($handle);
if (count($logs) >= $page * $perPage) {
break;
}
}
// 倒序排列
krsort($logs);
$total = count($logs);
$offset = ($page - 1) * $perPage;
$list = array_slice($logs, $offset, $perPage);
return [
'total' => $total,
'page' => $page,
'perPage' => $perPage,
'list' => $list
];
}
/**
* 过滤器匹配
*/
private function matchFilters($logData, $filters) {
foreach ($filters as $key => $value) {
if (isset($logData[$key]) && $logData[$key] == $value) {
return true;
}
}
return empty($filters);
}
}
异常日志记录
<?php
/**
* 异常日志记录类
*/
class ExceptionLogger {
private static $instance = null;
private $logPath;
private function __construct($logPath = '/var/logs/php/error/') {
$this->logPath = $logPath;
if (!is_dir($logPath)) {
mkdir($logPath, 0755, true);
}
}
public static function getInstance($logPath = null) {
if (self::$instance === null) {
self::$instance = new self($logPath);
}
return self::$instance;
}
/**
* 记录异常
*/
public function logException(\Exception $e, $context = []) {
$logData = [
'timestamp' => date('Y-m-d H:i:s'),
'message' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'trace' => $e->getTraceAsString(),
'context' => json_encode($context),
'ip' => $_SERVER['REMOTE_ADDR'] ?? '',
'url' => $_SERVER['REQUEST_URI'] ?? ''
];
$logFile = $this->logPath . date('Y-m-d') . '_error.log';
$logLine = json_encode($logData, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . "\n";
file_put_contents($logFile, $logLine, FILE_APPEND | LOCK_EX);
// 可选:发送邮件通知
if (ENVIRONMENT === 'production') {
$this->sendEmailAlert($logData);
}
}
/**
* 记录PHP错误
*/
public function logError($errorNo, $errorStr, $errorFile, $errorLine) {
$logData = [
'timestamp' => date('Y-m-d H:i:s'),
'error_no' => $errorNo,
'error_str' => $errorStr,
'file' => $errorFile,
'line' => $errorLine,
'ip' => $_SERVER['REMOTE_ADDR'] ?? ''
];
$logFile = $this->logPath . date('Y-m-d') . '_error.log';
$logLine = json_encode($logData, JSON_UNESCAPED_UNICODE) . "\n";
error_log($logLine, 3, $logFile);
}
private function sendEmailAlert($data) {
// 实现邮件通知逻辑
$to = ADMIN_EMAIL;
$subject = 'PHP异常通知 - ' . date('Y-m-d H:i:s');
$message = "异常信息:{$data['message']}\n文件:{$data['file']}:{$data['line']}";
mail($to, $subject, $message);
}
}
日志查看器页面
<!DOCTYPE html>
<html>
<head>后台访问日志查询</title>
<style>
body { font-family: Arial, sans-serif; }
.filter-section { background: #f5f5f5; padding: 15px; margin-bottom: 20px; }
.log-table { width: 100%; border-collapse: collapse; }
.log-table th, .log-table td { border: 1px solid #ddd; padding: 8px; text-align: left; }
.pagination { margin-top: 20px; }
.detail-modal { display: none; position: fixed; z-index: 1; left: 0; top: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.4); }
.modal-content { background-color: #fefefe; margin: 10% auto; padding: 20px; border: 1px solid #888; width: 70%; }
</style>
</head>
<body>
<div class="filter-section">
<h2>访问日志查询</h2>
<form method="GET" action="">
日期:<input type="date" name="date" value="<?php echo $_GET['date'] ?? date('Y-m-d'); ?>">
IP:<input type="text" name="ip" value="<?php echo $_GET['ip'] ?? ''; ?>">
用户ID:<input type="text" name="user_id" value="<?php echo $_GET['user_id'] ?? ''; ?>">
<input type="submit" value="查询">
</form>
</div>
<table class="log-table">
<thead>
<tr>
<th>时间</th>
<th>IP</th>
<th>方法</th>
<th>URL</th>
<th>用户ID</th>
<th>Session</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<?php if (!empty($logs)): ?>
<?php foreach ($logs as $log): ?>
<tr>
<td><?php echo $log['timestamp']; ?></td>
<td><?php echo htmlspecialchars($log['ip']); ?></td>
<td><?php echo $log['method']; ?></td>
<td><?php echo htmlspecialchars($log['url']); ?></td>
<td><?php echo $log['user_id']; ?></td>
<td><?php echo substr($log['session_id'], 0, 8) . '...'; ?></td>
<td><button onclick="showDetail(<?php echo htmlspecialchars(json_encode($log)); ?>)">查看详情</button></td>
</tr>
<?php endforeach; ?>
<?php else: ?>
<tr><td colspan="7">暂无日志记录</td></tr>
<?php endif; ?>
</tbody>
</table>
<!-- 分页 -->
<div class="pagination">
<?php if ($totalPages > 1): ?>
<?php for ($i = 1; $i <= $totalPages; $i++): ?>
<a href="?page=<?php echo $i; ?>&date=<?php echo $_GET['date'] ?? ''; ?>"><?php echo $i; ?></a>
<?php endfor; ?>
<?php endif; ?>
</div>
<!-- 详情弹窗 -->
<div id="detailModal" class="detail-modal">
<div class="modal-content">
<span onclick="closeDetail()" style="float:right;cursor:pointer;">关闭</span>
<h3>日志详情</h3>
<div id="detailContent"></div>
</div>
</div>
<script>
function showDetail(data) {
document.getElementById('detailModal').style.display = 'block';
var content = '<pre>' + JSON.stringify(data, null, 2) + '</pre>';
document.getElementById('detailContent').innerHTML = content;
}
function closeDetail() {
document.getElementById('detailModal').style.display = 'none';
}
</script>
</body>
</html>
使用示例
<?php
// 初始化日志系统
$accessLogger = new AccessLogger('/path/to/logs/');
// 记录访问
$accessLogger->log([
'action' => 'user_login',
'username' => 'admin',
'is_success' => true
]);
// 记录访问日志在入口文件
// config.php 或 index.php
set_error_handler(function($errno, $errstr, $errfile, $errline) {
$logger = ExceptionLogger::getInstance();
$logger->logError($errno, $errstr, $errfile, $errline);
return true;
});
register_shutdown_function(function() {
$error = error_get_last();
if ($error) {
$logger = ExceptionLogger::getInstance();
$logger->logError($error['type'], $error['message'], $error['file'], $error['line']);
}
});
?>
安全最佳实践
<?php
/**
* 安全日志记录类 - 防止日志注入
*/
class SecureLogger {
private function sanitize($data) {
if (is_array($data)) {
return array_map([$this, 'sanitize'], $data);
}
// 移除控制字符
$data = preg_replace('/[\x00-\x1F\x7F]/', '', $data);
// 防止注入
$data = str_replace(
["\r\n", "\r", "\n", "\0"],
['', '', '', ''],
$data
);
return $data;
}
public function log($data) {
$cleanData = $this->sanitize($data);
// 日志写入逻辑...
}
}
// 日志文件权限设置
$logger = new AccessLogger();
if (function_exists('shell_exec')) {
shell_exec('chmod 600 ' . $logger->getLogFile());
}
?>
这个日志系统包含:
- 完整的访问日志记录
- 异常和错误日志
- 日志轮转机制
- 日志查看和查询界面
- 安全防护措施
- 数据过滤和清洗功能
版权声明: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直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播