Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
 
4
/**
5
 * File::Util
6
 *
7
 * PHP versions 4 and 5
8
 *
9
 * LICENSE: This source file is subject to version 3.0 of the PHP license
10
 * that is available through the world-wide-web at the following URI:
11
 * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
12
 * the PHP License and are unable to obtain it through the web, please
13
 * send a note to license@php.net so we can mail you a copy immediately.
14
 *
15
 * @category    File
16
 * @package     File
17
 * @author      Michael Wallner <mike@php.net>
18
 * @copyright   2004-2005 Michael Wallner
19
 * @license     http://www.php.net/license/3_0.txt  PHP License 3.0
20
 * @version     CVS: $Id: Util.php 309134 2011-03-12 16:45:50Z dufuz $
21
 * @link        http://pear.php.net/package/File
22
 */
23
 
24
/**#@+
25
 * Sorting Constants
26
 */
27
define('FILE_SORT_NONE',    0);
28
define('FILE_SORT_REVERSE', 1);
29
define('FILE_SORT_NAME',    2);
30
define('FILE_SORT_SIZE',    4);
31
define('FILE_SORT_DATE',    8);
32
define('FILE_SORT_RANDOM',  16);
33
/**#@-*/
34
 
35
/**#@+
36
 * Listing Constants
37
 */
38
define('FILE_LIST_FILES',   1);
39
define('FILE_LIST_DIRS',    2);
40
define('FILE_LIST_DOTS',    4);
41
define('FILE_LIST_ALL',     FILE_LIST_FILES | FILE_LIST_DIRS | FILE_LIST_DOTS);
42
/**#@-*/
43
 
44
/**
45
 * @ignore
46
 */
47
define('FILE_WIN32', defined('OS_WINDOWS') ? OS_WINDOWS : !strncasecmp(PHP_OS, 'win', 3));
48
 
49
/**
50
 * File_Util
51
 *
52
 * File and directory utility functions.
53
 *
54
 * @access  public
55
 * @static
56
 */
