2024 年 PHP Conference Japan

ZipArchive::extractTo

(PHP 5 >= 5.2.0, PHP 7, PHP 8, PECL zip >= 1.1.0)

ZipArchive::extractTo解壓縮封存內容

說明

public ZipArchive::extractTo(字串 $pathto, 陣列|字串|null $files = null): 布林值

將整個封存或指定的檔案解壓縮到指定的目的資料夾。

警告

已解壓縮的檔案和目錄的預設權限會授予最廣泛的存取權。這可以透過設定目前的 umask 來限制,可以使用 umask() 來更改。

基於安全性考量,原始權限不會被還原。關於如何還原權限的範例,請參閱 ZipArchive::getExternalAttributesIndex() 頁面上的 程式碼範例

參數

pathto

解壓縮檔案的目標位置。

files

要解壓縮的項目。它接受單個項目名稱或名稱陣列。

傳回值

成功時傳回 true,失敗時傳回 false

範例

範例 #1 解壓縮所有項目

<?php
$zip
= new ZipArchive;
if (
$zip->open('test.zip') === TRUE) {
$zip->extractTo('/my/destination/dir/');
$zip->close();
echo
'ok';
} else {
echo
'failed';
}
?>

範例 #2 解壓縮兩個項目

<?php
$zip
= new ZipArchive;
$res = $zip->open('test_im.zip');
if (
$res === TRUE) {
$zip->extractTo('/my/destination/dir/', array('pear_item.gif', 'testfromfile.php'));
$zip->close();
echo
'ok';
} else {
echo
'failed';
}
?>

注意事項

注意:

Windows NTFS 檔案系統不支援檔名中的某些字元,即 <|>*?":。 檔名尾端帶有句點也不支援。 與某些解壓縮工具不同的是,此方法不會將這些字元替換為底線,而是無法解壓縮此類檔案。

新增備註

使用者貢獻的備註 15 則備註

php-dev at proneticas dot net
14 年前
如果您想一次複製一個檔案並移除儲存在 ZIP 檔案中的資料夾名稱,這樣您就不必從 ZIP 檔案本身建立目錄,請使用以下程式碼片段(基本上是將 ZIP 檔案合併到一個資料夾中)。

<?php

$path
= 'zipfile.zip'

$zip = new ZipArchive;
if (
$zip->open($path) === true) {
for(
$i = 0; $i < $zip->numFiles; $i++) {
$filename = $zip->getNameIndex($i);
$fileinfo = pathinfo($filename);
copy("zip://".$path."#".$filename, "/your/new/destination/".$fileinfo['basename']);
}
$zip->close();
}

?>

*順帶一提,您也可以使用 $_FILES['userfile']['tmp_name'] 作為上傳 ZIP 的 $path,這樣您就不必移動它或解壓縮上傳的 ZIP 檔案。

加油!

ProNeticas 開發團隊
匿名
6 年前
如果您只想將檔案解壓縮到目前的資料夾,只需使用
$zip->extractTo(".");

我花了幾個小時才弄清楚這一點。
stanislav dot eckert at vizson dot de
9 年前
extractTo() 方法不提供任何參數來允許從 ZIP 封存內的另一個(父)資料夾遞迴解壓縮檔案和資料夾。使用以下方法是可行的

<?php
class my_ZipArchive extends ZipArchive
{
public function
extractSubdirTo($destination, $subdir)
{
$errors = array();

// Prepare dirs
$destination = str_replace(array("/", "\\"), DIRECTORY_SEPARATOR, $destination);
$subdir = str_replace(array("/", "\\"), "/", $subdir);

if (
substr($destination, mb_strlen(DIRECTORY_SEPARATOR, "UTF-8") * -1) != DIRECTORY_SEPARATOR)
$destination .= DIRECTORY_SEPARATOR;

if (
substr($subdir, -1) != "/")
$subdir .= "/";

// Extract files
for ($i = 0; $i < $this->numFiles; $i++)
{
$filename = $this->getNameIndex($i);

if (
substr($filename, 0, mb_strlen($subdir, "UTF-8")) == $subdir)
{
$relativePath = substr($filename, mb_strlen($subdir, "UTF-8"));
$relativePath = str_replace(array("/", "\\"), DIRECTORY_SEPARATOR, $relativePath);

if (
mb_strlen($relativePath, "UTF-8") > 0)
{
if (
substr($filename, -1) == "/") // Directory
{
// New dir
if (!is_dir($destination . $relativePath))
if (!@
mkdir($destination . $relativePath, 0755, true))
$errors[$i] = $filename;
}
else
{
if (
dirname($relativePath) != ".")
{
if (!
is_dir($destination . dirname($relativePath)))
{
// New dir (for file)
@mkdir($destination . dirname($relativePath), 0755, true);
}
}

// New file
if (@file_put_contents($destination . $relativePath, $this->getFromIndex($i)) === false)
$errors[$i] = $filename;
}
}
}
}

return
$errors;
}
}
?>

