Subversion Repositories Applications.gtt

Rev

Rev 94 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
94 jpm 1
<?php
2
//
3
// +------------------------------------------------------------------------+
4
// | PEAR :: Package File Manager                                           |
5
// +------------------------------------------------------------------------+
6
// | Copyright (c) 2003-2004 Gregory Beaver                                 |
7
// | Email         cellog@phpdoc.org                                        |
8
// +------------------------------------------------------------------------+
9
// | This source file is subject to version 3.00 of the PHP License,        |
10
// | that is available at http://www.php.net/license/3_0.txt.               |
11
// | If you did not receive a copy of the PHP license and are unable to     |
12
// | obtain it through the world-wide-web, please send a note to            |
13
// | license@php.net so we can mail you a copy immediately.                 |
14
// +------------------------------------------------------------------------+
15
// | Portions of this code based on phpDocumentor                           |
16
// | Web           http://www.phpdoc.org                                    |
17
// | Mirror        http://phpdocu.sourceforge.net/                          |
18
// +------------------------------------------------------------------------+
19
// $Id: File.php,v 1.21 2005/03/28 06:37:35 cellog Exp $
20
//
21
/**
22
 * Retrieve the files from a directory listing
23
 * @package PEAR_PackageFileManager
24
 */
25
/**
26
 * Retrieve the files from a directory listing
27
 *
28
 * This class is used to retrieve a raw directory
29
 * listing.  Use the {@link PEAR_PackageFileManager_CVS}
30
 * class to only retrieve the contents of a cvs
31
 * repository when generating the package.xml
32
 * @package PEAR_PackageFileManager
33
 */
