Source code for file /joomla/filesystem/archive/zip.php
Documentation is available at zip.php
* @version $Id:zip.php 6961 2007-03-15 16:06:53Z tcp $
* @package Joomla.Framework
* @copyright Copyright (C) 2005 - 2008 Open Source Matters. All rights reserved.
* @license GNU/GPL, see LICENSE.php
* Joomla! is free software. This version may have been modified pursuant
* to the GNU General Public License, and as distributed it includes or
* is derivative of works licensed under the GNU General Public License or
* other free or open source software licenses.
* See COPYRIGHT.php for copyright notices and details.
// Check to ensure this file is within the rest of the framework
* ZIP format adapter for the JArchive class
* The ZIP compression code is partially based on code from:
* Eric Mueller <eric@themepark.com>
* http://www.zend.com/codex.php?id=535&single=1
* Deins125 <webmaster@atlant.ru>
* http://www.zend.com/codex.php?id=470&single=1
* The ZIP compression date code is partially based on code from
* Peter Listiak <mlady@users.sourceforge.net>
* This class is inspired from and draws heavily in code and concept from the Compress package of
* The Horde Project <http://www.horde.org>
* @contributor Chuck Hagenbuch <chuck@horde.org>
* @contributor Michael Slusarz <slusarz@horde.org>
* @contributor Michael Cochrane <mike@graftonhall.co.nz>
* @author Louis Landry <louis.landry@joomla.org>
* @package Joomla.Framework
* ZIP compression methods.
* Beginning of central directory record.
* End of central directory record.
* Beginning of file contents.
* ZIP file metadata array
* Create a ZIP compressed file from an array of file data.
* @todo Finish Implementation
* @param string $archive Path to save archive
* @param array $files Array of files to add to archive
* @param array $options Compression options [unused]
* @return boolean True if successful
function create($archive, $files, $options =
array ())
foreach ($files as $file)
$this->_addToZIPFile($file, $contents, $ctrldir);
return $this->_createZIPFile($contents, $ctrldir, $archive);
* Extract a ZIP compressed file to a given path
* @param string $archive Path to ZIP archive to extract
* @param string $destination Path to extract archive into
* @param array $options Extraction options [unused]
* @return boolean True if successful
function extract($archive, $destination, $options =
array ())
$this->set('error.message', 'Archive does not exist');
return ($this->_extractNative($archive, $destination, $options))?
true :
JError::raiseWarning(100, $this->get('error.message'));
return ($this->_extract($archive, $destination, $options))?
true :
JError::raiseWarning(100, $this->get('error.message'));
* Method to determine if the server has native zip support for faster handling
* @return boolean True if php has native ZIP support
* Checks to see if the data is a valid ZIP file.
* @param string $data ZIP archive data buffer
* @return boolean True if valid, false if invalid.
* Extract a ZIP compressed file to a given path using a php based algorithm that only requires zlib support
* @param string $archive Path to ZIP archive to extract
* @param string $destination Path to extract archive into
* @param array $options Extraction options [unused]
* @return boolean True if successful
function _extract($archive, $destination, $options)
$this->set('error.message', 'Zlib Not Supported');
$this->set('error.message', 'Unable to read archive');
if (!$this->_getZipInfo($this->_data)) {
$buffer =
$this->_getFileData($i);
// Make sure the destination folder exists
$this->set('error.message', 'Unable to create destination');
$this->set('error.message', 'Unable to write entry');
* Extract a ZIP compressed file to a given path using native php api calls for speed
* @param string $archive Path to ZIP archive to extract
* @param string $destination Path to extract archive into
* @param array $options Extraction options [unused]
* @return boolean True if successful
function _extractNative($archive, $destination, $options)
// Make sure the destination folder exists
$this->set('error.message', 'Unable to create destination');
// Read files in the archive
$this->set('error.message', 'Unable to write entry');
$this->set('error.message', 'Unable to read entry');
$this->set('error.message', 'Unable to open archive');
* Get the list of files/data from a ZIP archive buffer.
* @param string $data The ZIP archive buffer.
* @return array Archive metadata array
* KEY: Position in zipfile
* VALUES: 'attr' -- File attributes
* 'csize' -- Compressed file size
* 'date' -- File modification time
* 'method' -- Compression method
* 'size' -- Original file size
function _getZipInfo(& $data)
// Get details from Central directory structure.
if (strlen($data) <
$fhStart +
31) {
$this->set('error.message', 'Invalid ZIP data');
$info =
unpack('vMethod/VTime/VCRC32/VCompressed/VUncompressed/vLength', substr($data, $fhStart +
10, 20));
$name =
substr($data, $fhStart +
46, $info['Length']);
$entries[$name] =
array('attr' =>
null, 'crc' =>
sprintf("%08s", dechex($info['CRC32'] )), 'csize' =>
$info['Compressed'], 'date' =>
null, '_dataStart' =>
null, 'name' =>
$name, 'method' =>
$this->_methods[$info['Method']], '_method' =>
$info['Method'], 'size' =>
$info['Uncompressed'], 'type' =>
null);
$entries[$name]['date'] =
mktime((($info['Time'] >>
11) & 0x1f), (($info['Time'] >>
5) & 0x3f), (($info['Time'] <<
1) & 0x3e), (($info['Time'] >>
21) & 0x07), (($info['Time'] >>
16) & 0x1f), ((($info['Time'] >>
25) & 0x7f) +
1980));
if (strlen($data) <
$fhStart +
43) {
$this->set('error.message', 'Invalid ZIP data');
$info =
unpack('vInternal/VExternal', substr($data, $fhStart +
36, 6));
$entries[$name]['type'] =
($info['Internal'] & 0x01) ?
'text' :
'binary';
$entries[$name]['attr'] =
(($info['External'] & 0x10) ?
'D' :
'-') .
(($info['External'] & 0x20) ?
'A' :
'-') .
(($info['External'] & 0x03) ?
'S' :
'-') .
(($info['External'] & 0x02) ?
'H' :
'-') .
(($info['External'] & 0x01) ?
'R' :
'-');
// Get details from local file header.
if (strlen($data) <
$fhStart +
34) {
$this->set('error.message', 'Invalid ZIP data');
$info =
unpack('vMethod/VTime/VCRC32/VCompressed/VUncompressed/vLength/vExtraLength', substr($data, $fhStart +
8, 25));
$name =
substr($data, $fhStart +
30, $info['Length']);
$entries[$name]['_dataStart'] =
$fhStart +
30 +
$info['Length'] +
$info['ExtraLength'];
} while (strlen($data) >
$fhStart +
30 +
$info['Length'] &&
($fhStart =
strpos($data, $this->_fileHeader, $fhStart +
30 +
$info['Length'])) !==
false);
* Returns the file data for a file by offsest in the ZIP archive
* @param int $key The position of the file in the archive.
* @return string Uncompresed file data buffer
function _getFileData($key) {
if ($this->_metadata[$key]['_method'] ==
0x8) {
// If zlib extention is loaded use it
elseif ($this->_metadata[$key]['_method'] ==
0x0) {
/* Files that aren't compressed. */
} elseif ($this->_metadata[$key]['_method'] ==
0x12) {
// Is bz2 extension loaded? If not try to load it
// If bz2 extention is sucessfully loaded use it
* Converts a UNIX timestamp to a 4-byte DOS date and time format
* (date in high 2-bytes, time in low 2-bytes allowing magnitude
* @param int $unixtime The current UNIX timestamp.
* @return int The current date in a 4-byte DOS format.
function _unix2DOSTime($unixtime =
null) {
if ($timearray['year'] <
1980) {
$timearray['year'] =
1980;
$timearray['minutes'] =
0;
$timearray['seconds'] =
0;