完整的ZIP文件处理解决方案(兼容PHP 8.3)
/*** 完整的ZIP文件处理解决方案(兼容PHP 8.3)
* 功能:下载ZIP文件、验证MD5、解压加密ZIP
*/
class ZipProcessor {
private $tempDir;
public function __construct() {
$this->tempDir = sys_get_temp_dir();
$this->checkDependencies();
}
private function checkDependencies() {
if (!extension_loaded('curl')) {
throw new Exception("需要CURL扩展支持");
}
if (!extension_loaded('zip')) {
throw new Exception("需要ZIP扩展支持");
}
}
public function processApiResponse($apiResponse, $extractDir) {
try {
$responseData = $this->parseApiResponse($apiResponse);
$zipFile = $this->downloadZipFile($responseData['download_url']);
$this->verifyFileIntegrity($zipFile, $responseData['zip_md5'], $responseData['zip_size']);
$this->extractZipFile($zipFile, $extractDir, $responseData['zip_password']);
$this->cleanupTempFiles($zipFile);
return [
'success' => true,
'message' => 'ZIP文件处理成功',
'version' => $responseData['version'],
'extract_dir' => realpath($extractDir)
];
} catch (Exception $e) {
if (isset($zipFile) && file_exists($zipFile)) {
$this->cleanupTempFiles($zipFile);
}
return [
'success' => false,
'message' => $e->getMessage()
];
}
}
/**
* 解析API响应
*/
private function parseApiResponse($apiResponse) {
$responseData = json_decode($apiResponse, true);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new Exception("JSON解析失败: " . json_last_error_msg());
}
if (!isset($responseData['code']) || $responseData['code'] !== 0) {
throw new Exception("API错误: " . ($responseData['msg'] ?? '未知错误'));
}
if (!isset($responseData['data'])) {
throw new Exception("API响应格式错误: 缺少data字段");
}
$requiredFields = ['download_url', 'zip_password', 'zip_md5', 'version'];
foreach ($requiredFields as $field) {
if (!isset($responseData['data'][$field])) {
throw new Exception("API响应格式错误: 缺少data字段 $field");
}
}
return $responseData['data'];
}
/**
* 下载ZIP文件
*/
private function downloadZipFile($url) {
$tempFile = tempnam($this->tempDir, 'zip_download_');
$ch = curl_init($url);
$fp = fopen($tempFile, 'w');
if (!$fp) {
throw new Exception("无法创建临时文件: $tempFile");
}
curl_setopt_array($ch, [
CURLOPT_FILE => $fp,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_AUTOREFERER => true,
CURLOPT_MAXREDIRS => 5,
CURLOPT_TIMEOUT => 60,
CURLOPT_CONNECTTIMEOUT => 30,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_USERAGENT => 'PHP-ZipProcessor/1.0'
]);
$result = curl_exec($ch);
if ($result === false) {
$error = curl_error($ch);
fclose($fp);
unlink($tempFile);
curl_close($ch);
throw new Exception("下载失败: $error");
}
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
curl_close($ch);
fclose($fp);
if ($httpCode < 200 || $httpCode >= 300) {
unlink($tempFile);
throw new Exception("HTTP错误: $httpCode");
}
if (!in_array($contentType, ['application/zip', 'application/x-zip-compressed', 'application/octet-stream'])) {
unlink($tempFile);
throw new Exception("下载的文件不是ZIP格式: $contentType");
}
if (filesize($tempFile) === 0) {
unlink($tempFile);
throw new Exception("下载的文件为空");
}
return $tempFile;
}
/**
* 验证文件完整性
*/
private function verifyFileIntegrity($filePath, $expectedMd5, $expectedSize = null) {
// 验证MD5
$actualMd5 = md5_file($filePath);
if (strtolower($actualMd5) !== strtolower($expectedMd5)) {
throw new Exception("MD5验证失败\n实际: $actualMd5\n期望: $expectedMd5");
}
// 验证文件大小(如果提供)
if ($expectedSize !== null && $expectedSize !== '0') {
$actualSize = filesize($filePath);
$expectedBytes = $this->humanToBytes($expectedSize);
if ($expectedBytes > 0 && abs($actualSize - $expectedBytes) > 1024) { // 允许1KB误差
throw new Exception("文件大小不匹配\n实际: " . $this->bytesToHuman($actualSize) .
"\n期望: $expectedSize");
}
}
}
/**
* 解压ZIP文件(兼容PHP 8.3)
*/
private function extractZipFile($zipFile, $extractDir, $password) {
// 创建解压目录
if (!file_exists($extractDir)) {
if (!mkdir($extractDir, 0755, true)) {
throw new Exception("无法创建解压目录: $extractDir");
}
}
if (!is_writable($extractDir)) {
throw new Exception("解压目录不可写: $extractDir");
}
$zip = new ZipArchive();
$openResult = $zip->open($zipFile);
if ($openResult !== true) {
throw new Exception("无法打开ZIP文件: " . $this->getZipErrorText($openResult));
}
try {
// 尝试使用密码(兼容PHP 8.3)
$zip->setPassword($password);
// 检查ZIP文件是否有内容
if ($zip->numFiles === 0) {
throw new Exception("ZIP文件为空");
}
// 尝试解压所有文件
$success = false;
// 先尝试解压第一个文件测试密码
$firstFileName = $zip->getNameIndex(0);
if ($zip->extractTo($extractDir, $firstFileName)) {
// 密码正确,继续解压其他文件
for ($i = 1; $i < $zip->numFiles; $i++) {
$fileName = $zip->getNameIndex($i);
$zip->extractTo($extractDir, $fileName);
}
$success = true;
} else {
// 可能是密码错误,尝试不使用密码
$zip->setPassword('');
if ($zip->extractTo($extractDir)) {
$success = true;
} else {
// 检查具体错误
if ($openResult === ZipArchive::ER_WRONGPASSWD) {
throw new Exception("ZIP文件密码错误");
}
throw new Exception("解压失败");
}
}
if (!$success) {
throw new Exception("解压失败");
}
} finally {
$zip->close();
}
return true;
}
private function cleanupTempFiles($filePath) {
if (file_exists($filePath)) {
unlink($filePath);
}
}
/**
* 获取ZIP错误信息
*/
private function getZipErrorText($errorCode) {
$errors = [
ZipArchive::ER_EXISTS => '文件已存在',
ZipArchive::ER_INCONS => 'Zip文件不一致',
ZipArchive::ER_INVAL => '无效的参数',
ZipArchive::ER_MEMORY => '内存分配失败',
ZipArchive::ER_NOENT => '没有这样的文件',
ZipArchive::ER_NOZIP => '不是zip归档',
ZipArchive::ER_OPEN => '无法打开文件',
ZipArchive::ER_READ => '读取错误',
ZipArchive::ER_SEEK => '查找错误',
ZipArchive::ER_WRONGPASSWD => '密码错误'
];
return $errors[$errorCode] ?? "未知错误: $errorCode";
}
/**
* 人类可读大小转字节
*/
private function humanToBytes($size) {
if ($size === null || $size === '') return 0;
$units = ['B', 'KB', 'MB', 'GB', 'TB'];
$unit = strtoupper(substr($size, -2));
if (!in_array($unit, $units)) {
$unit = strtoupper(substr($size, -1));
}
$value = (float)trim(rtrim($size, $unit));
$power = array_search($unit, $units);
return $value * pow(1024, $power);
}
/**
* 字节转人类可读大小
*/
private function bytesToHuman($bytes) {
$units = ['B', 'KB', 'MB', 'GB', 'TB'];
$power = floor(log($bytes, 1024));
return round($bytes / pow(1024, $power), 2) . $units[$power];
}
}
// 使用示例
try {
// API响应数据
$apiResponse = '{
"code": 0,
"msg": "加密更新包生成成功",
"data": {
"download_url": ",
"zip_password": "e26d556899c456915a61341802dad137",
"zip_size": "3.56KB",
"zip_md5": "90e356e66c38a0c5c9d023e94aa750e1",
"version": "3.1.20250928",
"cxid": 2
}
}';
$extractDirectory = ROOT;
$processor = new ZipProcessor();
// 执行处理流程
$result = $processor->processApiResponse($apiResponse, $extractDirectory);
if ($result['success']) {
echo "✅ 处理成功!\n";
echo "📁 解压目录: " . $result['extract_dir'] . "\n";
echo "🔢 版本号: " . $result['version'] . "\n";
} else {
echo "❌ 处理失败: " . $result['message'] . "\n";
}
} catch (Exception $e) {
echo "⚠️系统错误: " . $e->getMessage() . "\n";
}
页:
[1]