diff options
author | Robin Appelman <icewind@owncloud.com> | 2012-05-02 23:48:23 +0200 |
---|---|---|
committer | Robin Appelman <icewind@owncloud.com> | 2012-05-02 23:48:23 +0200 |
commit | e5ef3e1340f68fdcc46ba318dab1773b8fb530a8 (patch) | |
tree | ab6c54857001552b62254f4950cc6caf45ce7720 /lib | |
parent | 0b51c5344399d9990d46b275afb82fbfbd070ad4 (diff) | |
download | nextcloud-server-e5ef3e1340f68fdcc46ba318dab1773b8fb530a8.tar.gz nextcloud-server-e5ef3e1340f68fdcc46ba318dab1773b8fb530a8.zip |
move archive library to core so we can properly depend on it
Diffstat (limited to 'lib')
-rw-r--r-- | lib/archive.php | 115 | ||||
-rwxr-xr-x | lib/archive/tar.php | 279 | ||||
-rwxr-xr-x | lib/archive/zip.php | 200 |
3 files changed, 594 insertions, 0 deletions
diff --git a/lib/archive.php b/lib/archive.php new file mode 100644 index 00000000000..113f92e9604 --- /dev/null +++ b/lib/archive.php @@ -0,0 +1,115 @@ +<?php +/** + * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +abstract class OC_Archive{ + /** + * open any of the supporeted archive types + * @param string path + * @return OC_Archive + */ + public static function open($path){ + $ext=substr($path,strrpos($path,'.')); + switch($ext){ + case '.zip': + return new OC_Archive_ZIP($path); + case '.gz': + case '.bz': + case '.bz2': + if(strpos($path,'.tar.')){ + return new OC_Archive_TAR($path); + } + break; + case '.tgz': + return new OC_Archive_TAR($path); + } + } + + abstract function __construct($source); + /** + * add an empty folder to the archive + * @param string path + * @return bool + */ + abstract function addFolder($path); + /** + * add a file to the archive + * @param string path + * @param string source either a local file or string data + * @return bool + */ + abstract function addFile($path,$source=''); + /** + * rename a file or folder in the archive + * @param string source + * @param string dest + * @return bool + */ + abstract function rename($source,$dest); + /** + * get the uncompressed size of a file in the archive + * @param string path + * @return int + */ + abstract function filesize($path); + /** + * get the last modified time of a file in the archive + * @param string path + * @return int + */ + abstract function mtime($path); + /** + * get the files in a folder + * @param path + * @return array + */ + abstract function getFolder($path); + /** + *get all files in the archive + * @return array + */ + abstract function getFiles(); + /** + * get the content of a file + * @param string path + * @return string + */ + abstract function getFile($path); + /** + * extract a single file from the archive + * @param string path + * @param string dest + * @return bool + */ + abstract function extractFile($path,$dest); + /** + * extract the archive + * @param string path + * @param string dest + * @return bool + */ + abstract function extract($dest); + /** + * check if a file or folder exists in the archive + * @param string path + * @return bool + */ + abstract function fileExists($path); + /** + * remove a file or folder from the archive + * @param string path + * @return bool + */ + abstract function remove($path); + /** + * get a file handler + * @param string path + * @param string mode + * @return resource + */ + abstract function getStream($path,$mode); +} diff --git a/lib/archive/tar.php b/lib/archive/tar.php new file mode 100755 index 00000000000..07f0ba5bd8a --- /dev/null +++ b/lib/archive/tar.php @@ -0,0 +1,279 @@ +<?php +/** + * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +require_once '3rdparty/Archive/Tar.php'; + +class OC_Archive_TAR extends OC_Archive{ + const PLAIN=0; + const GZIP=1; + const BZIP=2; + + /** + * @var Archive_Tar tar + */ + private $tar=null; + private $path; + + function __construct($source){ + $types=array(null,'gz','bz'); + $this->path=$source; + $this->tar=new Archive_Tar($source,$types[self::getTarType($source)]); + } + + /** + * try to detect the type of tar compression + * @param string file + * @return str + */ + static public function getTarType($file){ + if(strpos($file,'.')){ + $extension=substr($file,strrpos($file,'.')); + switch($extension){ + case 'gz': + case 'tgz': + return self::GZIP; + case 'bz': + case 'bz2': + return self::BZIP; + default: + return self::PLAIN; + } + }else{ + return self::PLAIN; + } + } + + /** + * add an empty folder to the archive + * @param string path + * @return bool + */ + function addFolder($path){ + $tmpBase=get_temp_dir().'/'; + if(substr($path,-1,1)!='/'){ + $path.='/'; + } + if($this->fileExists($path)){ + return false; + } + mkdir($tmpBase.$path); + $result=$this->tar->addModify(array($tmpBase.$path),'',$tmpBase); + rmdir($tmpBase.$path); + return $result; + } + /** + * add a file to the archive + * @param string path + * @param string source either a local file or string data + * @return bool + */ + function addFile($path,$source=''){ + if($this->fileExists($path)){ + $this->remove($path); + } + if(file_exists($source)){ + $header=array(); + $dummy=''; + $this->tar->_openAppend(); + $result=$this->tar->_addfile($source,$header,$dummy,$dummy,$path); + }else{ + $result=$this->tar->addString($path,$source); + } + return $result; + } + + /** + * rename a file or folder in the archive + * @param string source + * @param string dest + * @return bool + */ + function rename($source,$dest){ + //no proper way to delete, rename entire archive, rename file and remake archive + $tmp=OCP\Files::tmpFolder(); + $this->tar->extract($tmp); + rename($tmp.$source,$tmp.$dest); + $this->tar=null; + unlink($this->path); + $types=array(null,'gz','bz'); + $this->tar=new Archive_Tar($this->path,$types[self::getTarType($this->path)]); + $this->tar->createModify(array($tmp),'',$tmp.'/'); + } + + private function getHeader($file){ + $headers=$this->tar->listContent(); + foreach($headers as $header){ + if($file==$header['filename'] or $file.'/'==$header['filename']){ + return $header; + } + } + return null; + } + + /** + * get the uncompressed size of a file in the archive + * @param string path + * @return int + */ + function filesize($path){ + $stat=$this->getHeader($path); + return $stat['size']; + } + /** + * get the last modified time of a file in the archive + * @param string path + * @return int + */ + function mtime($path){ + $stat=$this->getHeader($path); + return $stat['mtime']; + } + + /** + * get the files in a folder + * @param path + * @return array + */ + function getFolder($path){ + $files=$this->getFiles(); + $folderContent=array(); + $pathLength=strlen($path); + foreach($files as $file){ + if(substr($file,0,$pathLength)==$path and $file!=$path){ + if(strrpos(substr($file,0,-1),'/')<=$pathLength){ + $folderContent[]=substr($file,$pathLength); + } + } + } + return $folderContent; + } + /** + *get all files in the archive + * @return array + */ + function getFiles(){ + $headers=$this->tar->listContent(); + $files=array(); + foreach($headers as $header){ + $files[]=$header['filename']; + } + return $files; + } + /** + * get the content of a file + * @param string path + * @return string + */ + function getFile($path){ + return $this->tar->extractInString($path); + } + /** + * extract a single file from the archive + * @param string path + * @param string dest + * @return bool + */ + function extractFile($path,$dest){ + $tmp=OCP\Files::tmpFolder(); + if(!$this->fileExists($path)){ + return false; + } + $success=$this->tar->extractList(array($path),$tmp); + if($success){ + rename($tmp.$path,$dest); + } + OCP\Files::rmdirr($tmp); + return $success; + } + /** + * extract the archive + * @param string path + * @param string dest + * @return bool + */ + function extract($dest){ + return $this->tar->extract($dest); + } + /** + * check if a file or folder exists in the archive + * @param string path + * @return bool + */ + function fileExists($path){ + return $this->getHeader($path)!==null; + } + + /** + * remove a file or folder from the archive + * @param string path + * @return bool + */ + function remove($path){ + if(!$this->fileExists($path)){ + return false; + } + //no proper way to delete, extract entire archive, delete file and remake archive + $tmp=OCP\Files::tmpFolder(); + $this->tar->extract($tmp); + OCP\Files::rmdirr($tmp.$path); + $this->tar=null; + unlink($this->path); + $this->reopen(); + $this->tar->createModify(array($tmp),'',$tmp); + return true; + } + /** + * get a file handler + * @param string path + * @param string mode + * @return resource + */ + function getStream($path,$mode){ + if(strrpos($path,'.')!==false){ + $ext=substr($path,strrpos($path,'.')); + }else{ + $ext=''; + } + $tmpFile=OCP\Files::tmpFile($ext); + if($this->fileExists($path)){ + $this->extractFile($path,$tmpFile); + }elseif($mode=='r' or $mode=='rb'){ + return false; + } + if($mode=='r' or $mode=='rb'){ + return fopen($tmpFile,$mode); + }else{ + OC_CloseStreamWrapper::$callBacks[$tmpFile]=array($this,'writeBack'); + self::$tempFiles[$tmpFile]=$path; + return fopen('close://'.$tmpFile,$mode); + } + } + + private static $tempFiles=array(); + /** + * write back temporary files + */ + function writeBack($tmpFile){ + if(isset(self::$tempFiles[$tmpFile])){ + $this->addFile(self::$tempFiles[$tmpFile],$tmpFile); + unlink($tmpFile); + } + } + + /** + * reopen the archive to ensure everything is written + */ + private function reopen(){ + if($this->tar){ + $this->tar->_close(); + $this->tar=null; + } + $types=array(null,'gz','bz'); + $this->tar=new Archive_Tar($this->path,$types[self::getTarType($this->path)]); + } +} diff --git a/lib/archive/zip.php b/lib/archive/zip.php new file mode 100755 index 00000000000..22ab48937eb --- /dev/null +++ b/lib/archive/zip.php @@ -0,0 +1,200 @@ +<?php +/** + * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +class OC_Archive_ZIP extends OC_Archive{ + /** + * @var ZipArchive zip + */ + private $zip=null; + private $success=false; + private $path; + + function __construct($source){ + $this->path=$source; + $this->zip=new ZipArchive(); + if($this->zip->open($source,ZipArchive::CREATE)){ + }else{ + OCP\Util::writeLog('files_archive','Error while opening archive '.$source,OCP\Util::WARN); + } + } + /** + * add an empty folder to the archive + * @param string path + * @return bool + */ + function addFolder($path){ + return $this->zip->addEmptyDir($path); + } + /** + * add a file to the archive + * @param string path + * @param string source either a local file or string data + * @return bool + */ + function addFile($path,$source=''){ + if(file_exists($source)){ + $result=$this->zip->addFile($source,$path); + }else{ + $result=$this->zip->addFromString($path,$source); + } + if($result){ + $this->zip->close();//close and reopen to save the zip + $this->zip->open($this->path); + } + return $result; + } + /** + * rename a file or folder in the archive + * @param string source + * @param string dest + * @return bool + */ + function rename($source,$dest){ + $source=$this->stripPath($source); + $dest=$this->stripPath($dest); + $this->zip->renameName($source,$dest); + } + /** + * get the uncompressed size of a file in the archive + * @param string path + * @return int + */ + function filesize($path){ + $stat=$this->zip->statName($path); + return $stat['size']; + } + /** + * get the last modified time of a file in the archive + * @param string path + * @return int + */ + function mtime($path){ + $stat=$this->zip->statName($path); + return $stat['mtime']; + } + /** + * get the files in a folder + * @param path + * @return array + */ + function getFolder($path){ + $files=$this->getFiles(); + $folderContent=array(); + $pathLength=strlen($path); + foreach($files as $file){ + if(substr($file,0,$pathLength)==$path and $file!=$path){ + if(strrpos(substr($file,0,-1),'/')<=$pathLength){ + $folderContent[]=substr($file,$pathLength); + } + } + } + return $folderContent; + } + /** + *get all files in the archive + * @return array + */ + function getFiles(){ + $fileCount=$this->zip->numFiles; + $files=array(); + for($i=0;$i<$fileCount;$i++){ + $files[]=$this->zip->getNameIndex($i); + } + return $files; + } + /** + * get the content of a file + * @param string path + * @return string + */ + function getFile($path){ + return $this->zip->getFromName($path); + } + /** + * extract a single file from the archive + * @param string path + * @param string dest + * @return bool + */ + function extractFile($path,$dest){ + $fp = $this->zip->getStream($path); + file_put_contents($dest,$fp); + } + /** + * extract the archive + * @param string path + * @param string dest + * @return bool + */ + function extract($dest){ + return $this->zip->extractTo($dest); + } + /** + * check if a file or folder exists in the archive + * @param string path + * @return bool + */ + function fileExists($path){ + return ($this->zip->locateName($path)!==false) or ($this->zip->locateName($path.'/')!==false); + } + /** + * remove a file or folder from the archive + * @param string path + * @return bool + */ + function remove($path){ + if($this->fileExists($path.'/')){ + return $this->zip->deleteName($path.'/'); + }else{ + return $this->zip->deleteName($path); + } + } + /** + * get a file handler + * @param string path + * @param string mode + * @return resource + */ + function getStream($path,$mode){ + if($mode=='r' or $mode=='rb'){ + return $this->zip->getStream($path); + }else{//since we cant directly get a writable stream, make a temp copy of the file and put it back in the archive when the stream is closed + if(strrpos($path,'.')!==false){ + $ext=substr($path,strrpos($path,'.')); + }else{ + $ext=''; + } + $tmpFile=OCP\Files::tmpFile($ext); + OC_CloseStreamWrapper::$callBacks[$tmpFile]=array($this,'writeBack'); + if($this->fileExists($path)){ + $this->extractFile($path,$tmpFile); + } + self::$tempFiles[$tmpFile]=$path; + return fopen('close://'.$tmpFile,$mode); + } + } + + private static $tempFiles=array(); + /** + * write back temporary files + */ + function writeBack($tmpFile){ + if(isset(self::$tempFiles[$tmpFile])){ + $this->addFile(self::$tempFiles[$tmpFile],$tmpFile); + unlink($tmpFile); + } + } + + private function stripPath($path){ + if(substr($path,0,1)=='/'){ + return substr($path,1); + }else{ + return $path; + } + } +} |