/system/src/Grav/Common/Filesystem/Folder.php

https://github.com/810/grav · PHP · 221 lines · 195 code · 5 blank · 21 comment · 2 complexity · d9df5f18f4b8980dac0cd7b156499ad0 MD5 · raw file

  1. <?php
  2. namespace Grav\Common\Filesystem;
  3. /**
  4. * Folder helper class.
  5. *
  6. * @author RocketTheme
  7. * @license MIT
  8. */
  9. abstract class Folder
  10. {
  11. /**
  12. * Recursively find the last modified time under given path.
  13. *
  14. * @param string $path
  15. * @return int
  16. */
  17. public static function lastModified($path)
  18. {
  19. $directory = new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS);
  20. $iterator = new \RecursiveIteratorIterator($directory, \RecursiveIteratorIterator::SELF_FIRST);
  21. $last_modified = 0;
  22. /** @var \RecursiveDirectoryIterator $file */
  23. foreach ($iterator as $file) {
  24. $dir_modified = $file->getMTime();
  25. if ($dir_modified > $last_modified) {
  26. $last_modified = $dir_modified;
  27. }
  28. }
  29. return $last_modified;
  30. }
  31. /**
  32. * Return recursive list of all files and directories under given path.
  33. *
  34. * @param string $path
  35. * @param array $params
  36. * @return array
  37. * @throws \RuntimeException
  38. */
  39. public static function all($path, array $params = array())
  40. {
  41. $path = realpath($path);
  42. if ($path === false) {
  43. throw new \RuntimeException("Path to {$path} doesn't exist.");
  44. }
  45. $compare = $params['compare'] ? 'get' . $params['compare'] : null;
  46. $pattern = $params['pattern'] ? $params['pattern'] : null;
  47. $filters = $params['filters'] ? $params['filters'] : null;
  48. $key = $params['key'] ? 'get' . $params['key'] : null;
  49. $value = $params['value'] ? 'get' . $params['value'] : 'SubPathname';
  50. $directory = new \RecursiveDirectoryIterator($path,
  51. \RecursiveDirectoryIterator::SKIP_DOTS + \FilesystemIterator::UNIX_PATHS + \FilesystemIterator::CURRENT_AS_SELF);
  52. $iterator = new \RecursiveIteratorIterator($directory, \RecursiveIteratorIterator::SELF_FIRST);
  53. $results = array();
  54. /** @var \RecursiveDirectoryIterator $file */
  55. foreach ($iterator as $file) {
  56. if ($compare && $pattern && !preg_match($pattern, $file->{$compare}())) {
  57. continue;
  58. }
  59. $fileKey = $key ? $file->{$key}() : null;
  60. $filePath = $file->{$value}();
  61. if ($filters) {
  62. if (isset($filters['key'])) {
  63. $fileKey = preg_replace($filters['key'], '', $fileKey);
  64. }
  65. if (isset($filters['value'])) {
  66. $filePath = preg_replace($filters['value'], '', $filePath);
  67. }
  68. }
  69. $results[$fileKey] = $filePath;
  70. }
  71. return $results;
  72. }
  73. /**
  74. * Recursively copy directory in filesystem.
  75. *
  76. * @param string $source
  77. * @param string $target
  78. * @throws \RuntimeException
  79. */
  80. public static function copy($source, $target)
  81. {
  82. $source = rtrim($source, '\\/');
  83. $target = rtrim($target, '\\/');
  84. if (!is_dir($source)) {
  85. throw new \RuntimeException('Cannot copy non-existing folder.');
  86. }
  87. // Make sure that path to the target exists before copying.
  88. self::mkdir($target);
  89. $success = true;
  90. // Go through all sub-directories and copy everything.
  91. $files = self::all($source);
  92. foreach ($files as $file) {
  93. $src = $source .'/'. $file;
  94. $dst = $target .'/'. $file;
  95. if (is_dir($src)) {
  96. // Create current directory.
  97. $success &= @mkdir($dst);
  98. } else {
  99. // Or copy current file.
  100. $success &= @copy($src, $dst);
  101. }
  102. }
  103. if (!$success) {
  104. $error = error_get_last();
  105. throw new \RuntimeException($error['message']);
  106. }
  107. // Make sure that the change will be detected when caching.
  108. @touch(dirname($target));
  109. }
  110. /**
  111. * Move directory in filesystem.
  112. *
  113. * @param string $source
  114. * @param string $target
  115. * @throws \RuntimeException
  116. */
  117. public static function move($source, $target)
  118. {
  119. if (!is_dir($source)) {
  120. throw new \RuntimeException('Cannot move non-existing folder.');
  121. }
  122. // Make sure that path to the target exists before moving.
  123. self::mkdir(dirname($target));
  124. // Just rename the directory.
  125. $success = @rename($source, $target);
  126. if (!$success) {
  127. $error = error_get_last();
  128. throw new \RuntimeException($error['message']);
  129. }
  130. // Make sure that the change will be detected when caching.
  131. @touch(dirname($source));
  132. @touch(dirname($target));
  133. }
  134. /**
  135. * Recursively delete directory from filesystem.
  136. *
  137. * @param string $target
  138. * @throws \RuntimeException
  139. */
  140. public static function delete($target)
  141. {
  142. if (!is_dir($target)) {
  143. throw new \RuntimeException('Cannot delete non-existing folder.');
  144. }
  145. $success = self::doDelete($target);
  146. if (!$success) {
  147. $error = error_get_last();
  148. throw new \RuntimeException($error['message']);
  149. }
  150. // Make sure that the change will be detected when caching.
  151. @touch(dirname($target));
  152. }
  153. /**
  154. * @param string $folder
  155. * @return bool
  156. * @internal
  157. */
  158. protected static function doDelete($folder)
  159. {
  160. // Special case for symbolic links.
  161. if (is_link($folder)) {
  162. return @unlink($folder);
  163. }
  164. // Go through all items in filesystem and recursively remove everything.
  165. $files = array_diff(scandir($folder), array('.', '..'));
  166. foreach ($files as $file) {
  167. $path = "{$folder}/{$file}";
  168. (is_dir($path)) ? self::doDelete($path) : @unlink($path);
  169. }
  170. return @rmdir($folder);
  171. }
  172. /**
  173. * @param string $folder
  174. * @throws \RuntimeException
  175. * @internal
  176. */
  177. protected static function mkdir($folder)
  178. {
  179. if (is_dir($folder)) {
  180. return;
  181. }
  182. $success = @mkdir($folder, 0777, true);
  183. if (!$success) {
  184. $error = error_get_last();
  185. throw new \RuntimeException($error['message']);
  186. }
  187. }
  188. }