1 <?php rcs_id('$Id: FileFinder.php,v 1.21 2004-06-02 18:01:45 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);
50 * Unify used pathsep character.
51 * Accepts array of paths also.
52 * This might not work on Windows95 or FAT volumes. (not tested)
54 function slashifyPath ($path) {
55 return $this->forcePathSlashes($path, $this->_pathsep);
59 * Force using '/' as path seperator.
61 function forcePathSlashes ($path, $sep='/') {
62 if (is_array($path)) {
64 foreach ($path as $dir) { $result[] = $this->forcePathSlashes($dir,$sep); }
67 if (isWindows() or $this->_isOtherPathsep()) {
68 if (isMac()) $from = ":";
69 elseif (isWindows()) $from = "\\";
71 return strtr($path, $from, $sep);
78 * Try to include file.
80 * If file is found in the path, then the files directory is added
81 * to PHP's include_path (if it's not already there.) Then the
82 * file is include_once()'d.
84 * @param $file string File to include.
85 * @return bool True if file was successfully included.
87 function includeOnce ($file) {
88 if ( ($ret = @include_once($file)) )
91 if (!$this->_is_abs($file)) {
92 if ( ($dir = $this->_search_path($file)) && is_file($dir . $this->_pathsep . $file)) {
93 $this->_append_to_include_path($dir);
94 return include_once($file);
97 return $this->_not_found($file);
100 function _isOtherPathsep() {
101 return $this->_pathsep != '/';
105 * The system-dependent path-separator character.
106 * UNIX,WindowsNT,MacOSX: /
111 * @return string path_separator.
113 function _get_syspath_separator () {
114 if (!empty($this->_pathsep)) return $this->_pathsep;
115 elseif (isWindowsNT()) return "/"; // we can safely use '/'
116 elseif (isWindows()) return "\\"; // FAT might use '\'
117 elseif (isMac()) return ':'; // MacOsX is /
118 // VMS or LispM is really weird, we ignore it.
123 * The path-separator character of the given path.
124 * Windows accepts "/" also, but gets confused with mixed path_separators,
125 * e.g "C:\Apache\phpwiki/locale/button"
126 * > dir "C:\Apache\phpwiki/locale/button" =>
127 * Parameterformat nicht korrekt - "locale"
128 * So if there's any '\' in the path, either fix them to '/' (not in Win95 or FAT?)
129 * or use '\' for ours.
132 * @return string path_separator.
134 function _use_path_separator ($path) {
136 if (empty($path)) return "\\";
137 else return (strchr($path,"\\")) ? "\\" : '/';
139 if (empty($path)) return ":";
140 else return (strchr($path,":")) ? ":" : '/';
142 return $this->_get_syspath_separator();
147 * Determine if path is absolute.
150 * @param $path string Path.
151 * @return bool True if path is absolute.
153 function _is_abs($path) {
154 if (ereg('^/', $path)) return true;
155 elseif (isWindows() and (eregi('^[a-z]:[/\\]', $path))) return true;
160 * Strip ending '/' or '\' from path.
163 * @param $path string Path.
164 * @return bool New path (destructive)
166 function _strip_last_pathchar(&$path) {
168 if (substr($path,-1) == ':' or substr($path,-1) == "/")
169 $path = substr($path,0,-1);
171 if (substr($path,-1) == '/' or substr($path,-1) == "\\")
172 $path = substr($path,0,-1);
178 * Report a "file not found" error.
181 * @param $file string Name of missing file.
182 * @return bool false.
184 function _not_found($file) {
185 trigger_error(sprintf(_("%s: file not found"),$file), E_USER_ERROR);
191 * Search our path for a file.
194 * @param $file string File to find.
195 * @return string Directory which contains $file, or false.
197 function _search_path ($file) {
198 foreach ($this->_path as $dir) {
199 // ensure we use the same pathsep
200 if ($this->_isOtherPathsep()) {
201 $dir = $this->slashifyPath($dir);
202 $file = $this->slashifyPath($file);
203 if (file_exists($dir . $this->_pathsep . $file))
205 } elseif (@file_exists($dir . $this->_pathsep . $file))
212 * The system-dependent path-separator character. On UNIX systems,
213 * this character is ':'; on Win32 systems it is ';'.
215 * On Mac it cannot be : because this is the seperator there!
218 * @return string path_separator.
220 function _get_ini_separator () {
221 return isWindows() ? ';' : ':';
222 // return preg_match('/^Windows/', php_uname())
226 * Get the value of PHP's include_path.
229 * @return array Include path.
231 function _get_include_path() {
232 if (defined("INCLUDE_PATH"))
233 $path = INCLUDE_PATH;
235 $path = @get_cfg_var('include_path'); // FIXME: report warning
236 if (empty($path)) $path = @ini_get('include_path');
240 return explode($this->_get_ini_separator(), $this->slashifyPath($path));
244 * Add a directory to the end of PHP's include_path.
246 * The directory is appended only if it is not already listed in
250 * @param $dir string Directory to add.
252 function _append_to_include_path ($dir) {
253 $dir = $this->slashifyPath($dir);
254 if (!in_array($dir, $this->_path)) {
255 $this->_path[] = $dir;
256 //ini_set('include_path', implode(':', $path));
259 * Some (buggy) PHP's (notable SourceForge's PHP 4.0.6)
260 * sometimes don't seem to heed their include_path.
261 * I.e. sometimes a file is not found even though it seems to
262 * be in the current include_path. A simple
263 * ini_set('include_path', ini_get('include_path')) seems to
264 * be enough to fix the problem
266 * This following line should be in the above if-block, but we
267 * put it here, as it seems to work-around the bug.
269 ini_set('include_path', implode($this->_get_ini_separator(), $this->_path));
272 // Return all the possible shortened locale specifiers for the given locale.
273 // Most specific first.
274 // de_DE.iso8859-1@euro => de_DE.iso8859-1, de_DE, de
275 // This code might needed somewhere else also.
276 function locale_versions ($lang) {
277 // Try less specific versions of the locale
279 foreach (array('@', '.', '_') as $sep) {
280 if ( ($tail = strchr($lang, $sep)) )
281 $langs[] = substr($lang, 0, -strlen($tail));
287 * Try to figure out the appropriate value for $LANG.
290 *@return string The value of $LANG.
292 function _get_lang() {
293 if (!empty($GLOBALS['LANG']))
294 return $GLOBALS['LANG'];
296 foreach (array('LC_ALL', 'LC_MESSAGES', 'LC_RESPONSES') as $var) {
297 $lang = setlocale(constant($var), 0);
302 foreach (array('LC_ALL', 'LC_MESSAGES', 'LC_RESPONSES', 'LANG') as $var) {
303 $lang = getenv($var);
313 * A class for finding PEAR code.
315 * This is a subclass of FileFinder which searches a standard list of
316 * directories where PEAR code is likely to be installed.
321 * $pearFinder = new PearFileFinder;
322 * $pearFinder->includeOnce('DB.php');
325 * The above code will look for 'DB.php', if found, the directory in
326 * which it was found will be added to PHP's include_path, and the
327 * file will be included. (If the file is not found, and E_USER_ERROR
336 * @param $path array Where to look for PEAR library code.
337 * A good set of defaults is provided, so you can probably leave
338 * this parameter blank.
340 function PearFileFinder ($path = array()) {
341 $this->FileFinder(array_merge(
343 array('/usr/share/php4',
347 '/usr/local/share/php4',
348 '/usr/local/share/php',
349 '/usr/local/lib/php4',
350 '/usr/local/lib/php',
351 '/System/Library/PHP',
352 '/Apache/pear' // Windows
358 * Find PhpWiki localized files.
360 * This is a subclass of FileFinder which searches PHP's include_path
361 * for files. It looks first for "locale/$LANG/$file", then for
364 * If $LANG is something like "de_DE.iso8859-1@euro", this class will
365 * also search under various less specific variations like
366 * "de_DE.iso8859-1", "de_DE" and "de".
368 class LocalizedFileFinder
374 function LocalizedFileFinder () {
375 $this->_pathsep = $this->_get_syspath_separator();
376 $include_path = $this->_get_include_path();
379 $lang = $this->_get_lang();
380 assert(!empty($lang));
382 if ($locales = $this->locale_versions($lang)) {
383 foreach ($locales as $lang) {
384 if ($lang == 'C') $lang = 'en';
385 foreach ($include_path as $dir) {
386 $path[] = $this->slashifyPath($dir . "/locale/$lang");
390 $this->FileFinder(array_merge($path, $include_path));
395 * Find PhpWiki localized theme buttons.
397 * This is a subclass of FileFinder which searches PHP's include_path
398 * for files. It looks first for "buttons/$LANG/$file", then for
401 * If $LANG is something like "de_DE.iso8859-1@euro", this class will
402 * also search under various less specific variations like
403 * "de_DE.iso8859-1", "de_DE" and "de".
405 class LocalizedButtonFinder
411 function LocalizedButtonFinder () {
413 $this->_pathsep = $this->_get_syspath_separator();
414 $include_path = $this->_get_include_path();
417 $lang = $this->_get_lang();
418 assert(!empty($lang));
419 assert(!empty($Theme));
421 $langs = $this->locale_versions($lang);
423 foreach ($langs as $lang) {
424 if ($lang == 'C') $lang = 'en';
425 foreach ($include_path as $dir) {
426 $path[] = $this->slashifyPath($Theme->file("buttons/$lang"));
430 $this->FileFinder(array_merge($path, $include_path));
434 // Search PHP's include_path to find file or directory.
435 function FindFile ($file, $missing_okay = false, $slashify = false)
438 if (!isset($finder)) {
439 $finder = new FileFinder;
440 // remove "/lib" from dirname(__FILE__)
441 $wikidir = preg_replace('/.lib$/','',dirname(__FILE__));
442 $finder->_append_to_include_path($wikidir);
443 $finder->_append_to_include_path(dirname(__FILE__)."/pear");
444 // Don't override existing INCLUDE_PATH config.
445 if (!defined("INCLUDE_PATH"))
446 define("INCLUDE_PATH", implode($finder->_get_ini_separator(), $finder->_path));
448 $s = $finder->findFile($file, $missing_okay);
450 $s = $finder->slashifyPath($s);
454 // Search PHP's include_path to find file or directory.
455 // Searches for "locale/$LANG/$file", then for "$file".
456 function FindLocalizedFile ($file, $missing_okay = false, $re_init = false)
459 if ($re_init or !isset($finder))
460 $finder = new LocalizedFileFinder;
461 return $finder->findFile($file, $missing_okay);
464 function FindLocalizedButtonFile ($file, $missing_okay = false, $re_init = false)
466 static $buttonfinder;
467 if ($re_init or !isset($buttonfinder))
468 $buttonfinder = new LocalizedButtonFinder;
469 return $buttonfinder->findFile($file, $missing_okay);
473 * Prefixes with PHPWIKI_DIR and slashify.
474 * For example to unify with
475 * require_once dirname(__FILE__).'/lib/file.php'
476 * require_once 'lib/file.php' loading style.
477 * Doesn't expand "~" or symlinks yet. truename would be perfect.
479 * NormalizeLocalFileName("lib/config.php") => /home/user/phpwiki/lib/config.php
481 function NormalizeLocalFileName($file) {
483 if (!isset($finder)) {
484 $finder = new FileFinder;
486 // remove "/lib" from dirname(__FILE__)
487 if (defined("PHPWIKI_DIR")) $wikidir = PHPWIKI_DIR;
488 else $wikidir = preg_replace('/.lib$/','',dirname(__FILE__));
489 $wikidir = $finder->_strip_last_pathchar($wikidir);
490 $pathsep = $finder->_use_path_separator($wikidir);
491 // return PHPWIKI_DIR . "/" . $file;
492 return $finder->slashifyPath($wikidir . $pathsep . $file);
496 * Prefixes with DATA_PATH and slashify
498 function NormalizeWebFileName($file) {
500 if (!isset($finder)) {
501 $finder = new FileFinder;
503 if (defined("DATA_PATH")) {
504 $wikipath = DATA_PATH;
505 $wikipath = $finder->_strip_last_pathchar($wikipath);
507 return $finder->forcePathSlashes($wikipath);
509 return $finder->forcePathSlashes($wikipath . '/' . $file);
511 return $finder->forcePathSlashes($file);
515 function isWindows() {
517 if (isset($win)) return $win;
518 //return preg_match('/^Windows/', php_uname());
519 $win = (substr(PHP_OS,0,3) == 'WIN');
523 function isWindows95() {
525 if (isset($win95)) return $win95;
526 $win95 = isWindows() and !isWindowsNT();
530 function isWindowsNT() {
532 if (isset($winnt)) return $winnt;
533 // FIXME: Do this using PHP_OS instead of php_uname().
534 // $winnt = (PHP_OS == "WINNT"); // example from http://www.php.net/manual/en/ref.readline.php
535 if (function_usable('php_uname'))
536 $winnt = preg_match('/^Windows NT/', php_uname());
538 $winnt = false; // FIXME: punt.
543 * This is for the OLD Macintosh OS, NOT MacOSX or Darwin!
544 * This has really ugly pathname semantics.
545 * ":path" is relative, "Desktop:path" (I think) is absolute.
546 * FIXME: Please fix this someone. So far not supported.
549 return (substr(PHP_OS,0,9) == 'Macintosh'); // not tested!
552 // probably not needed, same behaviour as on unix.
553 function isCygwin() {
554 return (substr(PHP_OS,0,6) == 'CYGWIN');
557 // $Log: not supported by cvs2svn $
558 // Revision 1.20 2004/05/27 17:49:05 rurban
559 // renamed DB_Session to DbSession (in CVS also)
560 // added WikiDB->getParam and WikiDB->getAuthParam method to get rid of globals
561 // remove leading slash in error message
562 // added force_unlock parameter to File_Passwd (no return on stale locks)
563 // fixed adodb session AffectedRows
564 // added FileFinder helpers to unify local filenames and DATA_PATH names
565 // editpage.php: new edit toolbar javascript on ENABLE_EDIT_TOOLBAR
573 // c-hanging-comment-ender-p: nil
574 // indent-tabs-mode: nil