使用Exec函数压缩目录时重复生成两个压缩包的问题求助
压缩目录/文件时重复执行Exec导致覆盖压缩包的问题
使用Exec函数压缩目录或文件时出现异常:完成第一个压缩包生成后,程序会再次对同一目录/文件执行压缩操作,最终覆盖之前生成的压缩包。此前会生成多个压缩包,调整后目前仅会生成两个。
日志信息
2024-05-26 11:58:30 - Lock file is being created: /tmp/32f20e7fedb75ac2b1ebd53199bf7486.lock 2024-05-26 11:58:30 - Running zip command: /home/user/ZIP/file_name-2024-05-26-11-58-30.zip 2024-05-26 11:58:52 - Zip Archive Created Successfully: /home/user/ZIP/file_name-2024-05-26-11-58-30.zip 2024-05-26 11:58:52 - Lock file deleted: /tmp/32f20e7fedb75ac2b1ebd53199bf7486.loc
实现代码
function zipDataUsingSystem($source, $destination, $comment = '') { $zipsonuc = []; // Check if source directory or file exists if (!file_exists($source)) { $zipsonuc[] = "Source file or directory does not exist: " . $source; return $zipsonuc; } // Processing and securing file paths $sourceRealPath = realpath($source); $destinationSafe = escapeshellarg($destination); // Make it safe for command only // Specify the path to the lock file $lockFile = sys_get_temp_dir() . DIRECTORY_SEPARATOR . md5($sourceRealPath) . '.lock'; // Write to the log file that the lock file was created file_put_contents('/home/user/error.log', date('Y-m-d H:i:s') . " - Lock file is being created: " . $lockFile . "\n", FILE_APPEND); // Create and lock lock file $fp = fopen($lockFile, 'c'); if (!$fp) { $zipsonuc[] = "Lock file could not be created: " . $lockFile; return $zipsonuc; } // Lock operation if (!flock($fp, LOCK_EX | LOCK_NB)) { fclose($fp); $zipsonuc[] = "Another zip process in progress: " . $source; // Write to the log file that it could not be locked. file_put_contents('/home/user/error.log', date('Y-m-d H:i:s') . " - Another zip process in progress: " . $source . "\n", FILE_APPEND); return $zipsonuc; } // Check if the target directory exists and create it if necessary $destinationDirRealPath = dirname($destination); if (!file_exists(KOKYOLU.$destinationDirRealPath)) { if (!mkdir(KOKYOLU.$destinationDirRealPath, 0777, true)) { $zipsonuc[] = "Could not create target directory: " . $destinationDirRealPath; // Release the lock and close the lock file flock($fp, LOCK_UN); fclose($fp); // Write to the log file that the directory could not be created file_put_contents('/home/user/error.log', date('Y-m-d H:i:s') . " - Could not create target directory: " . $destinationDirRealPath . "\n", FILE_APPEND); return $zipsonuc; } } // Write in the log file that the zip command will be run file_put_contents('/home/user/error.log', date('Y-m-d H:i:s') . " - Running zip command: " . $destination . "\n", FILE_APPEND); // Create the zip command, go into the source directory and add its contents $command = "cd " . escapeshellarg($sourceRealPath) . " && zip -r $destinationSafe ."; $output = []; $return_var = 0; exec($command, $output, $return_var); // Check the results if ($return_var === 0) { // Comment adding process if ($comment !== '') { $comment = escapeshellarg(iconv(mb_detect_encoding($comment, mb_detect_order(), true), "UTF-8", $comment)); $commentCommand = "zip -z $destinationSafe <<< $comment"; exec($commentCommand); } // Remove single quotes in original filename $destinationClean = str_replace("'", "", $destination); $zipsonuc[] = "Zip Archive Created Successfully"; $zipsonuc["dosya_adi"] = $destinationClean; // Write to the log file that the zip process was completed successfully. file_put_contents('/home/user/error.log', date('Y-m-d H:i:s') . " - Zip Archive Created Successfully: " . $destinationClean . "\n", FILE_APPEND); } else { $zipsonuc[] = "Zip Archive Could Not Be Created Due to an Error: " . implode("<br>", $output); // Write the error message to the log file file_put_contents('/home/user/error.log', date('Y-m-d H:i:s') . " - Zip Archive Could Not Be Created Due to an Error: " . implode(", ", $output) . "\n", FILE_APPEND); } // Release the lock and close the lock file flock($fp, LOCK_UN); fclose($fp); unlink($lockFile); // Delete lock file // Write to the log file that the lock file has been deleted file_put_contents('/home/user/error.log', date('Y-m-d H:i:s') . " - Lock file deleted: " . $lockFile . "\n", FILE_APPEND); return $zipsonuc; }
排查与解决
1. 锁文件异常分析
日志最后一行显示删除的锁文件后缀为.loc而非定义的.lock,需先确认:
$lockFile变量在函数执行过程中未被意外修改- 日志输出语句未对
$lockFile做截断处理
若为笔误,重点检查锁机制有效性:flock依赖一致的锁文件名生效,需确保两次调用时$sourceRealPath完全一致。若$source为相对路径,需强制转换为绝对路径避免因工作目录变化导致锁文件名不同:
// 确保source为绝对路径,可自定义resolveAbsolutePath函数处理相对路径 $sourceRealPath = realpath($source) ?: $source;
2. 添加目标文件存在性检查
在函数开头增加目标压缩包的存在性判断,即使锁机制失效,也能直接跳过重复压缩:
function zipDataUsingSystem($source, $destination, $comment = '') { $zipsonuc = []; // 新增:检查目标压缩包是否已存在 if (file_exists($destination)) { $zipsonuc[] = "Zip archive already exists: " . $destination; file_put_contents('/home/user/error.log', date('Y-m-d H:i:s') . " - Zip archive already exists, skipping: " . $destination . "\n", FILE_APPEND); return $zipsonuc; } // 原有的source存在性检查... }
3. 排查重复调用源头
检查调用zipDataUsingSystem的入口:
- 是否存在前端按钮重复点击导致的HTTP请求重复发送
- 定时任务是否存在重复触发配置
- 事件监听是否被重复绑定
若存在重复调用,需在入口层做去重处理(如请求幂等性校验)。
4. 优化锁机制可靠性
调整锁文件处理顺序,利用fclose自动释放flock锁的特性,简化代码并确保原子性:
// 替换原锁释放代码块 fclose($fp); // fclose会自动释放flock锁 unlink($lockFile);
内容的提问来源于stack exchange,提问作者Adem
相关产品推荐
相关产品推荐

