feat(ImageProxy): 添加域名白名单和日志管理功能
- 在ImageProxy中添加了域名白名单配置,支持精确和子域名匹配,增强安全性。 - 实现了日志文件的自动清理和轮转功能,限制日志文件大小、保留时间和数量,优化日志管理。 - 更新README文档,详细说明了新功能和配置方法。
This commit is contained in:
@@ -23,7 +23,8 @@ class ImageProxy {
|
||||
'timeout' => 30,
|
||||
'connect_timeout' => 15,
|
||||
'max_redirects' => 5,
|
||||
'user_agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
|
||||
'user_agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
|
||||
'allowed_domains' => [] // 添加白名单域名配置
|
||||
];
|
||||
|
||||
private $config;
|
||||
@@ -115,8 +116,29 @@ class ImageProxy {
|
||||
* @return bool
|
||||
*/
|
||||
private function validateUrl(string $url): bool {
|
||||
return filter_var($url, FILTER_VALIDATE_URL) !== false &&
|
||||
preg_match('/^https?:\/\//i', $url);
|
||||
if (!filter_var($url, FILTER_VALIDATE_URL) || !preg_match('/^https?:\/\//i', $url)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查域名是否在白名单中
|
||||
$parsedUrl = parse_url($url);
|
||||
$host = $parsedUrl['host'] ?? '';
|
||||
|
||||
// 如果白名单为空,则允许所有域名
|
||||
if (empty($this->config['allowed_domains'])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 检查域名是否在白名单中
|
||||
foreach ($this->config['allowed_domains'] as $allowedDomain) {
|
||||
if (strcasecmp($host, $allowedDomain) === 0 ||
|
||||
preg_match('/\.' . preg_quote($allowedDomain, '/') . '$/', $host)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
$this->logger->error("Domain not in whitelist: $host");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -406,6 +428,9 @@ class ImageProxy {
|
||||
*/
|
||||
class Logger {
|
||||
private $logDir;
|
||||
private const MAX_LOG_SIZE = 10 * 1024 * 1024; // 10MB
|
||||
private const MAX_LOG_AGE = 30 * 24 * 60 * 60; // 30天
|
||||
private const MAX_LOGS = 10; // 最多保留10个日志文件
|
||||
|
||||
public function __construct(string $logDir) {
|
||||
$this->logDir = $logDir;
|
||||
@@ -413,6 +438,9 @@ class Logger {
|
||||
if (!file_exists($this->logDir)) {
|
||||
mkdir($this->logDir, 0777, true);
|
||||
}
|
||||
|
||||
// 清理旧日志
|
||||
$this->cleanupOldLogs();
|
||||
}
|
||||
|
||||
public function error(string $message) {
|
||||
@@ -423,19 +451,71 @@ class Logger {
|
||||
$this->log('INFO', $message);
|
||||
}
|
||||
|
||||
private function cleanupOldLogs() {
|
||||
try {
|
||||
$files = glob($this->logDir . '/*.log');
|
||||
if (!$files) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 按修改时间排序
|
||||
usort($files, function($a, $b) {
|
||||
return filemtime($b) - filemtime($a);
|
||||
});
|
||||
|
||||
// 删除超过保留时间的日志
|
||||
foreach ($files as $file) {
|
||||
if (time() - filemtime($file) > self::MAX_LOG_AGE) {
|
||||
unlink($file);
|
||||
}
|
||||
}
|
||||
|
||||
// 如果日志文件数量超过限制,删除最旧的
|
||||
$files = glob($this->logDir . '/*.log');
|
||||
if (count($files) > self::MAX_LOGS) {
|
||||
usort($files, function($a, $b) {
|
||||
return filemtime($a) - filemtime($b);
|
||||
});
|
||||
$filesToDelete = array_slice($files, 0, count($files) - self::MAX_LOGS);
|
||||
foreach ($filesToDelete as $file) {
|
||||
unlink($file);
|
||||
}
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
error_log("Logger cleanup error: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private function rotateLogIfNeeded(string $logFile) {
|
||||
if (!file_exists($logFile)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (filesize($logFile) >= self::MAX_LOG_SIZE) {
|
||||
$timestamp = date('Y-m-d_H-i-s');
|
||||
$newName = $logFile . '.' . $timestamp;
|
||||
rename($logFile, $newName);
|
||||
}
|
||||
}
|
||||
|
||||
private function log(string $level, string $message) {
|
||||
try {
|
||||
$date = date('Y-m-d');
|
||||
$time = date('Y-m-d H:i:s');
|
||||
$logFile = $this->logDir . "/{$date}.log";
|
||||
|
||||
// 检查并轮转日志
|
||||
$this->rotateLogIfNeeded($logFile);
|
||||
|
||||
$logMessage = "[{$time}] [{$level}] {$message}\n";
|
||||
// Ensure log directory is writable, though constructor should handle creation
|
||||
|
||||
// 确保日志目录可写
|
||||
if (!is_writable($this->logDir) && !mkdir($this->logDir, 0777, true) && !is_dir($this->logDir)) {
|
||||
// Cannot write to log, perhaps output to error_log as fallback
|
||||
error_log("Logger Error: Directory {$this->logDir} is not writable. Message: {$logMessage}");
|
||||
return;
|
||||
}
|
||||
|
||||
// 写入日志
|
||||
if (file_put_contents($logFile, $logMessage, FILE_APPEND) === false) {
|
||||
error_log("Logger Error: Failed to write to log file {$logFile}. Message: {$logMessage}");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user