[TASK] Inject cache into IconRegistry
[Packages/TYPO3.CMS.git] / typo3 / sysext / install / Classes / FolderStructure / AbstractNode.php
1 <?php
2
3 /*
4 * This file is part of the TYPO3 CMS project.
5 *
6 * It is free software; you can redistribute it and/or modify it under
7 * the terms of the GNU General Public License, either version 2
8 * of the License, or any later version.
9 *
10 * For the full copyright and license information, please read the
11 * LICENSE.txt file that was distributed with this source code.
12 *
13 * The TYPO3 project - inspiring people to share!
14 */
15
16 namespace TYPO3\CMS\Install\FolderStructure;
17
18 use TYPO3\CMS\Core\Core\Environment;
19 use TYPO3\CMS\Core\Messaging\FlashMessage;
20 use TYPO3\CMS\Install\FolderStructure\Exception\InvalidArgumentException;
21
22 /**
23 * Abstract node implements common methods
24 * @internal This class is only meant to be used within EXT:install and is not part of the TYPO3 Core API.
25 */
26 abstract class AbstractNode
27 {
28 /**
29 * @var string Name
30 */
31 protected $name = '';
32
33 /**
34 * @var string|null Target permissions for unix, eg. '2775' or '0664' (4 characters string)
35 */
36 protected $targetPermission;
37
38 /**
39 * @var NodeInterface|null Parent object of this structure node
40 */
41 protected $parent;
42
43 /**
44 * @var array Directories and root may have children, files and link always empty array
45 */
46 protected $children = [];
47
48 /**
49 * Get name
50 *
51 * @return string Name
52 */
53 public function getName()
54 {
55 return $this->name;
56 }
57
58 /**
59 * Get target permission
60 *
61 * Make sure to call octdec on the value when passing this to chmod
62 *
63 * @return string Permissions as a 4 character octal string, i.e. 2775 or 0644
64 */
65 protected function getTargetPermission()
66 {
67 return $this->targetPermission;
68 }
69
70 /**
71 * Set target permission
72 *
73 * @param string $permission Permissions as a 4 character octal string, i.e. 2775 or 0644
74 */
75 protected function setTargetPermission($permission)
76 {
77 // Normalize the permission string to "4 characters", padding with leading "0" if necessary:
78 $permission = substr($permission, 0, 4);
79 $permission = str_pad($permission, 4, '0', STR_PAD_LEFT);
80 $this->targetPermission = $permission;
81 }
82
83 /**
84 * Get children
85 *
86 * @return array
87 */
88 protected function getChildren()
89 {
90 return $this->children;
91 }
92
93 /**
94 * Get parent
95 *
96 * @return NodeInterface|null
97 */
98 protected function getParent()
99 {
100 return $this->parent;
101 }
102
103 /**
104 * Get absolute path of node
105 *
106 * @return string
107 */
108 public function getAbsolutePath()
109 {
110 return $this->getParent()->getAbsolutePath() . '/' . $this->name;
111 }
112
113 /**
114 * Current node is writable if parent is writable
115 *
116 * @return bool TRUE if parent is writable
117 */
118 public function isWritable()
119 {
120 return $this->getParent()->isWritable();
121 }
122
123 /**
124 * Checks if node exists.
125 * Returns TRUE if it is there, even if it is only a link.
126 * Does not check the type!
127 *
128 * @return bool
129 */
130 protected function exists()
131 {
132 if (@is_link($this->getAbsolutePath())) {
133 return true;
134 }
135 return @file_exists($this->getAbsolutePath());
136 }
137
138 /**
139 * Fix permission if they are not equal to target permission
140 *
141 * @throws Exception
142 * @return FlashMessage
143 */
144 protected function fixPermission(): FlashMessage
145 {
146 if ($this->isPermissionCorrect()) {
147 throw new Exception(
148 'Permission on ' . $this->getAbsolutePath() . ' are already ok',
149 1366744035
150 );
151 }
152 $result = @chmod($this->getAbsolutePath(), octdec($this->getTargetPermission()));
153 if ($result === true) {
154 return new FlashMessage(
155 '',
156 'Fixed permission on ' . $this->getRelativePathBelowSiteRoot() . '.'
157 );
158 }
159 return new FlashMessage(
160 'Permissions could not be changed to ' . $this->getTargetPermission()
161 . '. This only is a problem if files and folders within this node cannot be written.',
162 'Permission change on ' . $this->getRelativePathBelowSiteRoot() . ' not successful',
163 FlashMessage::NOTICE
164 );
165 }
166
167 /**
168 * Checks if current permission are identical to target permission
169 *
170 * @return bool
171 */
172 protected function isPermissionCorrect()
173 {
174 if ($this->isWindowsOs()) {
175 return true;
176 }
177 if ($this->getCurrentPermission() === $this->getTargetPermission()) {
178 return true;
179 }
180 return false;
181 }
182
183 /**
184 * Get current permission of node
185 *
186 * @return string eg. 2775 for dirs, 0664 for files
187 */
188 protected function getCurrentPermission()
189 {
190 $permissions = decoct((int)fileperms($this->getAbsolutePath()));
191 return substr($permissions, -4);
192 }
193
194 /**
195 * Returns TRUE if OS is windows
196 *
197 * @return bool TRUE on windows
198 */
199 protected function isWindowsOs()
200 {
201 return Environment::isWindows();
202 }
203
204 /**
205 * Cut off project path from given path
206 *
207 * @param string $path Given path
208 * @return string Relative path, but beginning with /
209 * @throws Exception\InvalidArgumentException
210 */
211 protected function getRelativePathBelowSiteRoot($path = null)
212 {
213 if ($path === null) {
214 $path = $this->getAbsolutePath();
215 }
216 $projectPath = Environment::getProjectPath();
217 if (strpos($path, $projectPath, 0) !== 0) {
218 throw new InvalidArgumentException(
219 'Public path is not first part of given path',
220 1366398198
221 );
222 }
223 $relativePath = substr($path, strlen($projectPath), strlen($path));
224 // Add a forward slash again, so we don't end up with an empty string
225 if ($relativePath === '') {
226 $relativePath = '/';
227 }
228 return $relativePath;
229 }
230 }