Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
//
3
// +----------------------------------------------------------------------+
4
// | PHP Version 4                                                        |
5
// +----------------------------------------------------------------------+
6
// | Copyright (c) 1997-2005 The PHP Group                                |
7
// +----------------------------------------------------------------------+
8
// | This source file is subject to version 2.02 of the PHP license,      |
9
// | that is bundled with this package in the file LICENSE, and is        |
10
// | available at through the world-wide-web at                           |
11
// | http://www.php.net/license/2_02.txt.                                 |
12
// | If you did not receive a copy of the PHP license and are unable to   |
13
// | obtain it through the world-wide-web, please send a note to          |
14
// | license@php.net so we can mail you a copy immediately.               |
15
// +----------------------------------------------------------------------+
16
// | Author: Sterling Hughes <sterling@php.net>                           |
17
// +----------------------------------------------------------------------+
18
//
19
// $Id: File_Find-1.3.0__Find.php,v 1.1 2008/06/28 13:04:01 farell Exp $
20
//
21
 
22
require_once 'PEAR.php';
23
 
24
define('FILE_FIND_VERSION', '@package_version@');
25
 
26
// to debug uncomment this string
27
// define('FILE_FIND_DEBUG', '');
28
 
29
/**
30
*  Commonly needed functions searching directory trees
31
*
32
* @access public
33
* @version $Id: File_Find-1.3.0__Find.php,v 1.1 2008/06/28 13:04:01 farell Exp $
34
* @package File
35
* @author Sterling Hughes <sterling@php.net>
36
*/
37
class File_Find
38
{
39
    /**
40
     * internal dir-list
41
     * @var array
42
     */
43
    var $_dirs = array();
44
 
45
    /**
46
     * directory separator
47
     * @var string
48
     */
49
    var $dirsep = "/";
50
 
51
    /**
52
     * found files
53
     * @var array
54
     */
55
    var $files = array();
56
 
57
    /**
58
     * found dirs
59
     * @var array
60
     */
61
    var $directories = array();
62
 
63
    /**
64
     * Search specified directory to find matches for specified pattern
65
     *
66
     * @param string $pattern a string containing the pattern to search
67
     * the directory for.
68
     *
69
     * @param string $dirpath a string containing the directory path
70
     * to search.
71
     *
72
     * @param string $pattern_type a string containing the type of
73
     * pattern matching functions to use (can either be 'php',
74
     * 'perl' or 'shell').
75
     *
76
     * @return array containing all of the files and directories
77
     * matching the pattern or null if no matches
78
     *
79
     * @author Sterling Hughes <sterling@php.net>
80
     * @access public
81
     * @static
82
     */
83
    function &glob($pattern, $dirpath, $pattern_type = 'php')
84
    {
85
        $dh = @opendir($dirpath);
86
 
87
        if (!$dh) {
88
            $pe = PEAR::raiseError("Cannot open directory $dirpath");
89
            return $pe;
90
        }
91
 
92
        $match_function = File_Find::_determineRegex($pattern, $pattern_type);
93
        $matches = array();
94
 
95
        // empty string cannot be specified for 'php' and 'perl' pattern
96
        if ($pattern || ($pattern_type != 'php' && $pattern_type != 'perl')) {
97
            while (false !== ($entry = @readdir($dh))) {
98
                if ($match_function($pattern, $entry) &&
99
                    $entry != '.' && $entry != '..') {
100
                    $matches[] = $entry;
101
                }
102
            }
103
        }
104
 
105
        @closedir($dh);
106
 
107
        if (0 == count($matches)) {
108
            $matches = null;
109
        }
110
 
111
        return $matches ;
112
    }
113
 
114
    /**
115
     * Map the directory tree given by the directory_path parameter.
116
     *
117
     * @param string $directory contains the directory path that you
118
     * want to map.
119
     *
120
     * @return array a two element array, the first element containing a list
121
     * of all the directories, the second element containing a list of all the
122
     * files.
123
     *
124
     * @author Sterling Hughes <sterling@php.net>
125
     * @access public
126
     */
127
    function &maptree($directory)
128
    {
129
 
130
        /* if called statically */
131
        if (!isset($this)  || !is_a($this, "File_Find")) {
132
            $obj = &new File_Find();
133
            return $obj->maptree($directory);
134
        }
135
 
136
        /* clear the results just in case */
137
        $this->files       = array();
138
        $this->directories = array();
139
 
140
        /* strip out trailing slashes */
141
        $directory = preg_replace('![\\\\/]+$!', '', $directory);
142
 
143
        $this->_dirs = array($directory);
144
 
145
        while (count($this->_dirs)) {
146
            $dir = array_pop($this->_dirs);
147
            File_Find::_build($dir, $this->dirsep);
148
            array_push($this->directories, $dir);
149
        }
150
 
151
        $retval = array($this->directories, $this->files);
152
        return $retval;
153
 
154
    }
155
 
156
    /**
157
     * Map the directory tree given by the directory parameter.
158
     *
159
     * @param string $directory contains the directory path that you
160
     * want to map.
161
     * @param integer $maxrecursion maximun number of folders to recursive
162
     * map
163
     *
164
     * @return array a multidimensional array containing all subdirectories
165
     * and their files. For example:
166
     *
167
     * Array
168
     * (
169
     *    [0] => file_1.php
170
     *    [1] => file_2.php
171
     *    [subdirname] => Array
172
     *       (
173
     *          [0] => file_1.php
174
     *       )
175
     * )
176
     *
177
     * @author Mika Tuupola <tuupola@appelsiini.net>
178
     * @access public
179
     * @static
180
     */
181
    function &mapTreeMultiple($directory, $maxrecursion = 0, $count = 0)
182
    {
183
        $retval = array();
184
 
185
        $count++;
186
 
187
        /* strip trailing slashes */
188
        $directory = preg_replace('![\\\\/]+$!', '', $directory);
189
 
190
        if (is_readable($directory)) {
191
            $dh = opendir($directory);
192
            while (false !== ($entry = @readdir($dh))) {
193
                if ($entry != '.' && $entry != '..') {
194
                     array_push($retval, $entry);
195
                }
196
            }
197
            closedir($dh);
198
        }
199
 
200
        while (list($key, $val) = each($retval)) {
201
            $path = $directory . "/" . $val;
202
 
203
            if (!is_array($val) && is_dir($path)) {
204
                unset($retval[$key]);
205
                if ($maxrecursion == 0 || $count < $maxrecursion) {
206
                    $retval[$val] = &File_Find::mapTreeMultiple($path,
207
                                    $maxrecursion, $count);
208
                }
209
            }
210
        }
211
 
212
        return $retval;
213
    }
214
 
215
    /**
216
     * Search the specified directory tree with the specified pattern.  Return
217
     * an array containing all matching files (no directories included).
218
     *
219
     * @param string $pattern the pattern to match every file with.
220
     *
221
     * @param string $directory the directory tree to search in.
222
     *
223
     * @param string $type the type of regular expression support to use, either
224
     * 'php', 'perl' or 'shell'.
225
     *
226
     * @param bool $fullpath whether the regex should be matched against the
227
     * full path or only against the filename
228
     *
229
     * @param string $match can be either 'files', 'dirs' or 'both' to specify
230
     * the kind of list to return
231
     *
232
     * @return array a list of files matching the pattern parameter in the the
233
     * directory path specified by the directory parameter
234
     *
235
     * @author Sterling Hughes <sterling@php.net>
236
     * @access public
237
     * @static
238
     */
239
    function &search($pattern, $directory, $type = 'php', $fullpath = true, $match = 'files')
240
    {
241
 
242
        $matches = array();
243
        list ($directories,$files)  = File_Find::maptree($directory);
244
        switch($match) {
245
            case 'directories':
246
                $data = $directories;
247
                break;
248
            case 'both':
249
                $data = array_merge($directories, $files);
250
                break;
251
            case 'files':
252
            default:
253
                $data = $files;
254
        }
255
        unset($files, $directories);
256
 
257
        $match_function = File_Find::_determineRegex($pattern, $type);
258
 
259
        reset($data);
260
        // check if empty string given (ok for 'shell' method, but bad for others)
261
        if ($pattern || ($type != 'php' && $type != 'perl')) {
262
            while (list(,$entry) = each($data)) {
263
                if ($match_function($pattern,
264
                                    $fullpath ? $entry : basename($entry))) {
265
                    $matches[] = $entry;
266
                }
267
            }
268
        }
269
 
270
        return $matches;
271
    }
272
 
273
    /**
274
     * Determine whether or not a variable is a PEAR error
275
     *
276
     * @param object PEAR_Error $var the variable to test.
277
     *
278
     * @return boolean returns true if the variable is a PEAR error, otherwise
279
     * it returns false.
280
     * @access public
281
     */
282
    function isError(&$var)
283
    {
284
        return PEAR::isError($var);
285
    }
286
 
287
    /**
288
     * internal function to build singular directory trees, used by
289
     * File_Find::maptree()
290
     *
291
     * @param string $directory name of the directory to read
292
     * @param string $separator directory separator
293
     * @return void
294
     */
295
    function _build($directory, $separator = "/")
296
    {
297
 
298
        $dh = @opendir($directory);
299
 
300
        if (!$dh) {
301
            $pe = PEAR::raiseError("Cannot open directory");
302
            return $pe;
303
        }
304
 
305
        while (false !== ($entry = @readdir($dh))) {
306
            if ($entry != '.' && $entry != '..') {
307
 
308
                $entry = $directory.$separator.$entry;
309
 
310
                if (is_dir($entry)) {
311
                    array_push($this->_dirs, $entry);
312
                } else {
313
                    array_push($this->files, $entry);
314
                }
315
            }
316
        }
317
 
318
        @closedir($dh);
319
    }
320
 
321
    /**
322
     * internal function to determine the type of regular expression to
323
     * use, implemented by File_Find::glob() and File_Find::search()
324
     *
325
     * @param string $type given RegExp type
326
     * @return string kind of function ( "eregi", "ereg" or "preg_match") ;
327
     *
328
     */
329
    function _determineRegex($pattern, $type)
330
    {
331
        if (!strcasecmp($type, 'shell')) {
332
            $match_function = 'File_Find_match_shell';
333
        } else if (!strcasecmp($type, 'perl')) {
334
            $match_function = 'preg_match';
335
        } else if (!strcasecmp(substr($pattern, -2), '/i')) {
336
            $match_function = 'eregi';
337
        } else {
338
            $match_function = 'ereg';
339
        }
340
        return $match_function;
341
    }
342
 
343
}
344
 
