1 <?php rcs_id('$Id: FileFinder.php,v 1.14 2003-09-20 00:02:12 carstenklapp Exp $');
3 require_once('lib/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();
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 ($this->_isOtherPathsep())
51 return strtr($path,$this->_use_path_separator($path),'/');
57 * Try to include file.
59 * If file is found in the path, then the files directory is added
60 * to PHP's include_path (if it's not already there.) Then the
61 * file is include_once()'d.
63 * @param $file string File to include.
64 * @return bool True if file was successfully included.
66 function includeOnce ($file) {
67 if ( ($ret = @include_once($file)) )
70 if (!$this->_is_abs($file)) {
71 if ( ($dir = $this->_search_path($file)) && is_file("$dir/$file")) {
72 $this->_append_to_include_path($dir);
73 return include_once($file);
77 return $this->_not_found($file);
80 function _isOtherPathsep() {
81 return $this->_pathsep != '/';
85 * The system-dependent path-separator character.
86 * UNIX,WindowsNT,MacOSX: /
91 * @return string path_separator.
93 function _get_syspath_separator () {
94 if (!empty($this->_pathsep)) return $this->_pathsep;
95 elseif (isWindowsNT()) return '\\';
96 elseif (isWindows()) return '\\';
97 elseif (isMac()) return ':'; // MacOsX is /
98 // VMS or LispM is really weird, we ignore it.
103 * The path-separator character of the given path.
104 * Windows accepts / also, but gets confused with mixed path_separators,
105 * e.g "C:\Apache\phpwiki/locale/button"
106 * > dir C:\Apache\phpwiki/locale/button =>
107 * Parameterformat nicht korrekt - "locale"
108 * So if there's any \\ in the path, either fix them to / (not in Win95!)
109 * or use \\ for ours.
112 * @return string path_separator.
114 function _use_path_separator ($path) {
116 return (strchr($path,'\\')) ? '\\' : '/';
118 return $this->_get_syspath_separator();
123 * Determine if path is absolute.
126 * @param $path string Path.
127 * @return bool True if path is absolute.
129 function _is_abs($path) {
130 if (ereg('^/', $path)) return true;
131 elseif (isWindows() and (eregi('^[a-z]:[/\\]', $path))) return true;
136 * Report a "file not found" error.
139 * @param $file string Name of missing file.
140 * @return bool false.
142 function _not_found($file) {
143 trigger_error(sprintf(_("%s: file not found"),$file), E_USER_ERROR);
149 * Search our path for a file.
152 * @param $file string File to find.
153 * @return string Directory which contains $file, or false.
155 function _search_path ($file) {
156 foreach ($this->_path as $dir) {
157 // ensure we use the same pathsep
158 if ($this->_pathsep != '/') {
159 $dir = $this->slashifyPath($dir);
160 $file = $this->slashifyPath($file);
161 if (file_exists($dir . $this->_pathsep . $file))
163 } elseif (@file_exists("$dir/$file"))
170 * The system-dependent path-separator character. On UNIX systems,
171 * this character is ':'; on Win32 systems it is ';'.
173 * On Mac it cannot be : because this is the seperator there!
176 * @return string path_separator.
178 function _get_ini_separator () {
179 return isWindows() ? ';' : ':';
180 // return preg_match('/^Windows/', php_uname())
184 * Get the value of PHP's include_path.
187 * @return array Include path.
189 function _get_include_path() {
190 $path = @ini_get('include_path'); // FIXME: report warning
193 return explode($this->_get_ini_separator(), $this->slashifyPath($path));
197 * Add a directory to the end of PHP's include_path.
199 * The directory is appended only if it is not already listed in
203 * @param $dir string Directory to add.
205 function _append_to_include_path ($dir) {
206 $path = $this->_get_include_path();
207 if (!in_array($dir, $path)) {
209 //ini_set('include_path', implode(':', $path));
212 * Some (buggy) PHP's (notable SourceForge's PHP 4.0.6)
213 * sometimes don't seem to heed their include_path.
214 * I.e. sometimes a file is not found even though it seems to
215 * be in the current include_path. A simple
216 * ini_set('include_path', ini_get('include_path')) seems to
217 * be enough to fix the problem
219 * This following line should be in the above if-block, but we
220 * put it here, as it seems to work-around the bug.
222 ini_set('include_path', implode($this->_get_ini_separator(), $this->slashifyPath($path)));
225 // Return all the possible shortened locale specifiers for the given locale.
226 // Most specific first.
227 // de_DE.iso8859-1@euro => de_DE.iso8859-1, de_DE, de
228 // This code might needed somewhere else also.
229 function locale_versions ($lang) {
230 // Try less specific versions of the locale
232 foreach (array('@', '.', '_') as $sep) {
233 if ( ($tail = strchr($lang, $sep)) )
234 $langs[] = substr($lang, 0, -strlen($tail));
240 * Try to figure out the appropriate value for $LANG.
243 *@return string The value of $LANG.
245 function _get_lang() {
246 if (!empty($GLOBALS['LANG']))
247 return $GLOBALS['LANG'];
249 foreach (array('LC_ALL', 'LC_MESSAGES', 'LC_RESPONSES') as $var) {
250 $lang = setlocale($var, 0);
255 foreach (array('LC_ALL', 'LC_MESSAGES', 'LC_RESPONSES', 'LANG') as $var) {
256 $lang = getenv($var);
266 * A class for finding PEAR code.
268 * This is a subclass of FileFinder which searches a standard list of
269 * directories where PEAR code is likely to be installed.
274 * $pearFinder = new PearFileFinder;
275 * $pearFinder->includeOnce('DB.php');
278 * The above code will look for 'DB.php', if found, the directory in
279 * which it was found will be added to PHP's include_path, and the
280 * file will be included. (If the file is not found, and E_USER_ERROR
289 * @param $path array Where to look for PEAR library code.
290 * A good set of defaults is provided, so you can probably leave
291 * this parameter blank.
293 function PearFileFinder ($path = array()) {
294 $this->FileFinder(array_merge(
296 array('/usr/share/php4',
300 '/usr/local/share/php4',
301 '/usr/local/share/php',
302 '/usr/local/lib/php4',
303 '/usr/local/lib/php',
304 '/System/Library/PHP',
305 '/Apache/pear' // Windows
311 * Find PhpWiki localized files.
313 * This is a subclass of FileFinder which searches PHP's include_path
314 * for files. It looks first for "locale/$LANG/$file", then for
317 * If $LANG is something like "de_DE.iso8859-1@euro", this class will
318 * also search under various less specific variations like
319 * "de_DE.iso8859-1", "de_DE" and "de".
321 class LocalizedFileFinder
327 function LocalizedFileFinder () {
328 $this->_pathsep = $this->_get_syspath_separator();
329 $include_path = $this->_get_include_path();
332 $lang = $this->_get_lang();
333 assert(!empty($lang));
335 if ($locales = $this->locale_versions($lang))
336 foreach ($locales as $lang) {
337 if ($lang == 'C') $lang='en';
338 foreach ($include_path as $dir) {
339 $path[] = $this->slashifyPath($dir) . "/locale/$lang";
342 $this->FileFinder(array_merge($path, $include_path));
347 * Find PhpWiki localized theme buttons.
349 * This is a subclass of FileFinder which searches PHP's include_path
350 * for files. It looks first for "buttons/$LANG/$file", then for
353 * If $LANG is something like "de_DE.iso8859-1@euro", this class will
354 * also search under various less specific variations like
355 * "de_DE.iso8859-1", "de_DE" and "de".
357 class LocalizedButtonFinder
363 function LocalizedButtonFinder () {
365 $this->_pathsep = $this->_get_syspath_separator();
366 $include_path = $this->_get_include_path();
369 $lang = $this->_get_lang();
370 assert(!empty($lang));
371 assert(!empty($Theme));
373 $langs = $this->locale_versions($lang);
375 foreach ($langs as $lang) {
376 if ($lang == 'C') $lang='en';
377 foreach ($include_path as $dir) {
378 $path[] = $Theme->file("buttons/$lang");
382 $this->FileFinder(array_merge($path, $include_path));
387 function isWindows() {
389 if (isset($win)) return $win;
390 //return preg_match('/^Windows/', php_uname());
391 $win = (substr(PHP_OS,0,3) == 'WIN');
395 function isWindows95() {
397 if (isset($win95)) return $win95;
398 $win95 = isWindows() and !isWindowsNT();
402 function isWindowsNT() {
404 if (isset($winnt)) return $winnt;
405 // FIXME: Do this using PHP_OS instead of php_uname().
406 // $winnt = (PHP_OS == "WINNT"); // example from http://www.php.net/manual/en/ref.readline.php
407 if (function_usable('php_uname'))
408 $winnt = preg_match('/^Windows NT/', php_uname());
410 $winnt = false; // FIXME: punt.
414 // So far not supported. This has really ugly pathname semantics.
415 // :path is relative, Desktop:path (I think) is absolute. Please fix this someone.
417 return (substr(PHP_OS,0,3) == 'MAC'); // not tested!
420 // probably not needed, same behaviour as on unix.
421 function isCygwin() {
422 return (substr(PHP_OS,0,6) == 'CYGWIN');
429 // c-hanging-comment-ender-p: nil
430 // indent-tabs-mode: nil