| 1 |
lars |
1 |
<?php
|
|
|
2 |
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
|
|
3 |
|
|
|
4 |
/**
|
|
|
5 |
* Factory to access the most common File_Archive features
|
|
|
6 |
* It uses lazy include, so you dont have to include the files from
|
|
|
7 |
* File/Archive/* directories
|
|
|
8 |
*
|
|
|
9 |
* PHP versions 4 and 5
|
|
|
10 |
*
|
|
|
11 |
* This library is free software; you can redistribute it and/or
|
|
|
12 |
* modify it under the terms of the GNU Lesser General Public
|
|
|
13 |
* License as published by the Free Software Foundation; either
|
|
|
14 |
* version 2.1 of the License, or (at your option) any later version.
|
|
|
15 |
*
|
|
|
16 |
* This library is distributed in the hope that it will be useful,
|
|
|
17 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
18 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
19 |
* Lesser General Public License for more details.
|
|
|
20 |
*
|
|
|
21 |
* You should have received a copy of the GNU Lesser General Public
|
|
|
22 |
* License along with this library; if not, write to the Free Software
|
|
|
23 |
* Foundation, Inc., 59 Temple Place, Suite 330,Boston,MA 02111-1307 USA
|
|
|
24 |
*
|
|
|
25 |
* @category File Formats
|
|
|
26 |
* @package File_Archive
|
|
|
27 |
* @author Vincent Lascaux <vincentlascaux@php.net>
|
|
|
28 |
* @copyright 1997-2005 The PHP Group
|
|
|
29 |
* @license http://www.gnu.org/copyleft/lesser.html LGPL
|
|
|
30 |
* @version CVS: $Id: Archive.php,v 1.90 2008/05/28 19:58:07 cbrunet Exp $
|
|
|
31 |
* @link http://pear.php.net/package/File_Archive
|
|
|
32 |
*/
|
|
|
33 |
|
|
|
34 |
/**
|
|
|
35 |
* To have access to PEAR::isError and PEAR::raiseError
|
|
|
36 |
* We should probably use lazy include and remove this inclusion...
|
|
|
37 |
*/
|
|
|
38 |
require_once "PEAR.php";
|
|
|
39 |
|
|
|
40 |
function File_Archive_cleanCache($file, $group)
|
|
|
41 |
{
|
|
|
42 |
$file = split('_', $file);
|
|
|
43 |
if (count($file) != 3) {
|
|
|
44 |
return false; //not a File_Archive file, keep it
|
|
|
45 |
}
|
|
|
46 |
|
|
|
47 |
$name = $file[2];
|
|
|
48 |
$name = urldecode($name);
|
|
|
49 |
|
|
|
50 |
$group = $file[1];
|
|
|
51 |
|
|
|
52 |
//clean the cache only for files in File_Archive groups
|
|
|
53 |
return substr($group, 0, 11) == 'FileArchive' &&
|
|
|
54 |
!file_exists($name); //and only if the related file no longer exists
|
|
|
55 |
}
|
|
|
56 |
|
|
|
57 |
/**
|
|
|
58 |
* Factory to access the most common File_Archive features
|
|
|
59 |
* It uses lazy include, so you dont have to include the files from
|
|
|
60 |
* File/Archive/* directories
|
|
|
61 |
*/
|
|
|
62 |
class File_Archive
|
|
|
63 |
{
|
|
|
64 |
function& _option($name)
|
|
|
65 |
{
|
|
|
66 |
static $container = array(
|
|
|
67 |
'zipCompressionLevel' => 9,
|
|
|
68 |
'gzCompressionLevel' => 9,
|
|
|
69 |
'tmpDirectory' => '.',
|
|
|
70 |
'cache' => null,
|
|
|
71 |
'appendRemoveDuplicates' => false,
|
|
|
72 |
'blockSize' => 65536,
|
|
|
73 |
'cacheCondition' => false
|
|
|
74 |
);
|
|
|
75 |
return $container[$name];
|
|
|
76 |
}
|
|
|
77 |
/**
|
|
|
78 |
* Sets an option that will be used by default by all readers or writers
|
|
|
79 |
* Option names are case sensitive
|
|
|
80 |
* Currently, the following options are used:
|
|
|
81 |
*
|
|
|
82 |
* "cache"
|
|
|
83 |
* Instance of a Cache_Lite object used to cache some compressed
|
|
|
84 |
* data to speed up future compressions of files
|
|
|
85 |
* Default: null (no cache used)
|
|
|
86 |
*
|
|
|
87 |
* "zipCompressionLevel"
|
|
|
88 |
* Value between 0 and 9 specifying the default compression level used
|
|
|
89 |
* by Zip writers (0 no compression, 9 highest compression)
|
|
|
90 |
* Default: 9
|
|
|
91 |
*
|
|
|
92 |
* "gzCompressionLevel"
|
|
|
93 |
* Value between 0 and 9 specifying the default compression level used
|
|
|
94 |
* by Gz writers (0 no compression, 9 highest compression)
|
|
|
95 |
* Default: 9
|
|
|
96 |
*
|
|
|
97 |
* "tmpDirectory"
|
|
|
98 |
* Directory where the temporary files generated by File_Archive will
|
|
|
99 |
* be created
|
|
|
100 |
* Default: '.'
|
|
|
101 |
*
|
|
|
102 |
* "appendRemoveDuplicates"
|
|
|
103 |
* If set to true, the appender created will by default remove the
|
|
|
104 |
* file present in the archive when adding a new one. This will slow the
|
|
|
105 |
* appending of files to archives
|
|
|
106 |
* Default: false
|
|
|
107 |
*
|
|
|
108 |
* "blockSize"
|
|
|
109 |
* To transfer data from a reader to a writer, some chunks a read from the
|
|
|
110 |
* source and written to the writer. This parameter controls the size of the
|
|
|
111 |
* chunks
|
|
|
112 |
* Default: 64kB
|
|
|
113 |
*
|
|
|
114 |
* "cacheCondition"
|
|
|
115 |
* This parameter specifies when a cache should be used. When the cache is
|
|
|
116 |
* used, the data of the reader is saved in a temporary file for future access.
|
|
|
117 |
* The cached reader will be read only once, even if you read it several times.
|
|
|
118 |
* This can be usefull to read compressed files or downloaded files (from http or ftp)
|
|
|
119 |
* The possible values for this option are
|
|
|
120 |
* - false: never use cache
|
|
|
121 |
* - a regexp: A cache will be used if the specified URL matches the regexp
|
|
|
122 |
* preg_match is used
|
|
|
123 |
* Default: false
|
|
|
124 |
* Example: '/^(http|ftp):\/\//' will cache all files downloaded via http or ftp
|
|
|
125 |
*
|
|
|
126 |
*/
|
|
|
127 |
function setOption($name, $value)
|
|
|
128 |
{
|
|
|
129 |
$option =& File_Archive::_option($name);
|
|
|
130 |
$option = $value;
|
|
|
131 |
if ($name == 'cache' && $value !== null) {
|
|
|
132 |
//TODO: ask to Cache_Lite to allow that
|
|
|
133 |
$value->_fileNameProtection = false;
|
|
|
134 |
}
|
|
|
135 |
}
|
|
|
136 |
|
|
|
137 |
/**
|
|
|
138 |
* Retrieve the value of an option
|
|
|
139 |
*/
|
|
|
140 |
function getOption($name)
|
|
|
141 |
{
|
|
|
142 |
return File_Archive::_option($name);
|
|
|
143 |
}
|
|
|
144 |
|
|
|
145 |
/**
|
|
|
146 |
* Create a reader to read the URL $URL.
|
|
|
147 |
* If the URL is a directory, it will recursively read that directory.
|
|
|
148 |
* If $uncompressionLevel is not null, the archives (files with extension
|
|
|
149 |
* tar, zip, gz or tgz) will be considered as directories (up to a depth of
|
|
|
150 |
* $uncompressionLevel if $uncompressionLevel > 0). The reader will only
|
|
|
151 |
* read files with a directory depth of $directoryDepth. It reader will
|
|
|
152 |
* replace the given URL ($URL) with $symbolic in the public filenames
|
|
|
153 |
* The default symbolic name is the last filename in the URL (or '' for
|
|
|
154 |
* directories)
|
|
|
155 |
*
|
|
|
156 |
* Examples:
|
|
|
157 |
* Considere the following file system
|
|
|
158 |
* <pre>
|
|
|
159 |
* a.txt
|
|
|
160 |
* b.tar (archive that contains the following files)
|
|
|
161 |
* c.txt
|
|
|
162 |
* d.tgz (archive that contains the following files)
|
|
|
163 |
* e.txt
|
|
|
164 |
* dir1/
|
|
|
165 |
* f.txt
|
|
|
166 |
* dir2/
|
|
|
167 |
* g.txt
|
|
|
168 |
* dir3/
|
|
|
169 |
* h.tar (archive that contains the following files)
|
|
|
170 |
* i.txt
|
|
|
171 |
* </pre>
|
|
|
172 |
*
|
|
|
173 |
* read('.') will return a reader that gives access to following
|
|
|
174 |
* files (recursively read current dir):
|
|
|
175 |
* <pre>
|
|
|
176 |
* a.txt
|
|
|
177 |
* b.tar
|
|
|
178 |
* dir2/g.txt
|
|
|
179 |
* dir2/dir3/h.tar
|
|
|
180 |
* </pre>
|
|
|
181 |
*
|
|
|
182 |
* read('.', 'myBaseDir') will return the following reader:
|
|
|
183 |
* <pre>
|
|
|
184 |
* myBaseDir/a.txt
|
|
|
185 |
* myBaseDir/b.tar
|
|
|
186 |
* myBaseDir/dir2/g.txt
|
|
|
187 |
* myBaseDir/dir2/dir3/h.tar
|
|
|
188 |
* </pre>
|
|
|
189 |
*
|
|
|
190 |
* read('.', '', -1) will return the following reader (uncompress
|
|
|
191 |
* everything)
|
|
|
192 |
* <pre>
|
|
|
193 |
* a.txt
|
|
|
194 |
* b.tar/c.txt
|
|
|
195 |
* b.tar/d.tgz/e.txt
|
|
|
196 |
* b.tar/d.tgz/dir1/f.txt
|
|
|
197 |
* dir2/g.txt
|
|
|
198 |
* dir2/dir3/h.tar/i.txt
|
|
|
199 |
* </pre>
|
|
|
200 |
*
|
|
|
201 |
* read('.', '', 1) will uncompress only one level (so d.tgz will
|
|
|
202 |
* not be uncompressed):
|
|
|
203 |
* <pre>
|
|
|
204 |
* a.txt
|
|
|
205 |
* b.tar/c.txt
|
|
|
206 |
* b.tar/d.tgz
|
|
|
207 |
* dir2/g.txt
|
|
|
208 |
* dir2/dir3/h.tar/i.txt
|
|
|
209 |
* </pre>
|
|
|
210 |
*
|
|
|
211 |
* read('.', '', 0, 0) will not recurse into subdirectories
|
|
|
212 |
* <pre>
|
|
|
213 |
* a.txt
|
|
|
214 |
* b.tar
|
|
|
215 |
* </pre>
|
|
|
216 |
*
|
|
|
217 |
* read('.', '', 0, 1) will recurse only one level in
|
|
|
218 |
* subdirectories
|
|
|
219 |
* <pre>
|
|
|
220 |
* a.txt
|
|
|
221 |
* b.tar
|
|
|
222 |
* dir2/g.txt
|
|
|
223 |
* </pre>
|
|
|
224 |
*
|
|
|
225 |
* read('.', '', -1, 2) will uncompress everything and recurse in
|
|
|
226 |
* only 2 levels in subdirectories or archives
|
|
|
227 |
* <pre>
|
|
|
228 |
* a.txt
|
|
|
229 |
* b.tar/c.txt
|
|
|
230 |
* b.tar/d.tgz/e.txt
|
|
|
231 |
* dir2/g.txt
|
|
|
232 |
* </pre>
|
|
|
233 |
*
|
|
|
234 |
* The recursion level is determined by the real path, not the symbolic one.
|
|
|
235 |
* So read('.', 'myBaseDir', -1, 2) will result to the same files:
|
|
|
236 |
* <pre>
|
|
|
237 |
* myBaseDir/a.txt
|
|
|
238 |
* myBaseDir/b.tar/c.txt
|
|
|
239 |
* myBaseDir/b.tar/d.tgz/e.txt (accepted because the real depth is 2)
|
|
|
240 |
* myBaseDir/dir2/g.txt
|
|
|
241 |
* </pre>
|
|
|
242 |
*
|
|
|
243 |
* Use readSource to do the same thing, reading from a specified reader instead of
|
|
|
244 |
* reading from the system files
|
|
|
245 |
*
|
|
|
246 |
* To read a single file, you can do read('a.txt', 'public_name.txt')
|
|
|
247 |
* If no public name is provided, the default one is the name of the file
|
|
|
248 |
* read('dir2/g.txt') contains the single file named 'g.txt'
|
|
|
249 |
* read('b.tar/c.txt') contains the single file named 'c.txt'
|
|
|
250 |
*
|
|
|
251 |
* Note: This function uncompress files reading their extension
|
|
|
252 |
* The compressed files must have a tar, zip, gz or tgz extension
|
|
|
253 |
* Since it is impossible for some URLs to use is_dir or is_file, this
|
|
|
254 |
* function may not work with
|
|
|
255 |
* URLs containing folders which name ends with such an extension
|
|
|
256 |
*/
|
|
|
257 |
function readSource(&$source, $URL, $symbolic = null,
|
|
|
258 |
$uncompression = 0, $directoryDepth = -1)
|
|
|
259 |
{
|
|
|
260 |
return File_Archive::_readSource($source, $URL, $reachable, $baseDir,
|
|
|
261 |
$symbolic, $uncompression, $directoryDepth);
|
|
|
262 |
}
|
|
|
263 |
|
|
|
264 |
/**
|
|
|
265 |
* This function performs exactly as readSource, but with two additional parameters
|
|
|
266 |
* ($reachable and $baseDir) that will be set so that $reachable."/".$baseDir == $URL
|
|
|
267 |
* and $reachable can be reached (in case of error)
|
|
|
268 |
*
|
|
|
269 |
* @access private
|
|
|
270 |
*/
|
|
|
271 |
function _readSource(&$toConvert, $URL, &$reachable, &$baseDir, $symbolic = null,
|
|
|
272 |
$uncompression = 0, $directoryDepth = -1)
|
|
|
273 |
{
|
|
|
274 |
$source =& File_Archive::_convertToReader($toConvert);
|
|
|
275 |
if (PEAR::isError($source)) {
|
|
|
276 |
return $source;
|
|
|
277 |
}
|
|
|
278 |
if (is_array($URL)) {
|
|
|
279 |
$converted = array();
|
|
|
280 |
foreach($URL as $key => $foo) {
|
|
|
281 |
$converted[] =& File_Archive::_convertToReader($URL[$key]);
|
|
|
282 |
}
|
|
|
283 |
return File_Archive::readMulti($converted);
|
|
|
284 |
}
|
|
|
285 |
|
|
|
286 |
//No need to uncompress more than $directoryDepth
|
|
|
287 |
//That's not perfect, and some archives will still be uncompressed just
|
|
|
288 |
//to be filtered out :(
|
|
|
289 |
if ($directoryDepth >= 0) {
|
|
|
290 |
$uncompressionLevel = min($uncompression, $directoryDepth);
|
|
|
291 |
} else {
|
|
|
292 |
$uncompressionLevel = $uncompression;
|
|
|
293 |
}
|
|
|
294 |
|
|
|
295 |
require_once 'File/Archive/Reader.php';
|
|
|
296 |
$std = File_Archive_Reader::getStandardURL($URL);
|
|
|
297 |
|
|
|
298 |
//Modify the symbolic name if necessary
|
|
|
299 |
$slashPos = strrpos($std, '/');
|
|
|
300 |
if ($symbolic === null) {
|
|
|
301 |
if ($slashPos === false) {
|
|
|
302 |
$realSymbolic = $std;
|
|
|
303 |
} else {
|
|
|
304 |
$realSymbolic = substr($std, $slashPos+1);
|
|
|
305 |
}
|
|
|
306 |
} else {
|
|
|
307 |
$realSymbolic = $symbolic;
|
|
|
308 |
}
|
|
|
309 |
if ($slashPos !== false) {
|
|
|
310 |
$baseFile = substr($std, 0, $slashPos+1);
|
|
|
311 |
$lastFile = substr($std, $slashPos+1);
|
|
|
312 |
} else {
|
|
|
313 |
$baseFile = '';
|
|
|
314 |
$lastFile = $std;
|
|
|
315 |
}
|
|
|
316 |
|
|
|
317 |
if (strpos($lastFile, '*')!==false ||
|
|
|
318 |
strpos($lastFile, '?')!==false) {
|
|
|
319 |
//We have to build a regexp here
|
|
|
320 |
$regexp = str_replace(
|
|
|
321 |
array('\*', '\?'),
|
|
|
322 |
array('[^/]*', '[^/]'),
|
|
|
323 |
preg_quote($lastFile)
|
|
|
324 |
);
|
|
|
325 |
$result = File_Archive::_readSource($source, $baseFile,
|
|
|
326 |
$reachable, $baseDir, null, 0, -1);
|
|
|
327 |
return File_Archive::filter(
|
|
|
328 |
File_Archive::predEreg('^'.$regexp.'$'),
|
|
|
329 |
$result
|
|
|
330 |
);
|
|
|
331 |
}
|
|
|
332 |
|
|
|
333 |
//If the URL can be interpreted as a directory, and we are reading from the file system
|
|
|
334 |
if ((empty($URL) || is_dir($URL)) && $source === null) {
|
|
|
335 |
require_once "File/Archive/Reader/Directory.php";
|
|
|
336 |
|
|
|
337 |
if ($uncompressionLevel != 0) {
|
|
|
338 |
require_once "File/Archive/Reader/Uncompress.php";
|
|
|
339 |
$result = new File_Archive_Reader_Uncompress(
|
|
|
340 |
new File_Archive_Reader_Directory($std, '', $directoryDepth),
|
|
|
341 |
$uncompressionLevel
|
|
|
342 |
);
|
|
|
343 |
} else {
|
|
|
344 |
$result = new File_Archive_Reader_Directory($std, '', $directoryDepth);
|
|
|
345 |
}
|
|
|
346 |
|
|
|
347 |
if ($directoryDepth >= 0) {
|
|
|
348 |
require_once 'File/Archive/Reader/Filter.php';
|
|
|
349 |
require_once 'File/Archive/Predicate/MaxDepth.php';
|
|
|
350 |
|
|
|
351 |
$tmp =& File_Archive::filter(
|
|
|
352 |
new File_Archive_Predicate_MaxDepth($directoryDepth),
|
|
|
353 |
$result
|
|
|
354 |
);
|
|
|
355 |
unset($result);
|
|
|
356 |
$result =& $tmp;
|
|
|
357 |
}
|
|
|
358 |
if (!empty($realSymbolic)) {
|
|
|
359 |
if ($symbolic === null) {
|
|
|
360 |
$realSymbolic = '';
|
|
|
361 |
}
|
|
|
362 |
require_once "File/Archive/Reader/ChangeName/AddDirectory.php";
|
|
|
363 |
$tmp =& new File_Archive_Reader_ChangeName_AddDirectory(
|
|
|
364 |
$realSymbolic,
|
|
|
365 |
$result
|
|
|
366 |
);
|
|
|
367 |
unset($result);
|
|
|
368 |
$result =& $tmp;
|
|
|
369 |
}
|
|
|
370 |
|
|
|
371 |
//If the URL can be interpreted as a file, and we are reading from the file system
|
|
|
372 |
} else if (is_file($URL) && substr($URL, -1)!='/' && $source === null) {
|
|
|
373 |
require_once "File/Archive/Reader/File.php";
|
|
|
374 |
$result = new File_Archive_Reader_File($URL, $realSymbolic);
|
|
|
375 |
|
|
|
376 |
//Else, we will have to build a complex reader
|
|
|
377 |
} else {
|
|
|
378 |
require_once "File/Archive/Reader/File.php";
|
|
|
379 |
|
|
|
380 |
$realPath = $std;
|
|
|
381 |
|
|
|
382 |
// Try to find a file with a known extension in the path (
|
|
|
383 |
// (to manage URLs like archive.tar/directory/file)
|
|
|
384 |
$pos = 0;
|
|
|
385 |
do {
|
|
|
386 |
if ($pos+1<strlen($realPath)) {
|
|
|
387 |
$pos = strpos($realPath, '/', $pos+1);
|
|
|
388 |
} else {
|
|
|
389 |
$pos = false;
|
|
|
390 |
}
|
|
|
391 |
if ($pos === false) {
|
|
|
392 |
$pos = strlen($realPath);
|
|
|
393 |
}
|
|
|
394 |
|
|
|
395 |
$file = substr($realPath, 0, $pos);
|
|
|
396 |
$baseDir = substr($realPath, $pos+1);
|
|
|
397 |
$dotPos = strrpos($file, '.');
|
|
|
398 |
$extension = '';
|
|
|
399 |
if ($dotPos !== false) {
|
|
|
400 |
$extension = substr($file, $dotPos+1);
|
|
|
401 |
}
|
|
|
402 |
} while ($pos < strlen($realPath) &&
|
|
|
403 |
(!File_Archive::isKnownExtension($extension) ||
|
|
|
404 |
(is_dir($file) && $source==null)));
|
|
|
405 |
|
|
|
406 |
$reachable = $file;
|
|
|
407 |
|
|
|
408 |
//If we are reading from the file system
|
|
|
409 |
if ($source === null) {
|
|
|
410 |
//Create a file reader
|
|
|
411 |
$result = new File_Archive_Reader_File($file);
|
|
|
412 |
} else {
|
|
|
413 |
//Select in the source the file $file
|
|
|
414 |
|
|
|
415 |
require_once "File/Archive/Reader/Select.php";
|
|
|
416 |
$result = new File_Archive_Reader_Select($file, $source);
|
|
|
417 |
}
|
|
|
418 |
|
|
|
419 |
require_once "File/Archive/Reader/Uncompress.php";
|
|
|
420 |
$tmp = new File_Archive_Reader_Uncompress($result, $uncompressionLevel);
|
|
|
421 |
unset($result);
|
|
|
422 |
$result = $tmp;
|
|
|
423 |
|
|
|
424 |
//Select the requested folder in the uncompress reader
|
|
|
425 |
$isDir = $result->setBaseDir($std);
|
|
|
426 |
if (PEAR::isError($isDir)) {
|
|
|
427 |
return $isDir;
|
|
|
428 |
}
|
|
|
429 |
if ($isDir && $symbolic==null) {
|
|
|
430 |
//Default symbolic name for directories is empty
|
|
|
431 |
$realSymbolic = '';
|
|
|
432 |
}
|
|
|
433 |
|
|
|
434 |
if ($directoryDepth >= 0) {
|
|
|
435 |
//Limit the maximum depth if necessary
|
|
|
436 |
require_once "File/Archive/Reader/Filter.php";
|
|
|
437 |
require_once "File/Archive/Predicate/MaxDepth.php";
|
|
|
438 |
|
|
|
439 |
$tmp = new File_Archive_Reader_Filter(
|
|
|
440 |
new File_Archive_Predicate(
|
|
|
441 |
$directoryDepth +
|
|
|
442 |
substr_count(substr($std, $pos+1), '/')
|
|
|
443 |
),
|
|
|
444 |
$result
|
|
|
445 |
);
|
|
|
446 |
unset($result);
|
|
|
447 |
$result =& $tmp;
|
|
|
448 |
}
|
|
|
449 |
|
|
|
450 |
if ($std != $realSymbolic) {
|
|
|
451 |
require_once "File/Archive/Reader/ChangeName/Directory.php";
|
|
|
452 |
|
|
|
453 |
//Change the base name to the symbolic one if necessary
|
|
|
454 |
$tmp = new File_Archive_Reader_ChangeName_Directory(
|
|
|
455 |
$std,
|
|
|
456 |
$realSymbolic,
|
|
|
457 |
$result
|
|
|
458 |
);
|
|
|
459 |
unset($result);
|
|
|
460 |
$result =& $tmp;
|
|
|
461 |
}
|
|
|
462 |
}
|
|
|
463 |
|
|
|
464 |
$cacheCondition = File_Archive::getOption('cacheCondition');
|
|
|
465 |
if ($cacheCondition !== false &&
|
|
|
466 |
preg_match($cacheCondition, $URL)) {
|
|
|
467 |
$tmp =& File_Archive::cache($result);
|
|
|
468 |
unset($result);
|
|
|
469 |
$result =& $tmp;
|
|
|
470 |
}
|
|
|
471 |
|
|
|
472 |
return $result;
|
|
|
473 |
}
|
|
|
474 |
function read($URL, $symbolic = null,
|
|
|
475 |
$uncompression = 0, $directoryDepth = -1)
|
|
|
476 |
{
|
|
|
477 |
$source = null;
|
|
|
478 |
return File_Archive::readSource($source, $URL, $symbolic, $uncompression, $directoryDepth);
|
|
|
479 |
}
|
|
|
480 |
|
|
|
481 |
/**
|
|
|
482 |
* Create a file reader on an uploaded file. The reader will read
|
|
|
483 |
* $_FILES[$name]['tmp_name'] and will have $_FILES[$name]['name']
|
|
|
484 |
* as a symbolic filename.
|
|
|
485 |
*
|
|
|
486 |
* A PEAR error is returned if one of the following happen
|
|
|
487 |
* - $_FILES[$name] is not set
|
|
|
488 |
* - $_FILES[$name]['error'] is not 0
|
|
|
489 |
* - is_uploaded_file returns false
|
|
|
490 |
*
|
|
|
491 |
* @param string $name Index of the file in the $_FILES array
|
|
|
492 |
* @return File_Archive_Reader File reader on the uploaded file
|
|
|
493 |
*/
|
|
|
494 |
function readUploadedFile($name)
|
|
|
495 |
{
|
|
|
496 |
if (!isset($_FILES[$name])) {
|
|
|
497 |
return PEAR::raiseError("File $name has not been uploaded");
|
|
|
498 |
}
|
|
|
499 |
switch ($_FILES[$name]['error']) {
|
|
|
500 |
case 0:
|
|
|
501 |
//No error
|
|
|
502 |
break;
|
|
|
503 |
case 1:
|
|
|
504 |
return PEAR::raiseError(
|
|
|
505 |
"The upload size limit didn't allow to upload file ".
|
|
|
506 |
$_FILES[$name]['name']
|
|
|
507 |
);
|
|
|
508 |
case 2:
|
|
|
509 |
return PEAR::raiseError(
|
|
|
510 |
"The form size limit didn't allow to upload file ".
|
|
|
511 |
$_FILES[$name]['name']
|
|
|
512 |
);
|
|
|
513 |
case 3:
|
|
|
514 |
return PEAR::raiseError(
|
|
|
515 |
"The file was not entirely uploaded"
|
|
|
516 |
);
|
|
|
517 |
case 4:
|
|
|
518 |
return PEAR::raiseError(
|
|
|
519 |
"The uploaded file is empty"
|
|
|
520 |
);
|
|
|
521 |
default:
|
|
|
522 |
return PEAR::raiseError(
|
|
|
523 |
"Unknown error ".$_FILES[$name]['error']." in file upload. ".
|
|
|
524 |
"Please, report a bug"
|
|
|
525 |
);
|
|
|
526 |
}
|
|
|
527 |
if (!is_uploaded_file($_FILES[$name]['tmp_name'])) {
|
|
|
528 |
return PEAR::raiseError("The file is not an uploaded file");
|
|
|
529 |
}
|
|
|
530 |
|
|
|
531 |
require_once "File/Archive/Reader/File.php";
|
|
|
532 |
return new File_Archive_Reader_File(
|
|
|
533 |
$_FILES[$name]['tmp_name'],
|
|
|
534 |
$_FILES[$name]['name'],
|
|
|
535 |
$_FILES[$name]['type']
|
|
|
536 |
);
|
|
|
537 |
}
|
|
|
538 |
|
|
|
539 |
/**
|
|
|
540 |
* Adds a cache layer above the specified reader
|
|
|
541 |
* The data of the reader is saved in a temporary file for future access.
|
|
|
542 |
* The cached reader will be read only once, even if you read it several times.
|
|
|
543 |
* This can be usefull to read compressed files or downloaded files (from http or ftp)
|
|
|
544 |
*
|
|
|
545 |
* @param mixed $toConvert The reader to cache
|
|
|
546 |
* It can be a File_Archive_Reader or a string, which will be converted using the
|
|
|
547 |
* read function
|
|
|
548 |
*/
|
|
|
549 |
function cache(&$toConvert)
|
|
|
550 |
{
|
|
|
551 |
$source =& File_Archive::_convertToReader($toConvert);
|
|
|
552 |
if (PEAR::isError($source)) {
|
|
|
553 |
return $source;
|
|
|
554 |
}
|
|
|
555 |
|
|
|
556 |
require_once 'File/Archive/Reader/Cache.php';
|
|
|
557 |
return new File_Archive_Reader_Cache($source);
|
|
|
558 |
}
|
|
|
559 |
|
|
|
560 |
/**
|
|
|
561 |
* Try to interpret the object as a reader
|
|
|
562 |
* Strings are converted to readers using File_Archive::read
|
|
|
563 |
* Arrays are converted to readers using File_Archive::readMulti
|
|
|
564 |
*
|
|
|
565 |
* @access private
|
|
|
566 |
*/
|
|
|
567 |
function &_convertToReader(&$source)
|
|
|
568 |
{
|
|
|
569 |
if (is_string($source)) {
|
|
|
570 |
$cacheCondition = File_Archive::getOption('cacheCondition');
|
|
|
571 |
if ($cacheCondition !== false &&
|
|
|
572 |
preg_match($cacheCondition, $source)) {
|
|
|
573 |
$obj = File_Archive::cache(File_Archive::read($source));
|
|
|
574 |
return $obj;
|
|
|
575 |
} else {
|
|
|
576 |
$obj = File_Archive::read($source);
|
|
|
577 |
return $obj;
|
|
|
578 |
}
|
|
|
579 |
} else if (is_array($source)) {
|
|
|
580 |
return File_Archive::readMulti($source);
|
|
|
581 |
} else {
|
|
|
582 |
return $source;
|
|
|
583 |
}
|
|
|
584 |
}
|
|
|
585 |
|
|
|
586 |
/**
|
|
|
587 |
* Try to interpret the object as a writer
|
|
|
588 |
* Strings are converted to writers using File_Archive::appender
|
|
|
589 |
* Arrays are converted to writers using a multi writer
|
|
|
590 |
*
|
|
|
591 |
* @access private
|
|
|
592 |
*/
|
|
|
593 |
function &_convertToWriter(&$dest)
|
|
|
594 |
{
|
|
|
595 |
if (is_string($dest)) {
|
|
|
596 |
$obj =& File_Archive::appender($dest);
|
|
|
597 |
return $obj;
|
|
|
598 |
} else if (is_array($dest)) {
|
|
|
599 |
require_once 'File/Archive/Writer/Multi.php';
|
|
|
600 |
$writer = new File_Archive_Writer_Multi();
|
|
|
601 |
foreach($dest as $key => $foo) {
|
|
|
602 |
$writer->addWriter($dest[$key]);
|
|
|
603 |
}
|
|
|
604 |
return $writer;
|
|
|
605 |
} else {
|
|
|
606 |
return $dest;
|
|
|
607 |
}
|
|
|
608 |
}
|
|
|
609 |
|
|
|
610 |
/**
|
|
|
611 |
* Check if a file with a specific extension can be read as an archive
|
|
|
612 |
* with File_Archive::read*
|
|
|
613 |
* This function is case sensitive.
|
|
|
614 |
*
|
|
|
615 |
* @param string $extension the checked extension
|
|
|
616 |
* @return bool whether this file can be understood reading its extension
|
|
|
617 |
* Currently, supported extensions are tar, zip, jar, gz, tgz,
|
|
|
618 |
* tbz, bz2, bzip2, ar, deb
|
|
|
619 |
*/
|
|
|
620 |
function isKnownExtension($extension)
|
|
|
621 |
{
|
|
|
622 |
return $extension == 'tar' ||
|
|
|
623 |
$extension == 'zip' ||
|
|
|
624 |
$extension == 'jar' ||
|
|
|
625 |
$extension == 'gz' ||
|
|
|
626 |
$extension == 'tgz' ||
|
|
|
627 |
$extension == 'tbz' ||
|
|
|
628 |
$extension == 'bz2' ||
|
|
|
629 |
$extension == 'bzip2' ||
|
|
|
630 |
$extension == 'ar' ||
|
|
|
631 |
$extension == 'deb' /* ||
|
|
|
632 |
$extension == 'cab' ||
|
|
|
633 |
$extension == 'rar' */;
|
|
|
634 |
}
|
|
|
635 |
|
|
|
636 |
/**
|
|
|
637 |
* Create a reader that will read the single file source $source as
|
|
|
638 |
* a specific archive
|
|
|
639 |
*
|
|
|
640 |
* @param string $extension determines the kind of archive $source contains
|
|
|
641 |
* $extension is case sensitive
|
|
|
642 |
* @param File_Archive_Reader $source stores the archive
|
|
|
643 |
* @param bool $sourceOpened specifies if the archive is already opened
|
|
|
644 |
* if false, next will be called on source
|
|
|
645 |
* Closing the returned archive will close $source iif $sourceOpened
|
|
|
646 |
* is true
|
|
|
647 |
* @return A File_Archive_Reader that uncompresses the archive contained in
|
|
|
648 |
* $source interpreting it as a $extension archive
|
|
|
649 |
* If $extension is not handled return false
|
|
|
650 |
*/
|
|
|
651 |
function readArchive($extension, &$toConvert, $sourceOpened = false)
|
|
|
652 |
{
|
|
|
653 |
$source =& File_Archive::_convertToReader($toConvert);
|
|
|
654 |
if (PEAR::isError($source)) {
|
|
|
655 |
return $source;
|
|
|
656 |
}
|
|
|
657 |
|
|
|
658 |
switch($extension) {
|
|
|
659 |
case 'tgz':
|
|
|
660 |
return File_Archive::readArchive('tar',
|
|
|
661 |
File_Archive::readArchive('gz', $source, $sourceOpened)
|
|
|
662 |
);
|
|
|
663 |
case 'tbz':
|
|
|
664 |
return File_Archive::readArchive('tar',
|
|
|
665 |
File_Archive::readArchive('bz2', $source, $sourceOpened)
|
|
|
666 |
);
|
|
|
667 |
case 'tar':
|
|
|
668 |
require_once 'File/Archive/Reader/Tar.php';
|
|
|
669 |
return new File_Archive_Reader_Tar($source, $sourceOpened);
|
|
|
670 |
|
|
|
671 |
case 'gz':
|
|
|
672 |
case 'gzip':
|
|
|
673 |
require_once 'File/Archive/Reader/Gzip.php';
|
|
|
674 |
return new File_Archive_Reader_Gzip($source, $sourceOpened);
|
|
|
675 |
|
|
|
676 |
case 'zip':
|
|
|
677 |
case 'jar':
|
|
|
678 |
require_once 'File/Archive/Reader/Zip.php';
|
|
|
679 |
return new File_Archive_Reader_Zip($source, $sourceOpened);
|
|
|
680 |
|
|
|
681 |
case 'bz2':
|
|
|
682 |
case 'bzip2':
|
|
|
683 |
require_once 'File/Archive/Reader/Bzip2.php';
|
|
|
684 |
return new File_Archive_Reader_Bzip2($source, $sourceOpened);
|
|
|
685 |
|
|
|
686 |
case 'deb':
|
|
|
687 |
case 'ar':
|
|
|
688 |
require_once 'File/Archive/Reader/Ar.php';
|
|
|
689 |
return new File_Archive_Reader_Ar($source, $sourceOpened);
|
|
|
690 |
|
|
|
691 |
/* case 'cab':
|
|
|
692 |
require_once 'File/Archive/Reader/Cab.php';
|
|
|
693 |
return new File_Archive_Reader_Cab($source, $sourceOpened);
|
|
|
694 |
|
|
|
695 |
|
|
|
696 |
case 'rar':
|
|
|
697 |
require_once "File/Archive/Reader/Rar.php";
|
|
|
698 |
return new File_Archive_Reader_Rar($source, $sourceOpened); */
|
|
|
699 |
|
|
|
700 |
default:
|
|
|
701 |
return false;
|
|
|
702 |
}
|
|
|
703 |
}
|
|
|
704 |
|
|
|
705 |
/**
|
|
|
706 |
* Contains only one file with data read from a memory buffer
|
|
|
707 |
*
|
|
|
708 |
* @param string $memory content of the file
|
|
|
709 |
* @param string $filename public name of the file
|
|
|
710 |
* @param array $stat statistics of the file. Index 7 (size) will be
|
|
|
711 |
* overwritten to match the size of $memory
|
|
|
712 |
* @param string $mime mime type of the file. Default will determine the
|
|
|
713 |
* mime type thanks to the extension of $filename
|
|
|
714 |
* @see File_Archive_Reader_Memory
|
|
|
715 |
*/
|
|
|
716 |
function readMemory($memory, $filename, $stat=array(), $mime=null)
|
|
|
717 |
{
|
|
|
718 |
require_once "File/Archive/Reader/Memory.php";
|
|
|
719 |
return new File_Archive_Reader_Memory($memory, $filename, $stat, $mime);
|
|
|
720 |
}
|
|
|
721 |
|
|
|
722 |
/**
|
|
|
723 |
* Contains several other sources. Take care the sources don't have several
|
|
|
724 |
* files with the same filename. The sources are given as a parameter, or
|
|
|
725 |
* can be added thanks to the reader addSource method
|
|
|
726 |
*
|
|
|
727 |
* @param array $sources Array of strings or readers that will be added to
|
|
|
728 |
* the multi reader. If the parameter is a string, a reader will be
|
|
|
729 |
* built thanks to the read function
|
|
|
730 |
* @see File_Archive_Reader_Multi, File_Archive::read()
|
|
|
731 |
*/
|
|
|
732 |
function readMulti($sources = array())
|
|
|
733 |
{
|
|
|
734 |
require_once "File/Archive/Reader/Multi.php";
|
|
|
735 |
$result = new File_Archive_Reader_Multi();
|
|
|
736 |
foreach ($sources as $index => $foo) {
|
|
|
737 |
$s =& File_Archive::_convertToReader($sources[$index]);
|
|
|
738 |
if (PEAR::isError($s)) {
|
|
|
739 |
return $s;
|
|
|
740 |
} else {
|
|
|
741 |
$result->addSource($s);
|
|
|
742 |
}
|
|
|
743 |
}
|
|
|
744 |
return $result;
|
|
|
745 |
}
|
|
|
746 |
/**
|
|
|
747 |
* Make the files of a source appear as one large file whose content is the
|
|
|
748 |
* concatenation of the content of all the files
|
|
|
749 |
*
|
|
|
750 |
* @param File_Archive_Reader $toConvert The source whose files must be
|
|
|
751 |
* concatened
|
|
|
752 |
* @param string $filename name of the only file of the created reader
|
|
|
753 |
* @param array $stat statistics of the file. Index 7 (size) will be
|
|
|
754 |
* overwritten to match the total size of the files
|
|
|
755 |
* @param string $mime mime type of the file. Default will determine the
|
|
|
756 |
* mime type thanks to the extension of $filename
|
|
|
757 |
* @see File_Archive_Reader_Concat
|
|
|
758 |
*/
|
|
|
759 |
function readConcat(&$toConvert, $filename, $stat=array(), $mime=null)
|
|
|
760 |
{
|
|
|
761 |
$source =& File_Archive::_convertToReader($toConvert);
|
|
|
762 |
if (PEAR::isError($source)) {
|
|
|
763 |
return $source;
|
|
|
764 |
}
|
|
|
765 |
|
|
|
766 |
require_once "File/Archive/Reader/Concat.php";
|
|
|
767 |
return new File_Archive_Reader_Concat($source, $filename, $stat, $mime);
|
|
|
768 |
}
|
|
|
769 |
|
|
|
770 |
/**
|
|
|
771 |
* Changes the name of each file in a reader by applying a custom function
|
|
|
772 |
* The function must return false if the file is to be discarded, or the new
|
|
|
773 |
* name of the file else
|
|
|
774 |
*
|
|
|
775 |
* @param Callable $function Function called to modify the name of the file
|
|
|
776 |
* $function takes the name of the file as a parameter and returns the
|
|
|
777 |
* new name, or false if the file must be discarded
|
|
|
778 |
* @param File_Archive_Reader $toConvert The files of this source will be
|
|
|
779 |
* modified
|
|
|
780 |
* @return File_Archive_Reader a new reader that contains the same files
|
|
|
781 |
* as $toConvert but with a different name
|
|
|
782 |
*/
|
|
|
783 |
function changeName($function, &$toConvert)
|
|
|
784 |
{
|
|
|
785 |
$source =& File_Archive::_convertToReader($toConvert);
|
|
|
786 |
if (PEAR::isError($source)) {
|
|
|
787 |
return $source;
|
|
|
788 |
}
|
|
|
789 |
|
|
|
790 |
require_once "File/Archive/Reader/ChangeName.php";
|
|
|
791 |
return new File_Archive_Reader_RemoveDirectory($source);
|
|
|
792 |
}
|
|
|
793 |
|
|
|
794 |
/**
|
|
|
795 |
* Removes from a source the files that do not follow a given predicat
|
|
|
796 |
*
|
|
|
797 |
* @param File_Archive_Predicate $predicate Only the files for which
|
|
|
798 |
* $predicate->isTrue() will be kept
|
|
|
799 |
* @param File_Archive_Reader $source Source that will be filtered
|
|
|
800 |
* @see File_Archive_Reader_Filter
|
|
|
801 |
*/
|
|
|
802 |
function filter($predicate, &$toConvert)
|
|
|
803 |
{
|
|
|
804 |
$source =& File_Archive::_convertToReader($toConvert);
|
|
|
805 |
if (PEAR::isError($source)) {
|
|
|
806 |
return $source;
|
|
|
807 |
}
|
|
|
808 |
|
|
|
809 |
require_once "File/Archive/Reader/Filter.php";
|
|
|
810 |
return new File_Archive_Reader_Filter($predicate, $source);
|
|
|
811 |
}
|
|
|
812 |
/**
|
|
|
813 |
* Predicate that always evaluate to true
|
|
|
814 |
*
|
|
|
815 |
* @see File_Archive_Predicate_True
|
|
|
816 |
*/
|
|
|
817 |
function predTrue()
|
|
|
818 |
{
|
|
|
819 |
require_once "File/Archive/Predicate/True.php";
|
|
|
820 |
return new File_Archive_Predicate_True();
|
|
|
821 |
}
|
|
|
822 |
/**
|
|
|
823 |
* Predicate that always evaluate to false
|
|
|
824 |
*
|
|
|
825 |
* @see File_Archive_Predicate_False
|
|
|
826 |
*/
|
|
|
827 |
function predFalse()
|
|
|
828 |
{
|
|
|
829 |
require_once "File/Archive/Predicate/False.php";
|
|
|
830 |
return new File_Archive_Predicate_False();
|
|
|
831 |
}
|
|
|
832 |
/**
|
|
|
833 |
* Predicate that evaluates to the logical AND of the parameters
|
|
|
834 |
* You can add other predicates thanks to the
|
|
|
835 |
* File_Archive_Predicate_And::addPredicate() function
|
|
|
836 |
*
|
|
|
837 |
* @param File_Archive_Predicate (any number of them)
|
|
|
838 |
* @see File_Archive_Predicate_And
|
|
|
839 |
*/
|
|
|
840 |
function predAnd()
|
|
|
841 |
{
|
|
|
842 |
require_once "File/Archive/Predicate/And.php";
|
|
|
843 |
$pred = new File_Archive_Predicate_And();
|
|
|
844 |
$args = func_get_args();
|
|
|
845 |
foreach ($args as $p) {
|
|
|
846 |
$pred->addPredicate($p);
|
|
|
847 |
}
|
|
|
848 |
return $pred;
|
|
|
849 |
}
|
|
|
850 |
/**
|
|
|
851 |
* Predicate that evaluates to the logical OR of the parameters
|
|
|
852 |
* You can add other predicates thanks to the
|
|
|
853 |
* File_Archive_Predicate_Or::addPredicate() function
|
|
|
854 |
*
|
|
|
855 |
* @param File_Archive_Predicate (any number of them)
|
|
|
856 |
* @see File_Archive_Predicate_Or
|
|
|
857 |
*/
|
|
|
858 |
function predOr()
|
|
|
859 |
{
|
|
|
860 |
require_once "File/Archive/Predicate/Or.php";
|
|
|
861 |
$pred = new File_Archive_Predicate_Or();
|
|
|
862 |
$args = func_get_args();
|
|
|
863 |
foreach ($args as $p) {
|
|
|
864 |
$pred->addPredicate($p);
|
|
|
865 |
}
|
|
|
866 |
return $pred;
|
|
|
867 |
}
|
|
|
868 |
/**
|
|
|
869 |
* Negate a predicate
|
|
|
870 |
*
|
|
|
871 |
* @param File_Archive_Predicate $pred Predicate to negate
|
|
|
872 |
* @see File_Archive_Predicate_Not
|
|
|
873 |
*/
|
|
|
874 |
function predNot($pred)
|
|
|
875 |
{
|
|
|
876 |
require_once "File/Archive/Predicate/Not.php";
|
|
|
877 |
return new File_Archive_Predicate_Not($pred);
|
|
|
878 |
}
|
|
|
879 |
/**
|
|
|
880 |
* Evaluates to true iif the file is larger than a given size
|
|
|
881 |
*
|
|
|
882 |
* @param int $size the minimal size of the files (in Bytes)
|
|
|
883 |
* @see File_Archive_Predicate_MinSize
|
|
|
884 |
*/
|
|
|
885 |
function predMinSize($size)
|
|
|
886 |
{
|
|
|
887 |
require_once "File/Archive/Predicate/MinSize.php";
|
|
|
888 |
return new File_Archive_Predicate_MinSize($size);
|
|
|
889 |
}
|
|
|
890 |
/**
|
|
|
891 |
* Evaluates to true iif the file has been modified after a given time
|
|
|
892 |
*
|
|
|
893 |
* @param int $time Unix timestamp of the minimal modification time of the
|
|
|
894 |
* files
|
|
|
895 |
* @see File_Archive_Predicate_MinTime
|
|
|
896 |
*/
|
|
|
897 |
function predMinTime($time)
|
|
|
898 |
{
|
|
|
899 |
require_once "File/Archive/Predicate/MinTime.php";
|
|
|
900 |
return new File_Archive_Predicate_MinTime($time);
|
|
|
901 |
}
|
|
|
902 |
/**
|
|
|
903 |
* Evaluates to true iif the file has less that a given number of
|
|
|
904 |
* directories in its path
|
|
|
905 |
*
|
|
|
906 |
* @param int $depth Maximal number of directories in path of the files
|
|
|
907 |
* @see File_Archive_Predicate_MaxDepth
|
|
|
908 |
*/
|
|
|
909 |
function predMaxDepth($depth)
|
|
|
910 |
{
|
|
|
911 |
require_once "File/Archive/Predicate/MaxDepth.php";
|
|
|
912 |
return new File_Archive_Predicate_MaxDepth($depth);
|
|
|
913 |
}
|
|
|
914 |
/**
|
|
|
915 |
* Evaluates to true iif the extension of the file is in a given list
|
|
|
916 |
*
|
|
|
917 |
* @param array or string $list List or comma separated string of possible
|
|
|
918 |
* extension of the files
|
|
|
919 |
* @see File_Archive_Predicate_Extension
|
|
|
920 |
*/
|
|
|
921 |
function predExtension($list)
|
|
|
922 |
{
|
|
|
923 |
require_once "File/Archive/Predicate/Extension.php";
|
|
|
924 |
return new File_Archive_Predicate_Extension($list);
|
|
|
925 |
}
|
|
|
926 |
/**
|
|
|
927 |
* Evaluates to true iif the MIME type of the file is in a given list
|
|
|
928 |
*
|
|
|
929 |
* @param array or string $list List or comma separated string of possible
|
|
|
930 |
* MIME types of the files. You may enter wildcards like "image/*" to
|
|
|
931 |
* select all the MIME in class image
|
|
|
932 |
* @see File_Archive_Predicate_MIME, MIME_Type::isWildcard()
|
|
|
933 |
*/
|
|
|
934 |
function predMIME($list)
|
|
|
935 |
{
|
|
|
936 |
require_once "File/Archive/Predicate/MIME.php";
|
|
|
937 |
return new File_Archive_Predicate_MIME($list);
|
|
|
938 |
}
|
|
|
939 |
/**
|
|
|
940 |
* Evaluates to true iif the name of the file follow a given regular
|
|
|
941 |
* expression
|
|
|
942 |
*
|
|
|
943 |
* @param string $ereg regular expression that the filename must follow
|
|
|
944 |
* @see File_Archive_Predicate_Ereg, ereg()
|
|
|
945 |
*/
|
|
|
946 |
function predEreg($ereg)
|
|
|
947 |
{
|
|
|
948 |
require_once "File/Archive/Predicate/Ereg.php";
|
|
|
949 |
return new File_Archive_Predicate_Ereg($ereg);
|
|
|
950 |
}
|
|
|
951 |
/**
|
|
|
952 |
* Evaluates to true iif the name of the file follow a given regular
|
|
|
953 |
* expression (case insensitive version)
|
|
|
954 |
*
|
|
|
955 |
* @param string $ereg regular expression that the filename must follow
|
|
|
956 |
* @see File_Archive_Predicate_Eregi, eregi
|
|
|
957 |
*/
|
|
|
958 |
function predEregi($ereg)
|
|
|
959 |
{
|
|
|
960 |
require_once "File/Archive/Predicate/Eregi.php";
|
|
|
961 |
return new File_Archive_Predicate_Eregi($ereg);
|
|
|
962 |
}
|
|
|
963 |
/**
|
|
|
964 |
* Evaluates to true only after a given number of evaluations
|
|
|
965 |
* This can be used to select files by index since the evaluation is done
|
|
|
966 |
* once per file
|
|
|
967 |
*
|
|
|
968 |
* @param array The indexes for which the returned predicate will return true
|
|
|
969 |
* are the keys of the array
|
|
|
970 |
* The predicate will return true if isset($indexes[$pos])
|
|
|
971 |
*/
|
|
|
972 |
function predIndex($indexes)
|
|
|
973 |
{
|
|
|
974 |
require_once "File/Archive/Predicate/Index.php";
|
|
|
975 |
return new File_Archive_Predicate_Index($indexes);
|
|
|
976 |
}
|
|
|
977 |
/**
|
|
|
978 |
* Custom predicate built by supplying a string expression
|
|
|
979 |
*
|
|
|
980 |
* Here are different ways to create a predicate that keeps only files
|
|
|
981 |
* with names shorter than 100 chars
|
|
|
982 |
* <sample>
|
|
|
983 |
* File_Archive::predCustom("return strlen($name)<100;")
|
|
|
984 |
* File_Archive::predCustom("strlen($name)<100;")
|
|
|
985 |
* File_Archive::predCustom("strlen($name)<100")
|
|
|
986 |
* File_Archive::predCustom("strlen($source->getFilename())<100")
|
|
|
987 |
* </sample>
|
|
|
988 |
*
|
|
|
989 |
* @param string $expression String containing an expression that evaluates
|
|
|
990 |
* to a boolean. If the expression doesn't contain a return
|
|
|
991 |
* statement, it will be added at the begining of the expression
|
|
|
992 |
* A ';' will be added at the end of the expression so that you don't
|
|
|
993 |
* have to write it. You may use the $name variable to refer to the
|
|
|
994 |
* current filename (with path...), $time for the modification time
|
|
|
995 |
* (unix timestamp), $size for the size of the file in bytes, $mime
|
|
|
996 |
* for the MIME type of the file
|
|
|
997 |
* @see File_Archive_Predicate_Custom
|
|
|
998 |
*/
|
|
|
999 |
function predCustom($expression)
|
|
|
1000 |
{
|
|
|
1001 |
require_once "File/Archive/Predicate/Custom.php";
|
|
|
1002 |
return new File_Archive_Predicate_Custom($expression);
|
|
|
1003 |
}
|
|
|
1004 |
|
|
|
1005 |
/**
|
|
|
1006 |
* Send the files as a mail attachment
|
|
|
1007 |
*
|
|
|
1008 |
* @param Mail $mail Object used to send mail (see Mail::factory)
|
|
|
1009 |
* @param array or String $to An array or a string with comma separated
|
|
|
1010 |
* recipients
|
|
|
1011 |
* @param array $headers The headers that will be passed to the Mail_mime
|
|
|
1012 |
* object
|
|
|
1013 |
* @param string $message Text body of the mail
|
|
|
1014 |
* @see File_Archive_Writer_Mail
|
|
|
1015 |
*/
|
|
|
1016 |
function toMail($to, $headers, $message, $mail = null)
|
|
|
1017 |
{
|
|
|
1018 |
require_once "File/Archive/Writer/Mail.php";
|
|
|
1019 |
return new File_Archive_Writer_Mail($to, $headers, $message, $mail);
|
|
|
1020 |
}
|
|
|
1021 |
/**
|
|
|
1022 |
* Write the files on the hard drive
|
|
|
1023 |
*
|
|
|
1024 |
* @param string $baseDir if specified, the files will be created in that
|
|
|
1025 |
* directory. If they don't exist, the directories will automatically
|
|
|
1026 |
* be created
|
|
|
1027 |
* @see File_Archive_Writer_Files
|
|
|
1028 |
*/
|
|
|
1029 |
function toFiles($baseDir = "")
|
|
|
1030 |
{
|
|
|
1031 |
require_once "File/Archive/Writer/Files.php";
|
|
|
1032 |
return new File_Archive_Writer_Files($baseDir);
|
|
|
1033 |
}
|
|
|
1034 |
/**
|
|
|
1035 |
* Send the content of the files to a memory buffer
|
|
|
1036 |
*
|
|
|
1037 |
* toMemory returns a writer where the data will be written.
|
|
|
1038 |
* In this case, the data is accessible using the getData member
|
|
|
1039 |
*
|
|
|
1040 |
* toVariable returns a writer that will write into the given
|
|
|
1041 |
* variable
|
|
|
1042 |
*
|
|
|
1043 |
* @param out $data if specified, the data will be written to this buffer
|
|
|
1044 |
* Else, you can retrieve the buffer with the
|
|
|
1045 |
* File_Archive_Writer_Memory::getData() function
|
|
|
1046 |
* @see File_Archive_Writer_Memory
|
|
|
1047 |
*/
|
|
|
1048 |
function toMemory()
|
|
|
1049 |
{
|
|
|
1050 |
$v = '';
|
|
|
1051 |
return File_Archive::toVariable($v);
|
|
|
1052 |
}
|
|
|
1053 |
function toVariable(&$v)
|
|
|
1054 |
{
|
|
|
1055 |
require_once "File/Archive/Writer/Memory.php";
|
|
|
1056 |
return new File_Archive_Writer_Memory($v);
|
|
|
1057 |
}
|
|
|
1058 |
/**
|
|
|
1059 |
* Duplicate the writing operation on two writers
|
|
|
1060 |
*
|
|
|
1061 |
* @param File_Archive_Writer $a, $b writers where data will be duplicated
|
|
|
1062 |
* @see File_Archive_Writer_Multi
|
|
|
1063 |
*/
|
|
|
1064 |
function toMulti(&$aC, &$bC)
|
|
|
1065 |
{
|
|
|
1066 |
$a =& File_Archive::_convertToWriter($aC);
|
|
|
1067 |
$b =& File_Archive::_convertToWriter($bC);
|
|
|
1068 |
|
|
|
1069 |
if (PEAR::isError($a)) {
|
|
|
1070 |
return $a;
|
|
|
1071 |
}
|
|
|
1072 |
if (PEAR::isError($b)) {
|
|
|
1073 |
return $b;
|
|
|
1074 |
}
|
|
|
1075 |
|
|
|
1076 |
require_once "File/Archive/Writer/Multi.php";
|
|
|
1077 |
$writer = new File_Archive_Writer_Multi();
|
|
|
1078 |
$writer->addWriter($a);
|
|
|
1079 |
$writer->addWriter($b);
|
|
|
1080 |
return $writer;
|
|
|
1081 |
}
|
|
|
1082 |
/**
|
|
|
1083 |
* Send the content of the files to the standard output (so to the client
|
|
|
1084 |
* for a website)
|
|
|
1085 |
*
|
|
|
1086 |
* @param bool $sendHeaders If true some headers will be sent to force the
|
|
|
1087 |
* download of the file. Default value is true
|
|
|
1088 |
* @see File_Archive_Writer_Output
|
|
|
1089 |
*/
|
|
|
1090 |
function toOutput($sendHeaders = true)
|
|
|
1091 |
{
|
|
|
1092 |
require_once "File/Archive/Writer/Output.php";
|
|
|
1093 |
return new File_Archive_Writer_Output($sendHeaders);
|
|
|
1094 |
}
|
|
|
1095 |
/**
|
|
|
1096 |
* Compress the data to a tar, gz, tar/gz or zip format
|
|
|
1097 |
*
|
|
|
1098 |
* @param string $filename name of the archive file
|
|
|
1099 |
* @param File_Archive_Writer $innerWriter writer where the archive will be
|
|
|
1100 |
* written
|
|
|
1101 |
* @param string $type can be one of tgz, tbz, tar, zip, gz, gzip, bz2,
|
|
|
1102 |
* bzip2 (default is the extension of $filename) or any composition
|
|
|
1103 |
* of them (for example tar.gz or tar.bz2). The case of this
|
|
|
1104 |
* parameter is not important.
|
|
|
1105 |
* @param array $stat Statistics of the archive (see stat function)
|
|
|
1106 |
* @param bool $autoClose If set to true, $innerWriter will be closed when
|
|
|
1107 |
* the returned archive is close. Default value is true.
|
|
|
1108 |
*/
|
|
|
1109 |
function toArchive($filename, &$toConvert, $type = null,
|
|
|
1110 |
$stat = array(), $autoClose = true)
|
|
|
1111 |
{
|
|
|
1112 |
$innerWriter =& File_Archive::_convertToWriter($toConvert);
|
|
|
1113 |
if (PEAR::isError($innerWriter)) {
|
|
|
1114 |
return $innerWriter;
|
|
|
1115 |
}
|
|
|
1116 |
$shortcuts = array("tgz" , "tbz" );
|
|
|
1117 |
$reals = array("tar.gz", "tar.bz2");
|
|
|
1118 |
|
|
|
1119 |
if ($type === null) {
|
|
|
1120 |
$extensions = strtolower($filename);
|
|
|
1121 |
} else {
|
|
|
1122 |
$extensions = strtolower($type);
|
|
|
1123 |
}
|
|
|
1124 |
$extensions = explode('.', str_replace($shortcuts, $reals, $extensions));
|
|
|
1125 |
if ($innerWriter !== null) {
|
|
|
1126 |
$writer =& $innerWriter;
|
|
|
1127 |
} else {
|
|
|
1128 |
$writer = File_Archive::toFiles();
|
|
|
1129 |
}
|
|
|
1130 |
$nbCompressions = 0;
|
|
|
1131 |
$currentFilename = $filename;
|
|
|
1132 |
while (($extension = array_pop($extensions)) !== null) {
|
|
|
1133 |
unset($next);
|
|
|
1134 |
switch($extension) {
|
|
|
1135 |
case "tar":
|
|
|
1136 |
require_once "File/Archive/Writer/Tar.php";
|
|
|
1137 |
$next = new File_Archive_Writer_Tar(
|
|
|
1138 |
$currentFilename, $writer, $stat, $autoClose
|
|
|
1139 |
);
|
|
|
1140 |
unset($writer); $writer =& $next;
|
|
|
1141 |
break;
|
|
|
1142 |
case "zip":
|
|
|
1143 |
require_once "File/Archive/Writer/Zip.php";
|
|
|
1144 |
$next = new File_Archive_Writer_Zip(
|
|
|
1145 |
$currentFilename, $writer, $stat, $autoClose
|
|
|
1146 |
);
|
|
|
1147 |
unset($writer); $writer =& $next;
|
|
|
1148 |
break;
|
|
|
1149 |
case "gz":
|
|
|
1150 |
case "gzip":
|
|
|
1151 |
require_once "File/Archive/Writer/Gzip.php";
|
|
|
1152 |
$next = new File_Archive_Writer_Gzip(
|
|
|
1153 |
$currentFilename, $writer, $stat, $autoClose
|
|
|
1154 |
);
|
|
|
1155 |
unset($writer); $writer =& $next;
|
|
|
1156 |
break;
|
|
|
1157 |
case "bz2":
|
|
|
1158 |
case "bzip2":
|
|
|
1159 |
require_once "File/Archive/Writer/Bzip2.php";
|
|
|
1160 |
$next = new File_Archive_Writer_Bzip2(
|
|
|
1161 |
$currentFilename, $writer, $stat, $autoClose
|
|
|
1162 |
);
|
|
|
1163 |
unset($writer); $writer =& $next;
|
|
|
1164 |
break;
|
|
|
1165 |
case "deb":
|
|
|
1166 |
case "ar":
|
|
|
1167 |
require_once "File/Archive/Writer/Ar.php";
|
|
|
1168 |
$next = new File_Archive_Writer_Ar(
|
|
|
1169 |
$currentFilename, $writer, $stat, $autoClose
|
|
|
1170 |
);
|
|
|
1171 |
unset($writer); $writer =& $next;
|
|
|
1172 |
break;
|
|
|
1173 |
default:
|
|
|
1174 |
if ($type !== null || $nbCompressions == 0) {
|
|
|
1175 |
return PEAR::raiseError("Archive $extension unknown");
|
|
|
1176 |
}
|
|
|
1177 |
break;
|
|
|
1178 |
}
|
|
|
1179 |
$nbCompressions ++;
|
|
|
1180 |
$autoClose = true;
|
|
|
1181 |
$currentFilename = implode(".", $extensions);
|
|
|
1182 |
}
|
|
|
1183 |
return $writer;
|
|
|
1184 |
}
|
|
|
1185 |
|
|
|
1186 |
|
|
|
1187 |
/**
|
|
|
1188 |
* File_Archive::extract($source, $dest) is equivalent to $source->extract($dest)
|
|
|
1189 |
* If $source is a PEAR error, the error will be returned
|
|
|
1190 |
* It is thus easier to use this function than $source->extract, since it reduces the number of
|
|
|
1191 |
* error checking and doesn't force you to define a variable $source
|
|
|
1192 |
*
|
|
|
1193 |
* You may use strings as source and dest. In that case the source is automatically
|
|
|
1194 |
* converted to a reader using File_Archive::read and the dest is converted to a
|
|
|
1195 |
* writer using File_Archive::appender
|
|
|
1196 |
* Since PHP doesn't allow to pass literal strings by ref, you will have to use temporary
|
|
|
1197 |
* variables.
|
|
|
1198 |
* File_Archive::extract($src = 'archive.zip/', $dest = 'dir') will extract the archive to 'dir'
|
|
|
1199 |
* It is the same as
|
|
|
1200 |
* File_Archive::extract(
|
|
|
1201 |
* File_Archive::read('archive.zip/'),
|
|
|
1202 |
* File_Archive::appender('dir')
|
|
|
1203 |
* );
|
|
|
1204 |
* You may use any variable in the extract function ($from/$to, $a/$b...).
|
|
|
1205 |
*
|
|
|
1206 |
* @param File_Archive_Reader $source The source that will be read
|
|
|
1207 |
* @param File_Archive_Writer $dest Where to copy $source files
|
|
|
1208 |
* @param bool $autoClose if true (default), $dest will be closed after the extraction
|
|
|
1209 |
* @param int $bufferSize Size of the buffer to use to move data from the reader to the buffer
|
|
|
1210 |
* If $bufferSize <= 0 (default), the blockSize option is used
|
|
|
1211 |
* You shouldn't need to change that
|
|
|
1212 |
* @return null or a PEAR error if an error occured
|
|
|
1213 |
*/
|
|
|
1214 |
function extract(&$sourceToConvert, &$destToConvert, $autoClose = true, $bufferSize = 0)
|
|
|
1215 |
{
|
|
|
1216 |
$source =& File_Archive::_convertToReader($sourceToConvert);
|
|
|
1217 |
if (PEAR::isError($source)) {
|
|
|
1218 |
return $source;
|
|
|
1219 |
}
|
|
|
1220 |
$dest =& File_Archive::_convertToWriter($destToConvert);
|
|
|
1221 |
return $source->extract($dest, $autoClose, $bufferSize);
|
|
|
1222 |
}
|
|
|
1223 |
|
|
|
1224 |
/**
|
|
|
1225 |
* Create a writer that can be used to append files to an archive inside a source
|
|
|
1226 |
* If the archive can't be found in the source, it will be created
|
|
|
1227 |
* If source is set to null, File_Archive::toFiles will be assumed
|
|
|
1228 |
* If type is set to null, the type of the archive will be determined looking at
|
|
|
1229 |
* the extension in the URL
|
|
|
1230 |
* stat is the array of stat (returned by stat() PHP function of Reader getStat())
|
|
|
1231 |
* to use if the archive must be created
|
|
|
1232 |
*
|
|
|
1233 |
* This function allows to create or append data to nested archives. Only one
|
|
|
1234 |
* archive will be created and if your creation requires creating several nested
|
|
|
1235 |
* archives, a PEAR error will be returned
|
|
|
1236 |
*
|
|
|
1237 |
* After this call, $source will be closed and should not be used until the
|
|
|
1238 |
* returned writer is closed.
|
|
|
1239 |
*
|
|
|
1240 |
* @param File_Archive_Reader $source A reader where some files will be appended
|
|
|
1241 |
* @param string $URL URL to reach the archive in the source.
|
|
|
1242 |
* if $URL is null, a writer to append files to the $source reader will
|
|
|
1243 |
* be returned
|
|
|
1244 |
* @param bool $unique If true, the duplicate files will be deleted on close
|
|
|
1245 |
* Default is false (and setting it to true may have some performance
|
|
|
1246 |
* consequences)
|
|
|
1247 |
* @param string $type Extension of the archive (or null to use the one in the URL)
|
|
|
1248 |
* @param array $stat Used only if archive is created, array of stat as returned
|
|
|
1249 |
* by PHP stat function or Reader getStat function: stats of the archive)
|
|
|
1250 |
* Time (index 9) will be overwritten to current time
|
|
|
1251 |
* @return File_Archive_Writer a writer that you can use to append files to the reader
|
|
|
1252 |
*/
|
|
|
1253 |
function appenderFromSource(&$toConvert, $URL = null, $unique = null,
|
|
|
1254 |
$type = null, $stat = array())
|
|
|
1255 |
{
|
|
|
1256 |
$source =& File_Archive::_convertToReader($toConvert);
|
|
|
1257 |
if (PEAR::isError($source)) {
|
|
|
1258 |
return $source;
|
|
|
1259 |
}
|
|
|
1260 |
if ($unique == null) {
|
|
|
1261 |
$unique = File_Archive::getOption("appendRemoveDuplicates");
|
|
|
1262 |
}
|
|
|
1263 |
|
|
|
1264 |
//Do not report the fact that the archive does not exist as an error
|
|
|
1265 |
PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
|
|
|
1266 |
|
|
|
1267 |
if ($URL === null) {
|
|
|
1268 |
$result =& $source;
|
|
|
1269 |
} else {
|
|
|
1270 |
if ($type === null) {
|
|
|
1271 |
$result = File_Archive::_readSource($source, $URL.'/', $reachable, $baseDir);
|
|
|
1272 |
} else {
|
|
|
1273 |
$result = File_Archive::readArchive(
|
|
|
1274 |
$type,
|
|
|
1275 |
File_Archive::_readSource($source, $URL, $reachable, $baseDir)
|
|
|
1276 |
);
|
|
|
1277 |
}
|
|
|
1278 |
}
|
|
|
1279 |
|
|
|
1280 |
PEAR::popErrorHandling();
|
|
|
1281 |
|
|
|
1282 |
if (!PEAR::isError($result)) {
|
|
|
1283 |
if ($unique) {
|
|
|
1284 |
require_once "File/Archive/Writer/UniqueAppender.php";
|
|
|
1285 |
return new File_Archive_Writer_UniqueAppender($result);
|
|
|
1286 |
} else {
|
|
|
1287 |
return $result->makeAppendWriter();
|
|
|
1288 |
}
|
|
|
1289 |
}
|
|
|
1290 |
|
|
|
1291 |
//The source can't be found and has to be created
|
|
|
1292 |
$stat[9] = $stat['mtime'] = time();
|
|
|
1293 |
|
|
|
1294 |
if (empty($baseDir)) {
|
|
|
1295 |
if ($source !== null) {
|
|
|
1296 |
$writer =& $source->makeWriter();
|
|
|
1297 |
} else {
|
|
|
1298 |
$writer =& File_Archive::toFiles();
|
|
|
1299 |
}
|
|
|
1300 |
if (PEAR::isError($writer)) {
|
|
|
1301 |
return $writer;
|
|
|
1302 |
}
|
|
|
1303 |
|
|
|
1304 |
PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
|
|
|
1305 |
$result = File_Archive::toArchive($reachable, $writer, $type);
|
|
|
1306 |
PEAR::popErrorHandling();
|
|
|
1307 |
|
|
|
1308 |
if (PEAR::isError($result)) {
|
|
|
1309 |
$result = File_Archive::toFiles($reachable);
|
|
|
1310 |
}
|
|
|
1311 |
} else {
|
|
|
1312 |
$reachedSource = File_Archive::readSource($source, $reachable);
|
|
|
1313 |
if (PEAR::isError($reachedSource)) {
|
|
|
1314 |
return $reachedSource;
|
|
|
1315 |
}
|
|
|
1316 |
$writer = $reachedSource->makeWriter();
|
|
|
1317 |
if (PEAR::isError($writer)) {
|
|
|
1318 |
return $writer;
|
|
|
1319 |
}
|
|
|
1320 |
|
|
|
1321 |
PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
|
|
|
1322 |
$result = File_Archive::toArchive($baseDir, $writer, $type);
|
|
|
1323 |
PEAR::popErrorHandling();
|
|
|
1324 |
|
|
|
1325 |
if (PEAR::isError($result)) {
|
|
|
1326 |
require_once "File/Archive/Writer/AddBaseName.php";
|
|
|
1327 |
$result = new File_Archive_Writer_AddBaseName(
|
|
|
1328 |
$baseDir, $writer);
|
|
|
1329 |
if (PEAR::isError($result)) {
|
|
|
1330 |
return $result;
|
|
|
1331 |
}
|
|
|
1332 |
}
|
|
|
1333 |
}
|
|
|
1334 |
return $result;
|
|
|
1335 |
}
|
|
|
1336 |
|
|
|
1337 |
/**
|
|
|
1338 |
* Create a writer that allows appending new files to an existing archive
|
|
|
1339 |
* This function actes as appendToSource with source being the system files
|
|
|
1340 |
* $URL can't be null here
|
|
|
1341 |
*
|
|
|
1342 |
* @param File_Archive_Reader $source A reader where some files will be appended
|
|
|
1343 |
* @return File_Archive_Writer a writer that you can use to append files to the reader
|
|
|
1344 |
*/
|
|
|
1345 |
function appender($URL, $unique = null, $type = null, $stat = array())
|
|
|
1346 |
{
|
|
|
1347 |
$source = null;
|
|
|
1348 |
return File_Archive::appenderFromSource($source, $URL, $unique, $type, $stat);
|
|
|
1349 |
}
|
|
|
1350 |
|
|
|
1351 |
/**
|
|
|
1352 |
* Remove the files that follow a given predicate from the source
|
|
|
1353 |
* If URL is null, the files will be removed from the source directly
|
|
|
1354 |
* Else, URL must link to a source from which the files will be removed
|
|
|
1355 |
*
|
|
|
1356 |
* @param File_Archive_Predicate $pred The files that follow the predicate
|
|
|
1357 |
* (for which $pred->isTrue($source) is true) will be erased
|
|
|
1358 |
* @param File_Archive_Reader $source A reader that contains the files to remove
|
|
|
1359 |
*/
|
|
|
1360 |
function removeFromSource(&$pred, &$toConvert, $URL = null)
|
|
|
1361 |
{
|
|
|
1362 |
$source =& File_Archive::_convertToReader($toConvert);
|
|
|
1363 |
if (PEAR::isError($source)) {
|
|
|
1364 |
return $source;
|
|
|
1365 |
}
|
|
|
1366 |
if ($URL === null) {
|
|
|
1367 |
$result = &$source;
|
|
|
1368 |
} else {
|
|
|
1369 |
if (substr($URL, -1) !== '/') {
|
|
|
1370 |
$URL .= '/';
|
|
|
1371 |
}
|
|
|
1372 |
$result = File_Archive::readSource($source, $URL);
|
|
|
1373 |
}
|
|
|
1374 |
|
|
|
1375 |
$writer = $result->makeWriterRemoveFiles($pred);
|
|
|
1376 |
if (PEAR::isError($writer)) {
|
|
|
1377 |
return $writer;
|
|
|
1378 |
}
|
|
|
1379 |
$writer->close();
|
|
|
1380 |
}
|
|
|
1381 |
|
|
|
1382 |
/**
|
|
|
1383 |
* Remove the files that follow a given predicate from the archive specified
|
|
|
1384 |
* in $URL
|
|
|
1385 |
*
|
|
|
1386 |
* @param $URL URL of the archive where some files must be removed
|
|
|
1387 |
*/
|
|
|
1388 |
function remove($pred, $URL)
|
|
|
1389 |
{
|
|
|
1390 |
$source = null;
|
|
|
1391 |
return File_Archive::removeFromSource($pred, $source, $URL);
|
|
|
1392 |
}
|
|
|
1393 |
|
|
|
1394 |
/**
|
|
|
1395 |
* Remove duplicates from a source, keeping the most recent one (or the one that has highest pos in
|
|
|
1396 |
* the archive if the files have same date or no date specified)
|
|
|
1397 |
*
|
|
|
1398 |
* @param File_Archive_Reader a reader that may contain duplicates
|
|
|
1399 |
*/
|
|
|
1400 |
function removeDuplicatesFromSource(&$toConvert, $URL = null)
|
|
|
1401 |
{
|
|
|
1402 |
$source =& File_Archive::_convertToReader($toConvert);
|
|
|
1403 |
if (PEAR::isError($source)) {
|
|
|
1404 |
return $source;
|
|
|
1405 |
}
|
|
|
1406 |
if ($URL !== null && substr($URL, -1) != '/') {
|
|
|
1407 |
$URL .= '/';
|
|
|
1408 |
}
|
|
|
1409 |
|
|
|
1410 |
if ($source === null) {
|
|
|
1411 |
$source = File_Archive::read($URL);
|
|
|
1412 |
}
|
|
|
1413 |
|
|
|
1414 |
require_once "File/Archive/Predicate/Duplicate.php";
|
|
|
1415 |
$pred = new File_Archive_Predicate_Duplicate($source);
|
|
|
1416 |
$source->close();
|
|
|
1417 |
return File_Archive::removeFromSource(
|
|
|
1418 |
$pred,
|
|
|
1419 |
$source,
|
|
|
1420 |
null
|
|
|
1421 |
);
|
|
|
1422 |
}
|
|
|
1423 |
|
|
|
1424 |
/**
|
|
|
1425 |
* Remove duplicates from the archive specified in the URL
|
|
|
1426 |
*/
|
|
|
1427 |
function removeDuplicates($URL)
|
|
|
1428 |
{
|
|
|
1429 |
$source = null;
|
|
|
1430 |
return File_Archive::removeDuplicatesFromSource($source, $URL);
|
|
|
1431 |
}
|
|
|
1432 |
}
|
|
|
1433 |
|
|
|
1434 |
?>
|