PageRenderTime 25ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/limb/util/src/system/lmbFs.class.php

https://github.com/limb-php-framework/limb-app-buildman
PHP | 543 lines | 466 code | 53 blank | 24 comment | 70 complexity | 872068705ead28bb9f3b1f9fe94c4d0f MD5 | raw file
  1. <?php
  2. /**
  3. * Limb Web Application Framework
  4. *
  5. * @link http://limb-project.com
  6. *
  7. * @copyright Copyright &copy; 2004-2007 BIT
  8. * @license LGPL http://www.gnu.org/copyleft/lesser.html
  9. * @version $Id: lmbFs.class.php 5009 2007-02-08 15:37:31Z pachanga $
  10. * @package util
  11. */
  12. //inspired by EZpublish(http://ez.no), Dir class
  13. lmb_require(dirname(__FILE__) . '/lmbSys.class.php');
  14. lmb_require('limb/util/src/exception/lmbIOException.class.php');
  15. class lmbFs
  16. {
  17. const LOCAL = 1;
  18. const UNIX = 2;
  19. const DOS = 3;
  20. const WIN32_NET_PREFIX = '\\\\';
  21. static function safeWrite($file, $content, $perm=0664)
  22. {
  23. self :: mkdir(dirname($file));
  24. $tmp = tempnam(LIMB_VAR_DIR, '_');
  25. $fh = fopen($tmp, 'w');
  26. if($fh === false)
  27. {
  28. @unlink($tmp);
  29. throw new lmbIOException('could not open file for writing', array('file' => $file));
  30. }
  31. //just for safety
  32. @flock($fh, LOCK_EX);
  33. fwrite($fh, $content);
  34. @flock($fh, LOCK_UN);
  35. fclose($fh);
  36. if(lmbSys :: isWin32() && file_exists($file))
  37. @unlink($file);
  38. if(!@rename($tmp, $file))
  39. {
  40. @unlink($tmp);
  41. throw new lmbIOException('could not move file', array('src' => $tmp, 'file' => $file));
  42. }
  43. @chmod($file, $perm);
  44. if(file_exists($tmp))
  45. @unlink($tmp);
  46. }
  47. static function generateTempFile()
  48. {
  49. return tempnam(LIMB_VAR_DIR, 'p');
  50. }
  51. static function dirpath($path)
  52. {
  53. $path = self :: normalizePath($path);
  54. if(($dir_pos = strrpos($path, self :: separator())) !== false )
  55. return substr($path, 0, $dir_pos);
  56. return $path;
  57. }
  58. /**
  59. * Creates the directory $dir with permissions $perm.
  60. * If $parents is true it will create any missing parent directories,
  61. * just like 'mkdir -p'.
  62. */
  63. static function mkdir($dir, $perm=0777, $parents=true)
  64. {
  65. if(is_dir($dir))
  66. return;
  67. $dir = self :: normalizePath($dir);
  68. if(!$parents)
  69. {
  70. self :: _doMkdir($dir, $perm);
  71. return;
  72. }
  73. $separator = self :: separator();
  74. $path_elements = self :: explodePath($dir);
  75. if(count($path_elements) == 0)
  76. return;
  77. $index = self :: _getFirstExistingPathIndex($path_elements, $separator);
  78. if($index === false)
  79. {
  80. throw new lmbIOException('cant find first existent path', array('dir' => $dir));
  81. }
  82. $offset_path = '';
  83. for($i=0; $i < $index; $i++)
  84. {
  85. $offset_path .= $path_elements[$i] . $separator;
  86. }
  87. for($i=$index; $i < count($path_elements); $i++)
  88. {
  89. $offset_path .= $path_elements[$i] . $separator;
  90. self :: _doMkdir($offset_path, $perm);
  91. }
  92. }
  93. protected static function _getFirstExistingPathIndex($path_elements, $separator)
  94. {
  95. for($i=count($path_elements); $i > 0; $i--)
  96. {
  97. $path = implode($separator, $path_elements);
  98. if(is_dir($path))
  99. return $i;
  100. array_pop($path_elements);
  101. }
  102. if(self :: isPathAbsolute($path))
  103. return false;
  104. else
  105. return 0;
  106. }
  107. /**
  108. * Creates the directory $dir with permission $perm.
  109. */
  110. protected static function _doMkdir($dir, $perm)
  111. {
  112. if(is_dir($dir))
  113. return;
  114. if(self :: _hasWin32NetPrefix($dir))
  115. return;
  116. $oldumask = umask(0);
  117. if(!mkdir($dir, $perm))
  118. {
  119. umask($oldumask);
  120. throw new lmbIOException('failed to create directory', array('dir' => $dir));
  121. }
  122. umask($oldumask);
  123. }
  124. static function explodePath($path, $fs_type = self :: UNIX)
  125. {
  126. $path = self :: normalizePath($path, $fs_type);
  127. $separator = self :: separator($fs_type);
  128. $dir_elements = explode($separator, $path);
  129. if(sizeof($dir_elements) > 1 && $dir_elements[sizeof($dir_elements)-1] === '')
  130. array_pop($dir_elements);
  131. if(self :: _hasWin32NetPrefix($path))
  132. {
  133. array_shift($dir_elements);
  134. array_shift($dir_elements);
  135. $dir_elements[0] = self :: WIN32_NET_PREFIX . $dir_elements[0];
  136. }
  137. return $dir_elements;
  138. }
  139. static function joinPath($arr, $fs_type = self :: UNIX)
  140. {
  141. return implode(self :: separator($fs_type), $arr);
  142. }
  143. static function chop($path)
  144. {
  145. if(substr($path, -1) == '/' || substr($path, -1) == '\\')
  146. $path = substr($path, 0, -1);
  147. return $path;
  148. }
  149. static function rm($file)
  150. {
  151. if(!file_exists($file))
  152. return false;
  153. self :: _doRm(self :: normalizePath($file), self :: separator());
  154. clearstatcache();
  155. return true;
  156. }
  157. protected static function _doRm($item, $separator)
  158. {
  159. if(!is_dir($item))
  160. {
  161. if(!@unlink($item))
  162. throw new lmbIOException('failed to remove file', array('file' => $item));
  163. return;
  164. }
  165. if(!$handle = @opendir($item))
  166. throw new lmbIOException('failed to open directory', array('dir' => $item));
  167. while(($file = readdir($handle)) !== false)
  168. {
  169. if($file == '.' || $file == '..')
  170. continue;
  171. self :: _doRm($item . $separator . $file, $separator);
  172. }
  173. closedir($handle);
  174. if(!@rmdir($item))
  175. throw new lmbIOException('failed to remove directory', array('dir' => $item));
  176. }
  177. static function cp($src, $dest, $as_child = false, $include_regex = '', $exclude_regex = '', $include_hidden = false)
  178. {
  179. if(!is_dir($src))
  180. {
  181. if(@copy($src, $dest) === false)
  182. throw new lmbIOException('failed to copy file', array('src' => $src, 'dest' => $dest));
  183. return;
  184. }
  185. self :: mkdir($dest);
  186. $src = self :: normalizePath($src);
  187. $dest = self :: normalizePath($dest);
  188. $separator = self :: separator();
  189. if($as_child)
  190. {
  191. $separator_regex = preg_quote($separator);
  192. if(preg_match( "#^.+{$separator_regex}([^{$separator_regex}]+)$#", $src, $matches))
  193. {
  194. self :: _doMkdir($dest . $separator . $matches[1], 0777);
  195. $dest .= $separator . $matches[1];
  196. }
  197. else
  198. return false;
  199. }
  200. $items = self :: find($src, 'df', $include_regex, $exclude_regex, false, $include_hidden);
  201. $total_items = $items;
  202. while (count($items) > 0)
  203. {
  204. $current_items = $items;
  205. $items = array();
  206. foreach ($current_items as $item)
  207. {
  208. $full_path = $src . $separator . $item;
  209. if(is_file( $full_path))
  210. copy($full_path, $dest . $separator . $item);
  211. elseif (is_dir( $full_path))
  212. {
  213. self :: _doMkdir($dest . $separator . $item, 0777);
  214. $new_items = self :: find($full_path, 'df', $include_regex, $exclude_regex, $item, $include_hidden);
  215. $items = array_merge($items, $new_items);
  216. $total_items = array_merge($total_items, $new_items);
  217. unset($new_items);
  218. }
  219. }
  220. }
  221. if($total_items)
  222. clearstatcache();
  223. return $total_items;
  224. }
  225. static function ls($path)
  226. {
  227. if(!is_dir($path))
  228. return array();
  229. $files = array();
  230. $path = self :: normalizePath($path);
  231. if($handle = opendir($path))
  232. {
  233. while(($file = readdir($handle)) !== false)
  234. {
  235. if($file != '.' && $file != '..' )
  236. {
  237. $files[] = $file;
  238. }
  239. }
  240. closedir($handle);
  241. }
  242. return $files;
  243. }
  244. /**
  245. * Return the separator used between directories and files according to $type.
  246. */
  247. static function separator($type = lmbFs :: UNIX)
  248. {
  249. switch(self :: _concreteSeparatorType($type))
  250. {
  251. case self :: UNIX:
  252. return '/';
  253. case self :: DOS:
  254. return "\\";
  255. }
  256. }
  257. protected static function _concreteSeparatorType($type)
  258. {
  259. if($type == self :: LOCAL)
  260. {
  261. if(lmbSys :: isWin32())
  262. $type = self :: DOS;
  263. else
  264. $type = lmbFs :: UNIX;
  265. }
  266. return $type;
  267. }
  268. /**
  269. * Converts any directory separators found in $path, in both unix and dos style, into
  270. * the separator type specified by $to_type and returns it.
  271. */
  272. static function convertSeparators($path, $to_type = self :: UNIX)
  273. {
  274. $separator = self :: separator($to_type);
  275. return preg_replace("#[/\\\\]#", $separator, $path);
  276. }
  277. /**
  278. * Removes all unneeded directory separators and resolves any "."s and ".."s found in $path.
  279. *
  280. * For instance: "var/../lib/db" becomes "lib/db", while "../site/var" will not be changed.
  281. * Will also convert separators
  282. */
  283. static function normalizePath($path, $to_type = self :: UNIX)
  284. {
  285. $path = self :: convertSeparators($path, $to_type);
  286. $separator = self :: separator($to_type);
  287. $path = self :: _normalizeSeparators($path, $separator);
  288. $path_elements= explode($separator, $path);
  289. $newpath_elements= array();
  290. foreach($path_elements as $path_element)
  291. {
  292. if($path_element == '.')
  293. continue;
  294. if($path_element == '..' &&
  295. count($newpath_elements) > 0)
  296. array_pop($newpath_elements);
  297. else
  298. $newpath_elements[] = $path_element;
  299. }
  300. if(count( $newpath_elements) == 0)
  301. $newpath_elements[] = '.';
  302. $path = implode($separator, $newpath_elements);
  303. return rtrim($path, '/\\');
  304. }
  305. static function isPathRelative($path, $fs_type = self :: LOCAL)
  306. {
  307. return !self :: isPathAbsolute($path, $os_type);
  308. }
  309. static function isPathAbsolute($path, $fs_type = self :: LOCAL)
  310. {
  311. switch(self :: _concreteSeparatorType($fs_type))
  312. {
  313. case self :: UNIX:
  314. return $path{0} == '/';
  315. case self :: DOS:
  316. return $path{0} == '/' ||
  317. $path{0} == "\\" ||
  318. preg_match('~^[a-zA-Z]+:~', $path);
  319. }
  320. }
  321. protected static function _normalizeSeparators($path, $separator)
  322. {
  323. $quoted = preg_quote($separator);
  324. $clean_path = preg_replace( "~$quoted$quoted+~", $separator, $path);
  325. if(self :: _hasWin32NetPrefix($path))
  326. $clean_path = '\\' . $clean_path;
  327. return $clean_path;
  328. }
  329. protected static function _hasWin32NetPrefix($path)//ugly!!!
  330. {
  331. if(lmbSys :: isWin32() && strlen($path) > 2)
  332. {
  333. return (substr($path, 0, 2) == self :: WIN32_NET_PREFIX);
  334. }
  335. return false;
  336. }
  337. static function path($names, $include_end_separator=false, $type = self :: UNIX)
  338. {
  339. $separator = self :: separator($type);
  340. $path = implode($separator, $names);
  341. $path = self :: normalizePath($path, $type);
  342. $has_end_separator = (strlen($path) > 0 && $path[strlen($path) - 1] == $separator);
  343. if($include_end_separator && !$has_end_separator)
  344. $path .= $separator;
  345. elseif (!$include_end_separator && $has_end_separator)
  346. $path = substr($path, 0, strlen($path) - 1);
  347. return $path;
  348. }
  349. static function find($dir, $types = 'dfl', $include_regex = '', $exclude_regex = '', $add_path = true, $include_hidden = false)
  350. {
  351. $dir = self :: normalizePath($dir);
  352. $dir = self :: chop($dir);
  353. $items = array();
  354. $separator = self :: separator();
  355. if($handle = @opendir($dir))
  356. {
  357. while(($element = readdir($handle)) !== false)
  358. {
  359. if($element == '.' || $element == '..')
  360. continue;
  361. if(!$include_hidden && $element[0] == '.')
  362. continue;
  363. if($include_regex && !preg_match($include_regex, $element, $m))
  364. continue;
  365. if($exclude_regex && preg_match($exclude_regex, $element, $m))
  366. continue;
  367. if(is_dir($dir . $separator . $element) && strpos($types, 'd') === false)
  368. continue;
  369. if(is_link($dir . $separator . $element) && strpos($types, 'l') === false)
  370. continue;
  371. if(is_file( $dir . $separator . $element ) && strpos($types, 'f') === false)
  372. continue;
  373. if($add_path)
  374. {
  375. if(is_string($add_path))
  376. $items[] = $add_path . $separator . $element;
  377. else
  378. $items[] = $dir . $separator . $element;
  379. }
  380. else
  381. $items[] = $element;
  382. }
  383. closedir($handle);
  384. }
  385. sort($items);
  386. return $items;
  387. }
  388. static function findRecursive($path, $types = 'dfl', $include_regex = '', $exclude_regex = '', $add_path = true, $include_hidden = false)
  389. {
  390. return self :: walkDir($path,
  391. array('lmbFs', '_doFindRecursive'),
  392. array('types' => $types,
  393. 'include_regex' => $include_regex,
  394. 'exclude_regex' => $exclude_regex,
  395. 'add_path' => $add_path,
  396. 'include_hidden' => $include_hidden),
  397. true);
  398. }
  399. protected static function _doFindRecursive($dir, $file, $path, $params, &$return_params)
  400. {
  401. if(!is_dir($path))
  402. return;
  403. $items = self :: find($path,
  404. $params['types'],
  405. $params['include_regex'],
  406. $params['exclude_regex'],
  407. $params['add_path'],
  408. $params['include_hidden']);
  409. foreach($items as $item)
  410. $return_params[] = $item;
  411. }
  412. static function walkDir($dir, $function_def, $params=array(), $include_first=false)
  413. {
  414. $return_params = array();
  415. $separator = self :: separator();
  416. $dir = self :: normalizePath($dir);
  417. $dir = self :: chop($dir);
  418. $params['separator'] = $separator;
  419. self :: _doWalkDir($dir,
  420. $separator,
  421. $function_def,
  422. $return_params,
  423. $params,
  424. $include_first);
  425. return $return_params;
  426. }
  427. protected static function _doWalkDir($item, $separator, $function_def, &$return_params, $params, $include_first, $level=0)
  428. {
  429. if($level > 0 || ($level == 0 && $include_first))
  430. call_user_func_array($function_def, array('dir' => dirname($item),
  431. 'file' => basename($item),
  432. 'path' => $item,
  433. 'params' => $params,
  434. 'return_params' => &$return_params));
  435. if(!is_dir($item))
  436. return;
  437. $handle = opendir($item);
  438. while(($file = readdir($handle)) !== false)
  439. {
  440. if(($file == '.') || ($file == '..'))
  441. continue;
  442. self :: _doWalkDir($item . $separator . $file,
  443. $separator,
  444. $function_def,
  445. $return_params,
  446. $params,
  447. $level + 1);
  448. }
  449. closedir($handle);
  450. }
  451. }
  452. ?>