本文目录导读:

在PHP项目中拦截超额存储(超出磁盘配额或存储限制)的上传文件,可以通过以下几种方案实现:
服务器层配额控制
PHP配置文件限制
// php.ini 配置 upload_max_filesize = 50M post_max_size = 55M max_file_uploads = 10
磁盘配额管理(Linux)
# 创建配额限制 sudo setquota -u www-data 500M 600M /var/www/html # 检查配额 sudo repquota -a
程序层实时监控
检查磁盘空间
<?php
class FileStorageGuard {
private $maxStorage;
private $uploadDir;
public function __construct($maxStorage = 1073741824) { // 1GB
$this->maxStorage = $maxStorage;
$this->uploadDir = '/path/to/uploads';
}
/**
* 检查剩余空间
*/
public function checkAvailableSpace($fileSize) {
$freeSpace = disk_free_space($this->uploadDir);
$usedSpace = $this->getUsedSpace();
$remainingSpace = $this->maxStorage - $usedSpace;
if ($remainingSpace <= 0) {
throw new Exception('存储空间已满');
}
if ($fileSize > $remainingSpace) {
throw new Exception('文件过大,剩余空间不足');
}
return $remainingSpace;
}
/**
* 计算已用空间
*/
private function getUsedSpace() {
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($this->uploadDir,
RecursiveDirectoryIterator::SKIP_DOTS)
);
$totalSize = 0;
foreach ($iterator as $file) {
if ($file->isFile()) {
$totalSize += $file->getSize();
}
}
return $totalSize;
}
/**
* 处理上传文件
*/
public function handleUpload($file, $destination) {
// 检查文件大小
if ($file['size'] > $this->checkAvailableSpace($file['size'])) {
return false;
}
// 移动文件
return move_uploaded_file($file['tmp_name'], $destination);
}
}
// 使用示例
$guard = new FileStorageGuard(5 * 1024 * 1024 * 1024); // 5GB
try {
$guard->handleUpload($_FILES['file'], '/path/to/destination/file.pdf');
} catch (Exception $e) {
echo '上传失败: ' . $e->getMessage();
}
数据库存储配额
<?php
class QuotaManager {
private $db;
private $userId;
public function __construct($userId) {
$this->db = new PDO('mysql:host=localhost;dbname=file_manager', 'user', 'pass');
$this->userId = $userId;
}
/**
* 获取用户配额
*/
public function getUserQuota() {
$stmt = $this->db->prepare("
SELECT quota_limit,
(SELECT COALESCE(SUM(file_size), 0) FROM files WHERE user_id = ?) as used
FROM users WHERE id = ?
");
$stmt->execute([$this->userId, $this->userId]);
return $stmt->fetch(PDO::FETCH_ASSOC);
}
/**
* 检查上传是否允许
*/
public function canUpload($fileSize) {
$quota = $this->getUserQuota();
$available = $quota['quota_limit'] - $quota['used'];
if ($fileSize > $available) {
throw new Exception("配额不足,剩余空间: " . $this->formatBytes($available));
}
return true;
}
/**
* 记录上传
*/
public function recordUpload($filePath, $fileSize) {
$stmt = $this->db->prepare("
INSERT INTO files (user_id, file_path, file_size, uploaded_at)
VALUES (?, ?, ?, NOW())
");
return $stmt->execute([$this->userId, $filePath, $fileSize]);
}
private function formatBytes($bytes) {
$units = ['B', 'KB', 'MB', 'GB', 'TB'];
$i = 0;
while ($bytes >= 1024 && $i < count($units) - 1) {
$bytes /= 1024;
$i++;
}
return round($bytes, 2) . ' ' . $units[$i];
}
}
高级方案:流式限制
使用流包装器限制写入
<?php
class LimitedWriteStream {
private $maxBytes;
private $written = 0;
private $stream;
public function __construct($stream, $maxBytes) {
$this->stream = $stream;
$this->maxBytes = $maxBytes;
}
public function write($data) {
$remaining = $this->maxBytes - $this->written;
if ($remaining <= 0) {
throw new Exception('写入限制已达到');
}
$writeLen = min(strlen($data), $remaining);
$written = fwrite($this->stream, substr($data, 0, $writeLen));
$this->written += $written;
return $written;
}
public function __destruct() {
fclose($this->stream);
}
}
// 使用示例
function uploadWithLimit($sourceFile, $destPath, $maxSize) {
$source = fopen($sourceFile, 'rb');
$dest = fopen($destPath, 'wb');
$limited = new LimitedWriteStream($dest, $maxSize);
while (!feof($source)) {
$data = fread($source, 8192);
$limited->write($data);
}
fclose($source);
}
监控与报警系统
实时磁盘监控
<?php
class DiskMonitor {
private $threshold = 90; // 90% 告警
public function checkDiskUsage($partition) {
$total = disk_total_space($partition);
$free = disk_free_space($partition);
$usedPercent = (($total - $free) / $total) * 100;
if ($usedPercent > $this->threshold) {
$this->sendAlert("磁盘使用率: {$usedPercent}%");
return false;
}
// 自动清理策略
if ($usedPercent > 80) {
$this->autoCleanup($partition);
}
return true;
}
private function autoCleanup($dir) {
$files = glob($dir . '/*.tmp'); // 清理临时文件
foreach ($files as $file) {
if (filemtime($file) < time() - 86400) { // 超过24小时
unlink($file);
}
}
}
private function sendAlert($message) {
// 发送邮件、短信或Webhook通知
mail('admin@example.com', '磁盘空间告警', $message);
}
}
前端拦截(辅助方案)
JavaScript预检查
function checkFileSize(file, maxSizeMB = 10) {
const maxSizeBytes = maxSizeMB * 1024 * 1024;
if (file.size > maxSizeBytes) {
alert(`文件大小不能超过 ${maxSizeMB}MB`);
return false;
}
// 可选:检查剩余空间(需要API支持)
checkServerStorage().then(available => {
if (file.size > available) {
alert('服务器存储空间不足');
return false;
}
});
return true;
}
// HTML表单
<form onsubmit="return checkFileSize(this.file.files[0], 50)">
<input type="file" name="file" required>
<button type="submit">上传</button>
</form>
推荐方案组合
- 初级项目:使用PHP配置 + 程序层检查
- 中级项目:数据库配额管理 + 磁盘监控
- 高级项目:流式限制 + 分布式存储 + 实时监控
关键点:
- 始终在服务端进行最终验证
- 实现多层防御(前端、应用层、系统层)
- 定期清理过期文件
- 设置合理的缓冲阈值(通常预留10-20%空间)
选择哪种方案取决于项目的具体需求和预算,对于大多数PHP项目,组合使用数据库配额管理和程序层检查就足够应对常见场景。
版权声明: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直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播