请注意,Zip 函数在发生错误时会返回一个整数错误号。因此
<?php
$zip = zip_open($file);
if ($zip) {
?>
是错误的。应该使用
<?php
$zip = zip_open($file);
if (is_resource($zip)) {
?>
(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 中已弃用。强烈建议不要依赖此函数。
filename
要打开的 ZIP 存档的文件名。
返回一个资源句柄,供以后使用 zip_read() 和 zip_close(),或者返回 false
或者错误数量(如果 filename
不存在或发生其他错误)。
请注意,Zip 函数在发生错误时会返回一个整数错误号。因此
<?php
$zip = zip_open($file);
if ($zip) {
?>
是错误的。应该使用
<?php
$zip = zip_open($file);
if (is_resource($zip)) {
?>
一些旧版本的 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 = 'unknown';
foreach ($zipFileFunctionsErrors as $constName => $errorMessage) {
if (defined($constName) and constant($constName) === $errno) {
return 'Zip File Function error: '.$errorMessage;
}
}
return 'Zip File Function error: unknown';
}
$zip = zip_open($zip_file);
if (!is_resource($zip)) {
die(zipFileErrMsg($zip));
}
获取 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;
}
?>
如果您的 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']);
}
?>
上面的 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;
}
否则,这是一个非常有用的库。谢谢!
zip 归档文件只有在调用 ZipArchive::close() 之后才会保存到磁盘上。(如果您没有编写该代码,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.';
}
?>
对于 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;
}
?>
@bisqwit at iki dot fi: 如果您使用的是较旧版本的 PHP,此脚本可能只读取前 8192 字节。无论如何,很棒!
由“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;
}
?>
参见此类以创建、读取信息或提取 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));
}
}
?>
如果你只想提取 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' );
?>
我的基本解压缩 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/');
?>