本文目录导读:

我来介绍几种在PHP项目中实现日志压缩的方法:
使用PHP内置的压缩函数
gzip压缩
<?php
class LogCompressor {
/**
* 压缩单个日志文件
*/
public function compressLogFile($sourceFile, $destinationFile = null) {
if (!file_exists($sourceFile)) {
throw new Exception("源文件不存在");
}
$destinationFile = $destinationFile ?? $sourceFile . '.gz';
$data = file_get_contents($sourceFile);
$compressed = gzencode($data, 9);
file_put_contents($destinationFile, $compressed);
// 可选:删除原文件
// unlink($sourceFile);
return $destinationFile;
}
/**
* 解压缩日志文件
*/
public function decompressLogFile($compressedFile, $destinationDir = null) {
if (!file_exists($compressedFile)) {
throw new Exception("压缩文件不存在");
}
$destinationDir = $destinationDir ?? dirname($compressedFile);
// 读取压缩文件
$compressed = file_get_contents($compressedFile);
$data = gzdecode($compressed);
// 生成解压后的文件名
$basename = basename($compressedFile, '.gz');
$destinationFile = $destinationDir . '/' . $basename;
file_put_contents($destinationFile, $data);
return $destinationFile;
}
}
bzip2压缩
<?php
function compressWithBzip2($sourceFile, $destinationFile = null) {
$destinationFile = $destinationFile ?? $sourceFile . '.bz2';
// 使用bzcompress
$data = file_get_contents($sourceFile);
$compressed = bzcompress($data, 9);
file_put_contents($destinationFile, $compressed);
return $destinationFile;
}
function decompressBzip2($compressedFile, $destinationFile = null) {
$data = file_get_contents($compressedFile);
$decompressed = bzdecompress($data);
$destinationFile = $destinationFile ?? preg_replace('/\.bz2$/', '', $compressedFile);
file_put_contents($destinationFile, $decompressed);
return $destinationFile;
}
批量压缩和归档
<?php
class LogArchiver {
private $logDir;
private $archiveDir;
public function __construct($logDir, $archiveDir) {
$this->logDir = rtrim($logDir, '/');
$this->archiveDir = rtrim($archiveDir, '/');
if (!is_dir($this->archiveDir)) {
mkdir($this->archiveDir, 0755, true);
}
}
/**
* 归档指定日期之前的日志
*/
public function archiveOldLogs($daysOld = 7) {
$files = glob($this->logDir . '/*.log');
$cutoff = time() - ($daysOld * 86400);
$archived = [];
foreach ($files as $file) {
if (filemtime($file) < $cutoff) {
$archiveName = basename($file) . '.' . date('Ymd') . '.gz';
$archivePath = $this->archiveDir . '/' . $archiveName;
// 压缩文件
if ($this->compressFile($file, $archivePath)) {
// 成功压缩后删除原文件
unlink($file);
$archived[] = $archiveName;
}
}
}
return $archived;
}
/**
* 压缩文件,使用流式处理避免内存问题
*/
private function compressFile($source, $destination) {
try {
$sfp = gzopen($destination, 'w9');
$fp = fopen($source, 'rb');
while (!feof($fp)) {
gzwrite($sfp, fread($fp, 8192));
}
fclose($fp);
gzclose($sfp);
return true;
} catch (Exception $e) {
error_log("压缩失败: " . $e->getMessage());
return false;
}
}
/**
* 创建tar归档并压缩
*/
public function createTarArchive($startDate, $endDate = null) {
$phar = new PharData(
$this->archiveDir . '/logs-' . date('Ymd') . '.tar.gz',
Phar::GZ
);
$files = glob($this->logDir . '/*.log');
foreach ($files as $file) {
$fileDate = date('Ymd', filemtime($file));
if ($fileDate >= $startDate &&
($endDate === null || $fileDate <= $endDate)) {
$phar->addFile($file, basename($file));
}
}
return $phar->getPath();
}
}
带日志轮转的压缩
<?php
class LogRotationCompressor {
private $logDir;
private $maxSize;
private $maxFiles;
public function __construct($logDir, $maxSize = 104857600, $maxFiles = 10) {
$this->logDir = rtrim($logDir, '/');
$this->maxSize = $maxSize; // 默认100MB
$this->maxFiles = $maxFiles;
}
/**
* 检查并压缩超过大小的日志
*/
public function checkAndRotate($logFile) {
if (!file_exists($logFile)) {
return false;
}
// 检查文件大小
if (filesize($logFile) < $this->maxSize) {
return false;
}
$basename = basename($logFile);
// 轮转并压缩
for ($i = $this->maxFiles - 1; $i > 0; $i--) {
$oldFile = $this->logDir . '/' . $basename . '.' . $i . '.gz';
$newFile = $this->logDir . '/' . $basename . '.' . ($i + 1) . '.gz';
if (file_exists($oldFile)) {
rename($oldFile, $newFile);
}
}
// 压缩当前日志
$destination = $this->logDir . '/' . $basename . '.1.gz';
$this->compressFile($logFile, $destination);
// 清空原日志文件
file_put_contents($logFile, '');
return true;
}
private function compressFile($source, $destination) {
$sfp = gzopen($destination, 'w9');
$fp = fopen($source, 'rb');
while (!feof($fp)) {
gzwrite($sfp, fread($fp, 8192));
}
fclose($fp);
gzclose($sfp);
return true;
}
}
使用exec执行系统命令
<?php
class SystemCommandCompressor {
/**
* 使用gzip命令压缩
*/
public function compressWithGzip($file) {
// 保留原文件
exec("gzip -c {$file} > {$file}.gz", $output, $returnVar);
if ($returnVar !== 0) {
throw new Exception("gzip压缩失败: " . implode("\n", $output));
}
return $file . '.gz';
}
/**
* 使用bzip2命令压缩
*/
public function compressWithBzip2($file) {
exec("bzip2 -z -k {$file}", $output, $returnVar);
if ($returnVar !== 0) {
throw new Exception("bzip2压缩失败: " . implode("\n", $output));
}
return $file . '.bz2';
}
/**
* 创建tar归档
*/
public function createTarArchive($files, $archiveName) {
$fileList = implode(' ', $files);
exec("tar -czf {$archiveName} {$fileList}", $output, $returnVar);
if ($returnVar !== 0) {
throw new Exception("tar归档失败: " . implode("\n", $output));
}
return $archiveName;
}
}
定时任务实现自动化压缩
创建压缩脚本 compress_logs.php
<?php
require_once 'LogArchiver.php';
$config = [
'log_dir' => '/var/log/myapp',
'archive_dir' => '/var/log/archives',
'days_old' => 7,
'max_file_size' => 104857600, // 100MB
];
$archiver = new LogArchiver($config['log_dir'], $config['archive_dir']);
// 归档旧日志
$archived = $archiver->archiveOldLogs($config['days_old']);
echo "已归档 " . count($archived) . " 个日志文件\n";
// 检查并轮转大文件
$rotator = new LogRotationCompressor(
$config['log_dir'],
$config['max_file_size']
);
$logFiles = glob($config['log_dir'] . '/*.log');
foreach ($logFiles as $logFile) {
if ($rotator->checkAndRotate($logFile)) {
echo "已轮转: " . basename($logFile) . "\n";
}
}
设置cron定时任务
# 每天凌晨2点执行日志压缩 0 2 * * * /usr/bin/php /path/to/compress_logs.php >> /var/log/log_compression.log 2>&1
使用建议
- 大文件处理:对于大日志文件,使用流式处理避免内存溢出
- 保留原文件:压缩完成后建议保留原文件一段时间,确认无问题再删除
- 错误处理:添加完善的错误处理和日志记录
- 性能考虑:使用适当压缩级别(通常6-9之间)
- 安全性:确保压缩和解压缩操作的目录权限正确
选择哪种方式取决于你的具体需求,内置函数适合简单场景,系统命令适合高性能需求,而类封装提供了更好的可维护性。