2024 PHP Conference Japan

zip_open

(PHP 4 >= 4.1.0, PHP 5 >= 5.2.0, PHP 7, PHP 8, PECL zip >= 1.0.0)

zip_open開啟 ZIP 檔案壓縮檔

警告

此函式自 PHP 8.0.0 起已被 _棄用_。強烈建議不要依賴此函式。

說明

#[\Deprecated]
zip_open(字串 $filename): 資源|整數|false

開啟一個新的 zip 壓縮檔以供讀取。

參數

filename

要開啟的 ZIP 壓縮檔的檔名。

返回值

傳回一個資源控制代碼,供後續與 zip_read()zip_close() 使用,或者如果 filename 不存在或發生其他錯誤時,返回 false 或錯誤代碼。

更新日誌

版本 說明
8.0.0 此函數已被棄用,建議使用物件導向 API,請參閱 ZipArchive::open()

另請參閱

新增註解

使用者貢獻的註解 13 則註解

david at php dot net
15 年前
請注意,Zip 函數在發生錯誤時會返回一個整數錯誤代碼。所以

<?php
$zip
= zip_open($file);

if (
$zip) {
?>

是不正確的。應該使用

<?php
$zip
= zip_open($file);

if (
is_resource($zip)) {
?>
saulius at solmetra dot lt
17 年前
一些較舊的 PHP 版本在 zip_open 失敗時會返回 false,而較新的版本會返回錯誤代碼(整數),因此不要使用

$zip = zip_open($zip_file);
if ($zip) {
// 認為 zip 檔案已成功開啟
}

而應該使用

$zip = zip_open($zip_file);
if (is_resource($zip)) {
// 認為 zip 檔案已成功開啟
}

您也可以使用以下函數根據錯誤代碼取得錯誤訊息

function zipFileErrMsg($errno) {
// 使用常數名稱作為字串以使此函數與 PHP4 相容
$zipFileFunctionsErrors = array(
'ZIPARCHIVE::ER_MULTIDISK' => '不支援多磁片 zip 檔案。',
'ZIPARCHIVE::ER_RENAME' => '重新命名暫存檔失敗。',
'ZIPARCHIVE::ER_CLOSE' => '關閉 zip 檔案失敗。',
'ZIPARCHIVE::ER_SEEK' => '搜尋錯誤。',
'ZIPARCHIVE::ER_READ' => '讀取錯誤。',
'ZIPARCHIVE::ER_WRITE' => '寫入錯誤。',
'ZIPARCHIVE::ER_CRC' => 'CRC 錯誤。',
'ZIPARCHIVE::ER_ZIPCLOSED' => '包含的 zip 檔案已關閉。',
'ZIPARCHIVE::ER_NOENT' => '找不到檔案。',
'ZIPARCHIVE::ER_EXISTS' => '檔案已存在。',
'ZIPARCHIVE::ER_OPEN' => '無法開啟檔案。',
'ZIPARCHIVE::ER_TMPOPEN' => '建立暫存檔失敗。',
'ZIPARCHIVE::ER_ZLIB' => 'Zlib 錯誤。',
'ZIPARCHIVE::ER_MEMORY' => '記憶體配置失敗。',
'ZIPARCHIVE::ER_CHANGED' => '項目已變更。',
'ZIPARCHIVE::ER_COMPNOTSUPP' => '不支援的壓縮方法。',
'ZIPARCHIVE::ER_EOF' => '提前出現 EOF。',
'ZIPARCHIVE::ER_INVAL' => '無效的參數。',
'ZIPARCHIVE::ER_NOZIP' => '不是 zip 檔案。',
'ZIPARCHIVE::ER_INTERNAL' => '內部錯誤。',
'ZIPARCHIVE::ER_INCONS' => 'Zip 檔案不一致。',
'ZIPARCHIVE::ER_REMOVE' => '無法移除檔案。',
'ZIPARCHIVE::ER_DELETED' => '項目已刪除',
);
$errmsg = '未知';
foreach ($zipFileFunctionsErrors as $constName => $errorMessage) {
if (defined($constName) and constant($constName) === $errno) {
return 'Zip 檔案函式錯誤:'.$errorMessage;
}
}
return 'Zip 檔案函式錯誤:未知';
}

$zip = zip_open($zip_file);
if (!is_resource($zip)) {
die(zipFileErrMsg($zip));
}
fuljencio at gmail dot com
15 年前
取得 Mozilla 附加元件版本(例如 Firefox 擴充功能)

<?php
function get_addon_version($path)
{
// 開啟 zip 檔案
$zip = zip_open($path);

// 尋找項目
do {
$entry = zip_read($zip);
} while (
$entry && zip_entry_name($entry) != "install.rdf");

// 開啟項目
zip_entry_open($zip, $entry, "r");

// 讀取項目
$entry_content = zip_entry_read($entry, zip_entry_filesize($entry));

// <em:version> 的位置
$version_open_pos = strpos($entry_content, "<em:version>");

// </em:version> 的位置
$version_close_pos = strpos($entry_content, "</em:version>", $version_open_pos);

// 版本
$version = substr(
$entry_content,
$version_open_pos + strlen("<em:version>"),
$version_close_pos - ($version_open_pos + strlen("<em:version>"))
);

// 關閉項目
zip_entry_close($entry);

// 關閉 zip 檔案
zip_close($zip);

return
$version;
}
?>
bisqwit at iki dot fi
19 年前
如果您的 PHP 安裝沒有 zip_open 函式,而且您因為某些原因無法安裝它,您可以改用這些函式,前提是伺服器可以存取「unzip」工具程式(大多數 Linux 系統都可以)。
到目前為止,我只在 Fedora Core 3 中測試過這些函式。
使用風險自負。

<?php

function ShellFix($s)
{
return
"'".str_replace("'", "'\''", $s)."'";
}

function
zip_open($s)
{
$fp = @fopen($s, 'rb');
if(!
$fp) return false;

$lines = Array();
$cmd = 'unzip -v '.shellfix($s);
exec($cmd, $lines);

$contents = Array();
$ok=false;
foreach(
$lines as $line)
{
if(
$line[0]=='-') { $ok=!$ok; continue; }
if(!
$ok) continue;

$length = (int)$line;
$fn = trim(substr($line,58));

$contents[] = Array('name' => $fn, 'length' => $length);
}

return
Array(
'fp' => $fp,
'name' => $s,
'contents' => $contents,
'pointer' => -1);
}
function
zip_read(&$fp)
{
if(!
$fp) return false;

$next = $fp['pointer'] + 1;
if(
$next >= count($fp['contents'])) return false;

$fp['pointer'] = $next;
return
$fp['contents'][$next];
}
function
zip_entry_name(&$res)
{
if(!
$res) return false;
return
$res['name'];
}
function
zip_entry_filesize(&$res)
{
if(!
$res) return false;
return
$res['length'];
}
function
zip_entry_open(&$fp, &$res)
{
if(!
$res) return false;

$cmd = 'unzip -p '.shellfix($fp['name']).' '.shellfix($res['name']);

$res['fp'] = popen($cmd, 'r');
return !!
$res['fp'];
}
function
zip_entry_read(&$res, $nbytes)
{
return
fread($res['fp'], $nbytes);
}
function
zip_entry_close(&$res)
{
fclose($res['fp']);
unset(
$res['fp']);
}
function
zip_close(&$fp)
{
fclose($fp['fp']);
}
?>
匿名
16 年前
注意,這個函式會忽略自訂的串流包裝器,例如透過 stream_wrapper_register 建立的包裝器 - 這實在很糟糕。
robert at cotran dot ca
19 年前
上面的 zip_entry_read 是錯誤的。由於檔案是用 popen 開啟的,您必須分塊讀取檔案,因此 zip_entry_read 應該要這樣寫

function zip_entry_read(&$res, $nbytes)
{
$contents = '';
while (!feof($res['fp'])) {
$contents .= fread($res['fp'], 8192);
}
return $contents;
}

除此之外,這是一個非常實用的函式庫。謝謝!
ohcc at 163 dot com
8 年前
在呼叫 ZipArchive::close() 之前,zip 壓縮檔並不會儲存到磁碟上。(如果您沒有撰寫該程式碼,ZipArchive::close() 將會在腳本結束時自動呼叫。)

如果您想在將檔案新增到 zip 壓縮檔後刪除該檔案,則應該在呼叫 ZipArchive::close() 之後再刪除。否則,檔案會在實際新增到壓縮檔之前就被刪除,這將導致您的 zip 壓縮檔儲存失敗。

<?php
$za
= new ZipArchive();
$za->open('./xc.zip', ZipArchive::CREATE|ZipArchive::OVERWRITE);
$file = './notes.txt';
if(
true === $za->addFile($file)){
unlink($file);
}
if(!
$za->close()){
echo
'failure.';
}
?>
ponsho
18 年前
對於 bisqwit at iki dot fi 提出的替代函式方案,在嘗試讀取檔案時只有一個問題,這是因為 fread 在處理 popen 時的錯誤,所以它只載入了 8192 位元組,以下是修正後的函式。

<?php

function zip_entry_read(&$res, $nbytes)
{
while (
$s = fgets($res['fp'],1024)) {
$data .= $s;
}
return
$data;
}
?>
flominator at gmx dot net
17 年前
@bisqwit at iki dot fi:如果您使用的是舊版本的 PHP,這個腳本可能只會讀取前 8192 個位元組。無論如何,這真是個好東西!
barbarinasv at interfree dot it
19 年前
由「bisqwit at iki dot fi」編寫的 zip_entry_read() 函式必須修改才能讀取整個檔案

<?php
function zip_entry_read(&$res, $nbytes) {
while (!
feof($res['fp'])) {
$contents .= fread($res['fp'], $nbytes);
}
return
$contents;
}
?>
alban dot lopez+php dot net at gmail dot com
17 年前
使用這個類別來建立、讀取資訊或解壓縮 ZIP 檔案。
參考 http://ajaxbrowser.free.fr/ 上的 EasyArchive.class.php 來管理 ZIP、GZIP、BZIP 和 TAR 檔案。

<?
$ARCHIVE = new zip;

$ARCHIVE->makeZip('./','./toto.zip'); // 建立一個 ZIP 檔案
var_export($ARCHIVE->infosZip('./toto.zip'), false); // 取得此 ZIP 檔案的資訊(不包含檔案內容)
var_export($ARCHIVE->infosZip('./toto.zip')); // 取得此 ZIP 檔案的資訊(包含檔案內容)
$ARCHIVE->extractZip('./toto.zip', './1/'); // 解壓縮 ZIP 檔案

class zip
{
public function infosZip ($src, $data=true)
{
if (($zip = zip_open(realpath($src))))
{
while (($zip_entry = zip_read($zip)))
{
$path = zip_entry_name($zip_entry);
if (zip_entry_open($zip, $zip_entry, "r"))
{
$content[$path] = array (
'Ratio' => zip_entry_filesize($zip_entry) ? round(100-zip_entry_compressedsize($zip_entry) / zip_entry_filesize($zip_entry)*100, 1) : false, // 壓縮比率
'Size' => zip_entry_compressedsize($zip_entry), // 壓縮後大小
'NormalSize' => zip_entry_filesize($zip_entry)); // 原始大小
if ($data)
$content[$path]['Data'] = zip_entry_read($zip_entry, zip_entry_filesize($zip_entry)); // 檔案資料
zip_entry_close($zip_entry);
}
else
$content[$path] = false;
}
zip_close($zip);
return $content;
}
return false;
}
public function extractZip ($src, $dest)
{
$zip = new ZipArchive;
if ($zip->open($src)===true)
{
$zip->extractTo($dest);
$zip->close();
return true;
}
return false;
}
public function makeZip ($src, $dest)
{
$zip = new ZipArchive;
$src = is_array($src) ? $src : array($src);
if ($zip->open($dest, ZipArchive::CREATE) === true)
{
foreach ($src as $item)
if (file_exists($item))
$this->addZipItem($zip, realpath(dirname($item)).'/', realpath($item).'/');
$zip->close();
return true;
}
return false;
}
private function addZipItem ($zip, $racine, $dir)
{
if (is_dir($dir))
{
$zip->addEmptyDir(str_replace($racine, '', $dir));
$lst = scandir($dir);
array_shift($lst);
array_shift($lst);
foreach ($lst as $item)
$this->addZipItem($zip, $racine, $dir.$item.(is_dir($dir.$item)?'/':''));
}
elseif (is_file($dir))
$zip->addFile($dir, str_replace($racine, '', $dir));
}
}
?>
xsign dot dll at clansuite dot com
16 年前
如果您只想解壓縮 zip 檔案中的特定檔案,可以使用這個函式,或許會有幫助。

<?php
/**
* This method unzips a directory within a zip-archive
*
* @author Florian 'x!sign.dll' Wolf
* @license LGPL v2 or later
* @link http://www.xsigndll.de
* @link http://www.clansuite.com
*/

function extractZip( $zipFile = '', $dirFromZip = '' )
{
define(DIRECTORY_SEPARATOR, '/');

$zipDir = getcwd() . DIRECTORY_SEPARATOR;
$zip = zip_open($zipDir.$zipFile);

if (
$zip)
{
while (
$zip_entry = zip_read($zip))
{
$completePath = $zipDir . dirname(zip_entry_name($zip_entry));
$completeName = $zipDir . zip_entry_name($zip_entry);

// Walk through path to create non existing directories
// This won't apply to empty directories ! They are created further below
if(!file_exists($completePath) && preg_match( '#^' . $dirFromZip .'.*#', dirname(zip_entry_name($zip_entry)) ) )
{
$tmp = '';
foreach(
explode('/',$completePath) AS $k)
{
$tmp .= $k.'/';
if(!
file_exists($tmp) )
{
@
mkdir($tmp, 0777);
}
}
}

if (
zip_entry_open($zip, $zip_entry, "r"))
{
if(
preg_match( '#^' . $dirFromZip .'.*#', dirname(zip_entry_name($zip_entry)) ) )
{
if (
$fd = @fopen($completeName, 'w+'))
{
fwrite($fd, zip_entry_read($zip_entry, zip_entry_filesize($zip_entry)));
fclose($fd);
}
else
{
// We think this was an empty directory
mkdir($completeName, 0777);
}
zip_entry_close($zip_entry);
}
}
}
zip_close($zip);
}
return
true;
}

// The call to exctract a path within the zip file
extractZip( 'clansuite.zip', 'core/filters' );
?>
strefrextor at gmail [.] com
15 年前
我的基本解壓縮 zip 檔案函式

<?php
函式 ezip($zip, $hedef = '')
{
$root = $_SERVER['DOCUMENT_ROOT'];
$zip = zip_open($root . $zip);
while(
$zip_icerik = zip_read($zip)):
$zip_dosya = zip_entry_name($zip_icerik);
if(
strpos($zip_dosya, '.')):
$hedef_yol = $root . $hedef . 'x/'.$zip_dosya;
touch($hedef_yol);
$yeni_dosya = fopen($hedef_yol, 'w+');
fwrite($yeni_dosya, zip_entry_read($zip_icerik));
fclose($yeni_dosya);
else:
@
mkdir($root . $hedef . 'x/'.$zip_dosya);
endif;
endwhile;
}

ezip('files.zip', 'unzip_files/');
?>
To Top