Blame | Letzte Änderung | Log anzeigen | RSS feed
<?php/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: *//*** Factory to access the most common File_Archive features* It uses lazy include, so you dont have to include the files from* File/Archive/* directories** PHP versions 4 and 5** This library is free software; you can redistribute it and/or* modify it under the terms of the GNU Lesser General Public* License as published by the Free Software Foundation; either* version 2.1 of the License, or (at your option) any later version.** This library is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU* Lesser General Public License for more details.** You should have received a copy of the GNU Lesser General Public* License along with this library; if not, write to the Free Software* Foundation, Inc., 59 Temple Place, Suite 330,Boston,MA 02111-1307 USA** @category File Formats* @package File_Archive* @author Vincent Lascaux <vincentlascaux@php.net>* @copyright 1997-2005 The PHP Group* @license http://www.gnu.org/copyleft/lesser.html LGPL* @version CVS: $Id: Archive.php,v 1.90 2008/05/28 19:58:07 cbrunet Exp $* @link http://pear.php.net/package/File_Archive*//*** To have access to PEAR::isError and PEAR::raiseError* We should probably use lazy include and remove this inclusion...*/require_once "PEAR.php";function File_Archive_cleanCache($file, $group){$file = split('_', $file);if (count($file) != 3) {return false; //not a File_Archive file, keep it}$name = $file[2];$name = urldecode($name);$group = $file[1];//clean the cache only for files in File_Archive groupsreturn substr($group, 0, 11) == 'FileArchive' &&!file_exists($name); //and only if the related file no longer exists}/*** Factory to access the most common File_Archive features* It uses lazy include, so you dont have to include the files from* File/Archive/* directories*/class File_Archive{function& _option($name){static $container = array('zipCompressionLevel' => 9,'gzCompressionLevel' => 9,'tmpDirectory' => '.','cache' => null,'appendRemoveDuplicates' => false,'blockSize' => 65536,'cacheCondition' => false);return $container[$name];}/*** Sets an option that will be used by default by all readers or writers* Option names are case sensitive* Currently, the following options are used:** "cache"* Instance of a Cache_Lite object used to cache some compressed* data to speed up future compressions of files* Default: null (no cache used)** "zipCompressionLevel"* Value between 0 and 9 specifying the default compression level used* by Zip writers (0 no compression, 9 highest compression)* Default: 9** "gzCompressionLevel"* Value between 0 and 9 specifying the default compression level used* by Gz writers (0 no compression, 9 highest compression)* Default: 9** "tmpDirectory"* Directory where the temporary files generated by File_Archive will* be created* Default: '.'** "appendRemoveDuplicates"* If set to true, the appender created will by default remove the* file present in the archive when adding a new one. This will slow the* appending of files to archives* Default: false** "blockSize"* To transfer data from a reader to a writer, some chunks a read from the* source and written to the writer. This parameter controls the size of the* chunks* Default: 64kB** "cacheCondition"* This parameter specifies when a cache should be used. When the cache is* used, the data of the reader is saved in a temporary file for future access.* The cached reader will be read only once, even if you read it several times.* This can be usefull to read compressed files or downloaded files (from http or ftp)* The possible values for this option are* - false: never use cache* - a regexp: A cache will be used if the specified URL matches the regexp* preg_match is used* Default: false* Example: '/^(http|ftp):\/\//' will cache all files downloaded via http or ftp**/function setOption($name, $value){$option =& File_Archive::_option($name);$option = $value;if ($name == 'cache' && $value !== null) {//TODO: ask to Cache_Lite to allow that$value->_fileNameProtection = false;}}/*** Retrieve the value of an option*/function getOption($name){return File_Archive::_option($name);}/*** Create a reader to read the URL $URL.* If the URL is a directory, it will recursively read that directory.* If $uncompressionLevel is not null, the archives (files with extension* tar, zip, gz or tgz) will be considered as directories (up to a depth of* $uncompressionLevel if $uncompressionLevel > 0). The reader will only* read files with a directory depth of $directoryDepth. It reader will* replace the given URL ($URL) with $symbolic in the public filenames* The default symbolic name is the last filename in the URL (or '' for* directories)** Examples:* Considere the following file system* <pre>* a.txt* b.tar (archive that contains the following files)* c.txt* d.tgz (archive that contains the following files)* e.txt* dir1/* f.txt* dir2/* g.txt* dir3/* h.tar (archive that contains the following files)* i.txt* </pre>** read('.') will return a reader that gives access to following* files (recursively read current dir):* <pre>* a.txt* b.tar* dir2/g.txt* dir2/dir3/h.tar* </pre>** read('.', 'myBaseDir') will return the following reader:* <pre>* myBaseDir/a.txt* myBaseDir/b.tar* myBaseDir/dir2/g.txt* myBaseDir/dir2/dir3/h.tar* </pre>** read('.', '', -1) will return the following reader (uncompress* everything)* <pre>* a.txt* b.tar/c.txt* b.tar/d.tgz/e.txt* b.tar/d.tgz/dir1/f.txt* dir2/g.txt* dir2/dir3/h.tar/i.txt* </pre>** read('.', '', 1) will uncompress only one level (so d.tgz will* not be uncompressed):* <pre>* a.txt* b.tar/c.txt* b.tar/d.tgz* dir2/g.txt* dir2/dir3/h.tar/i.txt* </pre>** read('.', '', 0, 0) will not recurse into subdirectories* <pre>* a.txt* b.tar* </pre>** read('.', '', 0, 1) will recurse only one level in* subdirectories* <pre>* a.txt* b.tar* dir2/g.txt* </pre>** read('.', '', -1, 2) will uncompress everything and recurse in* only 2 levels in subdirectories or archives* <pre>* a.txt* b.tar/c.txt* b.tar/d.tgz/e.txt* dir2/g.txt* </pre>** The recursion level is determined by the real path, not the symbolic one.* So read('.', 'myBaseDir', -1, 2) will result to the same files:* <pre>* myBaseDir/a.txt* myBaseDir/b.tar/c.txt* myBaseDir/b.tar/d.tgz/e.txt (accepted because the real depth is 2)* myBaseDir/dir2/g.txt* </pre>** Use readSource to do the same thing, reading from a specified reader instead of* reading from the system files** To read a single file, you can do read('a.txt', 'public_name.txt')* If no public name is provided, the default one is the name of the file* read('dir2/g.txt') contains the single file named 'g.txt'* read('b.tar/c.txt') contains the single file named 'c.txt'** Note: This function uncompress files reading their extension* The compressed files must have a tar, zip, gz or tgz extension* Since it is impossible for some URLs to use is_dir or is_file, this* function may not work with* URLs containing folders which name ends with such an extension*/function readSource(&$source, $URL, $symbolic = null,$uncompression = 0, $directoryDepth = -1){return File_Archive::_readSource($source, $URL, $reachable, $baseDir,$symbolic, $uncompression, $directoryDepth);}/*** This function performs exactly as readSource, but with two additional parameters* ($reachable and $baseDir) that will be set so that $reachable."/".$baseDir == $URL* and $reachable can be reached (in case of error)** @access private*/function _readSource(&$toConvert, $URL, &$reachable, &$baseDir, $symbolic = null,$uncompression = 0, $directoryDepth = -1){$source =& File_Archive::_convertToReader($toConvert);if (PEAR::isError($source)) {return $source;}if (is_array($URL)) {$converted = array();foreach($URL as $key => $foo) {$converted[] =& File_Archive::_convertToReader($URL[$key]);}return File_Archive::readMulti($converted);}//No need to uncompress more than $directoryDepth//That's not perfect, and some archives will still be uncompressed just//to be filtered out :(if ($directoryDepth >= 0) {$uncompressionLevel = min($uncompression, $directoryDepth);} else {$uncompressionLevel = $uncompression;}require_once 'File/Archive/Reader.php';$std = File_Archive_Reader::getStandardURL($URL);//Modify the symbolic name if necessary$slashPos = strrpos($std, '/');if ($symbolic === null) {if ($slashPos === false) {$realSymbolic = $std;} else {$realSymbolic = substr($std, $slashPos+1);}} else {$realSymbolic = $symbolic;}if ($slashPos !== false) {$baseFile = substr($std, 0, $slashPos+1);$lastFile = substr($std, $slashPos+1);} else {$baseFile = '';$lastFile = $std;}if (strpos($lastFile, '*')!==false ||strpos($lastFile, '?')!==false) {//We have to build a regexp here$regexp = str_replace(array('\*', '\?'),array('[^/]*', '[^/]'),preg_quote($lastFile));$result = File_Archive::_readSource($source, $baseFile,$reachable, $baseDir, null, 0, -1);return File_Archive::filter(File_Archive::predEreg('^'.$regexp.'$'),$result);}//If the URL can be interpreted as a directory, and we are reading from the file systemif ((empty($URL) || is_dir($URL)) && $source === null) {require_once "File/Archive/Reader/Directory.php";if ($uncompressionLevel != 0) {require_once "File/Archive/Reader/Uncompress.php";$result = new File_Archive_Reader_Uncompress(new File_Archive_Reader_Directory($std, '', $directoryDepth),$uncompressionLevel);} else {$result = new File_Archive_Reader_Directory($std, '', $directoryDepth);}if ($directoryDepth >= 0) {require_once 'File/Archive/Reader/Filter.php';require_once 'File/Archive/Predicate/MaxDepth.php';$tmp =& File_Archive::filter(new File_Archive_Predicate_MaxDepth($directoryDepth),$result);unset($result);$result =& $tmp;}if (!empty($realSymbolic)) {if ($symbolic === null) {$realSymbolic = '';}require_once "File/Archive/Reader/ChangeName/AddDirectory.php";$tmp =& new File_Archive_Reader_ChangeName_AddDirectory($realSymbolic,$result);unset($result);$result =& $tmp;}//If the URL can be interpreted as a file, and we are reading from the file system} else if (is_file($URL) && substr($URL, -1)!='/' && $source === null) {require_once "File/Archive/Reader/File.php";$result = new File_Archive_Reader_File($URL, $realSymbolic);//Else, we will have to build a complex reader} else {require_once "File/Archive/Reader/File.php";$realPath = $std;// Try to find a file with a known extension in the path (// (to manage URLs like archive.tar/directory/file)$pos = 0;do {if ($pos+1<strlen($realPath)) {$pos = strpos($realPath, '/', $pos+1);} else {$pos = false;}if ($pos === false) {$pos = strlen($realPath);}$file = substr($realPath, 0, $pos);$baseDir = substr($realPath, $pos+1);$dotPos = strrpos($file, '.');$extension = '';if ($dotPos !== false) {$extension = substr($file, $dotPos+1);}} while ($pos < strlen($realPath) &&(!File_Archive::isKnownExtension($extension) ||(is_dir($file) && $source==null)));$reachable = $file;//If we are reading from the file systemif ($source === null) {//Create a file reader$result = new File_Archive_Reader_File($file);} else {//Select in the source the file $filerequire_once "File/Archive/Reader/Select.php";$result = new File_Archive_Reader_Select($file, $source);}require_once "File/Archive/Reader/Uncompress.php";$tmp = new File_Archive_Reader_Uncompress($result, $uncompressionLevel);unset($result);$result = $tmp;//Select the requested folder in the uncompress reader$isDir = $result->setBaseDir($std);if (PEAR::isError($isDir)) {return $isDir;}if ($isDir && $symbolic==null) {//Default symbolic name for directories is empty$realSymbolic = '';}if ($directoryDepth >= 0) {//Limit the maximum depth if necessaryrequire_once "File/Archive/Reader/Filter.php";require_once "File/Archive/Predicate/MaxDepth.php";$tmp = new File_Archive_Reader_Filter(new File_Archive_Predicate($directoryDepth +substr_count(substr($std, $pos+1), '/')),$result);unset($result);$result =& $tmp;}if ($std != $realSymbolic) {require_once "File/Archive/Reader/ChangeName/Directory.php";//Change the base name to the symbolic one if necessary$tmp = new File_Archive_Reader_ChangeName_Directory($std,$realSymbolic,$result);unset($result);$result =& $tmp;}}$cacheCondition = File_Archive::getOption('cacheCondition');if ($cacheCondition !== false &&preg_match($cacheCondition, $URL)) {$tmp =& File_Archive::cache($result);unset($result);$result =& $tmp;}return $result;}function read($URL, $symbolic = null,$uncompression = 0, $directoryDepth = -1){$source = null;return File_Archive::readSource($source, $URL, $symbolic, $uncompression, $directoryDepth);}/*** Create a file reader on an uploaded file. The reader will read* $_FILES[$name]['tmp_name'] and will have $_FILES[$name]['name']* as a symbolic filename.** A PEAR error is returned if one of the following happen* - $_FILES[$name] is not set* - $_FILES[$name]['error'] is not 0* - is_uploaded_file returns false** @param string $name Index of the file in the $_FILES array* @return File_Archive_Reader File reader on the uploaded file*/function readUploadedFile($name){if (!isset($_FILES[$name])) {return PEAR::raiseError("File $name has not been uploaded");}switch ($_FILES[$name]['error']) {case 0://No errorbreak;case 1:return PEAR::raiseError("The upload size limit didn't allow to upload file ".$_FILES[$name]['name']);case 2:return PEAR::raiseError("The form size limit didn't allow to upload file ".$_FILES[$name]['name']);case 3:return PEAR::raiseError("The file was not entirely uploaded");case 4:return PEAR::raiseError("The uploaded file is empty");default:return PEAR::raiseError("Unknown error ".$_FILES[$name]['error']." in file upload. "."Please, report a bug");}if (!is_uploaded_file($_FILES[$name]['tmp_name'])) {return PEAR::raiseError("The file is not an uploaded file");}require_once "File/Archive/Reader/File.php";return new File_Archive_Reader_File($_FILES[$name]['tmp_name'],$_FILES[$name]['name'],$_FILES[$name]['type']);}/*** Adds a cache layer above the specified reader* The data of the reader is saved in a temporary file for future access.* The cached reader will be read only once, even if you read it several times.* This can be usefull to read compressed files or downloaded files (from http or ftp)** @param mixed $toConvert The reader to cache* It can be a File_Archive_Reader or a string, which will be converted using the* read function*/function cache(&$toConvert){$source =& File_Archive::_convertToReader($toConvert);if (PEAR::isError($source)) {return $source;}require_once 'File/Archive/Reader/Cache.php';return new File_Archive_Reader_Cache($source);}/*** Try to interpret the object as a reader* Strings are converted to readers using File_Archive::read* Arrays are converted to readers using File_Archive::readMulti** @access private*/function &_convertToReader(&$source){if (is_string($source)) {$cacheCondition = File_Archive::getOption('cacheCondition');if ($cacheCondition !== false &&preg_match($cacheCondition, $source)) {$obj = File_Archive::cache(File_Archive::read($source));return $obj;} else {$obj = File_Archive::read($source);return $obj;}} else if (is_array($source)) {return File_Archive::readMulti($source);} else {return $source;}}/*** Try to interpret the object as a writer* Strings are converted to writers using File_Archive::appender* Arrays are converted to writers using a multi writer** @access private*/function &_convertToWriter(&$dest){if (is_string($dest)) {$obj =& File_Archive::appender($dest);return $obj;} else if (is_array($dest)) {require_once 'File/Archive/Writer/Multi.php';$writer = new File_Archive_Writer_Multi();foreach($dest as $key => $foo) {$writer->addWriter($dest[$key]);}return $writer;} else {return $dest;}}/*** Check if a file with a specific extension can be read as an archive* with File_Archive::read** This function is case sensitive.** @param string $extension the checked extension* @return bool whether this file can be understood reading its extension* Currently, supported extensions are tar, zip, jar, gz, tgz,* tbz, bz2, bzip2, ar, deb*/function isKnownExtension($extension){return $extension == 'tar' ||$extension == 'zip' ||$extension == 'jar' ||$extension == 'gz' ||$extension == 'tgz' ||$extension == 'tbz' ||$extension == 'bz2' ||$extension == 'bzip2' ||$extension == 'ar' ||$extension == 'deb' /* ||$extension == 'cab' ||$extension == 'rar' */;}/*** Create a reader that will read the single file source $source as* a specific archive** @param string $extension determines the kind of archive $source contains* $extension is case sensitive* @param File_Archive_Reader $source stores the archive* @param bool $sourceOpened specifies if the archive is already opened* if false, next will be called on source* Closing the returned archive will close $source iif $sourceOpened* is true* @return A File_Archive_Reader that uncompresses the archive contained in* $source interpreting it as a $extension archive* If $extension is not handled return false*/function readArchive($extension, &$toConvert, $sourceOpened = false){$source =& File_Archive::_convertToReader($toConvert);if (PEAR::isError($source)) {return $source;}switch($extension) {case 'tgz':return File_Archive::readArchive('tar',File_Archive::readArchive('gz', $source, $sourceOpened));case 'tbz':return File_Archive::readArchive('tar',File_Archive::readArchive('bz2', $source, $sourceOpened));case 'tar':require_once 'File/Archive/Reader/Tar.php';return new File_Archive_Reader_Tar($source, $sourceOpened);case 'gz':case 'gzip':require_once 'File/Archive/Reader/Gzip.php';return new File_Archive_Reader_Gzip($source, $sourceOpened);case 'zip':case 'jar':require_once 'File/Archive/Reader/Zip.php';return new File_Archive_Reader_Zip($source, $sourceOpened);case 'bz2':case 'bzip2':require_once 'File/Archive/Reader/Bzip2.php';return new File_Archive_Reader_Bzip2($source, $sourceOpened);case 'deb':case 'ar':require_once 'File/Archive/Reader/Ar.php';return new File_Archive_Reader_Ar($source, $sourceOpened);/* case 'cab':require_once 'File/Archive/Reader/Cab.php';return new File_Archive_Reader_Cab($source, $sourceOpened);case 'rar':require_once "File/Archive/Reader/Rar.php";return new File_Archive_Reader_Rar($source, $sourceOpened); */default:return false;}}/*** Contains only one file with data read from a memory buffer** @param string $memory content of the file* @param string $filename public name of the file* @param array $stat statistics of the file. Index 7 (size) will be* overwritten to match the size of $memory* @param string $mime mime type of the file. Default will determine the* mime type thanks to the extension of $filename* @see File_Archive_Reader_Memory*/function readMemory($memory, $filename, $stat=array(), $mime=null){require_once "File/Archive/Reader/Memory.php";return new File_Archive_Reader_Memory($memory, $filename, $stat, $mime);}/*** Contains several other sources. Take care the sources don't have several* files with the same filename. The sources are given as a parameter, or* can be added thanks to the reader addSource method** @param array $sources Array of strings or readers that will be added to* the multi reader. If the parameter is a string, a reader will be* built thanks to the read function* @see File_Archive_Reader_Multi, File_Archive::read()*/function readMulti($sources = array()){require_once "File/Archive/Reader/Multi.php";$result = new File_Archive_Reader_Multi();foreach ($sources as $index => $foo) {$s =& File_Archive::_convertToReader($sources[$index]);if (PEAR::isError($s)) {return $s;} else {$result->addSource($s);}}return $result;}/*** Make the files of a source appear as one large file whose content is the* concatenation of the content of all the files** @param File_Archive_Reader $toConvert The source whose files must be* concatened* @param string $filename name of the only file of the created reader* @param array $stat statistics of the file. Index 7 (size) will be* overwritten to match the total size of the files* @param string $mime mime type of the file. Default will determine the* mime type thanks to the extension of $filename* @see File_Archive_Reader_Concat*/function readConcat(&$toConvert, $filename, $stat=array(), $mime=null){$source =& File_Archive::_convertToReader($toConvert);if (PEAR::isError($source)) {return $source;}require_once "File/Archive/Reader/Concat.php";return new File_Archive_Reader_Concat($source, $filename, $stat, $mime);}/*** Changes the name of each file in a reader by applying a custom function* The function must return false if the file is to be discarded, or the new* name of the file else** @param Callable $function Function called to modify the name of the file* $function takes the name of the file as a parameter and returns the* new name, or false if the file must be discarded* @param File_Archive_Reader $toConvert The files of this source will be* modified* @return File_Archive_Reader a new reader that contains the same files* as $toConvert but with a different name*/function changeName($function, &$toConvert){$source =& File_Archive::_convertToReader($toConvert);if (PEAR::isError($source)) {return $source;}require_once "File/Archive/Reader/ChangeName.php";return new File_Archive_Reader_RemoveDirectory($source);}/*** Removes from a source the files that do not follow a given predicat** @param File_Archive_Predicate $predicate Only the files for which* $predicate->isTrue() will be kept* @param File_Archive_Reader $source Source that will be filtered* @see File_Archive_Reader_Filter*/function filter($predicate, &$toConvert){$source =& File_Archive::_convertToReader($toConvert);if (PEAR::isError($source)) {return $source;}require_once "File/Archive/Reader/Filter.php";return new File_Archive_Reader_Filter($predicate, $source);}/*** Predicate that always evaluate to true** @see File_Archive_Predicate_True*/function predTrue(){require_once "File/Archive/Predicate/True.php";return new File_Archive_Predicate_True();}/*** Predicate that always evaluate to false** @see File_Archive_Predicate_False*/function predFalse(){require_once "File/Archive/Predicate/False.php";return new File_Archive_Predicate_False();}/*** Predicate that evaluates to the logical AND of the parameters* You can add other predicates thanks to the* File_Archive_Predicate_And::addPredicate() function** @param File_Archive_Predicate (any number of them)* @see File_Archive_Predicate_And*/function predAnd(){require_once "File/Archive/Predicate/And.php";$pred = new File_Archive_Predicate_And();$args = func_get_args();foreach ($args as $p) {$pred->addPredicate($p);}return $pred;}/*** Predicate that evaluates to the logical OR of the parameters* You can add other predicates thanks to the* File_Archive_Predicate_Or::addPredicate() function** @param File_Archive_Predicate (any number of them)* @see File_Archive_Predicate_Or*/function predOr(){require_once "File/Archive/Predicate/Or.php";$pred = new File_Archive_Predicate_Or();$args = func_get_args();foreach ($args as $p) {$pred->addPredicate($p);}return $pred;}/*** Negate a predicate** @param File_Archive_Predicate $pred Predicate to negate* @see File_Archive_Predicate_Not*/function predNot($pred){require_once "File/Archive/Predicate/Not.php";return new File_Archive_Predicate_Not($pred);}/*** Evaluates to true iif the file is larger than a given size** @param int $size the minimal size of the files (in Bytes)* @see File_Archive_Predicate_MinSize*/function predMinSize($size){require_once "File/Archive/Predicate/MinSize.php";return new File_Archive_Predicate_MinSize($size);}/*** Evaluates to true iif the file has been modified after a given time** @param int $time Unix timestamp of the minimal modification time of the* files* @see File_Archive_Predicate_MinTime*/function predMinTime($time){require_once "File/Archive/Predicate/MinTime.php";return new File_Archive_Predicate_MinTime($time);}/*** Evaluates to true iif the file has less that a given number of* directories in its path** @param int $depth Maximal number of directories in path of the files* @see File_Archive_Predicate_MaxDepth*/function predMaxDepth($depth){require_once "File/Archive/Predicate/MaxDepth.php";return new File_Archive_Predicate_MaxDepth($depth);}/*** Evaluates to true iif the extension of the file is in a given list** @param array or string $list List or comma separated string of possible* extension of the files* @see File_Archive_Predicate_Extension*/function predExtension($list){require_once "File/Archive/Predicate/Extension.php";return new File_Archive_Predicate_Extension($list);}/*** Evaluates to true iif the MIME type of the file is in a given list** @param array or string $list List or comma separated string of possible* MIME types of the files. You may enter wildcards like "image/*" to* select all the MIME in class image* @see File_Archive_Predicate_MIME, MIME_Type::isWildcard()*/function predMIME($list){require_once "File/Archive/Predicate/MIME.php";return new File_Archive_Predicate_MIME($list);}/*** Evaluates to true iif the name of the file follow a given regular* expression** @param string $ereg regular expression that the filename must follow* @see File_Archive_Predicate_Ereg, ereg()*/function predEreg($ereg){require_once "File/Archive/Predicate/Ereg.php";return new File_Archive_Predicate_Ereg($ereg);}/*** Evaluates to true iif the name of the file follow a given regular* expression (case insensitive version)** @param string $ereg regular expression that the filename must follow* @see File_Archive_Predicate_Eregi, eregi*/function predEregi($ereg){require_once "File/Archive/Predicate/Eregi.php";return new File_Archive_Predicate_Eregi($ereg);}/*** Evaluates to true only after a given number of evaluations* This can be used to select files by index since the evaluation is done* once per file** @param array The indexes for which the returned predicate will return true* are the keys of the array* The predicate will return true if isset($indexes[$pos])*/function predIndex($indexes){require_once "File/Archive/Predicate/Index.php";return new File_Archive_Predicate_Index($indexes);}/*** Custom predicate built by supplying a string expression** Here are different ways to create a predicate that keeps only files* with names shorter than 100 chars* <sample>* File_Archive::predCustom("return strlen($name)<100;")* File_Archive::predCustom("strlen($name)<100;")* File_Archive::predCustom("strlen($name)<100")* File_Archive::predCustom("strlen($source->getFilename())<100")* </sample>** @param string $expression String containing an expression that evaluates* to a boolean. If the expression doesn't contain a return* statement, it will be added at the begining of the expression* A ';' will be added at the end of the expression so that you don't* have to write it. You may use the $name variable to refer to the* current filename (with path...), $time for the modification time* (unix timestamp), $size for the size of the file in bytes, $mime* for the MIME type of the file* @see File_Archive_Predicate_Custom*/function predCustom($expression){require_once "File/Archive/Predicate/Custom.php";return new File_Archive_Predicate_Custom($expression);}/*** Send the files as a mail attachment** @param Mail $mail Object used to send mail (see Mail::factory)* @param array or String $to An array or a string with comma separated* recipients* @param array $headers The headers that will be passed to the Mail_mime* object* @param string $message Text body of the mail* @see File_Archive_Writer_Mail*/function toMail($to, $headers, $message, $mail = null){require_once "File/Archive/Writer/Mail.php";return new File_Archive_Writer_Mail($to, $headers, $message, $mail);}/*** Write the files on the hard drive** @param string $baseDir if specified, the files will be created in that* directory. If they don't exist, the directories will automatically* be created* @see File_Archive_Writer_Files*/function toFiles($baseDir = ""){require_once "File/Archive/Writer/Files.php";return new File_Archive_Writer_Files($baseDir);}/*** Send the content of the files to a memory buffer** toMemory returns a writer where the data will be written.* In this case, the data is accessible using the getData member** toVariable returns a writer that will write into the given* variable** @param out $data if specified, the data will be written to this buffer* Else, you can retrieve the buffer with the* File_Archive_Writer_Memory::getData() function* @see File_Archive_Writer_Memory*/function toMemory(){$v = '';return File_Archive::toVariable($v);}function toVariable(&$v){require_once "File/Archive/Writer/Memory.php";return new File_Archive_Writer_Memory($v);}/*** Duplicate the writing operation on two writers** @param File_Archive_Writer $a, $b writers where data will be duplicated* @see File_Archive_Writer_Multi*/function toMulti(&$aC, &$bC){$a =& File_Archive::_convertToWriter($aC);$b =& File_Archive::_convertToWriter($bC);if (PEAR::isError($a)) {return $a;}if (PEAR::isError($b)) {return $b;}require_once "File/Archive/Writer/Multi.php";$writer = new File_Archive_Writer_Multi();$writer->addWriter($a);$writer->addWriter($b);return $writer;}/*** Send the content of the files to the standard output (so to the client* for a website)** @param bool $sendHeaders If true some headers will be sent to force the* download of the file. Default value is true* @see File_Archive_Writer_Output*/function toOutput($sendHeaders = true){require_once "File/Archive/Writer/Output.php";return new File_Archive_Writer_Output($sendHeaders);}/*** Compress the data to a tar, gz, tar/gz or zip format** @param string $filename name of the archive file* @param File_Archive_Writer $innerWriter writer where the archive will be* written* @param string $type can be one of tgz, tbz, tar, zip, gz, gzip, bz2,* bzip2 (default is the extension of $filename) or any composition* of them (for example tar.gz or tar.bz2). The case of this* parameter is not important.* @param array $stat Statistics of the archive (see stat function)* @param bool $autoClose If set to true, $innerWriter will be closed when* the returned archive is close. Default value is true.*/function toArchive($filename, &$toConvert, $type = null,$stat = array(), $autoClose = true){$innerWriter =& File_Archive::_convertToWriter($toConvert);if (PEAR::isError($innerWriter)) {return $innerWriter;}$shortcuts = array("tgz" , "tbz" );$reals = array("tar.gz", "tar.bz2");if ($type === null) {$extensions = strtolower($filename);} else {$extensions = strtolower($type);}$extensions = explode('.', str_replace($shortcuts, $reals, $extensions));if ($innerWriter !== null) {$writer =& $innerWriter;} else {$writer = File_Archive::toFiles();}$nbCompressions = 0;$currentFilename = $filename;while (($extension = array_pop($extensions)) !== null) {unset($next);switch($extension) {case "tar":require_once "File/Archive/Writer/Tar.php";$next = new File_Archive_Writer_Tar($currentFilename, $writer, $stat, $autoClose);unset($writer); $writer =& $next;break;case "zip":require_once "File/Archive/Writer/Zip.php";$next = new File_Archive_Writer_Zip($currentFilename, $writer, $stat, $autoClose);unset($writer); $writer =& $next;break;case "gz":case "gzip":require_once "File/Archive/Writer/Gzip.php";$next = new File_Archive_Writer_Gzip($currentFilename, $writer, $stat, $autoClose);unset($writer); $writer =& $next;break;case "bz2":case "bzip2":require_once "File/Archive/Writer/Bzip2.php";$next = new File_Archive_Writer_Bzip2($currentFilename, $writer, $stat, $autoClose);unset($writer); $writer =& $next;break;case "deb":case "ar":require_once "File/Archive/Writer/Ar.php";$next = new File_Archive_Writer_Ar($currentFilename, $writer, $stat, $autoClose);unset($writer); $writer =& $next;break;default:if ($type !== null || $nbCompressions == 0) {return PEAR::raiseError("Archive $extension unknown");}break;}$nbCompressions ++;$autoClose = true;$currentFilename = implode(".", $extensions);}return $writer;}/*** File_Archive::extract($source, $dest) is equivalent to $source->extract($dest)* If $source is a PEAR error, the error will be returned* It is thus easier to use this function than $source->extract, since it reduces the number of* error checking and doesn't force you to define a variable $source** You may use strings as source and dest. In that case the source is automatically* converted to a reader using File_Archive::read and the dest is converted to a* writer using File_Archive::appender* Since PHP doesn't allow to pass literal strings by ref, you will have to use temporary* variables.* File_Archive::extract($src = 'archive.zip/', $dest = 'dir') will extract the archive to 'dir'* It is the same as* File_Archive::extract(* File_Archive::read('archive.zip/'),* File_Archive::appender('dir')* );* You may use any variable in the extract function ($from/$to, $a/$b...).** @param File_Archive_Reader $source The source that will be read* @param File_Archive_Writer $dest Where to copy $source files* @param bool $autoClose if true (default), $dest will be closed after the extraction* @param int $bufferSize Size of the buffer to use to move data from the reader to the buffer* If $bufferSize <= 0 (default), the blockSize option is used* You shouldn't need to change that* @return null or a PEAR error if an error occured*/function extract(&$sourceToConvert, &$destToConvert, $autoClose = true, $bufferSize = 0){$source =& File_Archive::_convertToReader($sourceToConvert);if (PEAR::isError($source)) {return $source;}$dest =& File_Archive::_convertToWriter($destToConvert);return $source->extract($dest, $autoClose, $bufferSize);}/*** Create a writer that can be used to append files to an archive inside a source* If the archive can't be found in the source, it will be created* If source is set to null, File_Archive::toFiles will be assumed* If type is set to null, the type of the archive will be determined looking at* the extension in the URL* stat is the array of stat (returned by stat() PHP function of Reader getStat())* to use if the archive must be created** This function allows to create or append data to nested archives. Only one* archive will be created and if your creation requires creating several nested* archives, a PEAR error will be returned** After this call, $source will be closed and should not be used until the* returned writer is closed.** @param File_Archive_Reader $source A reader where some files will be appended* @param string $URL URL to reach the archive in the source.* if $URL is null, a writer to append files to the $source reader will* be returned* @param bool $unique If true, the duplicate files will be deleted on close* Default is false (and setting it to true may have some performance* consequences)* @param string $type Extension of the archive (or null to use the one in the URL)* @param array $stat Used only if archive is created, array of stat as returned* by PHP stat function or Reader getStat function: stats of the archive)* Time (index 9) will be overwritten to current time* @return File_Archive_Writer a writer that you can use to append files to the reader*/function appenderFromSource(&$toConvert, $URL = null, $unique = null,$type = null, $stat = array()){$source =& File_Archive::_convertToReader($toConvert);if (PEAR::isError($source)) {return $source;}if ($unique == null) {$unique = File_Archive::getOption("appendRemoveDuplicates");}//Do not report the fact that the archive does not exist as an errorPEAR::pushErrorHandling(PEAR_ERROR_RETURN);if ($URL === null) {$result =& $source;} else {if ($type === null) {$result = File_Archive::_readSource($source, $URL.'/', $reachable, $baseDir);} else {$result = File_Archive::readArchive($type,File_Archive::_readSource($source, $URL, $reachable, $baseDir));}}PEAR::popErrorHandling();if (!PEAR::isError($result)) {if ($unique) {require_once "File/Archive/Writer/UniqueAppender.php";return new File_Archive_Writer_UniqueAppender($result);} else {return $result->makeAppendWriter();}}//The source can't be found and has to be created$stat[9] = $stat['mtime'] = time();if (empty($baseDir)) {if ($source !== null) {$writer =& $source->makeWriter();} else {$writer =& File_Archive::toFiles();}if (PEAR::isError($writer)) {return $writer;}PEAR::pushErrorHandling(PEAR_ERROR_RETURN);$result = File_Archive::toArchive($reachable, $writer, $type);PEAR::popErrorHandling();if (PEAR::isError($result)) {$result = File_Archive::toFiles($reachable);}} else {$reachedSource = File_Archive::readSource($source, $reachable);if (PEAR::isError($reachedSource)) {return $reachedSource;}$writer = $reachedSource->makeWriter();if (PEAR::isError($writer)) {return $writer;}PEAR::pushErrorHandling(PEAR_ERROR_RETURN);$result = File_Archive::toArchive($baseDir, $writer, $type);PEAR::popErrorHandling();if (PEAR::isError($result)) {require_once "File/Archive/Writer/AddBaseName.php";$result = new File_Archive_Writer_AddBaseName($baseDir, $writer);if (PEAR::isError($result)) {return $result;}}}return $result;}/*** Create a writer that allows appending new files to an existing archive* This function actes as appendToSource with source being the system files* $URL can't be null here** @param File_Archive_Reader $source A reader where some files will be appended* @return File_Archive_Writer a writer that you can use to append files to the reader*/function appender($URL, $unique = null, $type = null, $stat = array()){$source = null;return File_Archive::appenderFromSource($source, $URL, $unique, $type, $stat);}/*** Remove the files that follow a given predicate from the source* If URL is null, the files will be removed from the source directly* Else, URL must link to a source from which the files will be removed** @param File_Archive_Predicate $pred The files that follow the predicate* (for which $pred->isTrue($source) is true) will be erased* @param File_Archive_Reader $source A reader that contains the files to remove*/function removeFromSource(&$pred, &$toConvert, $URL = null){$source =& File_Archive::_convertToReader($toConvert);if (PEAR::isError($source)) {return $source;}if ($URL === null) {$result = &$source;} else {if (substr($URL, -1) !== '/') {$URL .= '/';}$result = File_Archive::readSource($source, $URL);}$writer = $result->makeWriterRemoveFiles($pred);if (PEAR::isError($writer)) {return $writer;}$writer->close();}/*** Remove the files that follow a given predicate from the archive specified* in $URL** @param $URL URL of the archive where some files must be removed*/function remove($pred, $URL){$source = null;return File_Archive::removeFromSource($pred, $source, $URL);}/*** Remove duplicates from a source, keeping the most recent one (or the one that has highest pos in* the archive if the files have same date or no date specified)** @param File_Archive_Reader a reader that may contain duplicates*/function removeDuplicatesFromSource(&$toConvert, $URL = null){$source =& File_Archive::_convertToReader($toConvert);if (PEAR::isError($source)) {return $source;}if ($URL !== null && substr($URL, -1) != '/') {$URL .= '/';}if ($source === null) {$source = File_Archive::read($URL);}require_once "File/Archive/Predicate/Duplicate.php";$pred = new File_Archive_Predicate_Duplicate($source);$source->close();return File_Archive::removeFromSource($pred,$source,null);}/*** Remove duplicates from the archive specified in the URL*/function removeDuplicates($URL){$source = null;return File_Archive::removeDuplicatesFromSource($source, $URL);}}?>