345
/**
346
* Package method to match via 'shell' pattern. Provided in global
347
* scope, because it should be called like 'preg_match' and 'eregi'
348
* and can be easily copied into other packages
349
*
350
* @author techtonik <techtonik@php.net>
351
* @return mixed bool on success and PEAR_Error on failure
352
*/
353
function File_Find_match_shell($pattern, $filename)
354
{
355
    // {{{ convert pattern to positive and negative regexps
356
        $positive = $pattern;
357
        $negation = substr_count($pattern, "|");
358
 
359
        if ($negation > 1) {
360
            PEAR::raiseError("Mask string contains errors!");
361
            return FALSE;
362
        } elseif ($negation) {
363
            list($positive, $negative) = explode("|", $pattern);
364
            if (strlen($negative) == 0) {
365
                PEAR::raiseError("File-mask string contains errors!");
366
                return FALSE;
367
            }
368
        }
369
 
370
       $positive = _File_Find_match_shell_get_pattern($positive);
371
       if ($negation) {
372
           $negative = _File_Find_match_shell_get_pattern($negative);
373
       }
374
    // }}} convert end
375
 
376
 
377
    if (defined("FILE_FIND_DEBUG")) {
378
        print("Method: $type\nPattern: $pattern\n Converted pattern:");
379
        print_r($positive);
380
        if (isset($negative)) print_r($negative);
381
    }
382
 
383
    if (!preg_match($positive, $filename)) {
384
        return FALSE;
385
    } else {
386
        if (isset($negative)
387
              && preg_match($negative, $filename)) {
388
            return FALSE;
389
        } else {
390
            return TRUE;
391
        }
392
    }
393
}
394
 
