PageRenderTime 29ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/Ip/Internal/Update/Helper/FileSystem.php

https://gitlab.com/x33n/ImpressPages
PHP | 213 lines | 164 code | 33 blank | 16 comment | 40 complexity | 280daa351bdf52f945191965f6086cbd MD5 | raw file
  1. <?php
  2. /**
  3. * @package ImpressPages
  4. *
  5. */
  6. namespace Ip\Internal\Update\Helper;
  7. class FileSystem
  8. {
  9. public function createWritableDir($dir)
  10. {
  11. if (substr($dir, 0, 1) != '/' && $dir[1] != ':') { // Check if absolute path: '/' for unix, 'C:' for Windows
  12. throw new \Ip\Internal\Update\UpdateException('Absolute path required');
  13. }
  14. if ($dir == '/' && !is_writable($dir)) {
  15. $this->throwWritePermissionsError($dir);
  16. }
  17. $dir = $this->removeTrailingSlash($dir); //remove trailing slash
  18. $parentDir = $this->getParentDir($dir);
  19. if (!file_exists($parentDir) || !is_dir($parentDir)) {
  20. $this->createWritableDir($parentDir);
  21. }
  22. if (!is_writable($parentDir)) {
  23. $this->throwWritePermissionsError($parentDir);
  24. }
  25. if (!file_exists($dir)) {
  26. mkdir($dir);
  27. } else {
  28. $this->makeWritable($dir);
  29. }
  30. }
  31. /**
  32. * Make directory or file and all subdirs and files writable
  33. * @param string $path
  34. * @param int $permissions eg 0755. ZERO IS REQUIRED. Applied only to files and folders that are not writable.
  35. * @return boolean
  36. */
  37. function makeWritable($path, $permissions = null)
  38. {
  39. if ($permissions == null) {
  40. $permissions = $this->getParentPermissions($path);
  41. }
  42. $answer = true;
  43. if (!file_exists($path)) {
  44. return false;
  45. }
  46. if (!is_writable($path)) {
  47. $oldErrorHandler = set_error_handler(array('Ip\Internal\Update\Helper\FileSystem', 'handleError'));
  48. try {
  49. $originalIpErrorHandler = set_error_handler('Ip\Internal\ErrorHandler::ipSilentErrorHandler');
  50. chmod($path, $permissions);
  51. set_error_handler($originalIpErrorHandler);
  52. } catch (FileSystemException $e) {
  53. //do nothing. This is just the way to avoid warnings
  54. }
  55. set_error_handler($oldErrorHandler);
  56. if (!is_writable($path)) {
  57. $this->throwWritePermissionsError($path);
  58. }
  59. }
  60. if (is_dir($path)) {
  61. $path = $this->removeTrailingSlash($path);
  62. if ($handle = opendir($path)) {
  63. while (false !== ($file = readdir($handle))) {
  64. if ($file == ".." || $file == ".") {
  65. continue;
  66. }
  67. if (is_dir($path . '/' . $file)) {
  68. $this->makeWritable($path . '/' . $file, $permissions);
  69. } else {
  70. if (!is_writable($path . '/' . $file)) {
  71. chmod($path . '/' . $file, $permissions);
  72. }
  73. if (!is_writable($path . '/' . $file)) {
  74. $this->throwWritePermissionsError($path . '/' . $file);
  75. }
  76. }
  77. }
  78. closedir($handle);
  79. }
  80. }
  81. return $answer;
  82. }
  83. public function rm($dir)
  84. {
  85. if (!file_exists($dir)) {
  86. return;
  87. }
  88. $originalIpErrorHandler = set_error_handler('Ip\Internal\ErrorHandler::ipSilentErrorHandler');
  89. chmod($dir, 0777);
  90. set_error_handler($originalIpErrorHandler);
  91. if (!is_writable($dir)) {
  92. throw new \Ip\Internal\Update\UpdateException("Directory is not writable: " . $dir);
  93. }
  94. if (is_dir($dir)) {
  95. if ($handle = opendir($dir)) {
  96. while (false !== ($file = readdir($handle))) {
  97. if ($file == ".." || $file == ".") {
  98. continue;
  99. }
  100. $this->rm($dir . '/' . $file);
  101. }
  102. closedir($handle);
  103. }
  104. rmdir($dir);
  105. } else {
  106. unlink($dir);
  107. }
  108. }
  109. /**
  110. * Remove everything from dir. Make it empty
  111. * @var string $dir
  112. * @throws \Ip\Internal\Update\UpdateException
  113. */
  114. public function clean($dir)
  115. {
  116. if (!file_exists($dir) || !is_dir($dir)) {
  117. throw new \Ip\Internal\Update\UpdateException("Directory doesn't exist: " . $dir);
  118. }
  119. if ($handle = opendir($dir)) {
  120. while (false !== ($file = readdir($handle))) {
  121. if ($file == ".." || $file == ".") {
  122. continue;
  123. }
  124. $this->rm($dir . '/' . $file);
  125. }
  126. closedir($handle);
  127. }
  128. }
  129. /**
  130. * This is special copy. It copies all content from source into destination directory. But not the source folder it self.
  131. * @param string $source
  132. * @param string $dest
  133. * @throws \Exception
  134. */
  135. public function cpContent($source, $dest)
  136. {
  137. if (!is_dir($source) || !is_dir($dest)) {
  138. throw new \Ip\Internal\Update\UpdateException("Source or destination is not a folder. Source: " . $source . ". Destination: " . $dest . "");
  139. }
  140. $dir_handle = opendir($source);
  141. while ($file = readdir($dir_handle)) {
  142. if ($file != "." && $file != "..") {
  143. if (is_dir($source . "/" . $file)) {
  144. mkdir($dest . "/" . $file);
  145. $this->cpContent($source . "/" . $file, $dest . "/" . $file);
  146. } else {
  147. copy($source . "/" . $file, $dest . "/" . $file);
  148. }
  149. }
  150. }
  151. closedir($dir_handle);
  152. }
  153. public function getParentDir($path)
  154. {
  155. $path = $this->removeTrailingSlash($path);
  156. $parentDir = substr($path, 0, strrpos($path, '/') + 1);
  157. return $parentDir;
  158. }
  159. private function throwWritePermissionsError($dir)
  160. {
  161. throw new \Ip\Internal\Update\UpdateException("Can't write directory " . $dir);
  162. }
  163. private function getParentPermissions($path)
  164. {
  165. return fileperms($this->getParentDir($path));
  166. }
  167. private function removeTrailingSlash($path)
  168. {
  169. return preg_replace('{/$}', '', $path);
  170. }
  171. public static function handleError($errno, $errstr, $errfile, $errline, array $errcontext)
  172. {
  173. throw new \Ip\Internal\Update\UpdateException($errstr);
  174. }
  175. }