This is the simplest method to unzip a file. Pass the function your filename and it will unzip it to the current directory of the script with permissions done properly on unix type operating systems. Far simpler to understand and read.
<?php
function unzip($file){
$zip = zip_open($file);
if(is_resource($zip)){
$tree = "";
while(($zip_entry = zip_read($zip)) !== false){
echo "Unpacking ".zip_entry_name($zip_entry)."\n";
if(strpos(zip_entry_name($zip_entry), DIRECTORY_SEPARATOR) !== false){
$last = strrpos(zip_entry_name($zip_entry), DIRECTORY_SEPARATOR);
$dir = substr(zip_entry_name($zip_entry), 0, $last);
$file = substr(zip_entry_name($zip_entry), strrpos(zip_entry_name($zip_entry), DIRECTORY_SEPARATOR)+1);
if(!is_dir($dir)){
@mkdir($dir, 0755, true) or die("Unable to create $dir\n");
}
if(strlen(trim($file)) > 0){
$return = @file_put_contents($dir."/".$file, zip_entry_read($zip_entry, zip_entry_filesize($zip_entry)));
if($return === false){
die("Unable to write file $dir/$file\n");
}
}
}else{
file_put_contents($file, zip_entry_read($zip_entry, zip_entry_filesize($zip_entry)));
}
}
}else{
echo "Unable to open zip file\n";
}
}
?>
CLXXIX. Zip ファイル関数
導入
このモジュールにより、ZIP 圧縮されたアーカイブとその内部のファイルに対する 透過的な読み書きが可能となります。
要件
PHP 4 の同梱版
最初のバージョンは PHP 4 に同梱されています。また、PECL でバージョン 1.0 として公開されています。 http://pecl.php.net/package/zip を参照ください。 これは、Zip アーカイブの読み込みのみに対応しています。
このバージョンは、Guido Draheim による ZZIPlib ライブラリの関数を使用しています。 ZZIPlib バージョン >= 0.10.6 が必要です。
PECL 版および PHP 5.2 以降の版
最新のバージョンは PHP 5.2.0 以降に同梱されており、 PECL 版のバージョン 1.1.0 以降となっています。これは、 外部のライブラリを必要としません。PHP 5.1 以降で使用した場合には Zip アーカイブの読み書きが可能で、PHP 4 で使用した場合には 読み込みのみが可能となります。
インストール手順
この PECL 拡張 モジュールは PHP にバンドルされていません。 この PECL 拡張モジュールをインストールする方法は、 マニュアルの PECL 拡張モジュールのインストール という章にあります。 新規リリース・ダウンロード・ソースファイル・管理者情報・CHANGELOG といった関連する情報については、次の場所にあります。 http://pecl.php.net/package/zip.
Linux でのインストール
PHP 4 の同梱版のインストール
これらの関数を使用するには、zip サポートを有効にして PHP をコンパイルしなければなりません。そのためには、設定オプション --with-zip[=DIR] を使用します。 [DIR] は、ZZIPlib ライブラリのインストールされている場所です。
PECL 版あるいは PHP 5.2 以降のバージョンの同梱版のインストール
これらの関数を使用するには、zip サポートを有効にして PHP をコンパイルしなければなりません。そのためには、設定オプション --enable-zip を使用します。 これは外部のライブラリを必要としません。
注意: PECL 版を PHP 4 で使用することもできます。そのためには、 同梱版の zip 拡張モジュールを無効にするか、あるいは zip サポートを無効にして PHP を再コンパイルする必要があります。
Windows でのインストール
PHP 4 の同梱版のインストール
Windows ユーザは、php.ini で php_zip.dll を有効にすると、 これらの関数を使用できるようになります。 PHP 4 の場合、この DLL は PHP の Windows ダウンロードバイナリの extensions/ ディレクトリ にあります。 この PECL 拡張モジュール の DLL を PHP ダウンロード ページ または http://snaps.php.net/ からダウンロードできます。
注意: Zip のサポートは、PHP 4.1.0 以前は実験的なものでした。 この節に書かれている内容は、PHP 4.1.0 以降の Zip 拡張モジュールに関するものです。
PECL 版あるいは PHP 5.2 以降のバージョンの同梱版のインストール
Windows ユーザは、php.ini で php_zip.dll を有効にすると、 これらの関数を使用できるようになります。 PHP 4 の場合、この DLL は PHP の Windows ダウンロードバイナリの extensions/ ディレクトリ にあります。 この PECL 拡張モジュール の DLL を PHP ダウンロード ページ または http://snaps.php.net/ からダウンロードできます。
実行時設定
設定ディレクティブは定義されていません。
リソース型
Zip モジュールでは二種類のリソース型が使用されます。 まず最初が Zip アーカイブを表す Zip directory で、 もうひとつはアーカイブのエントリを表す Zip Entry です。
定義済み定数
以下の定数が定義されています。 この関数の拡張モジュールが PHP 組み込みでコンパイルされているか、 実行時に動的にロードされている場合のみ使用可能です。
ZipArchive はクラス定数を使用します。定数には フラグ (FL_)、エラー (ER_) あるいはモード (接頭辞なし) の三種類があります。
- ZIPARCHIVE::CREATE (integer)
アーカイブが存在しない場合に、作成します。
- ZIPARCHIVE::OVERWRITE (integer)
常に新しいアーカイブを開始します。このモードは、 ファイルが既に存在する場合にはそれを上書きします。
- ZIPARCHIVE::EXCL (integer)
アーカイブが既に存在する場合はエラーとします。
- ZIPARCHIVE::CHECKCONS (integer)
アーカイブの一貫性チェックを別途行い、 失敗した場合はエラーとします。
- ZIPARCHIVE::FL_NOCASE (integer)
名前で検索する際に大文字小文字を区別しません。
- ZIPARCHIVE::FL_NODIR (integer)
ディレクトリ要素を無視します。
- ZIPARCHIVE::FL_COMPRESSED (integer)
圧縮されたデータを読み込みます。
- ZIPARCHIVE::FL_UNCHANGED (integer)
元のデータを使用し、変更内容を無視します。
- ZIPARCHIVE::CM_DEFAULT (integer)
圧縮あるいは保存のどちらか有効なほうを実行します。
- ZIPARCHIVE::CM_STORE (integer)
保存します (圧縮しません)。
- ZIPARCHIVE::CM_SHRINK (integer)
圧縮します。
- ZIPARCHIVE::CM_REDUCE_1 (integer)
reduced with factor 1
- ZIPARCHIVE::CM_REDUCE_2 (integer)
reduced with factor 2
- ZIPARCHIVE::CM_REDUCE_3 (integer)
reduced with factor 3
- ZIPARCHIVE::CM_REDUCE_4 (integer)
reduced with factor 4
- ZIPARCHIVE::CM_IMPLODE (integer)
imploded
- ZIPARCHIVE::CM_DEFLATE (integer)
deflated
- ZIPARCHIVE::CM_DEFLATE64 (integer)
deflate64
- ZIPARCHIVE::CM_PKWARE_IMPLODE (integer)
PKWARE 方式。
- ZIPARCHIVE::CM_BZIP2 (integer)
BZIP2 アルゴリズム。
- ZIPARCHIVE::ER_OK (integer)
エラーはありません。
- ZIPARCHIVE::ER_MULTIDISK (integer)
複数ディスクの zip アーカイブはサポートされません。
- ZIPARCHIVE::ER_RENAME (integer)
一時ファイルの名前変更に失敗しました。
- ZIPARCHIVE::ER_CLOSE (integer)
zip アーカイブのクローズに失敗しました。
- ZIPARCHIVE::ER_SEEK (integer)
シークエラー。
- ZIPARCHIVE::ER_READ (integer)
読み込みエラー。
- ZIPARCHIVE::ER_WRITE (integer)
書き込みエラー。
- ZIPARCHIVE::ER_CRC (integer)
CRC エラー。
- ZIPARCHIVE::ER_ZIPCLOSED (integer)
zip アーカイブはクローズされました。
- ZIPARCHIVE::ER_NOENT (integer)
そのファイルはありません。
- ZIPARCHIVE::ER_EXISTS (integer)
ファイルが既に存在します。
- ZIPARCHIVE::ER_OPEN (integer)
ファイルをオープンできません。
- ZIPARCHIVE::ER_TMPOPEN (integer)
一時ファイルの作成に失敗しました。
- ZIPARCHIVE::ER_ZLIB (integer)
Zlib エラー。
- ZIPARCHIVE::ER_MEMORY (integer)
メモリの確保に失敗しました。
- ZIPARCHIVE::ER_CHANGED (string)
エントリが変更されました。
- ZIPARCHIVE::ER_COMPNOTSUPP (integer)
圧縮方式がサポートされていません。
- ZIPARCHIVE::ER_EOF (integer)
予期せぬ EOF です。
- ZIPARCHIVE::ER_INVAL (integer)
無効な引数です。
- ZIPARCHIVE::ER_NOZIP (integer)
zip アーカイブではありません。
- ZIPARCHIVE::ER_INTERNAL (integer)
内部エラー。
- ZIPARCHIVE::ER_INCONS (integer)
矛盾した Zip アーカイブです。
- ZIPARCHIVE::ER_REMOVE (integer)
ファイルを削除できません。
- ZIPARCHIVE::ER_DELETED (integer)
エントリが削除されました。
例
例 2. アーカイブの詳細の出力および一覧表示
|
例 3. Zip ストリームラッパーによる OpenOffice メタ情報の読み込み
|
この例は旧 API (PHP 4 用) を使用します。まず ZIP ファイルアーカイブをオープンし、アーカイブ内の各ファイルを読み込み、 その内容を出力します。この例で使用するアーカイブ test2.zip は、ZZIPlib のソース配布物に含まれているテスト用アーカイブのひとつです。
例 4. Zip の使用例
|
- 目次
- zip_close -- ZIP ファイルアーカイブを閉じる
- zip_entry_close -- ディレクトリエントリを閉じる
- zip_entry_compressedsize -- ディレクトリエントリの圧縮時のサイズを取得する
- zip_entry_compressionmethod -- ディレクトリエントリの圧縮方法を取得する
- zip_entry_filesize -- ディレクトリエントリの実際のファイルサイズを取得する
- zip_entry_name -- ディレクトリエントリの名前を取得する
- zip_entry_open -- 読込み用にディレクトリエントリをオープンする
- zip_entry_read -- オープンされたディレクトリエントリから読み込む
- zip_open -- Zip ファイルアーカイブをオープンする
- zip_read -- Zip ファイルアーカイブの中の次のエントリを読み込む
- ZipArchive::addFile -- 指定したパスからファイルを ZIP アーカイブに追加する
- ZipArchive::addFromString -- その内容を指定して、ファイルを ZIP アーカイブに追加する
- ZipArchive::close -- アクティブな (オープンされた、あるいは新しく作成された) アーカイブを閉じる
- ZipArchive::deleteIndex -- インデックスを使用して、アーカイブ内のエントリを削除する
- ZipArchive::deleteName -- 名前を使用して、アーカイブからエントリを削除する
- ZipArchive::extractTo -- アーカイブの内容を展開する
- ZipArchive::getArchiveComment -- ZIP アーカイブのコメントを返す
- ZipArchive::getCommentIndex -- エントリのインデックスを使用して、エントリのコメントを返す
- ZipArchive::getCommentName -- エントリ名を使用して、エントリのコメントを返す
- ZipArchive::getFromIndex -- インデックスを使用して、エントリの内容を返す
- ZipArchive::getFromName -- 名前を使用して、エントリの内容を返す
- ZipArchive::getNameIndex -- インデックスを使用して、エントリの名前を返す
- ZipArchive::getStream -- 名前を使用して、エントリのファイルハンドラ (読み込み専用) を取得する
- ZipArchive::locateName -- アーカイブ内のエントリのインデックスを返す
- ZipArchive::open -- ZIP ファイルアーカイブをオープンする
- ZipArchive::renameIndex -- インデックスを使用してエントリ名を変更する
- ZipArchive::renameName -- 名前を使用してエントリ名を変更する
- ZipArchive::setArchiveComment -- ZIP アーカイブのコメントを設定する
- ZipArchive::setCommentIndex -- インデックスを使用してエントリのコメントを設定する
- ZipArchive::setCommentName -- 名前を使用してエントリのコメントを設定する
- ZipArchive::statIndex -- インデックスを使用してエントリの詳細を取得する
- ZipArchive::statName -- 名前を使用してエントリの詳細を取得する
- ZipArchive::unchangeAll -- アーカイブに対するすべての変更を取り消す
- ZipArchive::unchangeArchive -- アーカイブ全体に対して行われたすべての変更を取り消す
- ZipArchive::unchangeIndex -- 指定したインデックスのエントリに対するすべての変更を取り消す
- ZipArchive::unchangeName -- 指定した名前のエントリに対するすべての変更を取り消す
Hi,
if you have the RAW CONTENT OF THE ZIP FILE IN A STRING ONLY and you can't create files on your server (because of the SAFE MODE) to be able to create a file which you can then pass to zip_open(), you'll be having hard times getting the uncompressed content of your ZIP data.
This may help:
I've written simple ZIP decompression function for decompressing the first file from the archive stored in a string (no matter what file it is). It's just about parsing a local file header of the first file, getting raw compressed data of that file and decompression of that data (usually, data in ZIP files are compressed by 'DEFLATE' method, so we'll just decompress it by gzinflate() function then).
<?php
function decompress_first_file_from_zip($ZIPContentStr){
//Input: ZIP archive - content of entire ZIP archive as a string
//Output: decompressed content of the first file packed in the ZIP archive
//let's parse the ZIP archive
//(see 'http://en.wikipedia.org/wiki/ZIP_%28file_format%29' for details)
//parse 'local file header' for the first file entry in the ZIP archive
if(strlen($ZIPContentStr)<102){
//any ZIP file smaller than 102 bytes is invalid
printf("error: input data too short<br />\n");
return '';
}
$CompressedSize=binstrtonum(substr($ZIPContentStr,18,4));
$UncompressedSize=binstrtonum(substr($ZIPContentStr,22,4));
$FileNameLen=binstrtonum(substr($ZIPContentStr,26,2));
$ExtraFieldLen=binstrtonum(substr($ZIPContentStr,28,2));
$Offs=30+$FileNameLen+$ExtraFieldLen;
$ZIPData=substr($ZIPContentStr,$Offs,$CompressedSize);
$Data=gzinflate($ZIPData);
if(strlen($Data)!=$UncompressedSize){
printf("error: uncompressed data have wrong size<br />\n");
return '';
}
else return $Data;
}
function binstrtonum($Str){
//Returns a number represented in a raw binary data passed as string.
//This is useful for example when reading integers from a file,
// when we have the content of the file in a string only.
//Examples:
// chr(0xFF) will result as 255
// chr(0xFF).chr(0xFF).chr(0x00).chr(0x00) will result as 65535
// chr(0xFF).chr(0xFF).chr(0xFF).chr(0x00) will result as 16777215
$Num=0;
for($TC1=strlen($Str)-1;$TC1>=0;$TC1--){ //go from most significant byte
$Num<<=8; //shift to left by one byte (8 bits)
$Num|=ord($Str[$TC1]); //add new byte
}
return $Num;
}
?>
ENJOY!!!
wdim
I had some memory problems with very large files in the zip file. The problem with the provided scripts is, that they write file all data at once using something like this:
<?php
$fstream = zip_entry_read($zip_entry, zip_entry_filesize($zip_entry));
file_put_contents($file_name, $fstream );
?>
On a 130MB image this resulted in a "Fatal error: Allowed memory size of ... bytes exhausted" message.
I changed that to always write just a maximum of 10kb at once (you may change the size as wanted).
<?php
// get the file's size
$fileSize = zip_entry_filesize($zip_entry);
// open the target file
$outFile = fopen($file_name,"wb");
while ($fileSize>0) {
// read/write only up to 10kb per step
$readSize = min($fileSize,10240);
// decrease the size of the remaining data to read
$fileSize -= $readSize;
// get the data
$content = zip_entry_read($zip_entry, $readSize);
// write the data (if any)
if ($content !== false)
fwrite($outFile,$content);
}
fclose($outFile);
?>
Cheers
very short version of function for unzipping files with folders structure:
<?php
function unzip($file){
$zip=zip_open(realpath(".")."/".$file);
if(!$zip) {return("Unable to proccess file '{$file}'");}
$e='';
while($zip_entry=zip_read($zip)) {
$zdir=dirname(zip_entry_name($zip_entry));
$zname=zip_entry_name($zip_entry);
if(!zip_entry_open($zip,$zip_entry,"r")) {$e.="Unable to proccess file '{$zname}'";continue;}
if(!is_dir($zdir)) mkdirr($zdir,0777);
#print "{$zdir} | {$zname} \n";
$zip_fs=zip_entry_filesize($zip_entry);
if(empty($zip_fs)) continue;
$zz=zip_entry_read($zip_entry,$zip_fs);
$z=fopen($zname,"w");
fwrite($z,$zz);
fclose($z);
zip_entry_close($zip_entry);
}
zip_close($zip);
return($e);
}
function mkdirr($pn,$mode=null) {
if(is_dir($pn)||empty($pn)) return true;
$pn=str_replace(array('/', ''),DIRECTORY_SEPARATOR,$pn);
if(is_file($pn)) {trigger_error('mkdirr() File exists', E_USER_WARNING);return false;}
$next_pathname=substr($pn,0,strrpos($pn,DIRECTORY_SEPARATOR));
if(mkdirr($next_pathname,$mode)) {if(!file_exists($pn)) {return mkdir($pn,$mode);} }
return false;
}
unzip("test.zip");
?>
have a nice day :)
You could just use the linux commands
<?php
// Get the date
$date = date("m-d-y");
// Make Zip name
$zipname = "archive/site-script-backup." . $date . ".zip";
// Make a zip file
$cmd = `zip -r $zipname *`;
?>
Here's a more simple extended class to add a whole directory recursively, keeping the same structure. It uses SPL.
<?php
class MyZipArchive extends ZipArchive
{
/**
*
* Adds a directory recursively.
*
* @param string $filename The path to the file to add.
*
* @param string $localname Local name inside ZIP archive.
*
*/
public function addDir($filename, $localname)
{
$this->addEmptyDir($localname);
$iter = new RecursiveDirectoryIterator($filename, FilesystemIterator::SKIP_DOTS);
foreach ($iter as $fileinfo) {
if (! $fileinfo->isFile() && !$fileinfo->isDir()) {
continue;
}
$method = $fileinfo->isFile() ? 'addFile' : 'addDir';
$this->$method($fileinfo->getPathname(), $localname . '/' .
$fileinfo->getFilename());
}
}
}
?>
[EDIT BY danbrown AT php DOT net: Contains a bugfix suggested by (bart AT blueberry DOT nl) on 29-JUN-2011 with the following message. "Fix for the endless Iteratore add the flag FilesystemIterator::SKIP_DOTS"]
Heres a function I wrote that will extract a zip file with the same directory structure...
Enjoy:
<?php
function unzip($zipfile)
{
$zip = zip_open($zipfile);
while ($zip_entry = zip_read($zip)) {
zip_entry_open($zip, $zip_entry);
if (substr(zip_entry_name($zip_entry), -1) == '/') {
$zdir = substr(zip_entry_name($zip_entry), 0, -1);
if (file_exists($zdir)) {
trigger_error('Directory "<b>' . $zdir . '</b>" exists', E_USER_ERROR);
return false;
}
mkdir($zdir);
}
else {
$name = zip_entry_name($zip_entry);
if (file_exists($name)) {
trigger_error('File "<b>' . $name . '</b>" exists', E_USER_ERROR);
return false;
}
$fopen = fopen($name, "w");
fwrite($fopen, zip_entry_read($zip_entry, zip_entry_filesize($zip_entry)), zip_entry_filesize($zip_entry));
}
zip_entry_close($zip_entry);
}
zip_close($zip);
return true;
}
?>
With this extension you can Add dirs with files with the ZipArchive Object
<?php
/**
* FlxZipArchive, Extends ZipArchiv.
* Add Dirs with Files and Subdirs.
*
* <code>
* $archive = new FlxZipArchive;
* // .....
* $archive->addDir( 'test/blub', 'blub' );
* </code>
*/
class FlxZipArchive extends ZipArchive {
/**
* Add a Dir with Files and Subdirs to the archive
*
* @param string $location Real Location
* @param string $name Name in Archive
* @author Nicolas Heimann
* @access private
**/
public function addDir($location, $name) {
$this->addEmptyDir($name);
$this->addDirDo($location, $name);
// } // EO addDir;
/**
* Add Files & Dirs to archive.
*
* @param string $location Real Location
* @param string $name Name in Archive
* @author Nicolas Heimann
* @access private
**/
private function addDirDo($location, $name) {
$name .= '/';
$location .= '/';
// Read all Files in Dir
$dir = opendir ($location);
while ($file = readdir($dir))
{
if ($file == '.' || $file == '..') continue;
// Rekursiv, If dir: FlxZipArchive::addDir(), else ::File();
$do = (filetype() == 'dir') ? 'addDir' : 'addFile';
$this->$do($location . $file, $name . $file);
}
} // EO addDirDo();
}
?>
I made a zip stream handler in case your distribution does not have the built in one using the new ZipArchive system. This one also features the ability to grab entries by index as well as by name. It is similar in capabilities to the builtin gzip/bzip2 compression stream handlers (http://us2.php.net/manual/en/wrappers.compression.php) except it does not support writing.
To use:
fopen('zip://absolute/path/to/file.zip?entryname', $mode) or
fopen('zip://absolute/path/to/file.zip#entryindex', $mode) or
fopen('zip://absolute/path/to/file.zip', $mode)
$mode can only be 'r' or 'rb'. In the last case the first entry in the zip file is used.
<?php
class ZipStream {
public $zip; //the zip file
public $entry; //the opened zip entry
public $length; //the uncompressed size of the zip entry
public $position; //the current position in the zip entry read
//Opens the zip file then retrieves and opens the entry to stream
public function stream_open($path, $mode, $options, &$opened_path) {
if ($mode != 'r' && $mode != 'rb') //only accept r and rb modes, no writing!
return false;
$path = 'file:///'.substr($path, 6); //switch out file:/// for zip:// so we can use url_parse
$url = parse_url($path);
//open the zip file
$filename = $url['path'];
$this->zip = zip_open($filename);
if (!is_resource($this->zip))
return false;
//if entry name is given, find that entry
if (array_key_exists('query', $url) && $url['query']) {
$path = $url['query'];
do {
$this->entry = zip_read($this->zip);
if (!is_resource($this->entry))
return false;
} while (zip_entry_name($this->entry) != $path);
} else { //otherwise get it by index (default to 0)
$id = 0;
if (array_key_exists('fragment', $url) && is_int($url['fragment']))
$id = $url['fragment']*1;
for ($i = 0; $i <= $id; $i++) {
$this->entry = zip_read($this->zip);
if (!is_resource($this->entry))
return false;
}
}
//setup length and open the entry for reading
$this->length = zip_entry_filesize($this->entry);
$this->position = 0;
zip_entry_open($this->zip, $this->entry, $mode);
return true;
}
//Closes the zip entry and file
public function stream_close() { @zip_entry_close($this->entry); @zip_close($this->zip); }
//Returns how many bytes have been read from the zip entry
public function stream_tell() { return $this->position; }
//Returns true if the end of the zip entry has been reached
public function stream_eof() { return $this->position >= $this->length; }
//Returns the stat array, only 'size' is filled in with the uncompressed zip entry size
public function url_stat() { return array('dev'=>0, 'ino'=>0, 'mode'=>0, 'nlink'=>0, 'uid'=>0, 'gid'=>0, 'rdev'=>0, 'size'=>$this->length, 'atime'=>0, 'mtime'=>0, 'ctime'=>0, 'blksize'=>0, 'blocks'=>0); }
//Reads the next $count bytes or until the end of the zip entry. Returns the data or false if no data was read.
public function stream_read($count) {
$this->position += $count;
if ($this->position > $this->length)
$this->position = $this->length;
return zip_entry_read($this->entry, $count);
}
}
//Register the zip stream handler
stream_wrapper_register('zip', 'ZipStream'); //if this fails there is already a zip stream handler and we will just use that one
?>
This is the function I use to unzip a file.
It includes the following options:
* Unzip in any directory you like
* Unzip in the directory of the zip file
* Unzip in a directory with the zipfile's name in the directory of the zip file. (i.e.: C:\test.zip will be unzipped in C:\test\)
* Overwrite existing files or not
* It creates non existing directories with the function Create_dirs($path)
You should use absolute paths with slashes (/) instead of backslashes (\).
I tested it with PHP 5.2.0 with php_zip.dll extension loaded
<?php
/**
* Unzip the source_file in the destination dir
*
* @param string The path to the ZIP-file.
* @param string The path where the zipfile should be unpacked, if false the directory of the zip-file is used
* @param boolean Indicates if the files will be unpacked in a directory with the name of the zip-file (true) or not (false) (only if the destination directory is set to false!)
* @param boolean Overwrite existing files (true) or not (false)
*
* @return boolean Succesful or not
*/
function unzip($src_file, $dest_dir=false, $create_zip_name_dir=true, $overwrite=true)
{
if ($zip = zip_open($src_file))
{
if ($zip)
{
$splitter = ($create_zip_name_dir === true) ? "." : "/";
if ($dest_dir === false) $dest_dir = substr($src_file, 0, strrpos($src_file, $splitter))."/";
// Create the directories to the destination dir if they don't already exist
create_dirs($dest_dir);
// For every file in the zip-packet
while ($zip_entry = zip_read($zip))
{
// Now we're going to create the directories in the destination directories
// If the file is not in the root dir
$pos_last_slash = strrpos(zip_entry_name($zip_entry), "/");
if ($pos_last_slash !== false)
{
// Create the directory where the zip-entry should be saved (with a "/" at the end)
create_dirs($dest_dir.substr(zip_entry_name($zip_entry), 0, $pos_last_slash+1));
}
// Open the entry
if (zip_entry_open($zip,$zip_entry,"r"))
{
// The name of the file to save on the disk
$file_name = $dest_dir.zip_entry_name($zip_entry);
// Check if the files should be overwritten or not
if ($overwrite === true || $overwrite === false && !is_file($file_name))
{
// Get the content of the zip entry
$fstream = zip_entry_read($zip_entry, zip_entry_filesize($zip_entry));
file_put_contents($file_name, $fstream );
// Set the rights
chmod($file_name, 0777);
echo "save: ".$file_name."<br />";
}
// Close the entry
zip_entry_close($zip_entry);
}
}
// Close the zip-file
zip_close($zip);
}
}
else
{
return false;
}
return true;
}
/**
* This function creates recursive directories if it doesn't already exist
*
* @param String The path that should be created
*
* @return void
*/
function create_dirs($path)
{
if (!is_dir($path))
{
$directory_path = "";
$directories = explode("/",$path);
array_pop($directories);
foreach($directories as $directory)
{
$directory_path .= $directory."/";
if (!is_dir($directory_path))
{
mkdir($directory_path);
chmod($directory_path, 0777);
}
}
}
}
// Extract C:/zipfiletest/zip-file.zip to C:/zipfiletest/zip-file/ and overwrites existing files
unzip("C:/zipfiletest/zip-file.zip", false, true, true);
// Extract C:/zipfiletest/zip-file.zip to C:/another_map/zipfiletest/ and doesn't overwrite existing files. NOTE: It doesn't create a map with the zip-file-name!
unzip("C:/zipfiletest/zip-file.zip", "C:/another_map/zipfiletest/", true, false);
?>
Hi, all
There are lot of functions given below which etracts files, but what they lack is setting file permissions. On some servers file permissions are very important and the script cease to work after creating first directory, So I have added chmod to the code. There is only one limitation to the code, files without file extension are neither treated as files or directories so they are not chmoded, anyway this does not affect the code. Hope this helps.
<?php
function unpackZip($dir,$file) {
if ($zip = zip_open($dir.$file.".zip")) {
if ($zip) {
mkdir($dir.$file);
chmod($dir.$file, 0777);
while ($zip_entry = zip_read($zip)) {
if (zip_entry_open($zip,$zip_entry,"r")) {
$buf = zip_entry_read($zip_entry, zip_entry_filesize($zip_entry));
$dir_name = dirname(zip_entry_name($zip_entry));
if ($dir_name != ".") {
$dir_op = $dir.$file."/";
foreach ( explode("/",$dir_name) as $k) {
$dir_op = $dir_op . $k;
if (is_file($dir_op)) unlink($dir_op);
if (!is_dir($dir_op)) mkdir($dir_op);
chmod($dir_op, 0777);
$dir_op = $dir_op . "/" ;
}
}
$fp=fopen($dir.$file."/".zip_entry_name($zip_entry),"w+");
chmod($dir.$file."/".zip_entry_name($zip_entry), 0777);
fwrite($fp,$buf);
fclose($fp);
zip_entry_close($zip_entry);
} else
return false;
}
zip_close($zip);
}
} else
return false;
return true;
}
$dir = $_SERVER['DOCUMENT_ROOT']."/"."destdirectory/";
$file = 'zipfilename_without_extension';
unpackZip($dir,$file);
$print = $_SERVER['DOCUMENT_ROOT'];
?>
This will simply unpack (including directories) $zip to $dir -- in this example the zip is being uploaded.
<?php
$dir = 'C:\\reports-temp\\';
$zip = zip_open($_FILES['report_zip']['tmp_name']);
while($zip_entry = zip_read($zip)) {
$entry = zip_entry_open($zip,$zip_entry);
$filename = zip_entry_name($zip_entry);
$target_dir = $dir.substr($filename,0,strrpos($filename,'/'));
$filesize = zip_entry_filesize($zip_entry);
if (is_dir($target_dir) || mkdir($target_dir)) {
if ($filesize > 0) {
$contents = zip_entry_read($zip_entry, $filesize);
file_put_contents($dir.$filename,$contents);
}
}
}
?>
this function extract all files and subdirectories, you can choose verbose mode for get paths of files extracted. the function return a msg what indicate the error, if msg is OK, all is done.
---
code:
<?php
function unzip($dir, $file, $verbose = 0) {
$dir_path = "$dir$file";
$zip_path = "$dir$file.zip";
$ERROR_MSGS[0] = "OK";
$ERROR_MSGS[1] = "Zip path $zip_path doesn't exists.";
$ERROR_MSGS[2] = "Directory $dir_path for unzip the pack already exists, impossible continue.";
$ERROR_MSGS[3] = "Error while opening the $zip_path file.";
$ERROR = 0;
if (file_exists($zip_path)) {
if (!file_exists($dir_path)) {
mkdir($dir_path);
if (($link = zip_open($zip_path))) {
while (($zip_entry = zip_read($link)) && (!$ERROR)) {
if (zip_entry_open($link, $zip_entry, "r")) {
$data = zip_entry_read($zip_entry, zip_entry_filesize($zip_entry));
$dir_name = dirname(zip_entry_name($zip_entry));
$name = zip_entry_name($zip_entry);
if ($name[strlen($name)-1] == '/') {
$base = "$dir_path/";
foreach ( explode("/", $name) as $k) {
$base .= "$k/";
if (!file_exists($base))
mkdir($base);
}
}
else {
$name = "$dir_path/$name";
if ($verbose)
echo "extracting: $name<br>";
$stream = fopen($name, "w");
fwrite($stream, $data);
}
zip_entry_close($zip_entry);
}
else
$ERROR = 4;
}
zip_close($link);
}
else
$ERROR = "3";
}
else
$ERROR = 2;
}
else
$ERROR = 1;
return $ERROR_MSGS[$ERROR];
}
?>
---
example:
<?php
$error = unzip("d:/www/dir/", "zipname", 1);
echo $error;
?>
---
i hope this help you,
good bye.
i try to find function that will show exists file in zip archive or not. of course i not found it. and so write mine:
first will just check archive for list of files, if not found all files function return FALSE:
<?php
function zipx_entries_exists()
{
$names=array();
$args=func_get_args();
$far_size=count($args);
if($args[0])
{
for(; $zip_entry=zip_read($args[0]); $names[]= zip_entry_name($zip_entry));
for($x=1; $x<=$far_size; $t+=in_array($args[$x], $names), $x++);
return $t==--$far_size;
}else{
return 'No zip file in descriptor!';
}
}
example:
$zip=zip_open('any_zip_file_zip');
var_dump(zip_entries_exists($zip, 'photo_1.jpg', 'photo_2.jpg'));
second function will try to find files in zip, if not found it return string with names of not found files with specified delimeter:
function zipx_entries_nonexists_list()
{
$names=array();
$args=func_get_args();
$m=NULL;
$far_size=count($args);
if($args[0])
{
for(; $zip_entry=zip_read($args[0]); $names[]= zip_entry_name($zip_entry));
for($x=2; $x<=$far_size; $m.=(in_array($args[$x], $names) ? NULL : $args[$x].$args[1]), $x++);
return trim($m, $args[1]);
}else{
return 'No zip file in descriptor!';
}
}
?>
example:
<?php
$zip=zip_open('any_zip_file_zip');
var_dump(zip_entries_nonexists_list($zip, '<br />', 'photo_1.jpg', 'photo_2.jpg'));
?>
it will return if not found files:
photo_1.jpg<br />photo_2.jpg
If you just want to unzip a zip folder an alternative to some of the lengthy functions below is:
<?php
function unzip($zip_file, $src_dir, $extract_dir)
{
copy($src_dir . "/" . $zip_file, $extract_dir . "/" . $zip_file);
chdir($extract_dir);
shell_exec("unzip $zip_file");
}
?>
You don't need the ZIP extension for this.
New Unzip function, recursive extract
Require mkdirr() (recursive create dir)
<?php
$file = "2537c61ef7f47fc3ae919da08bcc1911.zip";
$dir = getcwd();
function Unzip($dir, $file, $destiny="")
{
$dir .= DIRECTORY_SEPARATOR;
$path_file = $dir . $file;
$zip = zip_open($path_file);
$_tmp = array();
$count=0;
if ($zip)
{
while ($zip_entry = zip_read($zip))
{
$_tmp[$count]["filename"] = zip_entry_name($zip_entry);
$_tmp[$count]["stored_filename"] = zip_entry_name($zip_entry);
$_tmp[$count]["size"] = zip_entry_filesize($zip_entry);
$_tmp[$count]["compressed_size"] = zip_entry_compressedsize($zip_entry);
$_tmp[$count]["mtime"] = "";
$_tmp[$count]["comment"] = "";
$_tmp[$count]["folder"] = dirname(zip_entry_name($zip_entry));
$_tmp[$count]["index"] = $count;
$_tmp[$count]["status"] = "ok";
$_tmp[$count]["method"] = zip_entry_compressionmethod($zip_entry);
if (zip_entry_open($zip, $zip_entry, "r"))
{
$buf = zip_entry_read($zip_entry, zip_entry_filesize($zip_entry));
if($destiny)
{
$path_file = str_replace("/",DIRECTORY_SEPARATOR, $destiny . zip_entry_name($zip_entry));
}
else
{
$path_file = str_replace("/",DIRECTORY_SEPARATOR, $dir . zip_entry_name($zip_entry));
}
$new_dir = dirname($path_file);
// Create Recursive Directory
mkdirr($new_dir);
$fp = fopen($dir . zip_entry_name($zip_entry), "w");
fwrite($fp, $buf);
fclose($fp);
zip_entry_close($zip_entry);
}
echo "\n</pre>";
$count++;
}
zip_close($zip);
}
}
Unzip($dir,$file);
?>
If (as me) all you wanted to do is store a big string (for example, a serialized array or the like) in a mysql BLOB field, remember that mysql has a COMPRESS() and UNCOMPRESS() pair of functions that do exactly that. Compression/decompression is therefore available also when accessing the DB from other languages like java, etc.
If you want to unzip an password protected file with php..try the following command....it works in Unix/Apache environment...I haven't tested in any other environment...
system("`which unzip` -P Password $zipfile -d $des",$ret_val)
Where $zipfile is the path to the .zip to be unzipped and $des is path to the destination directory.....here both absolute and relative path to the script (which contains this system command) will work...
if everything runs well...file should be unzipped at the $des directory..and you will get 0 value for $ret_val , which means success(info-zip.org)
Regards
Krishnendu
just a not of caution--using the dynamic zip class mentioned earlier seems to cause issues with high ascii characters (their values are not preserved correctly, and the file will not unzip)
Watch out with archives that contain subfolders if you're using the zip functions to extract archives to actual files. Let's say you're trying to extract foldername/filename.txt from the archive. You can't fopen a directory that doesn't exist, so you'll have to check for the existance of directory foldername and create it if it isn't found, then fopen foldername/filename.txt and begin writing to that.
