本文目录导读:

我来为您介绍几种PHP项目目录同步的脚本编写方法:
基础文件同步脚本
<?php
class DirectorySync {
private $sourceDir;
private $targetDir;
private $logFile;
public function __construct($source, $target, $log = 'sync.log') {
$this->sourceDir = rtrim($source, '/') . '/';
$this->targetDir = rtrim($target, '/') . '/';
$this->logFile = $log;
}
public function sync() {
$this->log("开始同步: {$this->sourceDir} -> {$this->targetDir}");
$this->syncDirectory($this->sourceDir, $this->targetDir);
$this->log("同步完成");
}
private function syncDirectory($source, $target) {
if (!is_dir($target)) {
mkdir($target, 0755, true);
$this->log("创建目录: {$target}");
}
$items = scandir($source);
foreach ($items as $item) {
if ($item == '.' || $item == '..') continue;
$sourcePath = $source . $item;
$targetPath = $target . $item;
if (is_file($sourcePath)) {
$this->syncFile($sourcePath, $targetPath);
} elseif (is_dir($sourcePath)) {
if (!$this->shouldExclude($item)) {
$this->syncDirectory($sourcePath, $targetPath);
}
}
}
}
private function syncFile($source, $target) {
// 检查文件是否存在或是否需要更新
if (!file_exists($target) ||
md5_file($source) !== md5_file($target)) {
copy($source, $target);
$this->log("同步文件: {$source}");
}
}
private function shouldExclude($name) {
$exclude = ['.git', 'node_modules', '.idea', 'vendor'];
return in_array($name, $exclude);
}
private function log($message) {
$time = date('Y-m-d H:i:s');
file_put_contents($this->logFile, "[{$time}] {$message}\n", FILE_APPEND);
echo "[{$time}] {$message}\n";
}
}
// 使用示例
$sync = new DirectorySync('/path/to/source', '/path/to/target');
$sync->sync();
?>
实时监控同步脚本(使用inotify)
<?php
class RealtimeSync {
private $sourceDir;
private $targetDir;
private $watchProcess;
public function __construct($source, $target) {
$this->sourceDir = $source;
$this->targetDir = $target;
}
public function watch() {
// 使用 inotifywait (需要安装 inotify-tools)
$command = sprintf(
'inotifywait -m -r -e modify,create,delete,move %s --format "%%w%%e%%f"',
escapeshellarg($this->sourceDir)
);
$descriptors = [
0 => ['pipe', 'r'],
1 => ['pipe', 'w'],
2 => ['pipe', 'w']
];
$this->watchProcess = proc_open($command, $descriptors, $pipes);
if (is_resource($this->watchProcess)) {
while ($line = fgets($pipes[1])) {
$this->handleEvent(trim($line));
}
}
}
private function handleEvent($event) {
// 解析事件并执行同步
$parts = explode(' ', $event);
$action = $parts[0] ?? '';
$file = $parts[1] ?? '';
switch ($action) {
case 'CREATE':
case 'MODIFY':
$this->copyFile($file);
break;
case 'DELETE':
$this->deleteFile($file);
break;
case 'MOVED_FROM':
case 'MOVED_TO':
$this->moveFile($file);
break;
}
}
private function copyFile($file) {
$sourcePath = $this->sourceDir . '/' . $file;
$targetPath = $this->targetDir . '/' . $file;
$targetDir = dirname($targetPath);
if (!is_dir($targetDir)) {
mkdir($targetDir, 0755, true);
}
if (is_file($sourcePath)) {
copy($sourcePath, $targetPath);
echo "已同步: {$file}\n";
}
}
}
?>
基于MD5校验的增量同步脚本
<?php
class IncrementalSync {
private $source;
private $target;
private $checksumFile = '.sync_checksum.json';
public function __construct($source, $target) {
$this->source = rtrim($source, '/');
$this->target = rtrim($target, '/');
}
public function smartSync() {
// 读取上一次的校验和
$oldChecksums = $this->loadChecksums();
$newChecksums = [];
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($this->source)
);
foreach ($iterator as $file) {
if ($file->isFile()) {
$relativePath = str_replace($this->source . '/', '', $file->getPathname());
$md5 = md5_file($file->getPathname());
$newChecksums[$relativePath] = $md5;
// 检查是否需要同步
if (!isset($oldChecksums[$relativePath]) ||
$oldChecksums[$relativePath] !== $md5) {
$this->syncFile($relativePath);
}
}
}
// 检测删除的文件
foreach ($oldChecksums as $file => $checksum) {
if (!isset($newChecksums[$file])) {
$this->deleteFile($file);
}
}
// 保存新的校验和
$this->saveChecksums($newChecksums);
}
private function syncFile($relativePath) {
$sourcePath = $this->source . '/' . $relativePath;
$targetPath = $this->target . '/' . $relativePath;
$targetDir = dirname($targetPath);
if (!is_dir($targetDir)) {
mkdir($targetDir, 0755, true);
}
copy($sourcePath, $targetPath);
echo "同步: {$relativePath}\n";
}
private function deleteFile($relativePath) {
$targetPath = $this->target . '/' . $relativePath;
if (file_exists($targetPath)) {
unlink($targetPath);
echo "删除: {$relativePath}\n";
}
}
private function loadChecksums() {
$file = $this->target . '/' . $this->checksumFile;
if (file_exists($file)) {
return json_decode(file_get_contents($file), true) ?: [];
}
return [];
}
private function saveChecksums($checksums) {
$file = $this->target . '/' . $this->checksumFile;
file_put_contents($file, json_encode($checksums, JSON_PRETTY_PRINT));
}
}
?>
简单的命令行同步工具
#!/usr/bin/env php
<?php
// sync.php - 命令行同步工具
if ($argc < 3) {
echo "使用方法: php sync.php <源目录> <目标目录> [选项]\n";
echo "选项:\n";
echo " --exclude=dir1,dir2 排除目录\n";
echo " --delete 删除目标中不存在的文件\n";
echo " --dry-run 模拟运行\n";
exit(1);
}
$source = $argv[1];
$target = $argv[2];
// 解析选项
$options = [
'exclude' => [],
'delete' => false,
'dry-run' => false
];
for ($i = 3; $i < $argc; $i++) {
$arg = $argv[$i];
if (strpos($arg, '--exclude=') === 0) {
$options['exclude'] = explode(',', substr($arg, 10));
} elseif ($arg == '--delete') {
$options['delete'] = true;
} elseif ($arg == '--dry-run') {
$options['dry-run'] = true;
}
}
// 执行同步
syncDirectories($source, $target, $options);
function syncDirectories($source, $target, $options) {
if (!is_dir($source)) {
echo "错误: 源目录不存在\n";
exit(1);
}
if (!$options['dry-run'] && !is_dir($target)) {
mkdir($target, 0755, true);
}
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($source, RecursiveDirectoryIterator::SKIP_DOTS),
RecursiveIteratorIterator::SELF_FIRST
);
foreach ($files as $file) {
$relativePath = str_replace($source . '/', '', $file->getPathname());
// 检查排除
foreach ($options['exclude'] as $exclude) {
if (strpos($relativePath, $exclude) === 0) {
continue 2;
}
}
$targetPath = $target . '/' . $relativePath;
if ($file->isDir()) {
if (!$options['dry-run'] && !is_dir($targetPath)) {
mkdir($targetPath, 0755, true);
echo "创建目录: {$relativePath}\n";
}
} else {
if (!file_exists($targetPath) ||
filemtime($file) > filemtime($targetPath)) {
if ($options['dry-run']) {
echo "[模拟] 同步: {$relativePath}\n";
} else {
copy($file, $targetPath);
echo "同步: {$relativePath}\n";
}
}
}
}
// 处理删除
if ($options['delete']) {
deleteRemovedFiles($source, $target, $options);
}
}
?>
使用Rsync的PHP封装
<?php
class RsyncSync {
private $source;
private $target;
private $options = '-avz --delete';
public function __construct($source, $target) {
$this->source = $source;
$this->target = $target;
}
public function sync() {
$command = sprintf(
'rsync %s %s/ %s/',
$this->options,
escapeshellarg($this->source),
escapeshellarg($this->target)
);
$output = [];
$returnVar = 0;
exec($command, $output, $returnVar);
if ($returnVar === 0) {
echo "同步成功完成\n";
return $output;
} else {
echo "同步失败\n";
return false;
}
}
}
?>
使用建议
-
选择合适的同步方式:
- 小项目:使用基础的PHP文件操作
- 大项目:使用rsync或inotify
- 需要实时同步:使用inotify监控
-
安全考虑:
- 添加错误处理
- 设置适当的文件权限
- 记录日志
-
性能优化:
- 使用文件时间戳或MD5校验
- 排除不需要同步的目录
- 考虑使用多线程
根据您的具体需求选择合适的脚本,并根据实际情况进行调整。
版权声明: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直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播