範例
<?php
echo "<pre>";

$zip = new my_ZipArchive();
if (
$zip->open("test.zip") === TRUE)
{
$errors = $zip->extractSubdirTo("C:/output", "folder/subfolder/");
$zip->close();

echo
'ok, errors: ' . count($errors);
}
else
{
echo
'failed';
}
?>
quake2005 at gmail dot com
14 年前
如果您想要一次解壓縮一個檔案,您可以使用這個

<?php

$path
= 'zipfile.zip'

$zip = new ZipArchive;
if (
$zip->open($path) === true) {

for(
$i = 0; $i < $zip->numFiles; $i++) {

$zip->extractTo('path/to/extraction/', array($zip->getNameIndex($i)));

// 這裡可以針對個別解壓縮的檔案執行自訂函式

}

$zip->close();

}

?>
kawzaki at yahoo dot com
15 年前
請注意,使用此函式會直接覆寫檔案。

如果壓縮檔 (zip 檔案) 中包含與舊檔案名稱相同的檔案,則舊檔案將會被覆寫。

壓縮檔中沒有相符檔案的舊檔案將會保留。

希望有人能解釋如何避免覆寫舊檔案。
cory dot mawhorter at ephective dot com
14 年前
此函式將使用 ZipArchive 類別來展開 zip 檔案。

它會解壓縮 zip 檔中的所有檔案,並將它們儲存在單一的目標目錄中。也就是說,不會建立子目錄。

如果有人知道更好的方法來判斷一個項目是否為目錄,請提出。我覺得用檢查結尾反斜線的方式很笨拙。

<?php
// 目的地路徑 $dest 不應該包含結尾的斜線
function zip_flatten ( $zipfile, $dest='.' )
{
$zip = new ZipArchive;
if (
$zip->open( $zipfile ) )
{
for (
$i=0; $i < $zip->numFiles; $i++ )
{
$entry = $zip->getNameIndex($i);
if (
substr( $entry, -1 ) == '/' ) continue; // 跳過目錄

$fp = $zip->getStream( $entry );
$ofp = fopen( $dest.'/'.basename($entry), 'w' );

if ( !
$fp )
throw new
Exception('無法解壓縮檔案。');

while ( !
feof( $fp ) )
fwrite( $ofp, fread($fp, 8192) );

fclose($fp);
fclose($ofp);
}

$zip->close();
}
else
return
false;

return
$zip;
}

/*
使用範例:

zip_flatten( 'test.zip', 'my/path' );
*/
?>

[由 danbrown 於 php.net 編輯:根據原作者在 2010 年 4 月 18 日的後續說明,添加了 $zip-close()]
cucurella at gmail dot com
3 年前
// 逐一檔案處理錯誤!

<?php

$ERROR_UNZIP
= false;
$dest = "../";
$zipfile = "test.zip";

$zip = new ZipArchive;

if (
$zip->open("$zipfile") === true) {

for (
$i = 0; $i < $zip -> numFiles; $i++) {
$RETVAL = false;

$filename = $zip->getNameIndex($i);

$RETVAL = $zip->extractTo($dest,$filename);

if (
$RETVAL) {
print
"$filename ... [ 正常 ]<br>";
} else {
print
"$filename ... [ 錯誤 ]<br>";
$ERROR_UNZIP = true;
}
}

// 關閉
$zip -> close();

// 返回值
if ($ERROR_UNZIP) {
print
"<p>解壓縮 ${zipfile} 發生錯誤</p>";
} else {
print
"<p>解壓縮完成</p>";
}
} else {
print
"<p>開啟 ${zipfile} 發生錯誤</p>";
}

?>
skrzypecki at gmail dot com
7 年前
請注意,路徑不能太長!我不確定最大長度是多少,沒有找到相關資訊。但是我在使用 extractTo() 時一直遇到問題。

然後在 Google 後,我發現了這段簡短的評論:https://github.com/composer/composer/issues/2824#issuecomment-308201902

複製貼上的評論
===
我的機器上有這個路徑

C:/xampp5.0/htdocs/project-recordando-symfony/project-recordando-symfony
然後我執行 composer install 或/和 composer update,它返回了這個錯誤

ErrorException ZipArchive::extractTo...

這個錯誤是因為你的路徑太長了,我改成了