395
/**
396
* function used by File_Find_match_shell to convert 'shell' mask
397
* into pcre regexp. Some of the rules (see testcases for more):
398
*  escaping all special chars and replacing
399
*    . with \.
400
*    * with .*
401
*    ? with .{1}
402
*    also adding ^ and $ as the pattern matches whole filename
403
*
404
* @author techtonik <techtonik@php.net>
405
* @return string pcre regexp for preg_match
406
*/
407
function _File_Find_match_shell_get_pattern($mask) {
408
    // get array of several masks (if any) delimited by comma
409
    // do not touch commas in char class
410
    $premasks = preg_split("|(\[[^\]]+\])|", $mask, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY );
411
    if (defined("FILE_FIND_DEBUG")) {
412
        print("\nPremask: ");
413
        print_r($premasks);
414
    }
415
    $pi = 0;
416
    foreach($premasks as $pm) {
417
        if (!isset($masks[$pi])) $masks[$pi] = "";
418
        if ($pm{0} == '[' && $pm{strlen($pm)-1} == ']') {
419
            // strip commas from character class
420
            $masks[$pi] .= str_replace(",", "", $pm);
421
        } else {
422
            $tarr = explode(",", $pm);
423
            if (sizeof($tarr) == 1) {
424
                $masks[$pi] .= $pm;
425
            } else {
426
                foreach ($tarr as $te) {
427
                    $masks[$pi++] .= $te;
428
                    $masks[$pi] = "";
429
                }
430
                unset($masks[$pi--]);
431
            }
432
        }
433
    }
434
 
435
    // if empty string given return *.* pattern
436
    if (strlen($mask) == 0) return "!^.*$!";
437
 
438
    // convert to preg regexp
439
    $regexmask = implode("|", $masks);
440
    if (defined("FILE_FIND_DEBUG")) {
441
        print("regexMask step one(implode): $regexmask");
442
    }
443
    $regexmask = addcslashes($regexmask, '^$}!{)(\/.+');
444
    if (defined("FILE_FIND_DEBUG")) {
445
        print("\nregexMask step two(addcslashes): $regexmask");
446
    }
447
    $regexmask = preg_replace("!(\*|\?)!", ".$1", $regexmask);
448
    if (defined("FILE_FIND_DEBUG")) {
449
        print("\nregexMask step three(* ? -> .* .?): $regexmask");
450
    }
451
    // a special case '*.' at the end means that there is no extension
452
    $regexmask = preg_replace("!\.\*\\\.(\||$)!", "[^\.]*$1", $regexmask);
453
    // it is impossible to have dot at the end of filename
454
    $regexmask = preg_replace("!\\\.(\||$)!", "$1", $regexmask);
455
    // and .* at the end also means that there could be nothing at all
456
    //   (i.e. no dot at the end also)
457
    $regexmask = preg_replace("!\\\.\.\*(\||$)!", "(\\\\..*)?$1", $regexmask);
458
    if (defined("FILE_FIND_DEBUG")) {
459
        print("\nregexMask step two and half(*.$ \\..*$ .$ -> [^.]*$ .?.* $): $regexmask");
460
    }
461
    // if no extension supplied - add .* to match partially from filename start
462
    if (strpos($regexmask, "\\.") === FALSE) $regexmask .= ".*";
463
 
464
    // file mask match whole name - adding restrictions
465
    $regexmask = preg_replace("!(\|)!", '^'."$1".'$', $regexmask);
466
    $regexmask = '^'.$regexmask.'$';
467
    if (defined("FILE_FIND_DEBUG")) {
468
        print("\nregexMask step three(^ and $ to match whole name): $regexmask");
469
    }
470
    // wrap regex into ! since all ! are already escaped
471
    $regexmask = "!$regexmask!i";
472
    if (defined("FILE_FIND_DEBUG")) {
473
        print("\nWrapped regex: $regexmask\n");
474
    }
475
    return $regexmask;
476
}
477
 
478
/*
479
 * Local variables:
480
 * tab-width: 4
481
 * c-basic-offset: 4
482
 * End:
483
 */
484
 
485
?>