Filesystem.php 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Bundle\FrameworkBundle\Util;
  11. /**
  12. * Provides basic utility to manipulate the file system.
  13. *
  14. * @author Fabien Potencier <fabien@symfony.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. $statOrigin = stat($originFile);
  41. $mostRecent = $statOrigin['mtime'] > $statTarget['mtime'];
  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 Boolean 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. $fi = new \FilesystemIterator($file);
  93. foreach($fi as $item) {
  94. $this->remove($item->getPathname());
  95. }
  96. rmdir($file);
  97. } else {
  98. unlink($file);
  99. }
  100. }
  101. }
  102. /**
  103. * Change mode for an array of files or directories.
  104. *
  105. * @param array $files An array of files or directories
  106. * @param integer $mode The new mode
  107. * @param integer $umask The mode mask (octal)
  108. */
  109. public function chmod($files, $mode, $umask = 0000)
  110. {
  111. $currentUmask = umask();
  112. umask($umask);
  113. if (!is_array($files)) {
  114. $files = array($files);
  115. }
  116. foreach ($files as $file) {
  117. chmod($file, $mode);
  118. }
  119. umask($currentUmask);
  120. }
  121. /**
  122. * Renames a file.
  123. *
  124. * @param string $origin The origin filename
  125. * @param string $target The new filename
  126. *
  127. * @throws \RuntimeException When target file already exists
  128. */
  129. public function rename($origin, $target)
  130. {
  131. // we check that target does not exist
  132. if (is_readable($target)) {
  133. throw new \RuntimeException(sprintf('Cannot rename because the target "%" already exist.', $target));
  134. }
  135. rename($origin, $target);
  136. }
  137. /**
  138. * Creates a symbolic link or copy a directory.
  139. *
  140. * @param string $originDir The origin directory path
  141. * @param string $targetDir The symbolic link name
  142. * @param Boolean $copyOnWindows Whether to copy files if on windows
  143. */
  144. public function symlink($originDir, $targetDir, $copyOnWindows = false)
  145. {
  146. if (!function_exists('symlink') && $copyOnWindows) {
  147. $this->mirror($originDir, $targetDir);
  148. return;
  149. }
  150. $ok = false;
  151. if (is_link($targetDir)) {
  152. if (readlink($targetDir) != $originDir) {
  153. unlink($targetDir);
  154. } else {
  155. $ok = true;
  156. }
  157. }
  158. if (!$ok) {
  159. symlink($originDir, $targetDir);
  160. }
  161. }
  162. /**
  163. * Mirrors a directory to another.
  164. *
  165. * @param string $originDir The origin directory
  166. * @param string $targetDir The target directory
  167. * @param \Traversable $iterator A Traversable instance
  168. * @param array $options An array of options (see copy())
  169. *
  170. * @throws \RuntimeException When file type is unknown
  171. */
  172. public function mirror($originDir, $targetDir, \Traversable $iterator = null, $options = array())
  173. {
  174. if (null === $iterator) {
  175. $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($originDir, \FilesystemIterator::SKIP_DOTS), \RecursiveIteratorIterator::SELF_FIRST);
  176. }
  177. if ('/' === substr($targetDir, -1) || '\\' === substr($targetDir, -1)) {
  178. $targetDir = substr($targetDir, 0, -1);
  179. }
  180. if ('/' === substr($originDir, -1) || '\\' === substr($originDir, -1)) {
  181. $originDir = substr($originDir, 0, -1);
  182. }
  183. foreach ($iterator as $file) {
  184. $target = $targetDir.'/'.str_replace($originDir.DIRECTORY_SEPARATOR, '', $file->getPathname());
  185. if (is_dir($file)) {
  186. $this->mkdirs($target);
  187. } else if (is_file($file)) {
  188. $this->copy($file, $target, $options);
  189. } else if (is_link($file)) {
  190. $this->symlink($file, $target);
  191. } else {
  192. throw new \RuntimeException(sprintf('Unable to guess "%s" file type.', $file));
  193. }
  194. }
  195. }
  196. }