feat(ImageProxy): 添加域名白名单和日志管理功能
- 在ImageProxy中添加了域名白名单配置,支持精确和子域名匹配,增强安全性。 - 实现了日志文件的自动清理和轮转功能,限制日志文件大小、保留时间和数量,优化日志管理。 - 更新README文档,详细说明了新功能和配置方法。
This commit is contained in:
parent
192fc2f45c
commit
39d21d3a6a
@ -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}");
|
||||
}
|
||||
|
67
README.md
67
README.md
@ -13,6 +13,11 @@
|
||||
/index.php?url=https://example.com/image.jpg
|
||||
```
|
||||
|
||||
使用伪静态后的访问方式:
|
||||
```
|
||||
/image/https://example.com/image.jpg
|
||||
```
|
||||
|
||||
## 参数说明
|
||||
|
||||
- url: 必填参数,需要代理的远程图片URL
|
||||
@ -36,6 +41,7 @@
|
||||
- SSL验证:支持HTTPS图片获取
|
||||
- 图片数据验证:验证下载的图片数据是否有效
|
||||
- 错误处理:完善的错误处理和日志记录
|
||||
- 域名白名单:支持配置允许访问的域名列表,防止服务被滥用
|
||||
|
||||
## 性能优化
|
||||
|
||||
@ -61,17 +67,72 @@ $proxy = new ImageProxy([
|
||||
'cache_dir' => 'cache', // 缓存目录
|
||||
'timeout' => 30, // 请求超时时间(秒)
|
||||
'connect_timeout' => 15, // 连接超时时间(秒)
|
||||
'max_redirects' => 5 // 最大重定向次数
|
||||
'max_redirects' => 5, // 最大重定向次数
|
||||
'allowed_domains' => [ // 允许访问的域名白名单
|
||||
'example.com',
|
||||
'trusted-site.com',
|
||||
'images.example.org'
|
||||
// 添加更多允许的域名
|
||||
]
|
||||
]);
|
||||
```
|
||||
|
||||
白名单配置说明:
|
||||
- 如果 `allowed_domains` 为空数组,则允许访问所有域名
|
||||
- 支持精确域名匹配(如 `example.com`)
|
||||
- 支持子域名匹配(如 `images.example.com` 会匹配 `example.com`)
|
||||
- 域名比较不区分大小写
|
||||
- 不在白名单中的域名请求将被拒绝,并记录到日志中
|
||||
|
||||
## 错误处理
|
||||
|
||||
系统会自动记录所有错误到日志文件中,日志文件位于`cache/logs/`目录下,按日期命名。
|
||||
系统会自动记录所有错误到日志文件中,日志文件位于`cache/logs/`目录下,按日期命名。系统实现了自动日志轮转功能:
|
||||
|
||||
- 单个日志文件大小限制:10MB
|
||||
- 日志文件保留时间:30天
|
||||
- 最大保留日志文件数:10个
|
||||
- 自动清理过期日志
|
||||
- 自动轮转超大日志文件
|
||||
|
||||
日志文件命名规则:
|
||||
- 当前日志:`YYYY-MM-DD.log`
|
||||
- 轮转后的日志:`YYYY-MM-DD.log.YYYY-MM-DD_HH-mm-ss`
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. 确保服务器有足够的磁盘空间用于缓存
|
||||
2. 确保缓存目录有写入权限
|
||||
3. 建议定期清理缓存文件
|
||||
4. 建议监控日志文件大小
|
||||
4. 日志系统会自动管理日志文件大小和数量,无需手动干预
|
||||
|
||||
## 伪静态配置
|
||||
|
||||
### Apache 配置
|
||||
在网站根目录创建或编辑 `.htaccess` 文件:
|
||||
|
||||
```apache
|
||||
RewriteEngine On
|
||||
RewriteBase /
|
||||
|
||||
# 图片代理伪静态规则
|
||||
RewriteRule ^image/(.*)$ index.php?url=$1 [L,QSA]
|
||||
|
||||
# 禁止直接访问 index.php
|
||||
RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s/+index\.php [NC]
|
||||
RewriteRule ^ - [F]
|
||||
```
|
||||
|
||||
### Nginx 配置
|
||||
在网站配置文件中添加:
|
||||
|
||||
```nginx
|
||||
location / {
|
||||
# 图片代理伪静态规则
|
||||
rewrite ^/image/(.*)$ /index.php?url=$1 last;
|
||||
|
||||
# 禁止直接访问 index.php
|
||||
location = /index.php {
|
||||
return 403;
|
||||
}
|
||||
}
|
||||
```
|
Loading…
x
Reference in New Issue
Block a user