57
class File_Util
58
{
59
    /**
60
     * Returns a string path built from the array $pathParts. Where a join
61
     * occurs multiple separators are removed. Joins using the optional
62
     * separator, defaulting to the PHP DIRECTORY_SEPARATOR constant.
63
     *
64
     * @static
65
     * @access  public
66
     * @param   array   $parts Array containing the parts to be joined
67
     * @param   string  $separator The directory seperator
68
     */
69
    function buildPath($parts, $separator = DIRECTORY_SEPARATOR)
70
    {
71
        $qs = '/^'. preg_quote($separator, '/') .'+$/';
72
        for ($i = 0, $c = count($parts); $i < $c; $i++) {
73
            if (!strlen($parts[$i]) || preg_match($qs, $parts[$i])) {
74
                unset($parts[$i]);
75
            } elseif (0 == $i) {
76
                $parts[$i] = rtrim($parts[$i], $separator);
77
            } elseif ($c - 1 == $i) {
78
                $parts[$i] = ltrim($parts[$i], $separator);
79
            } else {
80
                $parts[$i] = trim($parts[$i], $separator);
81
            }
82
        }
83
        return implode($separator, $parts);
84
    }
85
 
86
    /**
87
     * Returns a path without leading / or C:\. If this is not
88
     * present the path is returned as is.
89
     *
90
     * @static
91
     * @access  public
92
     * @param   string  $path The path to be processed
93
     * @return  string  The processed path or the path as is
94
     */
95
    function skipRoot($path)
96
    {
97
        if (File_Util::isAbsolute($path)) {
98
            if (FILE_WIN32) {
99
                return substr($path, $path{3} == '\\' ? 4 : 3);
100
            }
101
            return ltrim($path, '/');
102
        }
103
        return $path;
104
    }
105
 
106
    /**
107
     * Returns the temp directory according to either the TMP, TMPDIR, or
108
     * TEMP env variables. If these are not set it will also check for the
109
     * existence of /tmp, %WINDIR%\temp
110
     *
111
     * @static
112
     * @access  public
113
     * @return  string  The system tmp directory
114
     */
115
    function tmpDir()
116
    {
117
        if (FILE_WIN32) {
118
            if (isset($_ENV['TEMP'])) {
119
                return $_ENV['TEMP'];
120
            }
121
            if (isset($_ENV['TMP'])) {
122
                return $_ENV['TMP'];
123
            }
124
            if (isset($_ENV['windir'])) {
125
                return $_ENV['windir'] . '\\temp';
126
            }
127
            if (isset($_ENV['SystemRoot'])) {
128
                return $_ENV['SystemRoot'] . '\\temp';
129
            }
130
            if (isset($_SERVER['TEMP'])) {
131
                return $_SERVER['TEMP'];
132
            }
133
            if (isset($_SERVER['TMP'])) {
134
                return $_SERVER['TMP'];
135
            }
136
            if (isset($_SERVER['windir'])) {
137
                return $_SERVER['windir'] . '\\temp';
138
            }
139
            if (isset($_SERVER['SystemRoot'])) {
140
                return $_SERVER['SystemRoot'] . '\\temp';
141
            }
142
            return '\temp';
143
        }
144
        if (isset($_ENV['TMPDIR'])) {
145
            return $_ENV['TMPDIR'];
146
        }
147
        if (isset($_SERVER['TMPDIR'])) {
148
            return $_SERVER['TMPDIR'];
149
        }
150
        return '/tmp';
151
    }
152
 
153
    /**
154
     * Returns a temporary filename using tempnam() and File::tmpDir().
155
     *
156
     * @static
157
     * @access  public
158
     * @param   string  $dirname Optional directory name for the tmp file
159
     * @return  string  Filename and path of the tmp file
160
     */
161
    function tmpFile($dirname = null)
162
    {
163
        if (!isset($dirname)) {
164
            $dirname = File_Util::tmpDir();
165
        }
166
        return tempnam($dirname, 'temp.');
167
    }
168
 
169
    /**
170
     * Returns boolean based on whether given path is absolute or not.
171
     *
172
     * @static
173
     * @access  public
174
     * @param   string  $path Given path
175
     * @return  boolean True if the path is absolute, false if it is not
176
     */
177
    function isAbsolute($path)
178
    {
179
        if (preg_match('/(?:\/|\\\)\.\.(?=\/|$)/', $path)) {
180
            return false;
181
        }
182
        if (FILE_WIN32) {
183
            return (($path{0} == '/') ||  preg_match('/^[a-zA-Z]:(\\\|\/)/', $path));
184
        }
185
        return ($path{0} == '/') || ($path{0} == '~');
186
    }
187
 
188
    /**
189
     * Checks for a file's existence, taking the current include path
190
     * into consideration
191
     *
192
     * This method can be called statically
193
     * (e.g., File_Util::isIncludable('config.php'))
194
     *
195
     * @param string $file
196
     * @param string $sep the directory separator (optional)
197
     * @return string the includable path
198
     * @access public
199
     * @static
200
     */
201
    function isIncludable($file, $sep = DIRECTORY_SEPARATOR)
202
    {
203
        foreach ((array) explode(PATH_SEPARATOR, ini_get('include_path')) as $path) {
204
            if (file_exists($path .= $sep . $file)) {
205
                return $path;
206
            }
207
        }
208
        if (file_exists($file)) {
209
            return $file;
210
        }
211
        return null;
212
    }
213
 
214
    /**
215
     * Get path relative to another path
216
     *
217
     * @static
218
     * @access  public
219
     * @return  string
220
     * @param   string  $path
221
     * @param   string  $root
222
     * @param   string  $separator
223
     */
224
    function relativePath($path, $root, $separator = DIRECTORY_SEPARATOR)
225
    {
226
        $path = File_Util::realpath($path, $separator);
227
        $root = File_Util::realpath($root, $separator);
228
        $dirs = explode($separator, $path);
229
        $comp = explode($separator, $root);
230
 
231
        if (FILE_WIN32) {
232
            if (strcasecmp($dirs[0], $comp[0])) {
233
                return $path;
234
            }
235
            unset($dirs[0], $comp[0]);
236
        }
237
 
238
        foreach ($comp as $i => $part) {
239
            if (isset($dirs[$i]) && $part == $dirs[$i]) {
240
                unset($dirs[$i], $comp[$i]);
241
            } else {
242
                break;
243
            }
244
        }
245
 
246
        return str_repeat('..' . $separator, count($comp)) . implode($separator, $dirs);
247
    }
248
 
249
    /**
250
     * Get real path (works with non-existant paths)
251
     *
252
     * @static
253
     * @access  public
254
     * @return  string
255
     * @param   string  $path
256
     * @param   string  $separator
257
     */
258
    function realPath($path, $separator = DIRECTORY_SEPARATOR)
259
    {
260
        if (!strlen($path)) {
261
            return $separator;
262
        }
263
 
264
        $drive = '';
265
        $path = preg_replace('/[\\\\\/]/', $separator, $path);
266
        if (FILE_WIN32) {
267
            if (preg_match('/([a-zA-Z]\:)(.*)/', $path, $matches)) {
268
                $drive = $matches[1];
269
                $path  = $matches[2];
270
            } else {
271
                $cwd   = getcwd();
272
                $drive = substr($cwd, 0, 2);
273
                if ($path{0} !== $separator{0}) {
274
                    $path  = substr($cwd, 3) . $separator . $path;
275
                }
276
            }
277
        } elseif ($path{0} !== $separator) {
278
            $path = getcwd() . $separator . $path;
279
        }
280
 
281
        $dirStack = array();
282
        foreach (explode($separator, $path) as $dir) {
283
            if (strlen($dir) && $dir !== '.') {
284
                if ($dir == '..') {
285
                    array_pop($dirStack);
286
                } else {
287
                    $dirStack[] = $dir;
288
                }
289
            }
290
        }
291
 
292
        return $drive . $separator . implode($separator, $dirStack);
293
    }
294
 
295
    /**
296
     * Check whether path is in root path
297
     *
298
     * @static
299
     * @access  public
300
     * @return  bool
301
     * @param   string  $path
302
     * @param   string  $root
303
     */
304
    function pathInRoot($path, $root)
305
    {
306
        static $realPaths = array();
307
 
308
        if (!isset($realPaths[$root])) {
309
            $realPaths[$root] = File_Util::realPath($root);
310
        }
311
 
312
        return false !== strstr(File_Util::realPath($path), $realPaths[$root]);
313
    }
314
 
315
    /**
316
     * List Directory
317
     *
318
     * The final argument, $cb, is a callback that either evaluates to true or
319
     * false and performs a filter operation, or it can also modify the
320
     * directory/file names returned.  To achieve the latter effect use as
321
     * follows:
322
     *
323
     * <code>
324
     * <?php
325
     * function uc(&$filename) {
326
     *     $filename = strtoupper($filename);
327
     *     return true;
328
     * }
329
     * $entries = File_Util::listDir('.', FILE_LIST_ALL, FILE_SORT_NONE, 'uc');
330
     * foreach ($entries as $e) {
331
     *     echo $e->name, "\n";
332
     * }
333
     * ?>
334
     * </code>
335
     *
336
     * @static
337
     * @access  public
338
     * @return  array
339
     * @param   string  $path
340
     * @param   int     $list
341
     * @param   int     $sort
342
     * @param   mixed   $cb
343
     */
344
    function listDir($path, $list = FILE_LIST_ALL, $sort = FILE_SORT_NONE, $cb = null)
345
    {
346
        if (!strlen($path) || !is_dir($path)) {
347
            return null;
348
        }
349
 
350
        $entries = array();
351
        for ($dir = dir($path); false !== $entry = $dir->read(); ) {
352
            if ($list & FILE_LIST_DOTS || $entry{0} !== '.') {
353
                $isRef = ($entry === '.' || $entry === '..');
354
                $isDir = $isRef || is_dir($path .'/'. $entry);
355
                if (    ((!$isDir && $list & FILE_LIST_FILES)   ||
356
                         ($isDir  && $list & FILE_LIST_DIRS))   &&
357
                        (!is_callable($cb) ||
358
                            call_user_func_array($cb, array(&$entry)))) {
359
                    $entries[] = (object) array(
360
                        'name'  => $entry,
361
                        'size'  => $isDir ? null : filesize($path .'/'. $entry),
362
                        'date'  => filemtime($path .'/'. $entry),
363
                    );
364
                }
365
            }
366
        }
367
        $dir->close();
368
 
369
        if ($sort) {
370
            $entries = File_Util::sortFiles($entries, $sort);
371
        }
372
 
373
        return $entries;
374
    }
375
 
376
    /**
377
     * Sort Files
378
     *
379
     * @static
380
     * @access  public
381
     * @return  array
382
     * @param   array   $files
383
     * @param   int     $sort
384
     */
385
    function sortFiles($files, $sort)
386
    {
387
        if (!$files) {
388
            return array();
389
        }
390
 
391
        if (!$sort) {
392
            return $files;
393
        }
394
 
395
        if ($sort === 1) {
396
            return array_reverse($files);
397
        }
398
 
399
        if ($sort & FILE_SORT_RANDOM) {
400
            shuffle($files);
401
            return $files;
402
        }
403
 
404
        $names = array();
405
        $sizes = array();
406
        $dates = array();
407
 
408
        if ($sort & FILE_SORT_NAME) {
409
            $r = &$names;
410
        } elseif ($sort & FILE_SORT_DATE) {
411
            $r = &$dates;
412
        } elseif ($sort & FILE_SORT_SIZE) {
413
            $r = &$sizes;
414
        } else {
415
            asort($files, SORT_REGULAR);
416
            return $files;
417
        }
418
 
419
        $sortFlags = array(
420
            FILE_SORT_NAME => SORT_STRING,
421
            FILE_SORT_DATE => SORT_NUMERIC,
422
            FILE_SORT_SIZE => SORT_NUMERIC,
423
        );
424
 
425
        foreach ($files as $file) {
426
            $names[] = $file->name;
427
            $sizes[] = $file->size;
428
            $dates[] = $file->date;
429
        }
430
 
431
        if ($sort & FILE_SORT_REVERSE) {
432
            arsort($r, $sortFlags[$sort & ~1]);
433
        } else {
434
            asort($r, $sortFlags[$sort]);
435
        }
436
 
437
        $result = array();
438
        foreach ($r as $i => $f) {
439
            $result[] = $files[$i];
440
        }
441
 
442
        return $result;
443
    }
444
 
445
    /**
446
     * Switch File Extension
447
     *
448
     * @static
449
     * @access  public
450
     * @return  string|array
451
     * @param   string|array    $filename
452
     * @param   string          $to new file extension
453
     * @param   string          $from change only files with this extension
454
     * @param   bool            $reverse change only files not having $from extension
455
     */
456
    function switchExt($filename, $to, $from = null, $reverse = false)
457
    {
458
        if (is_array($filename)) {
459
            foreach ($filename as $key => $file) {
460
                $filename[$key] = File_Util::switchExt($file, $to, $from);
461
            }
462
            return $filename;
463
        }
464
 
465
        if ($len = strlen($from)) {
466
            $ext = substr($filename, -$len - 1);
467
            $cfn = FILE_WIN32 ? 'strcasecmp' : 'strcmp';
468
            if (!$reverse == $cfn($ext, '.'. $from)) {
469
                return $filename;
470
            }
471
            return substr($filename, 0, -$len - 1) .'.'. $to;
472
        }
473
 
474
        if ($pos = strpos($filename, '.')) {
475
            return substr($filename, 0, $pos) .'.'. $to;
476
        }
477
 
478
        return $filename .'.'. $to;
479
    }
480
 
481
    /**
482
     * Returns the filesize using a prefix like "kilo", "mebi" or "giga"
483
     *
484
     * @author Christian Weiske <cweiske@cweiske.de>
485
     *
486
     * @param integer $size       The size to convert
487
     * @param integer $decimals   The number of decimals to use
488
     * @param boolean $long       Use long names (kilobyte) instead of
489
     *                            short ones (kB)
490
     * @param boolean $oldStyle   If the old style should be used
491
     * @param boolean $useBiBytes If the "BiBytes" names should be
492
     *                            used [applies only to !$bOldStyle]
493
     *
494
     * @return string The filesize in human readable format
495
     *
496
     * @static
497
     */
498
    function prefixed(
499
        $size, $decimals = 1, $long = false, $oldStyle = true,
500
        $useBiBytes = true
501
    ) {
502
        $base  = ($oldStyle || $useBiBytes) ? 1024 : 1000;
503
        $names = array(
504
            '', 'kilo', 'mega', 'giga', 'tera',
505
             'peta', 'exa', 'zetta', 'yotta'
506
        );
507
        $max   = count($names) - 1;
508
 
509
        for ($a = 0; $size >= $base && $a < $max; $a++) {
510
            $size /= $base;
511
        }
512
 
513
        $name = ($oldStyle || !$useBiBytes)
514
            ? $names[$a]
515
            : $names[$a] . 'bi';
516
        if (!$long) {
517
            $name = $oldStyle || !$useBiBytes
518
                ? strtoupper(substr($name, 0, 1))
519
                : strtoupper(substr($name, 0, 1)) . 'i';
520
            $name .= 'B';
521
        } else {
522
            $name .= $size == 1 ? 'byte' : 'bytes';
523
        }
524
 
525
        return round($size, $decimals) . ' ' . $name;
526
    }
527
 
528
}