Filesystem.php 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. <?php
  2. namespace Symfony\Bundle\FrameworkBundle\Util;
  3. /*
  4. * This file is part of the Symfony framework.
  5. *
  6. * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
  7. *
  8. * This source file is subject to the MIT license that is bundled
  9. * with this source code in the file LICENSE.
  10. */
  11. /**
  12. * Provides basic utility to manipulate the file system.
  13. *
  14. * @author Fabien Potencier <fabien.potencier@symfony-project.com>
  15. */
  16. class Filesystem
  17. {
  18. /**
  19. * Copies a file.
  20. *
  21. * This method only copies the file if the origin file is newer than the target file.
  22. *
  23. * By default, if the target already exists, it is not overridden.
  24. *
  25. * To override existing files, pass the "override" option.
  26. *
  27. * @param string $originFile The original filename
  28. * @param string $targetFile The target filename
  29. * @param array $options An array of options
  30. */
  31. public function copy($originFile, $targetFile, $options = array())
  32. {
  33. if (!array_key_exists('override', $options)) {
  34. $options['override'] = false;
  35. }
  36. $this->mkdirs(dirname($targetFile));
  37. $mostRecent = false;
  38. if (file_exists($targetFile)) {
  39. $statTarget = stat($targetFile);
  40. $stat_origin = stat($originFile);
  41. $mostRecent = ($stat_origin['mtime'] > $statTarget['mtime']) ? true : false;
  42. }
  43. if ($options['override'] || !file_exists($targetFile) || $mostRecent) {
  44. copy($originFile, $targetFile);
  45. }
  46. }
  47. /**
  48. * Creates a directory recursively.
  49. *
  50. * @param string $path The directory path
  51. * @param int $mode The directory mode
  52. *
  53. * @return bool true if the directory has been created, false otherwise
  54. */
  55. public function mkdirs($path, $mode = 0777)
  56. {
  57. if (is_dir($path)) {
  58. return true;
  59. }
  60. return @mkdir($path, $mode, true);
  61. }
  62. /**
  63. * Creates empty files.
  64. *
  65. * @param mixed $files The filename, or an array of filenames
  66. */
  67. public function touch($files)
  68. {
  69. if (!is_array($files)) {
  70. $files = array($files);
  71. }
  72. foreach ($files as $file) {
  73. touch($file);
  74. }
  75. }
  76. /**
  77. * Removes files or directories.
  78. *
  79. * @param mixed $files A filename or an array of files to remove
  80. */
  81. public function remove($files)
  82. {
  83. if (!is_array($files)) {
  84. $files = array($files);
  85. }
  86. $files = array_reverse($files);
  87. foreach ($files as $file) {
  88. if (!file_exists($file)) {
  89. continue;
  90. }
  91. if (is_dir($file) && !is_link($file)) {
  92. $fp = opendir($file);
  93. while (false !== $item = readdir($fp)) {
  94. if (!in_array($item, array('.', '..'))) {
  95. $this->remove($file.'/'.$item);
  96. }
  97. }
  98. closedir($fp);
  99. rmdir($file);
  100. } else {
  101. unlink($file);
  102. }
  103. }
  104. }
  105. /**
  106. * Change mode for an array of files or directories.
  107. *
  108. * @param array $files An array of files or directories
  109. * @param integer $mode The new mode
  110. * @param integer $umask The mode mask (octal)
  111. */
  112. public function chmod($files, $mode, $umask = 0000)
  113. {
  114. $currentUmask = umask();
  115. umask($umask);
  116. if (!is_array($files)) {
  117. $files = array($files);
  118. }
  119. foreach ($files as $file) {
  120. chmod($file, $mode);
  121. }
  122. umask($currentUmask);
  123. }
  124. /**
  125. * Renames a file.
  126. *
  127. * @param string $origin The origin filename
  128. * @param string $target The new filename
  129. *
  130. * @throws \RuntimeException When target file already exists
  131. */
  132. public function rename($origin, $target)
  133. {
  134. // we check that target does not exist
  135. if (is_readable($target)) {
  136. throw new \RuntimeException(sprintf('Cannot rename because the target "%" already exist.', $target));
  137. }
  138. rename($origin, $target);
  139. }
  140. /**
  141. * Creates a symbolic link or copy a directory.
  142. *
  143. * @param string $originDir The origin directory path
  144. * @param string $targetDir The symbolic link name
  145. * @param bool $copyOnWindows Whether to copy files if on windows
  146. */
  147. public function symlink($originDir, $targetDir, $copyOnWindows = false)
  148. {
  149. if (!function_exists('symlink') && $copyOnWindows) {
  150. $this->mirror($originDir, $targetDir);
  151. return;
  152. }
  153. $ok = false;
  154. if (is_link($targetDir)) {
  155. if (readlink($targetDir) != $originDir) {
  156. unlink($targetDir);
  157. } else {
  158. $ok = true;
  159. }
  160. }
  161. if (!$ok) {
  162. symlink($originDir, $targetDir);
  163. }
  164. }
  165. /**
  166. * Mirrors a directory to another.
  167. *
  168. * @param string $originDir The origin directory
  169. * @param string $targetDir The target directory
  170. * @param \Traversable $iterator A Traversable instance
  171. * @param array $options An array of options (see copy())
  172. *
  173. * @throws \RuntimeException When file type is unknown
  174. */
  175. public function mirror($originDir, $targetDir, \Traversable $iterator = null, $options = array())
  176. {
  177. if (null === $iterator) {
  178. $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($originDir, \FilesystemIterator::SKIP_DOTS), \RecursiveIteratorIterator::SELF_FIRST);
  179. }
  180. if ('/' === substr($targetDir, -1) || '\\' === substr($targetDir, -1)) {
  181. $targetDir = substr($targetDir, 0, -1);
  182. }
  183. if ('/' === substr($originDir, -1) || '\\' === substr($originDir, -1)) {
  184. $originDir = substr($originDir, 0, -1);
  185. }
  186. foreach ($iterator as $file) {
  187. $target = $targetDir.'/'.str_replace($originDir.DIRECTORY_SEPARATOR, '', $file->getPathname());
  188. if (is_dir($file)) {
  189. $this->mkdirs($target);
  190. } else if (is_file($file)) {
  191. $this->copy($file, $target, $options);
  192. } else if (is_link($file)) {
  193. $this->symlink($file, $target);
  194. } else {
  195. throw new \RuntimeException(sprintf('Unable to guess "%s" file type.', $file));
  196. }
  197. }
  198. }
  199. }