PHP Conference Japan 2024

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 起已弃用。强烈建议不要依赖此函数。

描述

打开一个新的 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' => '意外文件结尾',
'ZIPARCHIVE::ER_INVAL' => '无效参数',
'ZIPARCHIVE::ER_NOZIP' => '不是 zip 存档',
'ZIPARCHIVE::ER_INTERNAL' => '内部错误',
'ZIPARCHIVE::ER_INCONS' => 'zip 存档不一致',
'ZIPARCHIVE::ER_REMOVE' => '无法删除文件',
'ZIPARCHIVE::ER_DELETED' => '条目已被删除',
);
$errmsg = 'unknown';
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/'); //

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
/**
* 此方法解压zip压缩包中的一个目录
*
* @author Florian 'x!sign.dll' Wolf
* @license LGPL v2 或更高版本
* @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);

// 遍历路径以创建不存在的目录
// 这不适用于空目录!它们在下面创建
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
{
// 我们认为这是一个空目录
mkdir($completeName, 0777);
}
zip_entry_close($zip_entry);
}
}
}
zip_close($zip);
}
return
true;
}

// 调用以提取zip文件中的路径
extractZip( 'clansuite.zip', 'core/filters' );
?>
strefrextor at gmail [.] com
15 年前
我的基本解压zip文件函数

<?php
function 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