34
class PEAR_PackageFileManager_File {
35
    /**
36
     * @var array
37
     * @access private
38
     */
39
    var $_options =
40
            array(
41
                 );
42
 
43
    /**
44
     * @access private
45
     * @var PEAR_PackageFileManager
46
     */
47
    var $_parent;
48
 
49
    /**
50
     * @access private
51
     * @var array|false
52
     */
53
    var $_ignore = false;
54
 
55
    /**
56
     * Set up the File filelist generator
57
     *
58
     * 'ignore' and 'include' are the only options that this class uses.  See
59
     * {@link PEAR_PackageFileManager::setOptions()} for
60
     * more information and formatting of this option
61
     * @param PEAR_PackageFileManager
62
     * @param array
63
     */
64
    function PEAR_PackageFileManager_File(&$parent, $options)
65
    {
66
        $this->_parent = &$parent;
67
        $this->_options = array_merge($this->_options, $options);
68
    }
69
 
70
    /**
71
     * Generate the <filelist></filelist> section
72
     * of the package file.
73
     *
74
     * This function performs the backend generation of the array
75
     * containing all files in this package
76
     * @return array
77
     */
78
    function getFileList()
79
    {
80
        $package_directory = $this->_options['packagedirectory'];
81
        $ignore = $this->_options['ignore'];
82
        // implicitly ignore packagefile
83
        $ignore[] = $this->_options['packagefile'];
84
        if ($this->_options['packagefile'] == 'package.xml') {
85
            // ignore auto-generated package2.xml from PEAR 1.4.0
86
            $ignore[] = 'package2.xml';
87
        }
88
        $include = $this->_options['include'];
89
        $this->ignore = array(false, false);
90
        $this->_setupIgnore($ignore, 1);
91
        $this->_setupIgnore($include, 0);
92
        $allfiles = $this->dirList(substr($package_directory, 0, strlen($package_directory) - 1));
93
        if (PEAR::isError($allfiles)) {
94
            return $allfiles;
95
        }
96
        if (!count($allfiles)) {
97
            return PEAR_PackageFileManager::raiseError(PEAR_PACKAGEFILEMANAGER_NO_FILES,
98
                substr($package_directory, 0, strlen($package_directory) - 1));
99
        }
100
        $struc = array();
101
        foreach($allfiles as $file) {
102
        	$path = substr(dirname($file), strlen(str_replace(DIRECTORY_SEPARATOR,
103
                                                              '/',
104
                                                              realpath($package_directory))) + 1);
105
        	if (!$path) {
106
                $path = '/';
107
            }
108
        	$ext = array_pop(explode('.', $file));
109
        	if (strlen($ext) == strlen($file)) {
110
                $ext = '';
111
            }
112
        	$struc[$path][] = array('file' => basename($file),
113
                                    'ext' => $ext,
114
                                    'path' => (($path == '/') ? basename($file) : $path . '/' . basename($file)),
115
                                    'fullpath' => $file);
116
        }
117
        if (!count($struc)) {
118
            $newig = implode($this->_options['ignore'], ', ');
119
            return PEAR_PackageFileManager::raiseError(PEAR_PACKAGEFILEMANAGER_IGNORED_EVERYTHING,
120
                substr($package_directory, 0, strlen($package_directory) - 1), $newig);
121
        }
122
        uksort($struc,'strnatcasecmp');
123
        foreach($struc as $key => $ind) {
124
        	usort($ind, array($this, 'sortfiles'));
125
        	$struc[$key] = $ind;
126
        }
127
 
128
        $tempstruc = $struc;
129
        if (!isset($tempstruc['/'])) {
130
            $tempstruc['/'] = array();
131
        }
132
        $struc = array('/' => $tempstruc['/']);
133
        $bv = 0;
134
        foreach($tempstruc as $key => $ind) {
135
        	$save = $key;
136
        	if ($key != '/')
137
        	{
138
                $struc['/'] = $this->_setupDirs($struc['/'], explode('/',$key), $tempstruc[$key]);
139
        	}
140
        }
141
        uksort($struc['/'], array($this, 'mystrucsort'));
142
 
143
        return $struc;
144
    }
145
 
146
    /**
147
     * Retrieve a listing of every file in $directory and
148
     * all subdirectories.
149
     *
150
     * The return format is an array of full paths to files
151
     * @access protected
152
     * @return array list of files in a directory
153
     * @param string $directory full path to the directory you want the list of
154
     * @throws PEAR_PACKAGEFILEMANAGER_DIR_DOESNT_EXIST
155
     */
156
    function dirList($directory)
157
    {
158
        $ret = false;
159
        if (@is_dir($directory)) {
160
            $ret = array();
161
            $d = @dir($directory); // thanks to Jason E Sweat (jsweat@users.sourceforge.net) for fix
162
            while($d && false !== ($entry=$d->read())) {
163
                if ($this->_testFile($directory, $entry)) {
164
                    if (is_file($directory . '/' . $entry)) {
165
                        // if include option was set, then only pass included files
166
                        if ($this->ignore[0]) {
167
                            if ($this->_checkIgnore($entry, $directory . '/' . $entry, 0)) {
168
                                continue;
169
                            }
170
                        }
171
                        // if ignore option was set, then only pass included files
172
                        if ($this->ignore[1]) {
173
                            if ($this->_checkIgnore($entry, $directory . '/' . $entry, 1)) {
174
                                continue;
175
                            }
176
                        }
177
                        $ret[] = $directory . '/' . $entry;
178
                    }
179
                    if (is_dir($directory . '/' . $entry)) {
180
                        $tmp = $this->dirList($directory . '/' . $entry);
181
                        if (is_array($tmp)) {
182
                            foreach($tmp as $ent) {
183
                                $ret[] = $ent;
184
                            }
185
                        }
186
                    }
187
                }
188
            }
189
            if ($d) {
190
                $d->close();
191
            }
192
        } else {
193
            return PEAR_PackageFileManager::raiseError(PEAR_PACKAGEFILEMANAGER_DIR_DOESNT_EXIST, $directory);
194
        }
195
        return $ret;
196
    }
197
 
198
    /**
199
     * Test whether an entry should be processed.
200
     *
201
     * Normally, it ignores all files and directories that begin with "."  addhiddenfiles option
202
     * instead only ignores "." and ".." entries
203
     * @access private
204
     * @param string directory name of entry
205
     * @param string name
206
     */
207
    function _testFile($directory, $entry)
208
    {
209
        if ($this->_options['addhiddenfiles']) {
210
            return is_file($directory . '/' . $entry) || (is_dir($directory . '/' . $entry) && !in_array($entry, array('.', '..')));
211
        } else {
212
            return $entry{0} != '.';
213
        }
214
    }
215
 
216
    /**
217
     * Tell whether to ignore a file or a directory
218
     * allows * and ? wildcards
219
     *
220
     * @param    string  $file    just the file name of the file or directory,
221
     *                          in the case of directories this is the last dir
222
     * @param    string  $path    the full path
223
     * @param    1|0    $return  value to return if regexp matches.  Set this to
224
     *                            false to include only matches, true to exclude
225
     *                            all matches
226
     * @return   bool    true if $path should be ignored, false if it should not
227
     * @access private
228
     */
229
    function _checkIgnore($file, $path, $return = 1)
230
    {
231
        if (file_exists($path)) {
232
            $path = realpath($path);
233
        }
234
        if (is_array($this->ignore[$return])) {
235
            foreach($this->ignore[$return] as $match) {
236
                // match is an array if the ignore parameter was a /path/to/pattern
237
                if (is_array($match)) {
238
                    // check to see if the path matches with a path delimiter appended
239
                    preg_match('/^' . strtoupper($match[0]).'$/', strtoupper($path) . '/',$find);
240
                    if (!count($find)) {
241
                        // check to see if it matches without an appended path delimiter
242
                        preg_match('/^' . strtoupper($match[0]).'$/', strtoupper($path), $find);
243
                    }
244
                    if (count($find)) {
245
                        // check to see if the file matches the file portion of the regex string
246
                        preg_match('/^' . strtoupper($match[1]).'$/', strtoupper($file), $find);
247
                        if (count($find)) {
248
                            return $return;
249
                        }
250
                    }
251
                    // check to see if the full path matches the regex
252
                    preg_match('/^' . strtoupper($match[0]).'$/',
253
                               strtoupper($path . DIRECTORY_SEPARATOR . $file), $find);
254
                    if (count($find)) {
255
                        return $return;
256
                    }
257
                } else {
258
                    // ignore parameter was just a pattern with no path delimiters
259
                    // check it against the path
260
                    preg_match('/^' . strtoupper($match).'$/', strtoupper($path), $find);
261
                    if (count($find)) {
262
                        return $return;
263
                    }
264
                    // check it against the file only
265
                    preg_match('/^' . strtoupper($match).'$/', strtoupper($file), $find);
266
                    if (count($find)) {
267
                        return $return;
268
                    }
269
                }
270
            }
271
        }
272
        return !$return;
273
    }
274
 
275
    /**
276
     * Construct the {@link $ignore} array
277
     * @param array strings of files/paths/wildcards to ignore
278
     * @param 0|1 0 = files to include, 1 = files to ignore
279
     * @access private
280
     */
281
    function _setupIgnore($ignore, $index)
282
    {
283
        $ig = array();
284
        if (is_array($ignore)) {
285
            for($i=0; $i<count($ignore);$i++) {
286
                $ignore[$i] = strtr($ignore[$i], "\\", "/");
287
                $ignore[$i] = str_replace('//','/',$ignore[$i]);
288
 
289
                if (!empty($ignore[$i])) {
290
                    if (!is_numeric(strpos($ignore[$i], '/'))) {
291
                        $ig[] = $this->_getRegExpableSearchString($ignore[$i]);
292
                    } else {
293
                        if (basename($ignore[$i]) . '/' == $ignore[$i]) {
294
                            $ig[] = $this->_getRegExpableSearchString($ignore[$i]);
295
                        } else {
296
                            $ig[] = array($this->_getRegExpableSearchString($ignore[$i]),
297
                                      $this->_getRegExpableSearchString(basename($ignore[$i])));
298
                        }
299
                    }
300
                }
301
            }
302
            if (count($ig)) {
303
                $this->ignore[$index] = $ig;
304
            } else {
305
                $this->ignore[$index] = false;
306
            }
307
        } else $this->ignore[$index] = false;
308
    }
309
 
310
    /**
311
     * Converts $s into a string that can be used with preg_match
312
     * @param string $s string with wildcards ? and *
313
     * @return string converts * to .*, ? to ., etc.
314
     * @access private
315
     */
316
    function _getRegExpableSearchString($s)
317
    {
318
        $y = '\/';
319
        if (DIRECTORY_SEPARATOR == '\\') {
320
            $y = '\\\\';
321
        }
322
        $s = str_replace('/', DIRECTORY_SEPARATOR, $s);
323
        $x = strtr($s, array('?' => '.','*' => '.*','.' => '\\.','\\' => '\\\\','/' => '\\/',
324
                                '[' => '\\[',']' => '\\]','-' => '\\-'));
325
        if (strpos($s, DIRECTORY_SEPARATOR) !== false &&
326
              strrpos($s, DIRECTORY_SEPARATOR) === strlen($s) - 1) {
327
            $x = "(?:.*$y$x?.*|$x.*)";
328
        }
329
        return $x;
330
    }
331
 
332
    /**
333
     * Recursively move contents of $struc into associative array
334
     *
335
     * The contents of $struc have many indexes like 'dir/subdir/subdir2'.
336
     * This function converts them to
337
     * array('dir' => array('subdir' => array('subdir2')))
338
     * @param array struc is array('dir' => array of files in dir,
339
     *              'dir/subdir' => array of files in dir/subdir,...)
340
     * @param array array form of 'dir/subdir/subdir2' array('dir','subdir','subdir2')
341
     * @return array same as struc but with array('dir' =>
342
     *              array(file1,file2,'subdir' => array(file1,...)))
343
     * @access private
344
     */
345
    function _setupDirs($struc, $dir, $contents)
346
    {
347
        if (!count($dir)) {
348
            foreach($contents as $dir => $files) {
349
                if (is_string($dir)) {
350
                    if (strpos($dir, '/')) {
351
                        $test = true;
352
                        $a = $contents[$dir];
353
                        unset($contents[$dir]);
354
                        $b = explode('/', $dir);
355
                        $c = array_shift($b);
356
                        if (isset($contents[$c])) {
357
                            $contents[$c] = $this->_setDir($contents[$c], $this->_setupDirs(array(), $b, $a));
358
                        } else {
359
                            $contents[$c] = $this->_setupDirs(array(), $b, $a);
360
                        }
361
                    }
362
                }
363
            }
364
            return $contents;
365
        }
366
        $me = array_shift($dir);
367
        if (!isset($struc[$me])) {
368
            $struc[$me] = array();
369
        }
370
        $struc[$me] = $this->_setupDirs($struc[$me], $dir, $contents);
371
        return $struc;
372
    }
373
 
374
 
375
    /**
376
     * Recursively add all the subdirectories of $contents to $dir without erasing anything in
377
     * $dir
378
     * @param array
379
     * @param array
380
     * @return array processed $dir
381
     * @access private
382
     */
383
    function _setDir($dir, $contents)
384
    {
385
        while(list($one,$two) = each($contents)) {
386
            if (isset($dir[$one])) {
387
                $dir[$one] = $this->_setDir($dir[$one], $contents[$one]);
388
            } else {
389
                $dir[$one] = $two;
390
            }
391
        }
392
        return $dir;
393
    }
394
 
395
 
396
    /**#@+
397
     * Sorting functions for the file list
398
     * @param string
399
     * @param string
400
     * @access private
401
     */
402
    function sortfiles($a, $b)
403
    {
404
        return strnatcasecmp($a['file'],$b['file']);
405
    }
406
 
407
    function mystrucsort($a, $b)
408
    {
409
        if (is_numeric($a) && is_string($b)) return 1;
410
        if (is_numeric($b) && is_string($a)) return -1;
411
        if (is_numeric($a) && is_numeric($b))
412
        {
413
            if ($a > $b) return 1;
414
            if ($a < $b) return -1;
415
            if ($a == $b) return 0;
416
        }
417
        return strnatcasecmp($a,$b);
418
    }
419
    /**#@-*/
420
}
421
?>