1 <?php rcs_id('$Id: FileFinder.php,v 1.18 2004-04-26 20:01:21 rurban Exp $');
3 require_once(dirname(__FILE__).'/stdlib.php');
5 // FIXME: make this work with non-unix (e.g. DOS) filenames.
8 * A class for finding files.
10 * This should really provided by pear. We don't want really to mess around
11 * with all the lousy systems. (WindowsNT, Win95, Mac, VMS, ...)
12 * But pear has only System and File, which do nothing.
13 * Anyway, in good PHP style we ignore the rest of the world and try to behave
14 * as on unix only. That means we use / as pathsep in all our constants.
18 var $_pathsep, $_path;
23 * @param $path array A list of directories in which to search for files.
25 function FileFinder ($path = false) {
26 $this->_pathsep = $this->_get_syspath_separator();
27 if (!isset($this->_path) and $path === false)
28 $path = $this->_get_include_path();
35 * @param $file string File to search for.
36 * @return string The filename (including path), if found, otherwise false.
38 function findFile ($file, $missing_okay = false) {
39 if ($this->_is_abs($file)) {
40 if (file_exists($file))
43 elseif ( ($dir = $this->_search_path($file)) ) {
44 return $dir . $this->_use_path_separator($dir) . $file;
46 return $missing_okay ? false : $this->_not_found($file);
49 function slashifyPath ($path) {
50 if (is_array($path)) {
52 foreach ($path as $dir) { $result[] = $this->slashifyPath($dir); }
55 if ($this->_isOtherPathsep())
56 return strtr($path,$this->_use_path_separator($path),'/');
63 * Try to include file.
65 * If file is found in the path, then the files directory is added
66 * to PHP's include_path (if it's not already there.) Then the
67 * file is include_once()'d.
69 * @param $file string File to include.
70 * @return bool True if file was successfully included.
72 function includeOnce ($file) {
73 if ( ($ret = @include_once($file)) )
76 if (!$this->_is_abs($file)) {
77 if ( ($dir = $this->_search_path($file)) && is_file("$dir/$file")) {
78 $this->_append_to_include_path($dir);
79 return include_once($file);
83 return $this->_not_found($file);
86 function _isOtherPathsep() {
87 return $this->_pathsep != '/';
91 * The system-dependent path-separator character.
92 * UNIX,WindowsNT,MacOSX: /
97 * @return string path_separator.
99 function _get_syspath_separator () {
100 if (!empty($this->_pathsep)) return $this->_pathsep;
101 elseif (isWindowsNT()) return '\\';
102 elseif (isWindows()) return '\\';
103 elseif (isMac()) return ':'; // MacOsX is /
104 // VMS or LispM is really weird, we ignore it.
109 * The path-separator character of the given path.
110 * Windows accepts / also, but gets confused with mixed path_separators,
111 * e.g "C:\Apache\phpwiki/locale/button"
112 * > dir C:\Apache\phpwiki/locale/button =>
113 * Parameterformat nicht korrekt - "locale"
114 * So if there's any \\ in the path, either fix them to / (not in Win95!)
115 * or use \\ for ours.
118 * @return string path_separator.
120 function _use_path_separator ($path) {
122 return (strchr($path,'\\')) ? '\\' : '/';
124 return $this->_get_syspath_separator();
129 * Determine if path is absolute.
132 * @param $path string Path.
133 * @return bool True if path is absolute.
135 function _is_abs($path) {
136 if (ereg('^/', $path)) return true;
137 elseif (isWindows() and (eregi('^[a-z]:[/\\]', $path))) return true;
142 * Report a "file not found" error.
145 * @param $file string Name of missing file.
146 * @return bool false.
148 function _not_found($file) {
149 trigger_error(sprintf(_("%s: file not found"),$file), E_USER_ERROR);
155 * Search our path for a file.
158 * @param $file string File to find.
159 * @return string Directory which contains $file, or false.
161 function _search_path ($file) {
162 foreach ($this->_path as $dir) {
163 // ensure we use the same pathsep
164 if ($this->_pathsep != '/') {
165 $dir = $this->slashifyPath($dir);
166 $file = $this->slashifyPath($file);
167 if (file_exists($dir . $this->_pathsep . $file))
169 } elseif (@file_exists("$dir/$file"))
176 * The system-dependent path-separator character. On UNIX systems,
177 * this character is ':'; on Win32 systems it is ';'.
179 * On Mac it cannot be : because this is the seperator there!
182 * @return string path_separator.
184 function _get_ini_separator () {
185 return isWindows() ? ';' : ':';
186 // return preg_match('/^Windows/', php_uname())
190 * Get the value of PHP's include_path.
193 * @return array Include path.
195 function _get_include_path() {
196 if (defined("INCLUDE_PATH"))
197 $path = INCLUDE_PATH;
199 $path = @get_cfg_var('include_path'); // FIXME: report warning
202 return explode($this->_get_ini_separator(), $this->slashifyPath($path));
206 * Add a directory to the end of PHP's include_path.
208 * The directory is appended only if it is not already listed in
212 * @param $dir string Directory to add.
214 function _append_to_include_path ($dir) {
215 $dir = $this->slashifyPath($dir);
216 if (!in_array($dir, $this->_path)) {
217 $this->_path[] = $dir;
218 //ini_set('include_path', implode(':', $path));
221 * Some (buggy) PHP's (notable SourceForge's PHP 4.0.6)
222 * sometimes don't seem to heed their include_path.
223 * I.e. sometimes a file is not found even though it seems to
224 * be in the current include_path. A simple
225 * ini_set('include_path', ini_get('include_path')) seems to
226 * be enough to fix the problem
228 * This following line should be in the above if-block, but we
229 * put it here, as it seems to work-around the bug.
231 ini_set('include_path', implode($this->_get_ini_separator(), $this->_path));
234 // Return all the possible shortened locale specifiers for the given locale.
235 // Most specific first.
236 // de_DE.iso8859-1@euro => de_DE.iso8859-1, de_DE, de
237 // This code might needed somewhere else also.
238 function locale_versions ($lang) {
239 // Try less specific versions of the locale
241 foreach (array('@', '.', '_') as $sep) {
242 if ( ($tail = strchr($lang, $sep)) )
243 $langs[] = substr($lang, 0, -strlen($tail));
249 * Try to figure out the appropriate value for $LANG.
252 *@return string The value of $LANG.
254 function _get_lang() {
255 if (!empty($GLOBALS['LANG']))
256 return $GLOBALS['LANG'];
258 foreach (array('LC_ALL', 'LC_MESSAGES', 'LC_RESPONSES') as $var) {
259 $lang = setlocale(constant($var), 0);
264 foreach (array('LC_ALL', 'LC_MESSAGES', 'LC_RESPONSES', 'LANG') as $var) {
265 $lang = getenv($var);
275 * A class for finding PEAR code.
277 * This is a subclass of FileFinder which searches a standard list of
278 * directories where PEAR code is likely to be installed.
283 * $pearFinder = new PearFileFinder;
284 * $pearFinder->includeOnce('DB.php');
287 * The above code will look for 'DB.php', if found, the directory in
288 * which it was found will be added to PHP's include_path, and the
289 * file will be included. (If the file is not found, and E_USER_ERROR
298 * @param $path array Where to look for PEAR library code.
299 * A good set of defaults is provided, so you can probably leave
300 * this parameter blank.
302 function PearFileFinder ($path = array()) {
303 $this->FileFinder(array_merge(
305 array('/usr/share/php4',
309 '/usr/local/share/php4',
310 '/usr/local/share/php',
311 '/usr/local/lib/php4',
312 '/usr/local/lib/php',
313 '/System/Library/PHP',
314 '/Apache/pear' // Windows
320 * Find PhpWiki localized files.
322 * This is a subclass of FileFinder which searches PHP's include_path
323 * for files. It looks first for "locale/$LANG/$file", then for
326 * If $LANG is something like "de_DE.iso8859-1@euro", this class will
327 * also search under various less specific variations like
328 * "de_DE.iso8859-1", "de_DE" and "de".
330 class LocalizedFileFinder
336 function LocalizedFileFinder () {
337 $this->_pathsep = $this->_get_syspath_separator();
338 $include_path = $this->_get_include_path();
341 $lang = $this->_get_lang();
342 assert(!empty($lang));
344 if ($locales = $this->locale_versions($lang))
345 foreach ($locales as $lang) {
346 if ($lang == 'C') $lang='en';
347 foreach ($include_path as $dir) {
348 $path[] = $this->slashifyPath($dir) . "/locale/$lang";
351 $this->FileFinder(array_merge($path, $include_path));
356 * Find PhpWiki localized theme buttons.
358 * This is a subclass of FileFinder which searches PHP's include_path
359 * for files. It looks first for "buttons/$LANG/$file", then for
362 * If $LANG is something like "de_DE.iso8859-1@euro", this class will
363 * also search under various less specific variations like
364 * "de_DE.iso8859-1", "de_DE" and "de".
366 class LocalizedButtonFinder
372 function LocalizedButtonFinder () {
374 $this->_pathsep = $this->_get_syspath_separator();
375 $include_path = $this->_get_include_path();
378 $lang = $this->_get_lang();
379 assert(!empty($lang));
380 assert(!empty($Theme));
382 $langs = $this->locale_versions($lang);
384 foreach ($langs as $lang) {
385 if ($lang == 'C') $lang='en';
386 foreach ($include_path as $dir) {
387 $path[] = $Theme->file("buttons/$lang");
391 $this->FileFinder(array_merge($path, $include_path));
395 // Search PHP's include_path to find file or directory.
396 function FindFile ($file, $missing_okay = false, $slashify = false)
399 if (!isset($finder)) {
400 $finder = new FileFinder;
401 // remove "/lib" from dirname(__FILE__)
402 $wikidir = preg_replace('/.lib$/','',dirname(__FILE__));
403 $finder->_append_to_include_path($wikidir);
404 $finder->_append_to_include_path(dirname(__FILE__)."/pear");
405 define("INCLUDE_PATH",implode($finder->_get_ini_separator(), $finder->_path));
407 $s = $finder->findFile($file, $missing_okay);
409 $s = $finder->slashifyPath($s);
413 // Search PHP's include_path to find file or directory.
414 // Searches for "locale/$LANG/$file", then for "$file".
415 function FindLocalizedFile ($file, $missing_okay = false, $re_init = false)
418 if ($re_init or !isset($finder))
419 $finder = new LocalizedFileFinder;
420 return $finder->findFile($file, $missing_okay);
423 function FindLocalizedButtonFile ($file, $missing_okay = false, $re_init = false)
425 static $buttonfinder;
426 if ($re_init or !isset($buttonfinder))
427 $buttonfinder = new LocalizedButtonFinder;
428 return $buttonfinder->findFile($file, $missing_okay);
431 function isWindows() {
433 if (isset($win)) return $win;
434 //return preg_match('/^Windows/', php_uname());
435 $win = (substr(PHP_OS,0,3) == 'WIN');
439 function isWindows95() {
441 if (isset($win95)) return $win95;
442 $win95 = isWindows() and !isWindowsNT();
446 function isWindowsNT() {
448 if (isset($winnt)) return $winnt;
449 // FIXME: Do this using PHP_OS instead of php_uname().
450 // $winnt = (PHP_OS == "WINNT"); // example from http://www.php.net/manual/en/ref.readline.php
451 if (function_usable('php_uname'))
452 $winnt = preg_match('/^Windows NT/', php_uname());
454 $winnt = false; // FIXME: punt.
458 // So far not supported. This has really ugly pathname semantics.
459 // :path is relative, Desktop:path (I think) is absolute. Please fix this someone.
461 return (substr(PHP_OS,0,3) == 'MAC'); // not tested!
464 // probably not needed, same behaviour as on unix.
465 function isCygwin() {
466 return (substr(PHP_OS,0,6) == 'CYGWIN');
473 // c-hanging-comment-ender-p: nil
474 // indent-tabs-mode: nil