C:/xampp5.0/htdocs/p-symfony/*
然後就成功了!
===
synnus at gmail dot com
7 年前
<?php

// This version allows to see which file will be decompressed and to keep
// a follow-up on decompression

define( 'FILEPATH', dirname(__FILE__) . '\\' );
define( 'TEST', FILEPATH . 'test\\' );

$za = new ZipArchive();

$za->open(FILEPATH . 'test.zip');
print_r($za);
var_dump($za);
echo
"Nombre de fichiers : " . $za->numFiles . "\n";
echo
"Statut : " . $za->status . "\n";
echo
"Statut du système : " . $za->statusSys . "\n";
echo
"Nom du fichier : " . $za->filename . "\n";
echo
"Commentaire : " . $za->comment . "\n";

/* in $za->statIndex($i)

[name] => data/x.luac
[index] => 451
[crc] => -1266183263
[size] => 2936
[mtime] => 1464790482
[comp_size] => 976
[comp_method] => 8
*/

for ($i=0; $i<$za->numFiles;$i++) {
echo
"index : $i\n";
$name = $za->statIndex($i)['name'];
$size = $za->statIndex($i)['size'];
$comp_size = $za->statIndex($i)['comp_size'];
print_r($name . ' [ ' . $size . '>' . $comp_size . ']' );
$za->extractTo(TEST,$name);
}
echo
"Nombre de fichiers :" . $za->numFiles . "\n";

?>
sachinyadav at live dot com
14 年前
此腳本將在 test.zip 壓縮檔中搜尋「.txt」檔案(任何檔名)。假設找到了「example.txt」檔案,則腳本會將「example.txt」複製到「txt_files」目錄,並將其重新命名為「test.zip.txt」,然後從「test.zip.txt」中刪除所有空白行,重新儲存,並在不搜尋其餘項目的情況下退出迴圈。
此腳本可用於提取 .DIZ 和 GIF 檔案,以在您的腳本中顯示 ZIP 壓縮檔的詳細資訊。
<?php
$value
="test.zip";
$filename="zip_files/$value";
$zip = new ZipArchive;
if (
$zip->open($filename) === true) {
echo
"產生文字檔。";
for(
$i = 0; $i < $zip->numFiles; $i++) {
$entry = $zip->getNameIndex($i);
if(
preg_match('#\.(txt)$#i', $entry))
{
////這個複製函式會將項目移動到 "txt_files" 的根目錄,而不會像 "ZIP->EXTRACTO" 函式那樣建立任何子資料夾。
copy('zip://'.dirname(__FILE__).'/zip_files/'.$value.'#'.$entry, 'txt_files/'.$value.'.txt');
$content = file_get_contents("txt_files/$value.txt");
$newcontent = preg_replace("/(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+/", "\n", $content);
file_put_contents("txt_files/$value.txt", "$newcontent");
break;
}
}
$zip->close();
}
else{
echo
"ZIP 壓縮檔開啟失敗";
}
?>

享受 PHP 程式設計的樂趣。
Sachin Yadav
tBone
16 年前
至少根據我的經驗,這個函式會維持/強制執行 ZIP 檔案內的目錄結構。

例如,如果 ZIP 檔案中有 FOLDER1/File1.txt,而您使用
$zip->extractTo('/extract', 'FOLDER1/File1.txt');
解壓縮後的檔案位置將會是
/extract/FOLDER1/File1.txt
ben dot tyger at tygerclan dot net
8 年前
請注意,在 Linux(可能還有其他 *nix 平台)中,無法從 Zip 壓縮檔中解壓縮隱藏檔案(即檔名以「.」開頭的檔案)。
ohcc at 163 dot com
7 年前
警告!!!!

如果您在 Apache 下運行 PHP,zip 檔案內的 .htaccess 檔案可能會導致 extractTo() 方法失敗。
匿名
15 年前
我發現將以下程式碼加入函式中很有用。

<?php
/**
* 解壓縮 ZIP 壓縮檔到指定的解壓縮路徑
*
* @param string $file 要解壓縮的 ZIP 壓縮檔(包含路徑)
* @param string $extractPath 解壓縮 ZIP 壓縮檔的路徑
*
* @return boolean 如果 ZIP 壓縮檔成功解壓縮,則傳回 TURE,如果發生錯誤,則傳回 FALSE
*
*/
function zip_extract($file, $extractPath) {

$zip = new ZipArchive;
$res = $zip->open($file);
if (
$res === TRUE) {
$zip->extractTo($extractPath);
$zip->close();
return
TRUE;
} else {
return
FALSE;
}

}
// 函式結束
?>
icixtec at gmail dot com
4 年前
對於需要在不知道檔名大小寫的情況下解壓縮檔案的案例

$zip = new ZipArchive;
if ($zip->open('myfile.zip') === TRUE) {
// 無效
//$zip->extractTo('./', array( 'file1.XML', 'file1.xml'));
//有效
$zip->extractTo('./', 'file1.XML' );
$zip->extractTo('./', 'file1.xml' );
$zip->close();
}
To Top