]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/FileFinder.php
Fixed gettext problem with VIRTUAL_PATH scripts (Windows only probably)
[SourceForge/phpwiki.git] / lib / FileFinder.php
1 <?php rcs_id('$Id: FileFinder.php,v 1.15 2004-04-10 02:30:49 rurban Exp $');
2
3 require_once('lib/stdlib.php');
4
5 // FIXME: make this work with non-unix (e.g. DOS) filenames.
6
7 /**
8  * A class for finding files.
9  * 
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.
15  */
16 class FileFinder
17 {
18     var $_pathsep, $_path;
19
20     /**
21      * Constructor.
22      *
23      * @param $path array A list of directories in which to search for files.
24      */
25     function FileFinder ($path = false) {
26         $this->_pathsep = $this->_get_syspath_separator();
27         if ($path === false)
28             $path = $this->_get_include_path();
29         $this->_path = $path;
30     }
31
32     /**
33      * Find file.
34      *
35      * @param $file string File to search for.
36      * @return string The filename (including path), if found, otherwise false.
37      */
38     function findFile ($file, $missing_okay = false) {
39         if ($this->_is_abs($file)) {
40             if (file_exists($file))
41                 return $file;
42         }
43         elseif ( ($dir = $this->_search_path($file)) ) {
44             return $dir . $this->_use_path_separator($dir) . $file;
45         }
46         return $missing_okay ? false : $this->_not_found($file);
47     }
48
49     function slashifyPath ($path) {
50         if ($this->_isOtherPathsep())
51             return strtr($path,$this->_use_path_separator($path),'/');
52         else 
53             return $path;
54     }
55
56     /**
57      * Try to include file.
58      *
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.
62      *
63      * @param $file string File to include.
64      * @return bool True if file was successfully included.
65      */
66     function includeOnce ($file) {
67         if ( ($ret = @include_once($file)) )
68             return $ret;
69
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);
74             }
75         }
76
77         return $this->_not_found($file);
78     }
79
80     function _isOtherPathsep() {
81         return $this->_pathsep != '/';
82     }
83
84     /**
85      * The system-dependent path-separator character. 
86      * UNIX,WindowsNT,MacOSX: /
87      * Windows95: \
88      * Mac:       :
89      *
90      * @access private
91      * @return string path_separator.
92      */
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.
99         else return '/';
100     }
101
102     /**
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.
110      *
111      * @access private
112      * @return string path_separator.
113      */
114     function _use_path_separator ($path) {
115         if (isWindows95()) {
116             return (strchr($path,'\\')) ? '\\' : '/';
117         } else {
118             return $this->_get_syspath_separator();
119         }
120     }
121
122     /**
123      * Determine if path is absolute.
124      *
125      * @access private
126      * @param $path string Path.
127      * @return bool True if path is absolute. 
128      */
129     function _is_abs($path) {
130         if (ereg('^/', $path)) return true;
131         elseif (isWindows() and (eregi('^[a-z]:[/\\]', $path))) return true;
132         else return false;
133     }
134
135     /**
136      * Report a "file not found" error.
137      *
138      * @access private
139      * @param $file string Name of missing file.
140      * @return bool false.
141      */
142     function _not_found($file) {
143         trigger_error(sprintf(_("%s: file not found"),$file), E_USER_ERROR);
144         return false;
145     }
146
147
148     /**
149      * Search our path for a file.
150      *
151      * @access private
152      * @param $file string File to find.
153      * @return string Directory which contains $file, or false.
154      */
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))
162                     return $dir;
163             } elseif (@file_exists("$dir/$file"))
164                 return $dir;
165         }
166         return false;
167     }
168
169     /**
170      * The system-dependent path-separator character. On UNIX systems,
171      * this character is ':'; on Win32 systems it is ';'.
172      * Fixme:
173      * On Mac it cannot be : because this is the seperator there!
174      *
175      * @access private
176      * @return string path_separator.
177      */
178     function _get_ini_separator () {
179         return isWindows() ? ';' : ':';
180         // return preg_match('/^Windows/', php_uname()) 
181     }
182
183     /**
184      * Get the value of PHP's include_path.
185      *
186      * @access private
187      * @return array Include path.
188      */
189     function _get_include_path() {
190         $path = @ini_get('include_path'); // FIXME: report warning
191         if (empty($path))
192             $path = '.';
193         return explode($this->_get_ini_separator(), $this->slashifyPath($path));
194     }
195
196     /**
197      * Add a directory to the end of PHP's include_path.
198      *
199      * The directory is appended only if it is not already listed in
200      * the include_path.
201      *
202      * @access private
203      * @param $dir string Directory to add.
204      */
205     function _append_to_include_path ($dir) {
206         $path = $this->_get_include_path();
207         if (!in_array($dir, $path)) {
208             $path[] = $dir;
209             //ini_set('include_path', implode(':', $path));
210         }
211         /*
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
218          *
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.
221          */
222         ini_set('include_path', implode($this->_get_ini_separator(), $this->slashifyPath($path)));
223     }
224
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
231         $langs[] = $lang;
232         foreach (array('@', '.', '_') as $sep) {
233             if ( ($tail = strchr($lang, $sep)) )
234                 $langs[] = substr($lang, 0, -strlen($tail));
235         }
236         return $langs;
237     }
238
239     /**
240      * Try to figure out the appropriate value for $LANG.
241      *
242      *@access private
243      *@return string The value of $LANG.
244      */
245     function _get_lang() {
246         if (!empty($GLOBALS['LANG']))
247             return $GLOBALS['LANG'];
248
249         foreach (array('LC_ALL', 'LC_MESSAGES', 'LC_RESPONSES') as $var) {
250             $lang = setlocale(constant($var), 0);
251             if (!empty($lang))
252                 return $lang;
253         }
254             
255         foreach (array('LC_ALL', 'LC_MESSAGES', 'LC_RESPONSES', 'LANG') as $var) {
256             $lang = getenv($var);
257             if (!empty($lang))
258                 return $lang;
259         }
260
261         return "C";
262     }
263 }
264
265 /**
266  * A class for finding PEAR code.
267  *
268  * This is a subclass of FileFinder which searches a standard list of
269  * directories where PEAR code is likely to be installed.
270  *
271  * Example usage:
272  *
273  * <pre>
274  *   $pearFinder = new PearFileFinder;
275  *   $pearFinder->includeOnce('DB.php');
276  * </pre>
277  *
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
281  * will be thrown.)
282  */
283 class PearFileFinder
284     extends FileFinder
285 {
286     /**
287      * Constructor.
288      *
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.
292      */
293     function PearFileFinder ($path = array()) {
294         $this->FileFinder(array_merge(
295                           $path,
296                           array('/usr/share/php4',
297                                 '/usr/share/php',
298                                 '/usr/lib/php4',
299                                 '/usr/lib/php',
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
306                                 )));
307     }
308 }
309
310 /**
311  * Find PhpWiki localized files.
312  *
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
315  * "$file".
316  *
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".
320  */
321 class LocalizedFileFinder
322     extends FileFinder
323 {
324     /**
325      * Constructor.
326      */
327     function LocalizedFileFinder () {
328         $this->_pathsep = $this->_get_syspath_separator();
329         $include_path = $this->_get_include_path();
330         $path = array();
331
332         $lang = $this->_get_lang();
333         assert(!empty($lang));
334
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";
340             }
341           }
342         $this->FileFinder(array_merge($path, $include_path));
343     }
344 }
345
346 /**
347  * Find PhpWiki localized theme buttons.
348  *
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
351  * "$file".
352  *
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".
356  */
357 class LocalizedButtonFinder
358     extends FileFinder
359 {
360     /**
361      * Constructor.
362      */
363     function LocalizedButtonFinder () {
364         global $Theme;
365         $this->_pathsep = $this->_get_syspath_separator();
366         $include_path = $this->_get_include_path();
367         $path = array();
368
369         $lang = $this->_get_lang();
370         assert(!empty($lang));
371         assert(!empty($Theme));
372
373         $langs = $this->locale_versions($lang);
374
375         foreach ($langs as $lang) {
376             if ($lang == 'C') $lang='en';
377             foreach ($include_path as $dir) {
378                 $path[] = $Theme->file("buttons/$lang");
379             }
380         }
381
382         $this->FileFinder(array_merge($path, $include_path));
383     }
384
385 }
386
387 function isWindows() {
388     static $win;
389     if (isset($win)) return $win;
390     //return preg_match('/^Windows/', php_uname());
391     $win = (substr(PHP_OS,0,3) == 'WIN');
392     return $win;
393 }
394
395 function isWindows95() {
396     static $win95;
397     if (isset($win95)) return $win95;
398     $win95 = isWindows() and !isWindowsNT();
399     return $win95;
400 }
401
402 function isWindowsNT() {
403     static $winnt;
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());
409     else
410         $winnt = false;         // FIXME: punt.
411     return $winnt;
412 }
413
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.
416 function isMac() {
417     return (substr(PHP_OS,0,3) == 'MAC'); // not tested!
418 }
419
420 // probably not needed, same behaviour as on unix.
421 function isCygwin() {
422     return (substr(PHP_OS,0,6) == 'CYGWIN');
423 }
424
425 // Local Variables:
426 // mode: php
427 // tab-width: 8
428 // c-basic-offset: 4
429 // c-hanging-comment-ender-p: nil
430 // indent-tabs-mode: nil
431 // End:
432 ?>