當前位置: 首頁> 最新文章列表> 使用zip_read() 對加密Zip 文件無效的問題說明

使用zip_read() 對加密Zip 文件無效的問題說明

M66 2025-06-05

在PHP 中,操作Zip 文件時,我們經常會用到zip_read()函數,它屬於ZipArchive 類的一部分,主要用來遍歷和讀取Zip 包中的文件條目。然而,當遇到加密的Zip 文件時,很多開發者發現使用zip_read()讀取會失敗或根本無法訪問加密內容。那麼這是為什麼呢?本文將結合PHP 的Zip 擴展機制,詳細解析這一問題的原因及其解決思路。

一、問題現象

$zip = zip_open('encrypted.zip');
if ($zip) {
    while ($entry = zip_read($zip)) {
        echo zip_entry_name($entry) . "\n";
        if (zip_entry_open($zip, $entry)) {
            echo zip_entry_read($entry, zip_entry_filesize($entry));
            zip_entry_close($entry);
        }
    }
    zip_close($zip);
}

上述代碼在讀取普通Zip 文件時能夠正常工作,但在遇到加密的Zip 文件時,常出現如下問題:

  • 無法讀取文件內容, zip_entry_read()返回空字符串或錯誤。

  • 甚至無法遍歷到任何文件條目,表現為zip_read()返回false

二、根本原因分析

zip_read()屬於PHP 的libzip庫的舊接口(基於ZIP 文件的低層操作),而且原生並不支持對加密文件內容的解密。加密的Zip 文件(通常使用密碼保護)採用的是對文件數據進行加密的方式,數據不是簡單明文存儲。

  • zip_read()只能訪問Zip 文件中的文件條目和未加密的文件內容。

  • 如果Zip 文件加密了,Zip 擴展必須通過提供正確的密碼,調用對應的解密邏輯才能正確讀取文件。

  • PHP 的zip_read()並沒有提供密碼參數,也不支持自動解密。

簡言之, zip_read()設計上並不支持加密文件的讀取。

三、正確的做法:使用ZipArchive 類的密碼解密功能

PHP 從7.2 版本開始的Zip 擴展提供了更完整的ZipArchive 類,支持設置密碼讀取加密文件:

 $zip = new ZipArchive();
$res = $zip->open('encrypted.zip');
if ($res === true) {
    // 設置密碼
    $zip->setPassword('your_password');
    for ($i = 0; $i < $zip->numFiles; $i++) {
        $stat = $zip->statIndex($i);
        echo "File: " . $stat['name'] . "\n";

        $stream = $zip->getStream($stat['name']);
        if (!$stream) {
            echo "Failed to open stream for {$stat['name']}\n";
            continue;
        }

        $contents = stream_get_contents($stream);
        fclose($stream);
        echo $contents;
    }
    $zip->close();
} else {
    echo "Failed to open zip file\n";
}

重點說明:

  • setPassword()方法用於提供解密所需的密碼。

  • 使用getStream()可以獲取加密文件的內容流,前提是密碼正確。

  • 這種方法可以正常讀取加密的Zip 文件內容。

四、總結

  • zip_read()是PHP 早期的Zip 操作接口,不能處理加密文件。

  • 加密的Zip 文件必須使用支持密碼解密的接口,如ZipArchive。

  • 通過ZipArchive::setPassword() ,PHP 可以成功打開並讀取加密文件。

  • 在實際開發中,遇到加密Zip 文件推薦使用ZipArchive 類,避免使用過時的zip_read()